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:
parent
11fbb4df2d
commit
20ea82b9ef
@ -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
@ -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"
|
||||
}
|
@ -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
|
@ -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'),)
|
@ -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'
|
@ -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
|
@ -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 %}
|
@ -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 %}
|
@ -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 %}
|
@ -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>
|
@ -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)
|
@ -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'),
|
||||
]
|
@ -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
|
@ -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'
|
@ -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',
|
||||
|
@ -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
|
||||
|
@ -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))
|
@ -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):
|
||||
|
@ -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)
|
@ -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)
|
||||
|
||||
|
@ -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": [],
|
||||
|
@ -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:
|
||||
|
@ -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")
|
||||
|
@ -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
|
@ -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.
|
Loading…
x
Reference in New Issue
Block a user