Removing deprecate ceilometer code

The ceilometer code has been deprecated and disabled for
several cycles. Now removing the code.

Change-Id: I1dcfb8aae6ce6898cb46f6312731a92a01ae0b67
This commit is contained in:
David Lyle 2016-11-17 16:51:24 -07:00
parent 11fbb4df2d
commit 20ea82b9ef
27 changed files with 5 additions and 3255 deletions

View File

@ -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",
]

File diff suppressed because it is too large Load Diff

View File

@ -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"
}

View File

@ -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

View File

@ -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'),)

View File

@ -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'

View File

@ -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

View File

@ -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 %}

View File

@ -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 %}

View File

@ -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 %}

View File

@ -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>

View File

@ -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)

View File

@ -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'),
]

View File

@ -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

View File

@ -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'

View File

@ -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',

View File

@ -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

View File

@ -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))

View File

@ -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):

View File

@ -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)

View File

@ -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)

View File

@ -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": [],

View File

@ -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:

View File

@ -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")

View File

@ -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

View File

@ -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.