diff --git a/openstack_dashboard/api/__init__.py b/openstack_dashboard/api/__init__.py index 4f510ff68d..6ca3e45ace 100644 --- a/openstack_dashboard/api/__init__.py +++ b/openstack_dashboard/api/__init__.py @@ -32,7 +32,6 @@ shouldn't need to understand the finer details of APIs for Keystone/Nova/Glance/Swift et. al. """ from openstack_dashboard.api import base -from openstack_dashboard.api import ceilometer from openstack_dashboard.api import cinder from openstack_dashboard.api import fwaas from openstack_dashboard.api import glance @@ -56,6 +55,5 @@ __all__ = [ "neutron", "nova", "swift", - "ceilometer", "vpn", ] diff --git a/openstack_dashboard/api/ceilometer.py b/openstack_dashboard/api/ceilometer.py deleted file mode 100644 index deaf6ec11d..0000000000 --- a/openstack_dashboard/api/ceilometer.py +++ /dev/null @@ -1,1345 +0,0 @@ -# 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. - -from collections import OrderedDict -import threading - -from ceilometerclient import client as ceilometer_client -from django.conf import settings -from django.utils.translation import ugettext_lazy as _ - -from horizon import exceptions -from horizon.utils.memoized import memoized # noqa - -from openstack_dashboard.api import base -from openstack_dashboard.api import keystone - - -def is_iterable(var): - """Return True if the given is list or tuple.""" - - return (isinstance(var, (list, tuple)) or - issubclass(var.__class__, (list, tuple))) - - -def make_query(user_id=None, tenant_id=None, resource_id=None, - user_ids=None, tenant_ids=None, resource_ids=None): - """Returns query built from given parameters. - - This query can be then used for querying resources, meters and - statistics. - - :Parameters: - - `user_id`: user_id, has a priority over list of ids - - `tenant_id`: tenant_id, has a priority over list of ids - - `resource_id`: resource_id, has a priority over list of ids - - `user_ids`: list of user_ids - - `tenant_ids`: list of tenant_ids - - `resource_ids`: list of resource_ids - """ - user_ids = user_ids or [] - tenant_ids = tenant_ids or [] - resource_ids = resource_ids or [] - - query = [] - if user_id: - user_ids = [user_id] - for u_id in user_ids: - query.append({"field": "user_id", "op": "eq", "value": u_id}) - - if tenant_id: - tenant_ids = [tenant_id] - for t_id in tenant_ids: - query.append({"field": "project_id", "op": "eq", "value": t_id}) - - if resource_id: - resource_ids = [resource_id] - for r_id in resource_ids: - query.append({"field": "resource_id", "op": "eq", "value": r_id}) - - return query - - -class Meter(base.APIResourceWrapper): - """Represents one Ceilometer meter.""" - _attrs = ['name', 'type', 'unit', 'resource_id', 'user_id', 'project_id'] - - def __init__(self, apiresource): - super(Meter, self).__init__(apiresource) - - self._label = self.name - self._description = "" - - def augment(self, label=None, description=None): - if label: - self._label = label - if description: - self._description = description - - @property - def description(self): - return self._description - - @property - def label(self): - return self._label - - -class Resource(base.APIResourceWrapper): - """Represents one Ceilometer resource.""" - _attrs = ['resource_id', 'source', 'user_id', 'project_id', 'metadata', - 'links'] - - def __init__(self, apiresource, ceilometer_usage=None): - super(Resource, self).__init__(apiresource) - - # Save empty strings to IDs rather than None, so it gets - # serialized correctly. We don't want 'None' strings. - self.project_id = self.project_id or "" - self.user_id = self.user_id or "" - self.resource_id = self.resource_id or "" - - self._id = "%s__%s__%s" % (self.project_id, - self.user_id, - self.resource_id) - - # Meters with statistics data - self._meters = {} - - # TODO(lsmola) make parallel obtaining of tenant and user - # make the threading here, thread join into resource_list - if ceilometer_usage and self.project_id: - self._tenant = ceilometer_usage.get_tenant(self.project_id) - else: - self._tenant = None - - if ceilometer_usage and self.user_id: - self._user = ceilometer_usage.get_user(self.user_id) - else: - self._user = None - - self._query = make_query(tenant_id=self.project_id, - user_id=self.user_id, - resource_id=self.resource_id) - - @property - def name(self): - name = self.metadata.get("name", None) - display_name = self.metadata.get("display_name", None) - return name or display_name or "" - - @property - def id(self): - return self._id - - @property - def tenant(self): - return self._tenant - - @property - def user(self): - return self._user - - @property - def resource(self): - return self.resource_id - - @property - def query(self): - return self._query - - @property - def meters(self): - return self._meters - - def get_meter(self, meter_name): - return self._meters.get(meter_name, None) - - def set_meter(self, meter_name, value): - self._meters[meter_name] = value - - -class ResourceAggregate(Resource): - """Represents aggregate of more resources together. - - Aggregate of resources can be obtained by specifying - multiple ids in one parameter or by not specifying - one parameter. - It can also be specified by query directly. - - Example: - We can obtain an aggregate of resources by specifying - multiple resource_ids in resource_id parameter in init. - Or we can specify only tenant_id, which will return - all resources of that tenant. - """ - - def __init__(self, tenant_id=None, user_id=None, resource_id=None, - tenant_ids=None, user_ids=None, resource_ids=None, - ceilometer_usage=None, query=None, identifier=None): - - self._id = identifier - - self.tenant_id = None - self.user_id = None - self.resource_id = None - - # Meters with statistics data - self._meters = {} - - if query: - self._query = query - else: - # TODO(lsmola) make parallel obtaining of tenant and user - # make the threading here, thread join into resource_list - if ceilometer_usage and tenant_id: - self.tenant_id = tenant_id - self._tenant = ceilometer_usage.get_tenant(tenant_id) - else: - self._tenant = None - - if ceilometer_usage and user_id: - self.user_id = user_id - self._user = ceilometer_usage.get_user(user_id) - else: - self._user = None - - if resource_id: - self.resource_id = resource_id - - self._query = make_query(tenant_id=tenant_id, user_id=user_id, - resource_id=resource_id, - tenant_ids=tenant_ids, - user_ids=user_ids, - resource_ids=resource_ids) - - @property - def id(self): - return self._id - - -class Sample(base.APIResourceWrapper): - """Represents one Ceilometer sample.""" - - _attrs = ['counter_name', 'user_id', 'resource_id', 'timestamp', - 'resource_metadata', 'source', 'counter_unit', 'counter_volume', - 'project_id', 'counter_type', 'resource_metadata'] - - @property - def instance(self): - display_name = self.resource_metadata.get('display_name', None) - instance_id = self.resource_metadata.get('instance_id', None) - return display_name or instance_id - - @property - def name(self): - name = self.resource_metadata.get("name", None) - display_name = self.resource_metadata.get("display_name", None) - return name or display_name or "" - - -class Statistic(base.APIResourceWrapper): - """Represents one Ceilometer statistic.""" - - _attrs = ['period', 'period_start', 'period_end', - 'count', 'min', 'max', 'sum', 'avg', - 'duration', 'duration_start', 'duration_end'] - - -class Alarm(base.APIResourceWrapper): - """Represents one Ceilometer alarm.""" - _attrs = ['alarm_actions', 'ok_actions', 'name', - 'timestamp', 'description', 'time_constraints', - 'enabled', 'state_timestamp', 'alarm_id', - 'state', 'insufficient_data_actions', - 'repeat_actions', 'user_id', 'project_id', - 'type', 'severity', 'threshold_rule', 'period', 'query', - 'evaluation_periods', 'statistic', 'meter_name', - 'threshold', 'comparison_operator', 'exclude_outliers'] - - def __init__(self, apiresource, ceilometer_usage=None): - super(Alarm, self).__init__(apiresource) - self._tenant = None - self._user = None - - if ceilometer_usage and self.project_id: - self._tenant = ceilometer_usage.get_tenant(self.project_id) - - if ceilometer_usage and self.user_id: - self._user = ceilometer_usage.get_user(self.user_id) - - @property - def id(self): - return self.alarm_id - - @property - def tenant(self): - return self._tenant - - @property - def user(self): - return self._user - - -@memoized -def ceilometerclient(request): - """Initialization of Ceilometer client.""" - - endpoint = base.url_for(request, 'metering') - insecure = getattr(settings, 'OPENSTACK_SSL_NO_VERIFY', False) - cacert = getattr(settings, 'OPENSTACK_SSL_CACERT', None) - return ceilometer_client.Client('2', endpoint, - token=(lambda: request.user.token.id), - insecure=insecure, - cacert=cacert) - - -def alarm_list(request, query=None, ceilometer_usage=None): - """List alarms.""" - alarms = ceilometerclient(request).alarms.list(q=query) - return [Alarm(alarm, ceilometer_usage) for alarm in alarms] - - -def alarm_get(request, alarm_id, ceilometer_usage=None): - """Get an alarm.""" - alarm = ceilometerclient(request).alarms.get(alarm_id) - return Alarm(alarm, ceilometer_usage) - - -def alarm_update(request, alarm_id, ceilometer_usage=None, **kwargs): - """Update an alarm.""" - alarm = ceilometerclient(request).alarms.update(alarm_id, **kwargs) - return Alarm(alarm, ceilometer_usage) - - -def alarm_delete(request, alarm_id): - """Delete an alarm.""" - ceilometerclient(request).alarms.delete(alarm_id) - - -def alarm_create(request, ceilometer_usage=None, **kwargs): - """Create an alarm.""" - alarm = ceilometerclient(request).alarms.create(**kwargs) - return Alarm(alarm, ceilometer_usage) - - -def resource_list(request, query=None, ceilometer_usage_object=None): - """List the resources.""" - resources = ceilometerclient(request).resources.list(q=query) - return [Resource(r, ceilometer_usage_object) for r in resources] - - -def sample_list(request, meter_name, query=None, limit=None): - """List the samples for this meters.""" - samples = ceilometerclient(request).samples.list(meter_name=meter_name, - q=query, limit=limit) - return [Sample(s) for s in samples] - - -def meter_list(request, query=None): - """List the user's meters.""" - meters = ceilometerclient(request).meters.list(query) - return [Meter(m) for m in meters] - - -def statistic_list(request, meter_name, query=None, period=None): - """List of statistics.""" - statistics = ceilometerclient(request).\ - statistics.list(meter_name=meter_name, q=query, period=period) - return [Statistic(s) for s in statistics] - - -class ThreadedUpdateResourceWithStatistics(threading.Thread): - """Multithread wrapper for update_with_statistics method of - resource_usage. - - A join logic is placed in process_list class method. All resources - will have its statistics attribute filled in separate threads. - - The resource_usage object is shared between threads. Each thread is - updating one Resource. - - :Parameters: - - `resource`: Resource or ResourceAggregate object, that will - be filled by statistic data. - - `resources`: List of Resource or ResourceAggregate object, - that will be filled by statistic data. - - `resource_usage`: Wrapping resource usage object, that holds - all statistics data. - - `meter_names`: List of meter names of the statistics we want. - - `period`: In seconds. If no period is given, only one aggregate - statistic is returned. If given, a faceted result will be - returned, divided into given periods. Periods with no - data are ignored. - - `stats_attr`: String representing the attribute name of the stats. - E.g. (avg, max, min...) If None is given, whole - statistic object is returned, - - `additional_query`: Additional query for the statistics. - E.g. timespan, etc. - """ - # TODO(lsmola) Can be removed once Ceilometer supports sample-api - # and group-by, so all of this optimization will not be necessary. - # It is planned somewhere to I. - - def __init__(self, resource_usage, resource, meter_names=None, - period=None, filter_func=None, stats_attr=None, - additional_query=None): - super(ThreadedUpdateResourceWithStatistics, self).__init__() - self.resource_usage = resource_usage - self.resource = resource - self.meter_names = meter_names - self.period = period - self.stats_attr = stats_attr - self.additional_query = additional_query - - def run(self): - # Run the job - self.resource_usage.update_with_statistics( - self.resource, - meter_names=self.meter_names, period=self.period, - stats_attr=self.stats_attr, additional_query=self.additional_query) - - @classmethod - def process_list(cls, resource_usage, resources, meter_names=None, - period=None, filter_func=None, stats_attr=None, - additional_query=None): - threads = [] - - for resource in resources: - # add statistics data into resource - thread = cls(resource_usage, resource, meter_names=meter_names, - period=period, stats_attr=stats_attr, - additional_query=additional_query) - thread.start() - threads.append(thread) - - for thread in threads: - thread.join() - - -class CeilometerUsage(object): - """Represents wrapper of any Ceilometer queries. - - One instance of this class should be shared between resources - as this class provides a place where users and tenants are - cached. So there are no duplicate queries to API. - - This class also wraps Ceilometer API calls and provides parallel - HTTP calls to API. - - This class should also serve as reasonable abstraction, that will - cover huge amount of optimization due to optimization of Ceilometer - service, without changing of the interface. - """ - - def __init__(self, request): - self._request = request - - # Cached users and tenants. - self._users = {} - self._tenants = {} - - def get_user(self, user_id): - """Returns user fetched from API. - - Caching the result, so it doesn't contact API twice with the - same query. - """ - - user = self._users.get(user_id, None) - if not user: - user = keystone.user_get(self._request, user_id) - # caching the user, for later use - self._users[user_id] = user - return user - - def preload_all_users(self): - """Preloads all users into dictionary. - - It's more effective to preload all users, rather than fetching many - users by separate API get calls. - """ - - users = keystone.user_list(self._request) - # Cache all users on right indexes, this is more effective than to - # obtain large number of users one by one by keystone.user_get - for u in users: - self._users[u.id] = u - - def get_tenant(self, tenant_id): - """Returns tenant fetched from API. - - Caching the result, so it doesn't contact API twice with the - same query. - """ - - tenant = self._tenants.get(tenant_id, None) - if not tenant: - tenant = keystone.tenant_get(self._request, tenant_id) - # caching the tenant for later use - self._tenants[tenant_id] = tenant - return tenant - - def preload_all_tenants(self): - """Preloads all tenants into dictionary. - - It's more effective to preload all tenants, rather than fetching each - tenant by separate API get calls. - """ - - tenants, more = keystone.tenant_list(self._request) - # Cache all tenants on right indexes, this is more effective than to - # obtain large number of tenants one by one by keystone.tenant_get - for t in tenants: - self._tenants[t.id] = t - - def global_data_get(self, used_cls=None, query=None, - with_statistics=False, additional_query=None, - with_users_and_tenants=True): - """Obtaining a resources for table view. - - It obtains resources with statistics data according to declaration - in used_cls class. - - :Parameters: - - `user_cls`: Class wrapper for usage data. It acts as wrapper for - settings needed. See the call of this method for - details. - - `query`: Explicit query definition for fetching the resources. If - no query is provided, it takes a default_query from - used_cls. If no default query is provided, it fetches - all the resources and filters them by meters defined - in used_cls. - - `with_statistic`: Define whether statistics data from the meters - defined in used_cls should be fetched. - Can be used to first obtain only the pure - resources, then with the statistics data by - AJAX. - - `additional_query`: Additional query for the statistics. - E.g. timespan, etc. - - `with_users_and_tenants`: If true a user and a tenant object will - be added to each resource object. - """ - - default_query = used_cls.default_query - query = query or default_query - filter_func = None - - def filter_resources(resource): - """Method for filtering resources by their links.rel attr. - - The links.rel attributes contain all meters the resource has. - """ - for link in resource.links: - if link['rel'] in used_cls.meters: - return True - return False - - if not query: - # Not all resource types can be obtained by query, if there is not - # a query, we are filtering all resources by this function. - filter_func = filter_resources - - if with_statistics: - # Will add statistic data into resources. - resources = self.resources_with_statistics( - query, - used_cls.meters, - filter_func=filter_func, - stats_attr=used_cls.stats_attr, - additional_query=additional_query, - with_users_and_tenants=with_users_and_tenants) - else: - # Will load only resources without statistical data. - resources = self.resources( - query, filter_func=filter_func, - with_users_and_tenants=with_users_and_tenants) - - return [used_cls(resource) for resource in resources] - - def query_from_object_id(self, object_id): - """Obtaining a query from resource id. - - Query can be then used to identify a resource in resources or meters - API calls. ID is being built in the Resource initializer, or returned - by Datatable into UpdateRow functionality. - """ - try: - tenant_id, user_id, resource_id = object_id.split("__") - except ValueError: - return [] - - return make_query(tenant_id=tenant_id, user_id=user_id, - resource_id=resource_id) - - def update_with_statistics(self, resource, meter_names=None, period=None, - stats_attr=None, additional_query=None): - """Adding statistical data into one Resource or ResourceAggregate. - - It adds each statistic of each meter_names into the resource - attributes. Attribute name is the meter name with replaced '.' to '_'. - - :Parameters: - - `resource`: Resource or ResourceAggregate object, that will - be filled by statistic data. - - `meter_names`: List of meter names of which we want the - statistics. - - `period`: In seconds. If no period is given, only one aggregate - statistic is returned. If given a faceted result will be - returned, dividend into given periods. Periods with no - data are ignored. - - `stats_attr`: String representing the specific name of the stats. - E.g. (avg, max, min...) If defined, meter attribute - will contain just the one value. If None is given, - meter attribute will contain the whole Statistic - object. - - `additional_query`: Additional query for the statistics. - E.g. timespan, etc. - """ - - if not meter_names: - raise ValueError("meter_names and resources must be defined to be " - "able to obtain the statistics.") - - # query for identifying one resource in meters - query = resource.query - if additional_query: - if not is_iterable(additional_query): - raise ValueError("Additional query must be list of" - " conditions. See the docs for format.") - query = query + additional_query - - # TODO(lsmola) thread for each meter will be probably overkill - # but I should test lets say thread pool with 100 of threads - # and apply it only to this code. - # Though I do expect Ceilometer will support bulk requests, - # so all of this optimization will not be necessary. - for meter in meter_names: - statistics = statistic_list(self._request, meter, - query=query, period=period) - meter = meter.replace(".", "_") - if statistics: - if stats_attr: - # I want to load only a specific attribute - resource.set_meter( - meter, - getattr(statistics[0], stats_attr, None)) - else: - # I want a dictionary of all statistics - resource.set_meter(meter, statistics) - else: - resource.set_meter(meter, None) - - return resource - - def resources(self, query=None, filter_func=None, - with_users_and_tenants=False): - """Obtaining resources with the query or filter_func. - - Obtains resources and also fetch tenants and users associated - with those resources if with_users_and_tenants flag is true. - - :Parameters: - - `query`: Query for fetching the Ceilometer Resources. - - `filter_func`: Callable for filtering of the obtained - resources. - - `with_users_and_tenants`: If true a user and a tenant object will - be added to each resource object. - """ - if with_users_and_tenants: - ceilometer_usage_object = self - else: - ceilometer_usage_object = None - resources = resource_list( - self._request, - query=query, ceilometer_usage_object=ceilometer_usage_object) - if filter_func: - resources = [resource for resource in resources if - filter_func(resource)] - - return resources - - def resources_with_statistics(self, query=None, meter_names=None, - period=None, filter_func=None, - stats_attr=None, additional_query=None, - with_users_and_tenants=False): - """Obtaining resources with statistics data inside. - - :Parameters: - - `query`: Query for fetching the Ceilometer Resources. - - `filter_func`: Callable for filtering of the obtained - resources. - - `meter_names`: List of meter names of which we want the - statistics. - - `period`: In seconds. If no period is given, only one aggregate - statistic is returned. If given, a faceted result will - be returned, divided into given periods. Periods with - no data are ignored. - - `stats_attr`: String representing the specific name of the stats. - E.g. (avg, max, min...) If defined, meter attribute - will contain just the one value. If None is given, - meter attribute will contain the whole Statistic - object. - - `additional_query`: Additional query for the statistics. - E.g. timespan, etc. - - `with_users_and_tenants`: If true a user and a tenant object will - be added to each resource object. - """ - - resources = self.resources( - query, filter_func=filter_func, - with_users_and_tenants=with_users_and_tenants) - - ThreadedUpdateResourceWithStatistics.process_list( - self, resources, - meter_names=meter_names, period=period, stats_attr=stats_attr, - additional_query=additional_query) - - return resources - - def resource_aggregates(self, queries=None): - """Obtaining resource aggregates with queries. - - Representing a resource aggregate by query is a most general way - how to obtain a resource aggregates. - - :Parameters: - - `queries`: Dictionary of named queries that defines a bulk of - resource aggregates. - """ - resource_aggregates = [] - for identifier, query in queries.items(): - resource_aggregates.append(ResourceAggregate(query=query, - ceilometer_usage=None, - identifier=identifier)) - return resource_aggregates - - def resource_aggregates_with_statistics(self, queries=None, - meter_names=None, period=None, - filter_func=None, stats_attr=None, - additional_query=None): - """Obtaining resource aggregates with statistics data inside. - - :Parameters: - - `queries`: Dictionary of named queries that defines a bulk of - resource aggregates. - - `meter_names`: List of meter names of which we want the - statistics. - - `period`: In seconds. If no period is given, only one aggregate - statistic is returned. If given, a faceted result will - be returned, divided into given periods. Periods with - no data are ignored. - - `stats_attr`: String representing the specific name of the stats. - E.g. (avg, max, min...) If defined, meter attribute - will contain just the one value. If None is given, - meter attribute will contain the whole Statistic - object. - - `additional_query`: Additional query for the statistics. - E.g. timespan, etc. - """ - resource_aggregates = self.resource_aggregates(queries) - - ThreadedUpdateResourceWithStatistics.process_list( - self, - resource_aggregates, meter_names=meter_names, period=period, - stats_attr=stats_attr, additional_query=additional_query) - - return resource_aggregates - - -def diff_lists(a, b): - if not a: - return [] - elif not b: - return a - else: - return list(set(a) - set(b)) - - -class Meters(object): - """Class for listing of available meters. - - It is listing meters defined in this class that are available - in Ceilometer meter_list. - - It is storing information that is not available in Ceilometer, i.e. - label, description. - - """ - - def __init__(self, request=None, ceilometer_meter_list=None): - # Storing the request. - self._request = request - - # Storing the Ceilometer meter list - if ceilometer_meter_list: - self._ceilometer_meter_list = ceilometer_meter_list - else: - try: - self._ceilometer_meter_list = meter_list(request) - except Exception: - self._ceilometer_meter_list = [] - exceptions.handle(self._request, - _('Unable to retrieve Ceilometer meter ' - 'list.')) - - # Storing the meters info categorized by their services. - self._nova_meters_info = self._get_nova_meters_info() - self._neutron_meters_info = self._get_neutron_meters_info() - self._glance_meters_info = self._get_glance_meters_info() - self._cinder_meters_info = self._get_cinder_meters_info() - self._swift_meters_info = self._get_swift_meters_info() - self._kwapi_meters_info = self._get_kwapi_meters_info() - self._ipmi_meters_info = self._get_ipmi_meters_info() - - # Storing the meters info of all services together. - all_services_meters = (self._nova_meters_info, - self._neutron_meters_info, - self._glance_meters_info, - self._cinder_meters_info, - self._swift_meters_info, - self._kwapi_meters_info, - self._ipmi_meters_info) - self._all_meters_info = {} - for service_meters in all_services_meters: - self._all_meters_info.update(dict([(meter_name, meter_info) - for meter_name, meter_info - in service_meters.items()])) - - # Here will be the cached Meter objects, that will be reused for - # repeated listing. - self._cached_meters = {} - - def list_all(self, only_meters=None, except_meters=None): - """Returns a list of meters based on the meters names. - - :Parameters: - - `only_meters`: The list of meter names we want to show. - - `except_meters`: The list of meter names we don't want to show. - """ - - return self._list(only_meters=only_meters, - except_meters=except_meters) - - def list_nova(self, except_meters=None): - """Returns a list of meters tied to nova. - - :Parameters: - - `except_meters`: The list of meter names we don't want to show. - """ - - return self._list(only_meters=self._nova_meters_info.keys(), - except_meters=except_meters) - - def list_neutron(self, except_meters=None): - """Returns a list of meters tied to neutron. - - :Parameters: - - `except_meters`: The list of meter names we don't want to show. - """ - - return self._list(only_meters=self._neutron_meters_info.keys(), - except_meters=except_meters) - - def list_glance(self, except_meters=None): - """Returns a list of meters tied to glance. - - :Parameters: - - `except_meters`: The list of meter names we don't want to show. - """ - - return self._list(only_meters=self._glance_meters_info.keys(), - except_meters=except_meters) - - def list_cinder(self, except_meters=None): - """Returns a list of meters tied to cinder. - - :Parameters: - - `except_meters`: The list of meter names we don't want to show. - """ - - return self._list(only_meters=self._cinder_meters_info.keys(), - except_meters=except_meters) - - def list_swift(self, except_meters=None): - """Returns a list of meters tied to swift. - - :Parameters: - - `except_meters`: The list of meter names we don't want to show. - """ - - return self._list(only_meters=self._swift_meters_info.keys(), - except_meters=except_meters) - - def list_kwapi(self, except_meters=None): - """Returns a list of meters tied to kwapi. - - :Parameters: - - `except_meters`: The list of meter names we don't want to show. - """ - - return self._list(only_meters=self._kwapi_meters_info.keys(), - except_meters=except_meters) - - def list_ipmi(self, except_meters=None): - """Returns a list of meters tied to ipmi - - :Parameters: - - `except_meters`: The list of meter names we don't want to show - """ - - return self._list(only_meters=self._ipmi_meters_info.keys(), - except_meters=except_meters) - - def _list(self, only_meters=None, except_meters=None): - """Returns a list of meters based on the meters names. - - :Parameters: - - `only_meters`: The list of meter names we want to show. - - `except_meters`: The list of meter names we don't want to show. - """ - - # Get all wanted meter names. - if only_meters: - meter_names = only_meters - else: - meter_names = [meter_name for meter_name - in self._all_meters_info.keys()] - - meter_names = diff_lists(meter_names, except_meters) - # Collect meters for wanted meter names. - return self._get_meters(meter_names) - - def _get_meters(self, meter_names): - """Obtain meters based on meter_names. - - The meters that do not exist in Ceilometer meter list are left out. - - :Parameters: - - `meter_names`: A list of meter names we want to fetch. - """ - - meters = [] - for meter_name in meter_names: - meter = self._get_meter(meter_name) - if meter: - meters.append(meter) - return meters - - def _get_meter(self, meter_name): - """Obtains a meter. - - Obtains meter either from cache or from Ceilometer meter list - joined with statically defined meter info like label and description. - - :Parameters: - - `meter_name`: A meter name we want to fetch. - """ - meter = self._cached_meters.get(meter_name, None) - if not meter: - meter_candidates = [m for m in self._ceilometer_meter_list - if m.name == meter_name] - - if meter_candidates: - meter_info = self._all_meters_info.get(meter_name, None) - if meter_info: - label = meter_info["label"] - description = meter_info["description"] - else: - label = "" - description = "" - meter = meter_candidates[0] - meter.augment(label=label, description=description) - - self._cached_meters[meter_name] = meter - - return meter - - def _get_nova_meters_info(self): - """Returns additional info for each meter. - - That will be used for augmenting the Ceilometer meter. - """ - - # TODO(lsmola) Unless the Ceilometer will provide the information - # below, I need to define it as a static here. I will be joining this - # to info that I am able to obtain from Ceilometer meters, hopefully - # some day it will be supported all. - meters_info = OrderedDict([ - ("instance", { - 'label': '', - 'description': _("Existence of instance"), - }), - ("instance:", { - 'label': '', - 'description': _("Existence of instance " - "(openstack types)"), - }), - ("memory", { - 'label': '', - 'description': _("Volume of RAM"), - }), - ("memory.usage", { - 'label': '', - 'description': _("Volume of RAM used"), - }), - ("cpu", { - 'label': '', - 'description': _("CPU time used"), - }), - ("cpu_util", { - 'label': '', - 'description': _("Average CPU utilization"), - }), - ("vcpus", { - 'label': '', - 'description': _("Number of VCPUs"), - }), - ("disk.read.requests", { - 'label': '', - 'description': _("Number of read requests"), - }), - ("disk.write.requests", { - 'label': '', - 'description': _("Number of write requests"), - }), - ("disk.read.bytes", { - 'label': '', - 'description': _("Volume of reads"), - }), - ("disk.write.bytes", { - 'label': '', - 'description': _("Volume of writes"), - }), - ("disk.read.requests.rate", { - 'label': '', - 'description': _("Average rate of read requests"), - }), - ("disk.write.requests.rate", { - 'label': '', - 'description': _("Average rate of write requests"), - }), - ("disk.read.bytes.rate", { - 'label': '', - 'description': _("Average rate of reads"), - }), - ("disk.write.bytes.rate", { - 'label': '', - 'description': _("Average volume of writes"), - }), - ("disk.root.size", { - 'label': '', - 'description': _("Size of root disk"), - }), - ("disk.ephemeral.size", { - 'label': '', - 'description': _("Size of ephemeral disk"), - }), - ("network.incoming.bytes", { - 'label': '', - 'description': _("Number of incoming bytes " - "on the network for a VM interface"), - }), - ("network.outgoing.bytes", { - 'label': '', - 'description': _("Number of outgoing bytes " - "on the network for a VM interface"), - }), - ("network.incoming.packets", { - 'label': '', - 'description': _("Number of incoming " - "packets for a VM interface"), - }), - ("network.outgoing.packets", { - 'label': '', - 'description': _("Number of outgoing " - "packets for a VM interface"), - }), - ("network.incoming.bytes.rate", { - 'label': '', - 'description': _("Average rate per sec of incoming " - "bytes on a VM network interface"), - }), - ("network.outgoing.bytes.rate", { - 'label': '', - 'description': _("Average rate per sec of outgoing " - "bytes on a VM network interface"), - }), - ("network.incoming.packets.rate", { - 'label': '', - 'description': _("Average rate per sec of incoming " - "packets on a VM network interface"), - }), - ("network.outgoing.packets.rate", { - 'label': '', - 'description': _("Average rate per sec of outgoing " - "packets on a VM network interface"), - }), - ]) - - # TODO(lsmola) allow to set specific in local_settings. For all meters - # because users can have their own agents and meters. - return meters_info - - def _get_neutron_meters_info(self): - """Returns additional info for each meter. - - That will be used for augmenting the Ceilometer meter. - """ - - # TODO(lsmola) Unless the Ceilometer will provide the information - # below, I need to define it as a static here. I will be joining this - # to info that I am able to obtain from Ceilometer meters, hopefully - # some day it will be supported all. - return OrderedDict([ - ('network', { - 'label': '', - 'description': _("Existence of network"), - }), - ('network.create', { - 'label': '', - 'description': _("Creation requests for this network"), - }), - ('network.update', { - 'label': '', - 'description': _("Update requests for this network"), - }), - ('subnet', { - 'label': '', - 'description': _("Existence of subnet"), - }), - ('subnet.create', { - 'label': '', - 'description': _("Creation requests for this subnet"), - }), - ('subnet.update', { - 'label': '', - 'description': _("Update requests for this subnet"), - }), - ('port', { - 'label': '', - 'description': _("Existence of port"), - }), - ('port.create', { - 'label': '', - 'description': _("Creation requests for this port"), - }), - ('port.update', { - 'label': '', - 'description': _("Update requests for this port"), - }), - ('router', { - 'label': '', - 'description': _("Existence of router"), - }), - ('router.create', { - 'label': '', - 'description': _("Creation requests for this router"), - }), - ('router.update', { - 'label': '', - 'description': _("Update requests for this router"), - }), - ('ip.floating', { - 'label': '', - 'description': _("Existence of floating ip"), - }), - ('ip.floating.create', { - 'label': '', - 'description': _("Creation requests for this floating ip"), - }), - ('ip.floating.update', { - 'label': '', - 'description': _("Update requests for this floating ip"), - }), - ]) - - def _get_glance_meters_info(self): - """Returns additional info for each meter. - - That will be used for augmenting the Ceilometer meter. - """ - - # TODO(lsmola) Unless the Ceilometer will provide the information - # below, I need to define it as a static here. I will be joining this - # to info that I am able to obtain from Ceilometer meters, hopefully - # some day it will be supported all. - return OrderedDict([ - ('image', { - 'label': '', - 'description': _("Image existence check"), - }), - ('image.size', { - 'label': '', - 'description': _("Uploaded image size"), - }), - ('image.update', { - 'label': '', - 'description': _("Number of image updates"), - }), - ('image.upload', { - 'label': '', - 'description': _("Number of image uploads"), - }), - ('image.delete', { - 'label': '', - 'description': _("Number of image deletions"), - }), - ('image.download', { - 'label': '', - 'description': _("Image is downloaded"), - }), - ('image.serve', { - 'label': '', - 'description': _("Image is served out"), - }), - ]) - - def _get_cinder_meters_info(self): - """Returns additional info for each meter. - - That will be used for augmenting the Ceilometer meter. - """ - - # TODO(lsmola) Unless the Ceilometer will provide the information - # below, I need to define it as a static here. I will be joining this - # to info that I am able to obtain from Ceilometer meters, hopefully - # some day it will be supported all. - return OrderedDict([ - ('volume', { - 'label': '', - 'description': _("Existence of volume"), - }), - ('volume.size', { - 'label': '', - 'description': _("Size of volume"), - }), - ]) - - def _get_swift_meters_info(self): - """Returns additional info for each meter. - - That will be used for augmenting the Ceilometer meter. - """ - - # TODO(lsmola) Unless the Ceilometer will provide the information - # below, I need to define it as a static here. I will be joining this - # to info that I am able to obtain from Ceilometer meters, hopefully - # some day it will be supported all. - return OrderedDict([ - ('storage.objects', { - 'label': '', - 'description': _("Number of objects"), - }), - ('storage.objects.size', { - 'label': '', - 'description': _("Total size of stored objects"), - }), - ('storage.objects.containers', { - 'label': '', - 'description': _("Number of containers"), - }), - ('storage.objects.incoming.bytes', { - 'label': '', - 'description': _("Number of incoming bytes"), - }), - ('storage.objects.outgoing.bytes', { - 'label': '', - 'description': _("Number of outgoing bytes"), - }), - ('storage.api.request', { - 'label': '', - 'description': _("Number of API requests against swift"), - }), - ]) - - def _get_kwapi_meters_info(self): - """Returns additional info for each meter. - - That will be used for augmenting the Ceilometer meter. - """ - - # TODO(lsmola) Unless the Ceilometer will provide the information - # below, I need to define it as a static here. I will be joining this - # to info that I am able to obtain from Ceilometer meters, hopefully - # some day it will be supported all. - return OrderedDict([ - ('energy', { - 'label': '', - 'description': _("Amount of energy"), - }), - ('power', { - 'label': '', - 'description': _("Power consumption"), - }), - ]) - - def _get_ipmi_meters_info(self): - """Returns additional info for each meter - - That will be used for augmenting the Ceilometer meter - """ - - # TODO(lsmola) Unless the Ceilometer will provide the information - # below, I need to define it as a static here. I will be joining this - # to info that I am able to obtain from Ceilometer meters, hopefully - # some day it will be supported all. - return OrderedDict([ - ('hardware.ipmi.node.power', { - 'label': '', - 'description': _("System Current Power"), - }), - ('hardware.ipmi.fan', { - 'label': '', - 'description': _("Fan RPM"), - }), - ('hardware.ipmi.temperature', { - 'label': '', - 'description': _("Sensor Temperature Reading"), - }), - ('hardware.ipmi.current', { - 'label': '', - 'description': _("Sensor Current Reading"), - }), - ('hardware.ipmi.voltage', { - 'label': '', - 'description': _("Sensor Voltage Reading"), - }), - ('hardware.ipmi.node.temperature', { - 'label': '', - 'description': _("System Temperature Reading"), - }), - ('hardware.ipmi.node.outlet_temperature', { - 'label': '', - 'description': _("System Outlet Temperature Reading"), - }), - ('hardware.ipmi.node.airflow', { - 'label': '', - 'description': _("System Airflow Reading"), - }), - ('hardware.ipmi.node.cups', { - 'label': '', - 'description': _("System CUPS Reading"), - }), - ('hardware.ipmi.node.cpu_util', { - 'label': '', - 'description': _("System CPU Utility Reading"), - }), - ('hardware.ipmi.node.mem_util', { - 'label': '', - 'description': _("System Memory Utility Reading"), - }), - ('hardware.ipmi.node.io_util', { - 'label': '', - 'description': _("System IO Utility Reading"), - }), - ]) diff --git a/openstack_dashboard/conf/ceilometer_policy.json b/openstack_dashboard/conf/ceilometer_policy.json deleted file mode 100644 index 4c3ec47af1..0000000000 --- a/openstack_dashboard/conf/ceilometer_policy.json +++ /dev/null @@ -1,6 +0,0 @@ -{ - "context_is_admin": "role:admin", - "context_is_project": "project_id:%(target.project_id)s", - "context_is_owner": "user_id:%(target.user_id)s", - "segregation": "rule:context_is_admin" -} diff --git a/openstack_dashboard/dashboards/admin/metering/__init__.py b/openstack_dashboard/dashboards/admin/metering/__init__.py deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/openstack_dashboard/dashboards/admin/metering/forms.py b/openstack_dashboard/dashboards/admin/metering/forms.py deleted file mode 100644 index f18c384633..0000000000 --- a/openstack_dashboard/dashboards/admin/metering/forms.py +++ /dev/null @@ -1,65 +0,0 @@ -# Copyright 2014 OpenStack Foundation -# -# 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 datetime - -from django.forms import ValidationError # noqa -from django.utils.translation import ugettext_lazy as _ - -from horizon import forms - - -class UsageReportForm(forms.SelfHandlingForm): - PERIOD_CHOICES = (("1", _("Last day")), - ("7", _("Last week")), - (str(datetime.date.today().day), _("Month to date")), - ("15", _("Last 15 days")), - ("30", _("Last 30 days")), - ("365", _("Last year")), - ("other", _("Other")), - ) - period = forms.ThemableChoiceField(label=_("Period"), - choices=PERIOD_CHOICES) - date_from = forms.DateField(label=_("From"), required=False, - widget=forms.TextInput( - attrs={'data-date-picker': True})) - date_to = forms.DateField(label=_("To"), required=False, - widget=forms.TextInput( - attrs={'data-date-picker': True})) - - def clean_date_from(self): - period = self.cleaned_data['period'] - date_from = self.cleaned_data['date_from'] - if period == 'other' and date_from is None: - raise ValidationError(_('Must specify start of period')) - return date_from - - def clean_date_to(self): - data = super(UsageReportForm, self).clean() - date_from = data.get('date_from') - date_to = data.get('date_to') - period = data.get('period') - if (period == 'other' and date_to is not None - and date_from is not None and date_to < date_from): - raise ValidationError(_("Start must be earlier " - "than end of period.")) - else: - return date_to - - def handle(self, request, data): - if hasattr(request, 'session'): - request.session['date_from'] = data['date_from'] - request.session['date_to'] = data['date_to'] - request.session['period'] = data['period'] - return data diff --git a/openstack_dashboard/dashboards/admin/metering/panel.py b/openstack_dashboard/dashboards/admin/metering/panel.py deleted file mode 100644 index 14dfebe98e..0000000000 --- a/openstack_dashboard/dashboards/admin/metering/panel.py +++ /dev/null @@ -1,24 +0,0 @@ -# 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. - -from django.utils.translation import ugettext_lazy as _ - -import horizon - - -class Metering(horizon.Panel): - name = _("Resource Usage") - slug = 'metering' - permissions = ('openstack.services.metering', ) - policy_rules = (('identity', 'identity:list_projects'), - ('telemetry', 'telemetry:compute_statistics'), - ('telemetry', 'telemetry:get_meter'),) diff --git a/openstack_dashboard/dashboards/admin/metering/tables.py b/openstack_dashboard/dashboards/admin/metering/tables.py deleted file mode 100644 index 4f75a8a0b9..0000000000 --- a/openstack_dashboard/dashboards/admin/metering/tables.py +++ /dev/null @@ -1,88 +0,0 @@ -# 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. - -from django.contrib.humanize.templatetags import humanize -from django.utils import text -from django.utils.translation import ugettext_lazy as _ -import six - -from horizon import tables - - -def show_date(datum): - return datum.split('T')[0] - - -class ModifyUsageReportParameters(tables.LinkAction): - name = "create" - verbose_name = _("Modify Usage Report Parameters") - url = "horizon:admin:metering:create" - classes = ("ajax-modal",) - icon = "edit" - - -class CreateCSVUsageReport(tables.LinkAction): - name = "csv" - verbose_name = _("Download CSV Summary") - url = "horizon:admin:metering:csvreport" - classes = ("btn-create",) - icon = "download" - - -class ReportTable(tables.DataTable): - project = tables.Column('project', verbose_name=_('Project')) - service = tables.Column('service', verbose_name=_('Service')) - meter = tables.Column('meter', verbose_name=_('Meter')) - description = tables.Column('description', verbose_name=_('Description')) - time = tables.Column('time', verbose_name=_('Day'), - filters=[show_date]) - value = tables.Column('value', verbose_name=_('Value (Avg)'), - filters=[humanize.intcomma]) - unit = tables.Column('unit', verbose_name=_('Unit')) - - def get_object_id(self, obj): - return "%s-%s-%s" % (obj['project'], obj['service'], obj['meter']) - - class Meta(object): - name = 'report_table' - verbose_name = _("Daily Usage Report") - table_actions = (ModifyUsageReportParameters, CreateCSVUsageReport) - multi_select = False - - -@six.python_2_unicode_compatible -class UsageTable(tables.DataTable): - service = tables.Column('service', verbose_name=_('Service')) - meter = tables.Column('meter', verbose_name=_('Meter')) - description = tables.Column('description', verbose_name=_('Description')) - time = tables.Column('time', verbose_name=_('Day'), - filters=[show_date]) - value = tables.Column('value', verbose_name=_('Value (Avg)'), - filters=[humanize.intcomma]) - - def __init__(self, request, *args, **kwargs): - super(UsageTable, self).__init__(request, *args, **kwargs) - self.title = getattr(self, 'title', None) - - def get_object_id(self, datum): - return datum['time'] + datum['meter'] - - # since these tables are dynamically created and named, we use title - @property - def name(self): - return text.slugify(six.text_type(self.title)) - - def __str__(self): - return self.title - - class Meta(object): - name = 'daily' diff --git a/openstack_dashboard/dashboards/admin/metering/tabs.py b/openstack_dashboard/dashboards/admin/metering/tabs.py deleted file mode 100644 index aa42c23ecf..0000000000 --- a/openstack_dashboard/dashboards/admin/metering/tabs.py +++ /dev/null @@ -1,118 +0,0 @@ -# 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. - - -from django.utils.translation import ugettext_lazy as _ - -from horizon import exceptions -from horizon import messages -from horizon import tabs - -from openstack_dashboard.api import ceilometer - -from openstack_dashboard.dashboards.admin.metering import \ - tables as metering_tables - -from openstack_dashboard.utils import metering - - -class GlobalStatsTab(tabs.TableTab): - name = _("Stats") - slug = "stats" - template_name = "admin/metering/stats.html" - preload = False - table_classes = (metering_tables.UsageTable,) - - def get_context_data(self, request): - meters = ceilometer.Meters(request) - if not meters._ceilometer_meter_list: - msg = _("There are no meters defined yet.") - messages.warning(request, msg) - - context = { - 'nova_meters': meters.list_nova(), - 'neutron_meters': meters.list_neutron(), - 'glance_meters': meters.list_glance(), - 'cinder_meters': meters.list_cinder(), - 'swift_meters': meters.list_swift(), - 'kwapi_meters': meters.list_kwapi(), - 'ipmi_meters': meters.list_ipmi(), - } - - return context - - -class UsageReportTab(tabs.TableTab): - name = _("Usage Report") - slug = "usage_report" - template_name = "horizon/common/_detail_table.html" - table_classes = (metering_tables.ReportTable,) - - def get_report_table_data(self): - meters = ceilometer.Meters(self.request) - services = { - _('Nova'): meters.list_nova(), - _('Neutron'): meters.list_neutron(), - _('Glance'): meters.list_glance(), - _('Cinder'): meters.list_cinder(), - _('Swift_meters'): meters.list_swift(), - _('Kwapi'): meters.list_kwapi(), - _('IPMI'): meters.list_ipmi(), - } - report_rows = [] - - date_options = self.request.session.get('period', 1) - date_from = self.request.session.get('date_from', '') - date_to = self.request.session.get('date_to', '') - - try: - date_from, date_to = metering.calc_date_args(date_from, - date_to, - date_options) - except Exception: - exceptions.handle(self.request, _('Dates cannot be recognized.')) - try: - project_aggregates = metering.ProjectAggregatesQuery(self.request, - date_from, - date_to, - 3600 * 24) - except Exception: - exceptions.handle(self.request, - _('Unable to retrieve project list.')) - for meter in meters._cached_meters.values(): - service = None - for name, m_list in services.items(): - if meter in m_list: - service = name - break - res, unit = project_aggregates.query(meter.name) - - for re in res: - values = re.get_meter(meter.name.replace(".", "_")) - if values: - for value in values: - row = {"name": 'none', - "project": re.id, - "meter": meter.name, - "description": meter.description, - "service": service, - "time": value._apiresource.period_end, - "value": value._apiresource.avg, - "unit": meter.unit} - report_rows.append(row) - return report_rows - - -class CeilometerOverviewTabs(tabs.TabGroup): - slug = "ceilometer_overview" - tabs = (UsageReportTab, GlobalStatsTab,) - sticky = True diff --git a/openstack_dashboard/dashboards/admin/metering/templates/metering/_daily.html b/openstack_dashboard/dashboards/admin/metering/templates/metering/_daily.html deleted file mode 100644 index 6d19330541..0000000000 --- a/openstack_dashboard/dashboards/admin/metering/templates/metering/_daily.html +++ /dev/null @@ -1,32 +0,0 @@ -{% extends "horizon/common/_modal_form.html" %} -{% load i18n %} - -{% block form_id %}create_usage_report_form{% endblock %} -{% block form_action %}{% url 'horizon:admin:metering:create' %}{% endblock %} - -{% block modal_id %}create_usage_report_modal{% endblock %} -{% block modal-header %}{% trans "Modify Usage Report Parameters" %}{% endblock %} - -{% block modal-body %} -
-
- {% include "horizon/common/_form_fields.html" %} -
-
-
-

{% trans "Description:" %}

-

{% trans "Select a pre-defined period or specify date." %}

-
-{% endblock %} - -{% block modal-js %} - -{% endblock %} diff --git a/openstack_dashboard/dashboards/admin/metering/templates/metering/daily.html b/openstack_dashboard/dashboards/admin/metering/templates/metering/daily.html deleted file mode 100644 index daa6609aea..0000000000 --- a/openstack_dashboard/dashboards/admin/metering/templates/metering/daily.html +++ /dev/null @@ -1,7 +0,0 @@ -{% extends 'base.html' %} -{% load i18n %} -{% block title %}{% trans "Modify Usage Report Parameters" %}{% endblock %} - -{% block main %} - {% include "admin/metering/_daily.html" %} -{% endblock %} diff --git a/openstack_dashboard/dashboards/admin/metering/templates/metering/index.html b/openstack_dashboard/dashboards/admin/metering/templates/metering/index.html deleted file mode 100644 index 807ff62918..0000000000 --- a/openstack_dashboard/dashboards/admin/metering/templates/metering/index.html +++ /dev/null @@ -1,11 +0,0 @@ -{% extends 'base.html' %} -{% load i18n %} -{% block title %}{% trans "Resources Usage Overview" %}{% endblock %} - -{% block main %} -
-
- {{ tab_group.render }} -
-
-{% endblock %} diff --git a/openstack_dashboard/dashboards/admin/metering/templates/metering/stats.html b/openstack_dashboard/dashboards/admin/metering/templates/metering/stats.html deleted file mode 100644 index 872238d3f2..0000000000 --- a/openstack_dashboard/dashboards/admin/metering/templates/metering/stats.html +++ /dev/null @@ -1,175 +0,0 @@ -{% load i18n %} - -
-
-
- -
- -
- -
-
- -
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
-
- -
- -
-
- -
-
- -
-
-

{% trans "Statistics of all resources" %}

-
-
-
-
-
-
-
-
-
-
-
-
-
-
- - diff --git a/openstack_dashboard/dashboards/admin/metering/tests.py b/openstack_dashboard/dashboards/admin/metering/tests.py deleted file mode 100644 index 7cecbadd49..0000000000 --- a/openstack_dashboard/dashboards/admin/metering/tests.py +++ /dev/null @@ -1,180 +0,0 @@ -# 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. - -from django.core.urlresolvers import reverse -from django import http - -from mox3.mox import IsA # noqa -from oslo_serialization import jsonutils -import six - -from openstack_dashboard import api -from openstack_dashboard.test import helpers as test -from openstack_dashboard.test.test_data import utils as test_utils - - -INDEX_URL = reverse('horizon:admin:metering:index') -CREATE_URL = reverse('horizon:admin:metering:create') -SAMPLES_URL = reverse('horizon:admin:metering:samples') - - -class MeteringViewTests(test.BaseAdminViewTests): - def test_create_report_page(self): - formData = {'period': 7} - res = self.client.get(CREATE_URL) - self.assertTemplateUsed(res, 'admin/metering/daily.html') - res = self.client.post(CREATE_URL, formData) - self.assertNoFormErrors(res) - self.assertRedirectsNoFollow(res, INDEX_URL) - - def test_create_report_dates_messed_up(self): - # dates are swapped in create report form - formData = {'period': 'other', - 'date_to': '2014-01-01', - 'date_from': '2014-02-02'} - - res = self.client.post(CREATE_URL, formData) - self.assertFormError(res, "form", "date_to", - ['Start must be earlier than end of period.']) - - def test_create_report_date_missing(self): - formData = {'period': 'other', - 'date_to': '2014-01-01', - 'date_from': ''} - - res = self.client.post(CREATE_URL, formData) - self.assertFormError(res, "form", "date_from", - ['Must specify start of period']) - - -class MeteringLineChartTabTests(test.BaseAdminViewTests): - def setUp(self): - test.BaseAdminViewTests.setUp(self) - self.testdata = test_utils.TestData() - test_utils.load_test_data(self.testdata) - - def _verify_series(self, series, value, date, expected_names): - data = jsonutils.loads(series) - self.assertIn('series', data) - self.assertEqual(len(data['series']), len(expected_names)) - for d in data['series']: - self.assertIn('data', d) - self.assertEqual(len(d['data']), 1) - self.assertAlmostEqual(d['data'][0].get('y'), value) - self.assertEqual(d['data'][0].get('x'), date) - self.assertEqual(d.get('unit'), '') - self.assertIn(d.get('name'), expected_names) - expected_names.remove(d.get('name')) - - self.assertEqual(data.get('settings'), {}) - - @test.create_stubs({api.keystone: ('tenant_list',), - api.ceilometer: ('sample_list', - 'statistic_list', - ), }) - def test_stats_for_line_chart(self): - api.ceilometer.sample_list(IsA(http.HttpRequest), - IsA(six.text_type), - limit=IsA(int)).AndReturn([]) - api.ceilometer.statistic_list(IsA(http.HttpRequest), - 'memory', - period=IsA(int), - query=IsA(list)).MultipleTimes()\ - .AndReturn(self.testdata.statistics.list()) - api.keystone.tenant_list(IsA(http.HttpRequest), - domain=None, - paginate=False) \ - .AndReturn([self.testdata.tenants.list(), False]) - - self.mox.ReplayAll() - - # get all statistics of project aggregates - res = self.client.get( - reverse('horizon:admin:metering:samples') + - "?meter=memory&group_by=project&stats_attr=avg&date_options=7") - - self.assertEqual(res._headers['content-type'], - ('Content-Type', 'application/json')) - expected_names = ['test_tenant', - 'disabled_tenant', - u'\u4e91\u89c4\u5219'] - self._verify_series(res._container[0], 4.55, '2012-12-21T11:00:55', - expected_names) - - @test.create_stubs({api.keystone: ('tenant_list',), - api.ceilometer: ('sample_list', - 'statistic_list', - ), }) - def test_stats_for_line_chart_attr_max(self): - api.ceilometer.sample_list(IsA(http.HttpRequest), - IsA(six.text_type), - limit=IsA(int)).AndReturn([]) - api.ceilometer.statistic_list(IsA(http.HttpRequest), - 'memory', period=IsA(int), - query=IsA(list))\ - .MultipleTimes().AndReturn(self.testdata.statistics.list()) - api.keystone.tenant_list(IsA(http.HttpRequest), - domain=None, - paginate=False) \ - .AndReturn([self.testdata.tenants.list(), False]) - - self.mox.ReplayAll() - - # get all statistics of project aggregates - res = self.client.get( - reverse('horizon:admin:metering:samples') + - "?meter=memory&group_by=project&stats_attr=max&date_options=7") - - self.assertEqual(res._headers['content-type'], - ('Content-Type', 'application/json')) - expected_names = ['test_tenant', - 'disabled_tenant', - u'\u4e91\u89c4\u5219'] - - self._verify_series(res._container[0], 9.0, '2012-12-21T11:00:55', - expected_names) - - @test.create_stubs({api.keystone: ('tenant_list',), - api.ceilometer: ('sample_list', - 'resource_list', - 'statistic_list' - ), }) - def test_stats_for_line_chart_no_group(self): - api.ceilometer.sample_list(IsA(http.HttpRequest), - IsA(six.text_type), - limit=IsA(int)).AndReturn([]) - api.ceilometer.resource_list(IsA(http.HttpRequest), query=None, - ceilometer_usage_object=None)\ - .AndReturn(self.testdata.api_resources.list()) - api.ceilometer.statistic_list(IsA(http.HttpRequest), - 'memory', period=IsA(int), - query=IsA(list))\ - .MultipleTimes().AndReturn(self.testdata.statistics.list()) - api.keystone.tenant_list(IsA(http.HttpRequest), - domain=None, - paginate=False) \ - .AndReturn([self.testdata.tenants.list(), False]) - - self.mox.ReplayAll() - - # get all statistics of the meter - res = self.client.get( - reverse('horizon:admin:metering:samples') + - "?meter=memory&stats_attr=max&date_options=7") - - self.assertEqual(res._headers['content-type'], - ('Content-Type', 'application/json')) - - expected_names = ['fake_resource_id3'] - - self._verify_series(res._container[0], 9.0, '2012-12-21T11:00:55', - expected_names) diff --git a/openstack_dashboard/dashboards/admin/metering/urls.py b/openstack_dashboard/dashboards/admin/metering/urls.py deleted file mode 100644 index e1df2ce9cf..0000000000 --- a/openstack_dashboard/dashboards/admin/metering/urls.py +++ /dev/null @@ -1,22 +0,0 @@ -# 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. - -from django.conf.urls import url - -from openstack_dashboard.dashboards.admin.metering import views - -urlpatterns = [ - url(r'^$', views.IndexView.as_view(), name='index'), - url(r'^create/$', views.CreateUsageReport.as_view(), name='create'), - url(r'^samples$', views.SamplesView.as_view(), name='samples'), - url(r'^report/csv$', views.CsvReportView.as_view(), name='csvreport'), -] diff --git a/openstack_dashboard/dashboards/admin/metering/views.py b/openstack_dashboard/dashboards/admin/metering/views.py deleted file mode 100644 index 4d37c24443..0000000000 --- a/openstack_dashboard/dashboards/admin/metering/views.py +++ /dev/null @@ -1,171 +0,0 @@ -# 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 json - -from django.core.urlresolvers import reverse_lazy -from django.http import HttpResponse # noqa -from django.utils.translation import ugettext_lazy as _ -import django.views - -from horizon import exceptions -from horizon import forms -from horizon import tabs -from horizon.utils import csvbase - -from openstack_dashboard.api import ceilometer - -from openstack_dashboard.dashboards.admin.metering import forms as \ - metering_forms -from openstack_dashboard.dashboards.admin.metering import tabs as \ - metering_tabs -from openstack_dashboard.utils import metering as metering_utils - - -class IndexView(tabs.TabbedTableView): - tab_group_class = metering_tabs.CeilometerOverviewTabs - template_name = 'admin/metering/index.html' - page_title = _("Resources Usage Overview") - - -class CreateUsageReport(forms.ModalFormView): - form_class = metering_forms.UsageReportForm - template_name = 'admin/metering/daily.html' - success_url = reverse_lazy('horizon:admin:metering:index') - page_title = _("Modify Usage Report Parameters") - submit_label = _("View Usage Report") - - -class SamplesView(django.views.generic.TemplateView): - def get(self, request, *args, **kwargs): - meter = request.GET.get('meter', None) - if not meter: - return HttpResponse(json.dumps({}), - content_type='application/json') - - meter_name = meter.replace(".", "_") - date_options = request.GET.get('date_options', None) - date_from = request.GET.get('date_from', None) - date_to = request.GET.get('date_to', None) - stats_attr = request.GET.get('stats_attr', 'avg') - group_by = request.GET.get('group_by', None) - - try: - date_from, date_to = metering_utils.calc_date_args(date_from, - date_to, - date_options) - except Exception: - exceptions.handle(self.request, _('Dates cannot be recognized.')) - - if group_by == 'project': - query = metering_utils.ProjectAggregatesQuery(request, - date_from, - date_to, - 3600 * 24) - else: - query = metering_utils.MeterQuery(request, date_from, - date_to, 3600 * 24) - - resources, unit = query.query(meter) - series = metering_utils.series_for_meter(request, resources, - group_by, meter, - meter_name, stats_attr, unit) - - series = metering_utils.normalize_series_by_unit(series) - ret = {'series': series, 'settings': {}} - return HttpResponse(json.dumps(ret), content_type='application/json') - - -class CsvReportView(django.views.generic.View): - def get(self, request, **response_kwargs): - render_class = ReportCsvRenderer - response_kwargs.setdefault("filename", "usage.csv") - context = {'usage': load_report_data(request)} - resp = render_class(request=request, - template=None, - context=context, - content_type='csv', - **response_kwargs) - return resp - - -class ReportCsvRenderer(csvbase.BaseCsvResponse): - - columns = [_("Project Name"), _("Meter"), _("Description"), - _("Service"), _("Time"), _("Value (Avg)"), _("Unit")] - - def get_row_data(self): - - for p in self.context['usage'].values(): - for u in p: - yield (u["project"], - u["meter"], - u["description"], - u["service"], - u["time"], - u["value"], - u["unit"]) - - -def load_report_data(request): - meters = ceilometer.Meters(request) - services = { - _('Nova'): meters.list_nova(), - _('Neutron'): meters.list_neutron(), - _('Glance'): meters.list_glance(), - _('Cinder'): meters.list_cinder(), - _('Swift_meters'): meters.list_swift(), - _('Kwapi'): meters.list_kwapi(), - _('IPMI'): meters.list_ipmi(), - } - project_rows = {} - date_options = request.GET.get('date_options', 7) - date_from = request.GET.get('date_from') - date_to = request.GET.get('date_to') - try: - date_from, date_to = metering_utils.calc_date_args(date_from, - date_to, - date_options) - except Exception: - exceptions.handle(request, _('Dates cannot be recognized.')) - try: - project_aggregates = metering_utils.ProjectAggregatesQuery(request, - date_from, - date_to, - 3600 * 24) - except Exception: - exceptions.handle(request, - _('Unable to retrieve project list.')) - for meter in meters._cached_meters.values(): - service = None - for name, m_list in services.items(): - if meter in m_list: - service = name - break - res, unit = project_aggregates.query(meter.name) - for r in res: - values = r.get_meter(meter.name.replace(".", "_")) - if values: - for value in values: - row = {"name": 'none', - "project": r.id, - "meter": meter.name, - "description": meter.description, - "service": service, - "time": value._apiresource.period_end, - "value": value._apiresource.avg, - "unit": meter.unit} - if r.id not in project_rows: - project_rows[r.id] = [row] - else: - project_rows[r.id].append(row) - return project_rows diff --git a/openstack_dashboard/enabled/_2030_admin_metering_panel.py b/openstack_dashboard/enabled/_2030_admin_metering_panel.py deleted file mode 100644 index 7ca2ddd2ee..0000000000 --- a/openstack_dashboard/enabled/_2030_admin_metering_panel.py +++ /dev/null @@ -1,9 +0,0 @@ -# The slug of the panel to be added to HORIZON_CONFIG. Required. -PANEL = 'metering' -# The slug of the dashboard the PANEL associated with. Required. -PANEL_DASHBOARD = 'admin' -# The slug of the panel group the PANEL is associated with. -PANEL_GROUP = 'admin' - -# Python panel class of the PANEL to be added. -ADD_PANEL = 'openstack_dashboard.dashboards.admin.metering.panel.Metering' diff --git a/openstack_dashboard/local/local_settings.py.example b/openstack_dashboard/local/local_settings.py.example index 2c579aedb1..f9845c36cd 100644 --- a/openstack_dashboard/local/local_settings.py.example +++ b/openstack_dashboard/local/local_settings.py.example @@ -458,7 +458,6 @@ TIME_ZONE = "UTC" # 'image': 'glance_policy.json', # 'orchestration': 'heat_policy.json', # 'network': 'neutron_policy.json', -# 'telemetry': 'ceilometer_policy.json', #} # TODO: (david-lyle) remove when plugins support adding settings. @@ -565,11 +564,6 @@ LOGGING = { 'level': 'DEBUG', 'propagate': False, }, - 'ceilometerclient': { - 'handlers': ['console'], - 'level': 'DEBUG', - 'propagate': False, - }, 'swiftclient': { 'handlers': ['console'], 'level': 'DEBUG', diff --git a/openstack_dashboard/settings.py b/openstack_dashboard/settings.py index 987a3adbff..7f102210a0 100644 --- a/openstack_dashboard/settings.py +++ b/openstack_dashboard/settings.py @@ -251,7 +251,6 @@ POLICY_FILES = { 'image': 'glance_policy.json', 'orchestration': 'heat_policy.json', 'network': 'neutron_policy.json', - 'telemetry': 'ceilometer_policy.json', } SECRET_KEY = None diff --git a/openstack_dashboard/test/api_tests/ceilometer_tests.py b/openstack_dashboard/test/api_tests/ceilometer_tests.py deleted file mode 100644 index 16be994eef..0000000000 --- a/openstack_dashboard/test/api_tests/ceilometer_tests.py +++ /dev/null @@ -1,361 +0,0 @@ -# Copyright 2012 Canonical Ltd. -# -# 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. - -from django import http - -from mox3.mox import IsA # noqa - -from openstack_dashboard import api -from openstack_dashboard.test import helpers as test - - -class CeilometerApiTests(test.APITestCase): - def test_sample_list(self): - samples = self.samples.list() - meter_name = "meter_name" - ceilometerclient = self.stub_ceilometerclient() - ceilometerclient.samples = self.mox.CreateMockAnything() - ceilometerclient.samples.list(meter_name=meter_name, - q=[], - limit=None).AndReturn(samples) - self.mox.ReplayAll() - - ret_list = api.ceilometer.sample_list(self.request, - meter_name, - query=[]) - self.assertEqual(len(samples), len(ret_list)) - for c in ret_list: - self.assertIsInstance(c, api.ceilometer.Sample) - - def test_alarm_list(self): - alarms = self.alarms.list() - ceilometerclient = self.stub_ceilometerclient() - ceilometerclient.alarms = self.mox.CreateMockAnything() - ceilometerclient.alarms.list(q=[]).AndReturn(alarms) - self.mox.ReplayAll() - - ret_list = api.ceilometer.alarm_list(self.request, query=[]) - self.assertEqual(len(alarms), len(ret_list)) - for c in ret_list: - self.assertIsInstance(c, api.ceilometer.Alarm) - - def test_alarm_get(self): - alarm = self.alarms.first() - ceilometerclient = self.stub_ceilometerclient() - ceilometerclient.alarms = self.mox.CreateMockAnything() - ceilometerclient.alarms.get(alarm.id).AndReturn(alarm) - self.mox.ReplayAll() - - ret_alarm = api.ceilometer.alarm_get(self.request, - alarm_id='fake_alarm_id') - self.assertEqual(alarm.alarm_id, ret_alarm.alarm_id) - - def test_alarm_create(self): - alarm = self.alarms.first() - new_alarm = {'alarm': alarm} - ceilometerclient = self.stub_ceilometerclient() - ceilometerclient.alarms = self.mox.CreateMockAnything() - ceilometerclient.alarms.create(**new_alarm).AndReturn(alarm) - self.mox.ReplayAll() - test_alarm = api.ceilometer.alarm_create(self.request, - **new_alarm) - self.assertEqual(alarm.alarm_id, test_alarm.alarm_id) - - def test_alarm_update(self): - """test update parameters""" - alarm1 = self.alarms.first() - alarm2 = self.alarms.list()[1] - ceilometerclient = self.stub_ceilometerclient() - ceilometerclient.alarms = self.mox.CreateMockAnything() - # Return the mock object that has "New" as description - ceilometerclient.alarms.update(alarm1.id, - description='New').AndReturn(alarm2) - self.mox.ReplayAll() - test_alarm = api.ceilometer.alarm_update(self.request, - alarm1.id, - description='New') - self.assertEqual(alarm2.description, test_alarm.description) - - def test_meter_list(self): - meters = self.meters.list() - ceilometerclient = self.stub_ceilometerclient() - ceilometerclient.meters = self.mox.CreateMockAnything() - ceilometerclient.meters.list([]).AndReturn(meters) - self.mox.ReplayAll() - - ret_list = api.ceilometer.meter_list(self.request, []) - self.assertEqual(len(meters), len(ret_list)) - for m in ret_list: - self.assertIsInstance(m, api.ceilometer.Meter) - - def test_resource_list(self): - resources = self.resources.list() - ceilometerclient = self.stub_ceilometerclient() - ceilometerclient.resources = self.mox.CreateMockAnything() - ceilometerclient.resources.list(q=[]).AndReturn(resources) - self.mox.ReplayAll() - - ret_list = api.ceilometer.resource_list(self.request, query=[]) - self.assertEqual(len(resources), len(ret_list)) - for r in ret_list: - self.assertIsInstance(r, api.ceilometer.Resource) - - def test_statistic_list(self): - statistics = self.statistics.list() - meter_name = "meter_name" - ceilometerclient = self.stub_ceilometerclient() - ceilometerclient.statistics = self.mox.CreateMockAnything() - ceilometerclient.statistics.list(meter_name=meter_name, - period=None, q=[]).\ - AndReturn(statistics) - self.mox.ReplayAll() - - ret_list = api.ceilometer.statistic_list(self.request, - meter_name, - period=None, - query=[]) - self.assertEqual(len(statistics), len(ret_list)) - for s in ret_list: - self.assertIsInstance(s, api.ceilometer.Statistic) - - def test_meters_list_all(self): - meters = self.meters.list() - - ceilometerclient = self.stub_ceilometerclient() - ceilometerclient.meters = self.mox.CreateMockAnything() - ceilometerclient.meters.list(None).AndReturn(meters) - - self.mox.ReplayAll() - - meters_object = api.ceilometer.Meters(self.request) - - ret_list = meters_object.list_all() - - for m in ret_list: - self.assertIsInstance(m, api.ceilometer.Meter) - - self.assertEqual(3, len(ret_list)) - - names = ["disk.read.bytes", "disk.write.bytes", "instance"] - for ret in ret_list: - self.assertIn(ret.name, names) - names.remove(ret.name) - - def test_meters_list_all_only(self): - meters = self.meters.list() - - ceilometerclient = self.stub_ceilometerclient() - ceilometerclient.meters = self.mox.CreateMockAnything() - ceilometerclient.meters.list(None).AndReturn(meters) - - self.mox.ReplayAll() - - meters_object = api.ceilometer.Meters(self.request) - ret_list = meters_object.list_all(only_meters=["disk.read.bytes"]) - - self.assertEqual(1, len(ret_list)) - self.assertEqual("disk.read.bytes", ret_list[0].name) - - ret_list = meters_object.list_all(only_meters=["disk.read.bytes", - "instance"]) - - self.assertEqual(2, len(ret_list)) - self.assertEqual("disk.read.bytes", ret_list[0].name) - self.assertEqual("instance", ret_list[1].name) - - def test_meters_list_all_except(self): - meters = self.meters.list() - - ceilometerclient = self.stub_ceilometerclient() - ceilometerclient.meters = self.mox.CreateMockAnything() - ceilometerclient.meters.list(None).AndReturn(meters) - - self.mox.ReplayAll() - - meters_object = api.ceilometer.Meters(self.request) - ret_list = meters_object.list_all(except_meters=["disk.write.bytes", - "instance"]) - - self.assertEqual(1, len(ret_list)) - self.assertEqual("disk.read.bytes", ret_list[0].name) - - ret_list = meters_object.list_all(except_meters=["disk.write.bytes"]) - - self.assertEqual(len(ret_list), 2) - names = ["disk.read.bytes", "instance"] - - for ret in ret_list: - self.assertIn(ret.name, names) - names.remove(ret.name) - - # TODO(lsmola) Test resource aggregates. - - @test.create_stubs({api.ceilometer.CeilometerUsage: ("get_user", - "get_tenant")}) - def test_global_data_get(self): - class TempUsage(api.base.APIResourceWrapper): - _attrs = ["id", "tenant", "user", "resource", "get_meter"] - - meters = ["fake_meter_1", - "fake_meter_2"] - - default_query = ["Fake query"] - stats_attr = "max" - - resources = self.resources.list() - statistics = self.statistics.list() - user = self.ceilometer_users.list()[0] - tenant = self.ceilometer_tenants.list()[0] - - ceilometerclient = self.stub_ceilometerclient() - ceilometerclient.resources = self.mox.CreateMockAnything() - # I am returning only 1 resource - ceilometerclient.resources.list(q=IsA(list)).AndReturn(resources[:1]) - - ceilometerclient.statistics = self.mox.CreateMockAnything() - # check that list is called twice for one resource and 2 meters - ceilometerclient.statistics.list(meter_name=IsA(str), - period=None, q=IsA(list)).\ - AndReturn(statistics) - ceilometerclient.statistics.list(meter_name=IsA(str), - period=None, q=IsA(list)).\ - AndReturn(statistics) - - api.ceilometer.CeilometerUsage\ - .get_user(IsA(str)).AndReturn(user) - api.ceilometer.CeilometerUsage\ - .get_tenant(IsA(str)).AndReturn(tenant) - - self.mox.ReplayAll() - - # getting all resources and with statistics - ceilometer_usage = api.ceilometer.CeilometerUsage(http.HttpRequest) - data = ceilometer_usage.global_data_get( - used_cls=TempUsage, query=["fake_query"], with_statistics=True) - - first = data[0] - self.assertEqual('fake_project_id__fake_user_id__' - 'fake_resource_id', - first.id) - self.assertEqual('user', first.user.name) - self.assertEqual('test_tenant', first.tenant.name) - self.assertEqual('fake_resource_id', first.resource) - self.assertEqual(9, first.get_meter('fake_meter_1'),) - self.assertEqual(9, first.get_meter('fake_meter_2'),) - self.assertEqual(2, len(first.meters)) - # check that only one resource is returned - self.assertEqual(1, len(data)) - - @test.create_stubs({api.ceilometer.CeilometerUsage: ("get_user", - "get_tenant")}) - def test_global_data_get_without_statistic_data(self): - class TempUsage(api.base.APIResourceWrapper): - _attrs = ["id", "tenant", "user", "resource", "fake_meter_1", - "fake_meter_2"] - - meters = ["fake_meter_1", - "fake_meter_2"] - - default_query = ["Fake query"] - stats_attr = "max" - - resources = self.resources.list() - user = self.ceilometer_users.list()[0] - tenant = self.ceilometer_tenants.list()[0] - - ceilometerclient = self.stub_ceilometerclient() - ceilometerclient.resources = self.mox.CreateMockAnything() - ceilometerclient.resources.list(q=IsA(list)).AndReturn(resources) - - api.ceilometer.CeilometerUsage\ - .get_user(IsA(str)).MultipleTimes().AndReturn(user) - api.ceilometer.CeilometerUsage\ - .get_tenant(IsA(str)).MultipleTimes().AndReturn(tenant) - - self.mox.ReplayAll() - - # getting all resources and with statistics - ceilometer_usage = api.ceilometer.CeilometerUsage(http.HttpRequest) - data = ceilometer_usage.global_data_get( - used_cls=TempUsage, query=["fake_query"], with_statistics=False) - - first = data[0] - self.assertEqual('fake_project_id__fake_user_id__' - 'fake_resource_id', - first.id) - self.assertEqual('user', first.user.name) - self.assertEqual('test_tenant', first.tenant.name) - self.assertEqual('fake_resource_id', first.resource) - - self.assertRaises(AttributeError, getattr, first, 'fake_meter_1') - self.assertRaises(AttributeError, getattr, first, 'fake_meter_2') - - self.assertEqual(len(resources), len(data)) - - @test.create_stubs({api.ceilometer.CeilometerUsage: ("get_user", - "get_tenant")}) - def test_global_data_get_all_statistic_data(self): - class TempUsage(api.base.APIResourceWrapper): - _attrs = ["id", "tenant", "user", "resource", "get_meter", ] - - meters = ["fake_meter_1", - "fake_meter_2"] - - default_query = ["Fake query"] - stats_attr = None # have to return dictionary with all stats - - resources = self.resources.list() - - statistics = self.statistics.list() - user = self.ceilometer_users.list()[0] - tenant = self.ceilometer_tenants.list()[0] - - ceilometerclient = self.stub_ceilometerclient() - ceilometerclient.resources = self.mox.CreateMockAnything() - ceilometerclient.resources.list(q=IsA(list)).AndReturn(resources) - - ceilometerclient.statistics = self.mox.CreateMockAnything() - ceilometerclient.statistics.list(meter_name=IsA(str), - period=None, q=IsA(list)).\ - MultipleTimes().\ - AndReturn(statistics) - - api.ceilometer.CeilometerUsage\ - .get_user(IsA(str)).MultipleTimes().AndReturn(user) - api.ceilometer.CeilometerUsage\ - .get_tenant(IsA(str)).MultipleTimes().AndReturn(tenant) - - self.mox.ReplayAll() - - # getting all resources and with statistics - ceilometer_usage = api.ceilometer.CeilometerUsage(http.HttpRequest) - data = ceilometer_usage.global_data_get( - used_cls=TempUsage, query=["fake_query"], with_statistics=True) - - first = data[0] - self.assertEqual('fake_project_id__fake_user_id__' - 'fake_resource_id', - first.id) - self.assertEqual('user', first.user.name) - self.assertEqual('test_tenant', first.tenant.name) - self.assertEqual('fake_resource_id', first.resource) - - statistic_obj = api.ceilometer.Statistic(statistics[0]) - # check that it returns whole statistic object - self.assertEqual(vars(first.get_meter('fake_meter_1')[0]), - vars(statistic_obj)) - self.assertEqual(vars(first.get_meter('fake_meter_2')[0]), - vars(statistic_obj)) - - self.assertEqual(len(resources), len(data)) diff --git a/openstack_dashboard/test/helpers.py b/openstack_dashboard/test/helpers.py index 58ff917886..4f92e60801 100644 --- a/openstack_dashboard/test/helpers.py +++ b/openstack_dashboard/test/helpers.py @@ -32,7 +32,6 @@ from django.test.client import RequestFactory # noqa from django.test import utils as django_test_utils from django.utils import http -from ceilometerclient.v2 import client as ceilometer_client from cinderclient import client as cinder_client import glanceclient from heatclient import client as heat_client @@ -417,7 +416,6 @@ class APITestCase(TestCase): self._original_neutronclient = api.neutron.neutronclient self._original_cinderclient = api.cinder.cinderclient self._original_heatclient = api.heat.heatclient - self._original_ceilometerclient = api.ceilometer.ceilometerclient # Replace the clients with our stubs. api.glance.glanceclient = fake_glanceclient @@ -427,8 +425,6 @@ class APITestCase(TestCase): api.cinder.cinderclient = lambda request: self.stub_cinderclient() api.heat.heatclient = (lambda request, password=None: self.stub_heatclient()) - api.ceilometer.ceilometerclient = (lambda request: - self.stub_ceilometerclient()) def tearDown(self): super(APITestCase, self).tearDown() @@ -438,7 +434,6 @@ class APITestCase(TestCase): api.neutron.neutronclient = self._original_neutronclient api.cinder.cinderclient = self._original_cinderclient api.heat.heatclient = self._original_heatclient - api.ceilometer.ceilometerclient = self._original_ceilometerclient def stub_novaclient(self): if not hasattr(self, "novaclient"): @@ -506,13 +501,6 @@ class APITestCase(TestCase): self.heatclient = self.mox.CreateMock(heat_client.Client) return self.heatclient - def stub_ceilometerclient(self): - if not hasattr(self, "ceilometerclient"): - self.mox.StubOutWithMock(ceilometer_client, 'Client') - self.ceilometerclient = self.mox.\ - CreateMock(ceilometer_client.Client) - return self.ceilometerclient - # Need this to test both Glance API V1 and V2 versions class ResetImageAPIVersionMixin(object): diff --git a/openstack_dashboard/test/test_data/ceilometer_data.py b/openstack_dashboard/test/test_data/ceilometer_data.py deleted file mode 100644 index 1666b95d50..0000000000 --- a/openstack_dashboard/test/test_data/ceilometer_data.py +++ /dev/null @@ -1,331 +0,0 @@ -# Copyright 2012 Canonical Ltd. -# -# 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. - -from ceilometerclient.v2 import alarms -from ceilometerclient.v2 import meters -from ceilometerclient.v2 import resources -from ceilometerclient.v2 import samples -from ceilometerclient.v2 import statistics - -from keystoneclient.v2_0 import tenants -from keystoneclient.v2_0 import users - -from openstack_dashboard.api import ceilometer -from openstack_dashboard.test.test_data import utils - - -def data(TEST): - TEST.ceilometer_users = utils.TestDataContainer() - TEST.ceilometer_tenants = utils.TestDataContainer() - TEST.resources = utils.TestDataContainer() - TEST.api_resources = utils.TestDataContainer() - TEST.samples = utils.TestDataContainer() - TEST.meters = utils.TestDataContainer() - TEST.alarms = utils.TestDataContainer() - TEST.statistics = utils.TestDataContainer() - TEST.global_disk_usages = utils.TestDataContainer() - TEST.global_network_usages = utils.TestDataContainer() - TEST.global_network_traffic_usages = utils.TestDataContainer() - TEST.global_object_store_usages = utils.TestDataContainer() - TEST.statistics_array = utils.TestDataContainer() - - # users - ceilometer_user_dict1 = {'id': "1", - 'name': 'user', - 'email': 'test@example.com', - 'password': 'password', - 'token': 'test_token', - 'project_id': '1', - 'enabled': True, - 'domain_id': "1"} - ceilometer_user_dict2 = {'id': "2", - 'name': 'user2', - 'email': 'test2@example.com', - 'password': 'password', - 'token': 'test_token', - 'project_id': '2', - 'enabled': True, - 'domain_id': "2"} - TEST.ceilometer_users.add(users.User(None, - ceilometer_user_dict1)) - TEST.ceilometer_users.add(users.User(None, - ceilometer_user_dict2)) - - # Tenants. - tenant_dict = {'id': "1", - 'name': 'test_tenant', - 'description': "a test tenant.", - 'enabled': True, - 'domain_id': '1'} - tenant_dict_2 = {'id': "2", - 'name': 'disabled_tenant', - 'description': "a disabled test tenant.", - 'enabled': False, - 'domain_id': '2'} - tenant_dict_3 = {'id': "3", - 'name': u'\u4e91\u89c4\u5219', - 'description': "an unicode-named tenant.", - 'enabled': True, - 'domain_id': '2'} - ceilometer_tenant = tenants.Tenant(tenants.TenantManager, - tenant_dict) - ceilometer_disabled_tenant = tenants.Tenant(tenants.TenantManager, - tenant_dict_2) - ceilometer_tenant_unicode = tenants.Tenant(tenants.TenantManager, - tenant_dict_3) - - TEST.ceilometer_tenants.add(ceilometer_tenant, - ceilometer_disabled_tenant, - ceilometer_tenant_unicode) - - # resources - resource_dict_1 = dict( - resource_id='fake_resource_id', - project_id='fake_project_id', - user_id="fake_user_id", - timestamp='2012-07-02T10:42:00.000000', - metadata={'tag': 'self.counter3', 'display_name': 'test-server'}, - links=[{'url': 'test_url', 'rel': 'storage.objects'}], - ) - resource_dict_2 = dict( - resource_id='fake_resource_id2', - project_id='fake_project_id', - user_id="fake_user_id", - timestamp='2012-07-02T10:42:00.000000', - metadata={'tag': 'self.counter3', 'display_name': 'test-server'}, - links=[{'url': 'test_url', 'rel': 'storage.objects'}], - ) - resource_dict_3 = dict( - resource_id='fake_resource_id3', - project_id='fake_project_id', - user_id="fake_user_id", - timestamp='2012-07-02T10:42:00.000000', - metadata={'tag': 'self.counter3', 'display_name': 'test-server'}, - links=[{'url': 'test_url', 'rel': 'instance'}], - ) - resource_dict_4 = dict( - resource_id='fake_resource_id3', - project_id='fake_project_id', - user_id="fake_user_id", - timestamp='2012-07-02T10:42:00.000000', - metadata={'tag': 'self.counter3', 'display_name': 'test-server'}, - links=[{'url': 'test_url', 'rel': 'memory'}], - ) - - resource_1 = resources.Resource(resources.ResourceManager(None), - resource_dict_1) - resource_2 = resources.Resource(resources.ResourceManager(None), - resource_dict_2) - resource_3 = resources.Resource(resources.ResourceManager(None), - resource_dict_3) - resource_4 = resources.Resource(resources.ResourceManager(None), - resource_dict_4) - - TEST.resources.add(resource_1) - TEST.resources.add(resource_2) - TEST.resources.add(resource_3) - - # Having a separate set of fake objects for openstack_dashboard - # api Resource class. This is required because of additional methods - # defined in openstack_dashboard.api.ceilometer.Resource - - api_resource_1 = ceilometer.Resource(resource_1) - api_resource_2 = ceilometer.Resource(resource_2) - api_resource_3 = ceilometer.Resource(resource_3) - api_resource_4 = ceilometer.Resource(resource_4) - - TEST.api_resources.add(api_resource_1) - TEST.api_resources.add(api_resource_2) - TEST.api_resources.add(api_resource_3) - TEST.api_resources.add(api_resource_4) - - # samples - sample_dict_1 = {'resource_id': 'fake_resource_id', - 'project_id': 'fake_project_id', - 'user_id': 'fake_user_id', - 'counter_name': 'image', - 'counter_type': 'gauge', - 'counter_unit': 'image', - 'counter_volume': 1, - 'timestamp': '2012-12-21T11:00:55.000000', - 'metadata': {'name1': 'value1', 'name2': 'value2'}, - 'message_id': 'fake_message_id'} - sample_dict_2 = {'resource_id': 'fake_resource_id2', - 'project_id': 'fake_project_id', - 'user_id': 'fake_user_id', - 'counter_name': 'image', - 'counter_type': 'gauge', - 'counter_unit': 'image', - 'counter_volume': 1, - 'timestamp': '2012-12-21T11:00:55.000000', - 'metadata': {'name1': 'value1', 'name2': 'value2'}, - 'message_id': 'fake_message_id'} - sample_1 = samples.Sample(samples.SampleManager(None), sample_dict_1) - sample_2 = samples.Sample(samples.SampleManager(None), sample_dict_2) - TEST.samples.add(sample_1) - TEST.samples.add(sample_2) - - # alarms - alarm_dict_1 = {'alarm_actions': ['alarm_action1', 'alarm_action2'], - 'ok_actions': ['ok_action_1', 'ok_action_2'], - 'name': 'fake_alarm_name', - 'timestamp': '2015-08-07T05:32:20.970341', - 'description': 'fake_random_description', - 'time_constraints': [], - 'enabled': True, - 'state_timestamp': '2015-08-07T17:59:11.351033', - 'threshold_rule': {'meter_name': 'fake_meter_name', - 'evaluation_periods': 1, 'period': 300, - 'statistic': 'avg', 'threshold': 2.0, - 'query': [], - 'comparison_operator': 'ge', - 'exclude_outliers': False}, - 'alarm_id': 'fake_alarm_id', - 'state': 'ok', - 'insufficient_data_actions': ['fake_action_1', - 'fake_action_2'], - 'repeat_actions': True, - 'user_id': 'fake_user_id', - 'project_id': 'fake_project_id', - 'type': 'threshold', - 'severity': 'low'} - alarm_dict_2 = {'alarm_actions': ['alarm_action1', 'alarm_action2'], - 'ok_actions': ['ok_action_1', 'ok_action_2'], - 'name': 'fake_alarm_name', - 'timestamp': '2015-08-07T05:32:20.970341', - 'description': 'New', - 'time_constraints': [], - 'enabled': True, - 'state_timestamp': '2015-08-07T17:59:11.351033', - 'threshold_rule': {'meter_name': 'fake_meter_name', - 'evaluation_periods': 1, 'period': 300, - 'statistic': 'avg', 'threshold': 2.0, - 'query': [], - 'comparison_operator': 'ge', - 'exclude_outliers': False}, - 'alarm_id': 'fake_alarm_id2', - 'state': 'ok', - 'insufficient_data_actions': ['fake_action_1', - 'fake_action_2'], - 'repeat_actions': True, - 'user_id': 'fake_user_id', - 'project_id': 'fake_project_id', - 'type': 'threshold', - 'severity': 'low'} - alarm_dict_3 = {'alarm_actions': ['alarm_action1', 'alarm_action2'], - 'ok_actions': ['ok_action_1', 'ok_action_2'], - 'name': 'fake_alarm_name', - 'timestamp': '2015-08-07T05:32:20.970341', - 'description': 'fake_random_description', - 'time_constraints': [], - 'enabled': True, - 'state_timestamp': '2015-08-07T17:59:11.351033', - 'threshold_rule': {'meter_name': 'fake_meter_name', - 'evaluation_periods': 2, 'period': 300, - 'statistic': 'avg', 'threshold': 2.0, - 'query': [{'field': 'resource_id', - 'value': ''}], - 'comparison_operator': 'ge', - 'exclude_outliers': False}, - 'alarm_id': 'fake_alarm_id3', - 'state': 'ok', - 'insufficient_data_actions': ['fake_action_1', - 'fake_action_2'], - 'repeat_actions': True, - 'user_id': '', - 'project_id': '', - 'type': 'threshold', - 'severity': 'low'} - alarm_dict_4 = {'alarm_actions': ['alarm_action1', 'alarm_action2'], - 'ok_actions': ['ok_action_1', 'ok_action_2'], - 'name': 'fake_alarm_name4', - 'timestamp': '2015-08-07T05:32:20.970341', - 'description': 'fake_random_description', - 'time_constraints': [], - 'enabled': True, - 'state_timestamp': '2015-08-07T17:59:11.351033', - 'threshold_rule': {'meter_name': '', - 'evaluation_periods': -10, 'period': -1, - 'statistic': 'avg', 'threshold': '', - 'query': [{'field': 'resource_id', - 'value': ''}], - 'comparison_operator': 'ge', - 'exclude_outliers': False}, - 'alarm_id': 'fake_alarm_id4', - 'state': 'ok', - 'insufficient_data_actions': ['fake_action_1', - 'fake_action_2'], - 'repeat_actions': True, - 'user_id': 'fake_user_id', - 'project_id': 'fake_project_id', - 'type': 'threshold', - 'severity': 'low'} - - alarm_1 = alarms.Alarm(alarms.AlarmManager(None), alarm_dict_1) - alarm_2 = alarms.Alarm(alarms.AlarmManager(None), alarm_dict_2) - alarm_3 = alarms.Alarm(alarms.AlarmManager(None), alarm_dict_3) - alarm_4 = alarms.Alarm(alarms.AlarmManager(None), alarm_dict_4) - TEST.alarms.add(alarm_1) - TEST.alarms.add(alarm_2) - TEST.alarms.add(alarm_3) - TEST.alarms.add(alarm_4) - - # meters - meter_dict_1 = {'name': 'instance', - 'type': 'gauge', - 'unit': 'instance', - 'resource_id': 'fake_resource_id', - 'project_id': 'fake_project_id', - 'user_id': 'fake_user_id'} - meter_dict_2 = {'name': 'instance', - 'type': 'gauge', - 'unit': 'instance', - 'resource_id': 'fake_resource_id', - 'project_id': 'fake_project_id', - 'user_id': 'fake_user_id'} - meter_dict_3 = {'name': 'disk.read.bytes', - 'type': 'gauge', - 'unit': 'instance', - 'resource_id': 'fake_resource_id', - 'project_id': 'fake_project_id', - 'user_id': 'fake_user_id'} - meter_dict_4 = {'name': 'disk.write.bytes', - 'type': 'gauge', - 'unit': 'instance', - 'resource_id': 'fake_resource_id', - 'project_id': 'fake_project_id', - 'user_id': 'fake_user_id'} - meter_1 = meters.Meter(meters.MeterManager(None), meter_dict_1) - meter_2 = meters.Meter(meters.MeterManager(None), meter_dict_2) - meter_3 = meters.Meter(meters.MeterManager(None), meter_dict_3) - meter_4 = meters.Meter(meters.MeterManager(None), meter_dict_4) - TEST.meters.add(meter_1) - TEST.meters.add(meter_2) - TEST.meters.add(meter_3) - TEST.meters.add(meter_4) - - # statistic - statistic_dict_1 = {'min': 1, - 'max': 9, - 'avg': 4.55, - 'sum': 45, - 'count': 10, - 'duration_start': '2012-12-21T11:00:55.000000', - 'duration_end': '2012-12-21T11:00:55.000000', - 'period': 7200, - 'period_start': '2012-12-21T11:00:55.000000', - 'period_end': '2012-12-21T11:00:55.000000'} - statistic_1 = statistics.Statistics(statistics.StatisticsManager(None), - statistic_dict_1) - TEST.statistics.add(statistic_1) diff --git a/openstack_dashboard/test/test_data/exceptions.py b/openstack_dashboard/test/test_data/exceptions.py index 9a33e0b8a8..8f6e90bf10 100644 --- a/openstack_dashboard/test/test_data/exceptions.py +++ b/openstack_dashboard/test/test_data/exceptions.py @@ -12,7 +12,6 @@ # License for the specific language governing permissions and limitations # under the License. -import ceilometerclient.exc as ceilometer_exceptions from cinderclient import exceptions as cinder_exceptions import glanceclient.exc as glance_exceptions import heatclient.exc as heat_exceptions @@ -74,9 +73,6 @@ def data(TEST): glance_exception = glance_exceptions.ClientException TEST.exceptions.glance = create_stubbed_exception(glance_exception) - ceilometer_exception = ceilometer_exceptions.HTTPException - TEST.exceptions.ceilometer = create_stubbed_exception(ceilometer_exception) - neutron_exception = neutron_exceptions.NeutronClientException TEST.exceptions.neutron = create_stubbed_exception(neutron_exception) diff --git a/openstack_dashboard/test/test_data/keystone_data.py b/openstack_dashboard/test/test_data/keystone_data.py index 82762e1f91..6afd845801 100644 --- a/openstack_dashboard/test/test_data/keystone_data.py +++ b/openstack_dashboard/test/test_data/keystone_data.py @@ -103,14 +103,6 @@ SERVICE_CATALOG = [ "adminURL": "http://admin.nova.example.com:8773/services/Admin", "publicURL": "http://public.nova.example.com:8773/services/Cloud", "internalURL": "http://int.nova.example.com:8773/services/Cloud"}]}, - {"type": "metering", - "name": "ceilometer", - "endpoints_links": [], - "endpoints": [ - {"region": "RegionOne", - "adminURL": "http://admin.ceilometer.example.com:8777", - "publicURL": "http://public.ceilometer.example.com:8777", - "internalURL": "http://int.ceilometer.example.com:8777"}]}, {"type": "orchestration", "name": "Heat", "endpoints_links": [], diff --git a/openstack_dashboard/test/test_data/utils.py b/openstack_dashboard/test/test_data/utils.py index 707fac6a04..a739300651 100644 --- a/openstack_dashboard/test/test_data/utils.py +++ b/openstack_dashboard/test/test_data/utils.py @@ -14,7 +14,6 @@ def load_test_data(load_onto=None): - from openstack_dashboard.test.test_data import ceilometer_data from openstack_dashboard.test.test_data import cinder_data from openstack_dashboard.test.test_data import exceptions from openstack_dashboard.test.test_data import glance_data @@ -34,7 +33,6 @@ def load_test_data(load_onto=None): neutron_data.data, swift_data.data, heat_data.data, - ceilometer_data.data, ) if load_onto: for data_func in loaders: diff --git a/openstack_dashboard/test/tests/utils.py b/openstack_dashboard/test/tests/utils.py index 0a416f0aaa..0c6a4a917a 100644 --- a/openstack_dashboard/test/tests/utils.py +++ b/openstack_dashboard/test/tests/utils.py @@ -13,13 +13,10 @@ # License for the specific language governing permissions and limitations # under the License. -import datetime - from oslo_utils import uuidutils from openstack_dashboard.test import helpers as test from openstack_dashboard.utils import filters -from openstack_dashboard.utils import metering class UtilsFilterTests(test.TestCase): @@ -41,26 +38,3 @@ class UtilsFilterTests(test.TestCase): def test_reject_random_string(self): val = '55WbJTpJDf' self.assertRaises(ValueError, filters.get_int_or_uuid, val) - - -class UtilsMeteringTests(test.TestCase): - - def test_calc_date_args_strings(self): - date_from, date_to = metering.calc_date_args( - "2012-04-11", "2012-04-12", "other") - self.assertTrue(type(date_from) is datetime.datetime) - self.assertTrue(type(date_to) is datetime.datetime) - self.assertEqual("UTC", str(date_from.tzinfo)) - self.assertEqual("UTC", str(date_to.tzinfo)) - - def test_calc_date_args_datetime_dates(self): - date_from, date_to = metering.calc_date_args( - datetime.date(2012, 4, 11), datetime.date(2012, 4, 12), "other") - self.assertTrue(type(date_from) is datetime.datetime) - self.assertTrue(type(date_to) is datetime.datetime) - self.assertEqual("UTC", str(date_from.tzinfo)) - self.assertEqual("UTC", str(date_to.tzinfo)) - - def test_calc_date_args_invalid(self): - self.assertRaises( - ValueError, metering.calc_date_args, object, object, "other") diff --git a/openstack_dashboard/utils/metering.py b/openstack_dashboard/utils/metering.py deleted file mode 100644 index b956ecdfc3..0000000000 --- a/openstack_dashboard/utils/metering.py +++ /dev/null @@ -1,249 +0,0 @@ -# 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 datetime -import logging - -from django.utils import timezone -from django.utils.translation import ugettext_lazy as _ -import pytz - -from horizon.utils import units - -from openstack_dashboard import api - - -LOG = logging.getLogger(__name__) - - -METER_API_MAPPINGS = { - "instance": 'nova', - "cpu": 'nova', - "cpu_util": 'nova', - "disk_read_requests": 'nova', - "disk_write_requests": 'nova', - "disk_read_bytes": 'nova', - "disk_write_bytes": 'nova', - "image": 'glance', - "image_size": 'glance' -} - - -def calc_period(date_from, date_to, number_of_samples=400): - if date_from and date_to: - if date_to < date_from: - # TODO(lsmola) propagate the Value error through Horizon - # handler to the client with verbose message. - raise ValueError(_("To date to must be greater than From date.")) - - delta = date_to - date_from - delta_in_seconds = delta.days * 24 * 3600 + delta.seconds - period = delta_in_seconds / number_of_samples - else: - # If some date is missing, just set static window to one day. - period = 3600 * 24 - return period - - -def calc_date_args(date_from, date_to, date_options): - # TODO(lsmola) all timestamps should probably work with - # current timezone. And also show the current timezone in chart. - if date_options == "other": - try: - if date_from: - date_from = pytz.utc.localize( - datetime.datetime.strptime(str(date_from), "%Y-%m-%d")) - else: - # TODO(lsmola) there should be probably the date - # of the first sample as default, so it correctly - # counts the time window. Though I need ordering - # and limit of samples to obtain that. - pass - if date_to: - date_to = pytz.utc.localize( - datetime.datetime.strptime(str(date_to), "%Y-%m-%d")) - # It returns the beginning of the day, I want the end of - # the day, so I add one day without a second. - date_to = (date_to + datetime.timedelta(days=1) - - datetime.timedelta(seconds=1)) - else: - date_to = timezone.now() - except Exception: - raise ValueError(_("The dates haven't been recognized")) - else: - try: - date_to = timezone.now() - date_from = date_to - datetime.timedelta(days=float(date_options)) - except Exception: - raise ValueError(_("The time delta must be a number representing " - "the time span in days")) - return date_from, date_to - - -def get_resource_name(request, resource_id, resource_name, meter_name): - resource = None - try: - if resource_name == "resource_id": - meter_name = 'instance' if "instance" in meter_name else meter_name - api_type = METER_API_MAPPINGS.get(meter_name, '') - if api_type == 'nova': - resource = api.nova.server_get(request, resource_id) - elif api_type == 'glance': - resource = api.glance.image_get(request, resource_id) - - except Exception: - LOG.info(_("Failed to get the resource name: %s"), resource_id, - exc_info=True) - return resource.name if resource else resource_id - - -def series_for_meter(request, aggregates, group_by, meter_id, - meter_name, stats_name, unit, label=None): - """Construct datapoint series for a meter from resource aggregates.""" - series = [] - for resource in aggregates: - if resource.get_meter(meter_name): - if label: - name = label - else: - resource_name = ('id' if group_by == "project" - else 'resource_id') - resource_id = getattr(resource, resource_name) - name = get_resource_name(request, resource_id, - resource_name, meter_name) - point = {'unit': unit, - 'name': name, - 'meter': meter_id, - 'data': []} - for statistic in resource.get_meter(meter_name): - date = statistic.duration_end[:19] - value = float(getattr(statistic, stats_name)) - point['data'].append({'x': date, 'y': value}) - series.append(point) - return series - - -def normalize_series_by_unit(series): - """Transform series' values into a more human readable form: - 1) Determine the data point with the maximum value - 2) Decide the unit appropriate for this value (normalize it) - 3) Convert other values to this new unit, if necessary - """ - if not series: - return series - - source_unit = target_unit = series[0]['unit'] - - if not units.is_supported(source_unit): - return series - - # Find the data point with the largest value and normalize it to - # determine its unit - that will be the new unit - maximum = max([d['y'] for point in series for d in point['data']]) - unit = units.normalize(maximum, source_unit)[1] - - # If unit needs to be changed, set the new unit for all data points - # and convert all values to that unit - if units.is_larger(unit, target_unit): - target_unit = unit - for i, point in enumerate(series[:]): - if point['unit'] != target_unit: - series[i]['unit'] = target_unit - for j, d in enumerate(point['data'][:]): - series[i]['data'][j]['y'] = units.convert( - d['y'], source_unit, target_unit, fmt=True)[0] - - return series - - -def get_unit(meter, request): - sample_list = api.ceilometer.sample_list(request, meter, limit=1) - unit = "" - if sample_list: - unit = sample_list[0].counter_unit - return unit - - -class ProjectAggregatesQuery(object): - def __init__(self, request, date_from, date_to, - period=None, additional_query=None): - additional_query = additional_query or [] - if not period: - period = calc_period(date_from, date_to) - if date_from: - additional_query.append({'field': 'timestamp', - 'op': 'ge', - 'value': date_from}) - if date_to: - additional_query.append({'field': 'timestamp', - 'op': 'le', - 'value': date_to}) - - self.request = request - self.period = period - self.additional_query = additional_query - tenants, more = api.keystone.tenant_list(request, - domain=None, - paginate=False) - self.queries = {} - - for tenant in tenants: - tenant_query = [{ - "field": "project_id", - "op": "eq", - "value": tenant.id}] - - self.queries[tenant.name] = tenant_query - - def query(self, meter): - unit = get_unit(meter, self.request) - ceilometer_usage = api.ceilometer.CeilometerUsage(self.request) - resources = ceilometer_usage.resource_aggregates_with_statistics( - self.queries, [meter], period=self.period, - stats_attr=None, - additional_query=self.additional_query) - return resources, unit - - -class MeterQuery(ProjectAggregatesQuery): - def __init__(self, *args, **kwargs): - # pop filterfunc and add it later to self. - filterfunc = kwargs.pop('filterfunc', None) - super(MeterQuery, self).__init__(*args, **kwargs) - self.filterfunc = filterfunc - # Resetting the tenant based filter set in base class - self.queries = None - - def query(self, meter): - def filter_by_meter_name(resource): - """Function for filtering of the list of resources. - - Will pick the right resources according to currently selected - meter. - """ - for link in resource.links: - if link['rel'] == meter: - # If resource has the currently chosen meter. - return True - return False - - unit = get_unit(meter, self.request) - - ceilometer_usage = api.ceilometer.CeilometerUsage(self.request) - resources = ceilometer_usage.resources_with_statistics( - self.queries, [meter], - period=self.period, - stats_attr=None, - additional_query=self.additional_query, - filter_func=filter_by_meter_name) - - return resources, unit diff --git a/releasenotes/notes/remove-ceilometer-support-376d38802a3ef833.yaml b/releasenotes/notes/remove-ceilometer-support-376d38802a3ef833.yaml new file mode 100644 index 0000000000..a29fb57d56 --- /dev/null +++ b/releasenotes/notes/remove-ceilometer-support-376d38802a3ef833.yaml @@ -0,0 +1,5 @@ +--- +deprecations: + - The telemetry code in Horizon has been deprecated + and disabled for several releases now. The code has + now been removed from the tree.