summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Lyle <david.lyle@intel.com>2016-11-17 16:51:24 -0700
committerDavid Lyle <david.lyle@intel.com>2016-11-17 16:52:13 -0700
commit20ea82b9efe78516286c4b35c5dc644b296b4313 (patch)
tree2b538ea0bd53cc40b0fb8541c3a520b4048e3907
parent11fbb4df2da932af2668ea07b03055746540082b (diff)
downloadhorizon-20ea82b9efe78516286c4b35c5dc644b296b4313.tar.gz
Removing deprecate ceilometer code
The ceilometer code has been deprecated and disabled for several cycles. Now removing the code. Change-Id: I1dcfb8aae6ce6898cb46f6312731a92a01ae0b67
-rw-r--r--openstack_dashboard/api/__init__.py2
-rw-r--r--openstack_dashboard/api/ceilometer.py1345
-rw-r--r--openstack_dashboard/conf/ceilometer_policy.json6
-rw-r--r--openstack_dashboard/dashboards/admin/metering/__init__.py0
-rw-r--r--openstack_dashboard/dashboards/admin/metering/forms.py65
-rw-r--r--openstack_dashboard/dashboards/admin/metering/panel.py24
-rw-r--r--openstack_dashboard/dashboards/admin/metering/tables.py88
-rw-r--r--openstack_dashboard/dashboards/admin/metering/tabs.py118
-rw-r--r--openstack_dashboard/dashboards/admin/metering/templates/metering/_daily.html32
-rw-r--r--openstack_dashboard/dashboards/admin/metering/templates/metering/daily.html7
-rw-r--r--openstack_dashboard/dashboards/admin/metering/templates/metering/index.html11
-rw-r--r--openstack_dashboard/dashboards/admin/metering/templates/metering/stats.html175
-rw-r--r--openstack_dashboard/dashboards/admin/metering/tests.py180
-rw-r--r--openstack_dashboard/dashboards/admin/metering/urls.py22
-rw-r--r--openstack_dashboard/dashboards/admin/metering/views.py171
-rw-r--r--openstack_dashboard/enabled/_2030_admin_metering_panel.py9
-rw-r--r--openstack_dashboard/local/local_settings.py.example6
-rw-r--r--openstack_dashboard/settings.py1
-rw-r--r--openstack_dashboard/test/api_tests/ceilometer_tests.py361
-rw-r--r--openstack_dashboard/test/helpers.py12
-rw-r--r--openstack_dashboard/test/test_data/ceilometer_data.py331
-rw-r--r--openstack_dashboard/test/test_data/exceptions.py4
-rw-r--r--openstack_dashboard/test/test_data/keystone_data.py8
-rw-r--r--openstack_dashboard/test/test_data/utils.py2
-rw-r--r--openstack_dashboard/test/tests/utils.py26
-rw-r--r--openstack_dashboard/utils/metering.py249
-rw-r--r--releasenotes/notes/remove-ceilometer-support-376d38802a3ef833.yaml5
27 files changed, 5 insertions, 3255 deletions
diff --git a/openstack_dashboard/api/__init__.py b/openstack_dashboard/api/__init__.py
index 4f510ff68..6ca3e45ac 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 deaf6ec11..000000000
--- 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:<type>", {
- 'label': '',
- 'description': _("Existence of instance <type> "
- "(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 4c3ec47af..000000000
--- 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 e69de29bb..000000000
--- a/openstack_dashboard/dashboards/admin/metering/__init__.py
+++ /dev/null
diff --git a/openstack_dashboard/dashboards/admin/metering/forms.py b/openstack_dashboard/dashboards/admin/metering/forms.py
deleted file mode 100644
index f18c38463..000000000
--- 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 14dfebe98..000000000
--- 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 4f75a8a0b..000000000
--- 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 aa42c23ec..000000000
--- 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 6d1933054..000000000
--- 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 %}
-<div class="left">
- <fieldset>
- {% include "horizon/common/_form_fields.html" %}
- </fieldset>
-</div>
-<div class="right">
- <h3>{% trans "Description:" %}</h3>
- <p>{% trans "Select a pre-defined period or specify date." %}</p>
-</div>
-{% endblock %}
-
-{% block modal-js %}
-<script type="text/javascript">
- if (typeof horizon.metering !== 'undefined') {
- horizon.metering.init_create_usage_report_form();
- } else {
- addHorizonLoadEvent(function() {
- horizon.metering.init_create_usage_report_form();
- });
- }
-</script>
-{% 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 daa6609ae..000000000
--- 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 807ff6291..000000000
--- 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 %}
-<div class="row">
- <div class="col-sm-12">
- {{ tab_group.render }}
- </div>
-</div>
-{% 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 872238d3f..000000000
--- a/openstack_dashboard/dashboards/admin/metering/templates/metering/stats.html
+++ /dev/null
@@ -1,175 +0,0 @@
-{% load i18n %}
-
-<div id="samples_url" url="{% url "horizon:admin:metering:samples" %}"></div>
-<div id="ceilometer-stats">
- <form class="form-horizontal"
- id="linechart_general_form">
-
- <div class="form-group">
- <label for="meter" class="col-sm-2 control-label">{% trans "Metric:" %}</label>
- <div class="col-sm-4 line_chart_time_picker">
- <select data-line-chart-command="select_box_change"
- name="meter" id="meter" class="form-control example">
-
- {% if nova_meters %}
- <optgroup label='{% trans "Compute (Nova)" %}'>
- {% for meter in nova_meters %}
- <option title="{{ meter.description }}" value="{{ meter.name }}" data-unit="{{ meter.unit }}">
- {{ meter.label }}
- </option>
- {% endfor %}
- </optgroup>
- {% endif %}
-
- {% if neutron_meters %}
- <optgroup label='{% trans "Network (Neutron)" %}'>
- {% for meter in neutron_meters %}
- <option title="{{ meter.description }}" value="{{ meter.name }}" data-unit="{{ meter.unit }}">
- {{ meter.label }}
- </option>
- {% endfor %}
- </optgroup>
- {% endif %}
-
- {% if glance_meters %}
- <optgroup label='{% trans "Image (Glance)" %}'>
- {% for meter in glance_meters %}
- <option title="{{ meter.description }}" value="{{ meter.name }}" data-unit="{{ meter.unit }}">
- {{ meter.label }}
- </option>
- {% endfor %}
- </optgroup>
- {% endif %}
-
- {% if cinder_meters %}
- <optgroup label='{% trans "Volume (Cinder)" %}'>
- {% for meter in cinder_meters %}
- <option title="{{ meter.description }}" value="{{ meter.name }}" data-unit="{{ meter.unit }}">
- {{ meter.label }}
- </option>
- {% endfor %}
- </optgroup>
- {% endif %}
-
- {% if swift_meters %}
- <optgroup label='{% trans "Object Storage (Swift)" %}'>
- {% for meter in swift_meters %}
- <option title="{{ meter.description }}" value="{{ meter.name }}" data-unit="{{ meter.unit }}">
- {{ meter.label }}
- </option>
- {% endfor %}
- </optgroup>
- {% endif %}
-
- {% if kwapi_meters %}
- <optgroup label='{% trans "Energy (Kwapi)" %}'>
- {% for meter in kwapi_meters %}
- <option title="{{ meter.description }}" value="{{ meter.name }}" data-unit="{{ meter.unit }}">
- {{ meter.label }}
- </option>
- {% endfor %}
- </optgroup>
- {% endif %}
-
- {% if ipmi_meters %}
- <optgroup label='{% trans "Intelligent Platform Management Interface (IPMI)" %}'>
- {% for meter in ipmi_meters %}
- <option title="{{ meter.description }}" value="{{ meter.name }}" data-unit="{{ meter.unit }}">
- {{ meter.label }}
- </option>
- {% endfor %}
- </optgroup>
- {% endif %}
- </select>
- </div>
- </div>
-
- <div class="form-group">
- <label for="group_by" class="col-sm-2 control-label">{% trans "Group by:" %}</label>
- <div class="col-sm-4">
- <select data-line-chart-command="select_box_change"
- id="group_by" name="group_by" class="form-control">
- <option value="" selected="selected">{% trans "--" %}</option>
- <option selected="selected" value="project" selected>{% trans "Project" %}</option>
- </select>
- </div>
- </div>
- <div class="form-group">
- <label for="stats_attr" class="col-sm-2 control-label">{% trans "Value:" %}</label>
- <div class="col-sm-4">
- <select data-line-chart-command="select_box_change"
- id="stats_attr" name="stats_attr" class="form-control">
-
- <option selected="selected" value="avg">{% trans "Avg." %}</option>
- <option value="min">{% trans "Min." %}</option>
- <option value="max">{% trans "Max." %}</option>
- <option value="sum">{% trans "Sum." %}</option>
- </select>
- </div>
- </div>
- <div class="form-group">
- <label for="date_options" class="col-sm-2 control-label">{% trans "Period:" %}</label>
- <div class="col-sm-4">
- <select data-line-chart-command="select_box_change"
- id="date_options" name="date_options" class="form-control">
- <option value="1">{% trans "Last day" %}</option>
- <option value="7" selected="selected">{% trans "Last week" %}</option>
- <option value="{% now 'j' %}">{% trans "Month to date" %}</option>
- <option value="15">{% trans "Last 15 days" %}</option>
- <option value="30">{% trans "Last 30 days" %}</option>
- <option value="365">{% trans "Last year" %}</option>
- <option value="other">{% trans "Other" %}</option>
- </select>
- </div>
- </div>
- <div class="form-group" id="date_from">
- <label for="date_from" class="col-sm-2 control-label">{% trans "From:" %}</label>
- <div class="col-sm-4">
- <input data-line-chart-command="date_picker_change"
- type="text" id="date_from" name="date_from" class="form-control example"/>
- </div>
- </div>
- <div class="form-group" id="date_to">
- <label for="date_to" class="col-sm-2 control-label">{% trans "To:" %}</label>
- <div class="col-sm-4">
- <input data-line-chart-command="date_picker_change"
- type="text" name="date_to" class="form-control example"/>
- </div>
- </div>
-
- </form>
-</div>
-
-<div class="info row detail">
- <div class="col-sm-12">
- <h4>{% trans "Statistics of all resources" %}</h4>
- <hr class="header_rule" />
- <div class="info row detail">
- <div class="col-sm-9 chart_container">
- <div class="chart"
- data-chart-type="line_chart"
- data-url="{% url 'horizon:admin:metering:samples'%}"
- data-form-selector='#linechart_general_form'
- data-legend-selector="#legend"
- data-smoother-selector="#smoother"
- data-slider-selector="#slider">
- </div>
- <div id="slider"></div>
- <div class="col-sm-3 legend_container">
- <div id="smoother" title="Smoothing"></div>
- <div id="legend"></div>
- </div>
- </div>
- </div>
- </div>
-</div>
-
-<script type="text/javascript">
- if (typeof $ !== 'undefined') {
- horizon.metering.init_stats_page();
- } else {
- addHorizonLoadEvent(function() {
- horizon.metering.init_stats_page();
- });
- }
-</script>
diff --git a/openstack_dashboard/dashboards/admin/metering/tests.py b/openstack_dashboard/dashboards/admin/metering/tests.py
deleted file mode 100644
index 7cecbadd4..000000000
--- 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 e1df2ce9c..000000000
--- 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 4d37c2444..000000000
--- 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 7ca2ddd2e..000000000
--- 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 2c579aedb..f9845c36c 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 987a3adbf..7f102210a 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 16be994ee..000000000
--- 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 58ff91788..4f92e6080 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 1666b95d5..000000000
--- 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 9a33e0b8a..8f6e90bf1 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 82762e1f9..6afd84580 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 707fac6a0..a73930065 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 0a416f0aa..0c6a4a917 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 b956ecdfc..000000000
--- 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 000000000..a29fb57d5
--- /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.