Merge "Added /reports, /reports/domains, /reports/records & /reports/tenants"
This commit is contained in:
commit
1d1fcd608b
@ -62,7 +62,7 @@ default_log_levels = amqplib=WARN, sqlalchemy=WARN, boto=WARN, suds=INFO, keysto
|
||||
#auth_strategy = noauth
|
||||
|
||||
# Enabled API Version 1 extensions
|
||||
#enabled_extensions_v1 = diagnostics, sync, import, export
|
||||
#enabled_extensions_v1 = diagnostics, sync, import, export, reports
|
||||
|
||||
#-----------------------
|
||||
# Agent Service
|
||||
|
@ -33,6 +33,10 @@
|
||||
"use_sudo": "rule:admin",
|
||||
"use_blacklisted_domain": "rule:admin",
|
||||
|
||||
"count_domains": "rule:admin",
|
||||
"count_records": "rule:admin",
|
||||
"count_tenants": "rule:admin",
|
||||
|
||||
"diagnostics_ping": "rule:admin",
|
||||
"diagnostics_sync_domains": "rule:admin",
|
||||
"diagnostics_sync_domain": "rule:admin",
|
||||
|
92
moniker/api/v1/extensions/reports.py
Normal file
92
moniker/api/v1/extensions/reports.py
Normal file
@ -0,0 +1,92 @@
|
||||
# Copyright 2012 Hewlett-Packard Development Company, L.P. All Rights Reserved.
|
||||
#
|
||||
# Author: Simon McCartney <simon.mccartney@hp.com>
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
import flask
|
||||
from moniker.openstack.common import log as logging
|
||||
from moniker.openstack.common.rpc import common as rpc_common
|
||||
|
||||
from moniker import exceptions
|
||||
from moniker.central import api as central_api
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
blueprint = flask.Blueprint('reports', __name__)
|
||||
|
||||
|
||||
@blueprint.route('/reports', methods=['GET'])
|
||||
def reports():
|
||||
context = flask.request.environ.get('context')
|
||||
|
||||
try:
|
||||
domains = central_api.count_domains(context)
|
||||
records = central_api.count_records(context)
|
||||
tenants = central_api.count_tenants(context)
|
||||
except exceptions.Forbidden:
|
||||
return flask.Response(status=401)
|
||||
except exceptions.DomainNotFound:
|
||||
return flask.Response(status=404)
|
||||
except rpc_common.Timeout:
|
||||
return flask.Response(status=504)
|
||||
else:
|
||||
return flask.jsonify(domains=int(domains), records=int(records),
|
||||
tenants=int(tenants))
|
||||
|
||||
|
||||
@blueprint.route('/reports/domains', methods=['GET'])
|
||||
def reports_domains():
|
||||
context = flask.request.environ.get('context')
|
||||
|
||||
try:
|
||||
count = central_api.count_domains(context)
|
||||
except exceptions.Forbidden:
|
||||
return flask.Response(status=401)
|
||||
except exceptions.DomainNotFound:
|
||||
return flask.Response(status=404)
|
||||
except rpc_common.Timeout:
|
||||
return flask.Response(status=504)
|
||||
else:
|
||||
return flask.jsonify(domains=int(count))
|
||||
|
||||
|
||||
@blueprint.route('/reports/records', methods=['GET'])
|
||||
def reports_records():
|
||||
context = flask.request.environ.get('context')
|
||||
|
||||
try:
|
||||
count = central_api.count_records(context)
|
||||
except exceptions.Forbidden:
|
||||
return flask.Response(status=401)
|
||||
except exceptions.DomainNotFound:
|
||||
return flask.Response(status=404)
|
||||
except rpc_common.Timeout:
|
||||
return flask.Response(status=504)
|
||||
else:
|
||||
return flask.jsonify(records=int(count))
|
||||
|
||||
|
||||
@blueprint.route('/reports/tenants', methods=['GET'])
|
||||
def reports_tenants():
|
||||
context = flask.request.environ.get('context')
|
||||
|
||||
try:
|
||||
count = central_api.count_tenants(context)
|
||||
except exceptions.Forbidden:
|
||||
return flask.Response(status=401)
|
||||
except exceptions.DomainNotFound:
|
||||
return flask.Response(status=404)
|
||||
except rpc_common.Timeout:
|
||||
return flask.Response(status=504)
|
||||
else:
|
||||
LOG.debug(count)
|
||||
return flask.jsonify(tenants=int(count))
|
@ -206,6 +206,17 @@ def delete_domain(context, domain_id):
|
||||
return RPC.call(context, msg)
|
||||
|
||||
|
||||
def count_domains(context, criterion=None):
|
||||
msg = {
|
||||
'method': 'count_domains',
|
||||
'args': {
|
||||
'criterion': criterion,
|
||||
},
|
||||
}
|
||||
|
||||
return RPC.call(context, msg)
|
||||
|
||||
|
||||
def get_domain_servers(context, domain_id):
|
||||
msg = {
|
||||
'method': 'get_domain_servers',
|
||||
@ -283,6 +294,25 @@ def delete_record(context, domain_id, record_id, increment_serial=True):
|
||||
return RPC.call(context, msg)
|
||||
|
||||
|
||||
def count_records(context, criterion=None):
|
||||
msg = {
|
||||
'method': 'count_records',
|
||||
'args': {
|
||||
'criterion': criterion,
|
||||
},
|
||||
}
|
||||
|
||||
return RPC.call(context, msg)
|
||||
|
||||
|
||||
def count_tenants(context):
|
||||
msg = {
|
||||
'method': 'count_tenants',
|
||||
}
|
||||
|
||||
return RPC.call(context, msg)
|
||||
|
||||
|
||||
def sync_domains(context):
|
||||
msg = {
|
||||
'method': 'sync_domains',
|
||||
|
@ -468,6 +468,10 @@ class Service(rpc_service.Service):
|
||||
|
||||
return self.storage.delete_domain(context, domain_id)
|
||||
|
||||
def count_domains(self, context, criterion=None):
|
||||
policy.check('count_domains', context)
|
||||
return self.storage.count_domains(context, criterion)
|
||||
|
||||
def get_domain_servers(self, context, domain_id, criterion=None):
|
||||
domain = self.storage.get_domain(context, domain_id)
|
||||
|
||||
@ -642,6 +646,14 @@ class Service(rpc_service.Service):
|
||||
|
||||
return self.storage.delete_record(context, record_id)
|
||||
|
||||
def count_records(self, context, criterion=None):
|
||||
policy.check('count_records', context)
|
||||
return self.storage.count_records(context, criterion)
|
||||
|
||||
def count_tenants(self, context):
|
||||
policy.check('count_tenants', context)
|
||||
return self.storage.count_tenants(context)
|
||||
|
||||
# Diagnostics Methods
|
||||
def sync_domains(self, context):
|
||||
policy.check('diagnostics_sync_domains', context)
|
||||
|
@ -113,6 +113,14 @@ class Storage(Plugin):
|
||||
:param context: RPC Context.
|
||||
:param domain_id: Domain ID to delete.
|
||||
"""
|
||||
@abc.abstractmethod
|
||||
def count_domains(self, context, criterion=None):
|
||||
"""
|
||||
Count all Domains, across all accounts, applying criteria
|
||||
|
||||
:param context: RPC Context.
|
||||
:param criterion: Criteria to filter by.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def create_record(self, context, domain_id, values):
|
||||
@ -161,6 +169,23 @@ class Storage(Plugin):
|
||||
:param record_id: Record ID to delete
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def count_records(self, context, criterion=None):
|
||||
"""
|
||||
Count records, across all domains unless otherwise specified
|
||||
|
||||
:param context: RPC Context.
|
||||
:param criterion: Criteria to filter by.
|
||||
"""
|
||||
|
||||
@abc.abstractmethod
|
||||
def count_tenants(self, context):
|
||||
"""
|
||||
Count tenants, across all domains
|
||||
|
||||
:param context: RPC Context.
|
||||
"""
|
||||
|
||||
def ping(self, context):
|
||||
""" Ping the Storage connection """
|
||||
return {
|
||||
|
@ -15,6 +15,7 @@
|
||||
# under the License.
|
||||
import time
|
||||
from sqlalchemy.orm import exc
|
||||
from sqlalchemy import distinct
|
||||
from moniker.openstack.common import cfg
|
||||
from moniker.openstack.common import log as logging
|
||||
from moniker import exceptions
|
||||
@ -243,6 +244,11 @@ class SQLAlchemyStorage(base.Storage):
|
||||
|
||||
domain.delete(self.session)
|
||||
|
||||
def count_domains(self, context, criterion=None):
|
||||
query = self.session.query(models.Domain)
|
||||
query = self._apply_criterion(models.Domain, query, criterion)
|
||||
return query.count()
|
||||
|
||||
# Record Methods
|
||||
def create_record(self, context, domain_id, values):
|
||||
record = models.Record()
|
||||
@ -302,6 +308,17 @@ class SQLAlchemyStorage(base.Storage):
|
||||
|
||||
record.delete(self.session)
|
||||
|
||||
def count_records(self, context, criterion=None):
|
||||
query = self.session.query(models.Record)
|
||||
query = self._apply_criterion(models.Record, query, criterion)
|
||||
return query.count()
|
||||
|
||||
# tenants are the owner of domains, count the number of unique tenants
|
||||
# select count(distinct tenant_id) from domains
|
||||
def count_tenants(self, context):
|
||||
return self.session.query(distinct(models.Domain.tenant_id)).count()
|
||||
|
||||
# diagnostics
|
||||
def ping(self, context):
|
||||
start_time = time.time()
|
||||
|
||||
|
@ -899,3 +899,59 @@ class CentralServiceTest(CentralTestCase):
|
||||
with self.assertRaises(exceptions.RecordNotFound):
|
||||
self.central_service.delete_record(context, other_domain['id'],
|
||||
record['id'])
|
||||
|
||||
def test_count_domains(self):
|
||||
# in the beginning, there should be nothing
|
||||
domains = self.central_service.count_domains(self.admin_context)
|
||||
self.assertEqual(domains, 0)
|
||||
|
||||
# Create a single domain
|
||||
self.create_domain()
|
||||
|
||||
# count 'em up
|
||||
domains = self.central_service.count_domains(self.admin_context)
|
||||
|
||||
# well, did we get 1?
|
||||
self.assertEqual(domains, 1)
|
||||
|
||||
def test_count_domains_admin_only(self):
|
||||
with self.assertRaises(exceptions.Forbidden):
|
||||
self.central_service.count_domains(self.get_context())
|
||||
|
||||
def test_count_records(self):
|
||||
# in the beginning, there should be nothing
|
||||
records = self.central_service.count_records(self.admin_context)
|
||||
self.assertEqual(records, 0)
|
||||
|
||||
# Create a domain to put our record in
|
||||
domain = self.create_domain()
|
||||
|
||||
# Create a record
|
||||
self.create_record(domain)
|
||||
|
||||
# we should have 1 record now
|
||||
records = self.central_service.count_domains(self.admin_context)
|
||||
self.assertEqual(records, 1)
|
||||
|
||||
def test_count_records_admin_only(self):
|
||||
with self.assertRaises(exceptions.Forbidden):
|
||||
self.central_service.count_records(self.get_context())
|
||||
|
||||
def test_count_tenants(self):
|
||||
context = self.get_admin_context()
|
||||
# in the beginning, there should be nothing
|
||||
tenants = self.central_service.count_tenants(self.admin_context)
|
||||
self.assertEqual(tenants, 0)
|
||||
|
||||
# Explicitly set a tenant_id
|
||||
context.tenant_id = '1'
|
||||
self.create_domain(fixture=0, context=context)
|
||||
context.tenant_id = '2'
|
||||
self.create_domain(fixture=1, context=context)
|
||||
|
||||
tenants = self.central_service.count_tenants(self.admin_context)
|
||||
self.assertEqual(tenants, 2)
|
||||
|
||||
def test_count_tenants_admin_only(self):
|
||||
with self.assertRaises(exceptions.Forbidden):
|
||||
self.central_service.count_tenants(self.get_context())
|
||||
|
@ -607,3 +607,42 @@ class StorageTestCase(TestCase):
|
||||
|
||||
self.assertEqual(pong['status'], True)
|
||||
self.assertIsNotNone(pong['rtt'])
|
||||
|
||||
def test_count_domains(self):
|
||||
# in the beginning, there should be nothing
|
||||
domains = self.storage.count_domains(self.admin_context)
|
||||
self.assertEqual(domains, 0)
|
||||
|
||||
# Create a single domain
|
||||
self.create_domain()
|
||||
|
||||
# count 'em up
|
||||
domains = self.storage.count_domains(self.admin_context)
|
||||
|
||||
# well, did we get 1?
|
||||
self.assertEqual(domains, 1)
|
||||
|
||||
def test_count_records(self):
|
||||
# in the beginning, there should be nothing
|
||||
records = self.storage.count_records(self.admin_context)
|
||||
self.assertEqual(records, 0)
|
||||
|
||||
# Create a single domain & record
|
||||
_, domain = self.create_domain()
|
||||
self.create_record(domain)
|
||||
|
||||
# we should have 1 record now
|
||||
records = self.storage.count_domains(self.admin_context)
|
||||
self.assertEqual(records, 1)
|
||||
|
||||
def test_count_tenants(self):
|
||||
# in the beginning, there should be nothing
|
||||
tenants = self.storage.count_tenants(self.admin_context)
|
||||
self.assertEqual(tenants, 0)
|
||||
|
||||
# create 2 domains with 2 tenants
|
||||
self.create_domain(fixture=0, values={'tenant_id': 1})
|
||||
self.create_domain(fixture=1, values={'tenant_id': 2})
|
||||
|
||||
tenants = self.storage.count_tenants(self.admin_context)
|
||||
self.assertEqual(tenants, 2)
|
||||
|
1
setup.py
1
setup.py
@ -66,6 +66,7 @@ setup(
|
||||
[moniker.api.v1.extensions]
|
||||
diagnostics = moniker.api.v1.extensions.diagnostics:blueprint
|
||||
sync = moniker.api.v1.extensions.sync:blueprint
|
||||
reports = moniker.api.v1.extensions.reports:blueprint
|
||||
|
||||
[moniker.storage]
|
||||
sqlalchemy = moniker.storage.impl_sqlalchemy:SQLAlchemyStorage
|
||||
|
Loading…
x
Reference in New Issue
Block a user