Merge "Remove ceilometer datasource driver from congress"
This commit is contained in:
commit
4c4fcb300f
|
@ -1,284 +0,0 @@
|
|||
# Copyright (c) 2014 Montavista Software, LLC.
|
||||
#
|
||||
# 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 __future__ import print_function
|
||||
from __future__ import division
|
||||
from __future__ import absolute_import
|
||||
|
||||
import copy
|
||||
|
||||
import ceilometerclient
|
||||
import ceilometerclient.client as cc
|
||||
from keystoneauth1 import exceptions
|
||||
from oslo_log import log as logging
|
||||
import six
|
||||
|
||||
from congress.datasources import constants
|
||||
from congress.datasources import datasource_driver
|
||||
from congress.datasources import datasource_utils as ds_utils
|
||||
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
||||
|
||||
# TODO(thinrichs): figure out how to move even more of this boilerplate
|
||||
# into DataSourceDriver. E.g. change all the classes to Driver instead of
|
||||
# NeutronDriver, CeilometerDriver, etc. and move the d6instantiate function
|
||||
# to DataSourceDriver.
|
||||
class CeilometerDriver(datasource_driver.PollingDataSourceDriver,
|
||||
datasource_driver.ExecutionDriver):
|
||||
METERS = "meters"
|
||||
ALARMS = "alarms"
|
||||
EVENTS = "events"
|
||||
EVENT_TRAITS = "events.traits"
|
||||
ALARM_THRESHOLD_RULE = "alarms.threshold_rule"
|
||||
STATISTICS = "statistics"
|
||||
|
||||
value_trans = {'translation-type': 'VALUE'}
|
||||
|
||||
meters_translator = {
|
||||
'translation-type': 'HDICT',
|
||||
'table-name': METERS,
|
||||
'selector-type': 'DICT_SELECTOR',
|
||||
'field-translators':
|
||||
({'fieldname': 'meter_id', 'translator': value_trans},
|
||||
{'fieldname': 'name', 'translator': value_trans},
|
||||
{'fieldname': 'type', 'translator': value_trans},
|
||||
{'fieldname': 'unit', 'translator': value_trans},
|
||||
{'fieldname': 'source', 'translator': value_trans},
|
||||
{'fieldname': 'resource_id', 'translator': value_trans},
|
||||
{'fieldname': 'user_id', 'translator': value_trans},
|
||||
{'fieldname': 'project_id', 'translator': value_trans})}
|
||||
|
||||
alarms_translator = {
|
||||
'translation-type': 'HDICT',
|
||||
'table-name': ALARMS,
|
||||
'selector-type': 'DICT_SELECTOR',
|
||||
'field-translators':
|
||||
({'fieldname': 'alarm_id', 'translator': value_trans},
|
||||
{'fieldname': 'name', 'translator': value_trans},
|
||||
{'fieldname': 'state', 'translator': value_trans},
|
||||
{'fieldname': 'enabled', 'translator': value_trans},
|
||||
{'fieldname': 'threshold_rule', 'col': 'threshold_rule_id',
|
||||
'translator': {'translation-type': 'VDICT',
|
||||
'table-name': ALARM_THRESHOLD_RULE,
|
||||
'id-col': 'threshold_rule_id',
|
||||
'key-col': 'key', 'val-col': 'value',
|
||||
'translator': value_trans}},
|
||||
{'fieldname': 'type', 'translator': value_trans},
|
||||
{'fieldname': 'description', 'translator': value_trans},
|
||||
{'fieldname': 'time_constraints', 'translator': value_trans},
|
||||
{'fieldname': 'user_id', 'translator': value_trans},
|
||||
{'fieldname': 'project_id', 'translator': value_trans},
|
||||
{'fieldname': 'alarm_actions', 'translator': value_trans},
|
||||
{'fieldname': 'ok_actions', 'translator': value_trans},
|
||||
{'fieldname': 'insufficient_data_actions', 'translator':
|
||||
value_trans},
|
||||
{'fieldname': 'repeat_actions', 'translator': value_trans},
|
||||
{'fieldname': 'timestamp', 'translator': value_trans},
|
||||
{'fieldname': 'state_timestamp', 'translator': value_trans},
|
||||
)}
|
||||
|
||||
events_translator = {
|
||||
'translation-type': 'HDICT',
|
||||
'table-name': EVENTS,
|
||||
'selector-type': 'DICT_SELECTOR',
|
||||
'field-translators':
|
||||
({'fieldname': 'message_id', 'translator': value_trans},
|
||||
{'fieldname': 'event_type', 'translator': value_trans},
|
||||
{'fieldname': 'generated', 'translator': value_trans},
|
||||
{'fieldname': 'traits',
|
||||
'translator': {'translation-type': 'HDICT',
|
||||
'table-name': EVENT_TRAITS,
|
||||
'selector-type': 'DICT_SELECTOR',
|
||||
'in-list': True,
|
||||
'parent-key': 'message_id',
|
||||
'parent-col-name': 'event_message_id',
|
||||
'field-translators':
|
||||
({'fieldname': 'name',
|
||||
'translator': value_trans},
|
||||
{'fieldname': 'type',
|
||||
'translator': value_trans},
|
||||
{'fieldname': 'value',
|
||||
'translator': value_trans}
|
||||
)}}
|
||||
)}
|
||||
|
||||
def safe_id(x):
|
||||
if isinstance(x, six.string_types):
|
||||
return x
|
||||
try:
|
||||
return x['resource_id']
|
||||
except KeyError:
|
||||
return str(x)
|
||||
|
||||
statistics_translator = {
|
||||
'translation-type': 'HDICT',
|
||||
'table-name': STATISTICS,
|
||||
'selector-type': 'DICT_SELECTOR',
|
||||
'field-translators':
|
||||
({'fieldname': 'meter_name', 'translator': value_trans},
|
||||
{'fieldname': 'groupby', 'col': 'resource_id',
|
||||
'translator': {'translation-type': 'VALUE',
|
||||
'extract-fn': safe_id}},
|
||||
{'fieldname': 'avg', 'translator': value_trans},
|
||||
{'fieldname': 'count', 'translator': value_trans},
|
||||
{'fieldname': 'duration', 'translator': value_trans},
|
||||
{'fieldname': 'duration_start', 'translator': value_trans},
|
||||
{'fieldname': 'duration_end', 'translator': value_trans},
|
||||
{'fieldname': 'max', 'translator': value_trans},
|
||||
{'fieldname': 'min', 'translator': value_trans},
|
||||
{'fieldname': 'period', 'translator': value_trans},
|
||||
{'fieldname': 'period_end', 'translator': value_trans},
|
||||
{'fieldname': 'period_start', 'translator': value_trans},
|
||||
{'fieldname': 'sum', 'translator': value_trans},
|
||||
{'fieldname': 'unit', 'translator': value_trans})}
|
||||
|
||||
TRANSLATORS = [meters_translator, alarms_translator, events_translator,
|
||||
statistics_translator]
|
||||
|
||||
def __init__(self, name='', args=None):
|
||||
super(CeilometerDriver, self).__init__(name, args=args)
|
||||
datasource_driver.ExecutionDriver.__init__(self)
|
||||
session = ds_utils.get_keystone_session(args)
|
||||
self.ceilometer_client = cc.get_client(version='2', session=session)
|
||||
self.add_executable_client_methods(self.ceilometer_client,
|
||||
'ceilometerclient.v2.')
|
||||
self.initialize_update_method()
|
||||
self._init_end_start_poll()
|
||||
|
||||
@staticmethod
|
||||
def get_datasource_info():
|
||||
result = {}
|
||||
result['id'] = 'ceilometer'
|
||||
result['description'] = ('Datasource driver that interfaces with '
|
||||
'ceilometer.')
|
||||
result['config'] = ds_utils.get_openstack_required_config()
|
||||
result['config']['lazy_tables'] = constants.OPTIONAL
|
||||
result['secret'] = ['password']
|
||||
return result
|
||||
|
||||
def initialize_update_method(self):
|
||||
meters_method = lambda: self._translate_meters(
|
||||
self.ceilometer_client.meters.list())
|
||||
self.add_update_method(meters_method, self.meters_translator)
|
||||
|
||||
def alarms_list_suppress_no_aodh_error(ceilometer_client):
|
||||
'''Return alarms.list(), suppressing error due to Aodh absence
|
||||
|
||||
Requires python-ceilometerclient >= 2.6.2
|
||||
'''
|
||||
try:
|
||||
return self.ceilometer_client.alarms.list()
|
||||
except ceilometerclient.exc.HTTPException as e:
|
||||
if 'alarms URLs is unavailable when Aodh is disabled or ' \
|
||||
'unavailable' in str(e):
|
||||
LOG.info('alarms not available because Aodh is '
|
||||
'disabled or unavailable. '
|
||||
'Empty alarms list reported instead.')
|
||||
return []
|
||||
else:
|
||||
raise
|
||||
except exceptions.ConnectFailure:
|
||||
LOG.info('Unable to connect to Aodh service, not up '
|
||||
'or configured')
|
||||
return []
|
||||
|
||||
alarms_method = lambda: self._translate_alarms(
|
||||
alarms_list_suppress_no_aodh_error(self.ceilometer_client))
|
||||
self.add_update_method(alarms_method, self.alarms_translator)
|
||||
|
||||
events_method = lambda: self._translate_events(self._events_list())
|
||||
self.add_update_method(events_method, self.events_translator)
|
||||
|
||||
statistics_method = lambda: self._translate_statistics(
|
||||
self._get_statistics(self.ceilometer_client.meters.list()))
|
||||
self.add_update_method(statistics_method, self.statistics_translator)
|
||||
|
||||
def _events_list(self):
|
||||
try:
|
||||
return self.ceilometer_client.events.list()
|
||||
except (ceilometerclient.exc.HTTPException,
|
||||
exceptions.ConnectFailure):
|
||||
LOG.info('events list not available because Panko is disabled or '
|
||||
'unavailable. Empty list reported instead')
|
||||
return []
|
||||
|
||||
def _get_statistics(self, meters):
|
||||
statistics = []
|
||||
names = set()
|
||||
for m in meters:
|
||||
LOG.debug("Adding meter %s", m.name)
|
||||
names.add(m.name)
|
||||
for meter_name in names:
|
||||
LOG.debug("Getting all Resource ID for meter: %s",
|
||||
meter_name)
|
||||
stat_list = self.ceilometer_client.statistics.list(
|
||||
meter_name, groupby=['resource_id'])
|
||||
LOG.debug("Statistics List: %s", stat_list)
|
||||
if (stat_list):
|
||||
for temp in stat_list:
|
||||
temp_dict = copy.copy(temp.to_dict())
|
||||
temp_dict['meter_name'] = meter_name
|
||||
statistics.append(temp_dict)
|
||||
return statistics
|
||||
|
||||
@ds_utils.update_state_on_changed(METERS)
|
||||
def _translate_meters(self, obj):
|
||||
"""Translate the meters represented by OBJ into tables."""
|
||||
meters = [o.to_dict() for o in obj]
|
||||
|
||||
LOG.debug("METERS: %s", str(meters))
|
||||
|
||||
row_data = CeilometerDriver.convert_objs(meters,
|
||||
self.meters_translator)
|
||||
return row_data
|
||||
|
||||
@ds_utils.update_state_on_changed(ALARMS)
|
||||
def _translate_alarms(self, obj):
|
||||
"""Translate the alarms represented by OBJ into tables."""
|
||||
alarms = [o.to_dict() for o in obj]
|
||||
LOG.debug("ALARMS: %s", str(alarms))
|
||||
|
||||
row_data = CeilometerDriver.convert_objs(alarms,
|
||||
self.alarms_translator)
|
||||
return row_data
|
||||
|
||||
@ds_utils.update_state_on_changed(EVENTS)
|
||||
def _translate_events(self, obj):
|
||||
"""Translate the events represented by OBJ into tables."""
|
||||
events = [o.to_dict() for o in obj]
|
||||
LOG.debug("EVENTS: %s", str(events))
|
||||
|
||||
row_data = CeilometerDriver.convert_objs(events,
|
||||
self.events_translator)
|
||||
return row_data
|
||||
|
||||
@ds_utils.update_state_on_changed(STATISTICS)
|
||||
def _translate_statistics(self, obj):
|
||||
"""Translate the statistics represented by OBJ into tables."""
|
||||
LOG.debug("STATISTICS: %s", str(obj))
|
||||
|
||||
row_data = CeilometerDriver.convert_objs(obj,
|
||||
self.statistics_translator)
|
||||
return row_data
|
||||
|
||||
def execute(self, action, action_args):
|
||||
"""Overwrite ExecutionDriver.execute()."""
|
||||
# action can be written as a method or an API call.
|
||||
func = getattr(self, action, None)
|
||||
if func and self.is_executable(func):
|
||||
func(action_args)
|
||||
else:
|
||||
self._execute_api(self.ceilometer_client, action, action_args)
|
|
@ -1,287 +0,0 @@
|
|||
# Copyright (c) 2014 Montavista Software, LLC.
|
||||
#
|
||||
# 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 __future__ import print_function
|
||||
from __future__ import division
|
||||
from __future__ import absolute_import
|
||||
|
||||
from ceilometerclient.v2 import client
|
||||
import mock
|
||||
|
||||
from congress.datasources import ceilometer_driver
|
||||
from congress.tests import base
|
||||
from congress.tests.datasources import util
|
||||
from congress.tests import helper
|
||||
|
||||
ResponseObj = util.ResponseObj
|
||||
|
||||
|
||||
class TestCeilometerDriver(base.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestCeilometerDriver, self).setUp()
|
||||
self.ceilometer_client = mock.MagicMock()
|
||||
|
||||
args = helper.datasource_openstack_args()
|
||||
args['poll_time'] = 0
|
||||
with mock.patch.object(client.Client, '__init__',
|
||||
return_value=None):
|
||||
self.driver = ceilometer_driver.CeilometerDriver(
|
||||
name='testceilometer',
|
||||
args=args)
|
||||
|
||||
def test_list_meters(self):
|
||||
meters_data = [
|
||||
ResponseObj({'name': 'instance:m1.tiny',
|
||||
'type': 'gauge',
|
||||
'unit': 'instance',
|
||||
'resource_id': 'a257ba13-0b36-4a86-ae89-f78dd28b8ae5',
|
||||
'user_id': '2b01323fd71345bc8cdc5dbbd6d127ea',
|
||||
'project_id': '0020df0171ec41b597cd8b3002e21bee',
|
||||
'meter_id': 'YTI1N2JhMTMtMGIzNi00YTg2LWFlODktZjc4ZG',
|
||||
'source': 'openstack'}),
|
||||
ResponseObj({'name': 'network.incoming.bytes',
|
||||
'type': 'cumulative',
|
||||
'unit': 'B',
|
||||
'resource_id': 'instance-00000001-tap437ce69c-e5',
|
||||
'user_id': '2b01323fd71345bc8cdc5dbbd6d127ea',
|
||||
'project_id': '0020df0171ec41b597cd8b3002e21bee',
|
||||
'meter_id': 'aW5zdGFuY2UtMDAwMDAwMDEtYTI1N2JhMT',
|
||||
'source': 'openstack'})]
|
||||
|
||||
self.driver._translate_meters(meters_data)
|
||||
meter_list = list(self.driver.state['meters'])
|
||||
self.assertIsNotNone(meter_list)
|
||||
self.assertEqual(2, len(meter_list))
|
||||
|
||||
for meter in meter_list:
|
||||
if meter[1] == 'network.incoming.bytes':
|
||||
meter1 = meter
|
||||
elif meter[1] == 'instance:m1.tiny':
|
||||
meter2 = meter
|
||||
|
||||
# Verifying individual tuple data
|
||||
self.assertEqual(('aW5zdGFuY2UtMDAwMDAwMDEtYTI1N2JhMT',
|
||||
'network.incoming.bytes',
|
||||
'cumulative',
|
||||
'B',
|
||||
'openstack',
|
||||
'instance-00000001-tap437ce69c-e5',
|
||||
'2b01323fd71345bc8cdc5dbbd6d127ea',
|
||||
'0020df0171ec41b597cd8b3002e21bee'),
|
||||
meter1)
|
||||
|
||||
self.assertEqual(('YTI1N2JhMTMtMGIzNi00YTg2LWFlODktZjc4ZG',
|
||||
'instance:m1.tiny',
|
||||
'gauge',
|
||||
'instance',
|
||||
'openstack',
|
||||
'a257ba13-0b36-4a86-ae89-f78dd28b8ae5',
|
||||
'2b01323fd71345bc8cdc5dbbd6d127ea',
|
||||
'0020df0171ec41b597cd8b3002e21bee'),
|
||||
meter2)
|
||||
|
||||
def test_list_alarms(self):
|
||||
threshold_rule1 = {'key1': 'value1',
|
||||
'key2': 'value2',
|
||||
'key3': 'value3'}
|
||||
threshold_rule2 = {'key4': 'value4',
|
||||
'key5': 'value5',
|
||||
'key6': 'value6'}
|
||||
|
||||
alarms_data = [
|
||||
ResponseObj({'alarm_id': '7ef99553-a73f-4b18-a617-997a479c48e9',
|
||||
'name': 'cpu_high2',
|
||||
'state': 'insufficient data',
|
||||
'enabled': 'True',
|
||||
'threshold_rule': threshold_rule1,
|
||||
'type': 'threshold',
|
||||
'description': 'instance running hot',
|
||||
'time_constraints': '[]',
|
||||
'user_id': '2b01323fd71345bc8cdc5dbbd6d127ea',
|
||||
'project_id': '',
|
||||
'alarm_actions': "[u'log://']",
|
||||
'ok_actions': '[]',
|
||||
'insufficient_data_actions': '[]',
|
||||
'repeat_actions': 'False',
|
||||
'timestamp': '2014-09-30T05:00:43.351041',
|
||||
'state_timestamp': '2014-09-30T05:00:43.351041'}),
|
||||
ResponseObj({'alarm_id': 'd1b2b7a7-9512-4290-97ca-2580ed72c375',
|
||||
'name': 'cpu_high',
|
||||
'state': 'insufficient data',
|
||||
'enabled': 'True',
|
||||
'threshold_rule': threshold_rule2,
|
||||
'type': 'threshold',
|
||||
'description': 'instance running hot',
|
||||
'time_constraints': '[]',
|
||||
'user_id': '2b01323fd71345bc8cdc5dbbd6d127ea',
|
||||
'project_id': '',
|
||||
'alarm_actions': "[u'log://']",
|
||||
'ok_actions': '[]',
|
||||
'insufficient_data_actions': '[]',
|
||||
'repeat_actions': 'False',
|
||||
'timestamp': '2014-09-30T04:55:36.015925',
|
||||
'state_timestamp': '2014-09-30T04:55:36.015925'})]
|
||||
|
||||
self.driver._translate_alarms(alarms_data)
|
||||
alarm_list = list(self.driver.state['alarms'])
|
||||
self.assertIsNotNone(alarm_list)
|
||||
self.assertEqual(2, len(alarm_list))
|
||||
|
||||
alarm_threshold_rule = list(self.driver.state['alarms.threshold_rule'])
|
||||
self.assertIsNotNone(alarm_threshold_rule)
|
||||
self.assertEqual(6, len(alarm_threshold_rule))
|
||||
|
||||
for alarm in alarm_list:
|
||||
if alarm[1] == 'cpu_high2':
|
||||
alarm1 = alarm
|
||||
elif alarm[1] == 'cpu_high':
|
||||
alarm2 = alarm
|
||||
|
||||
for thres in alarm_threshold_rule:
|
||||
if thres[1] in ['key1', 'key2', 'key3']:
|
||||
thresh_rule_id1 = thres[0]
|
||||
elif thres[1] in ['key4', 'key5', 'key6']:
|
||||
thresh_rule_id2 = thres[0]
|
||||
|
||||
# Verifying individual tuple data
|
||||
self.assertEqual(('7ef99553-a73f-4b18-a617-997a479c48e9',
|
||||
'cpu_high2', 'insufficient data',
|
||||
'True',
|
||||
thresh_rule_id1,
|
||||
'threshold', 'instance running hot',
|
||||
'[]', '2b01323fd71345bc8cdc5dbbd6d127ea',
|
||||
'', "[u'log://']", '[]', '[]', 'False',
|
||||
'2014-09-30T05:00:43.351041',
|
||||
'2014-09-30T05:00:43.351041'),
|
||||
alarm1)
|
||||
self.assertEqual(('d1b2b7a7-9512-4290-97ca-2580ed72c375',
|
||||
'cpu_high', 'insufficient data', 'True',
|
||||
thresh_rule_id2,
|
||||
'threshold', 'instance running hot',
|
||||
'[]', '2b01323fd71345bc8cdc5dbbd6d127ea',
|
||||
'', "[u'log://']", '[]', '[]',
|
||||
'False', '2014-09-30T04:55:36.015925',
|
||||
'2014-09-30T04:55:36.015925'),
|
||||
alarm2)
|
||||
|
||||
def test_list_events(self):
|
||||
trait1 = [{'name': 'value1', 'type': 'value2', 'value': 'value3'},
|
||||
{'name': 'value7', 'type': 'value8', 'value': 'value9'}]
|
||||
trait2 = [{'name': 'value4', 'type': 'value5', 'value': 'value6'}]
|
||||
trait3 = []
|
||||
|
||||
events_data = [
|
||||
ResponseObj({'message_id': '6834861c-ccb3-4c6f-ac00-fe8fe1ad4ed4',
|
||||
'event_type': 'image.create',
|
||||
'generated': '2014-09-29T08:19:45.556301',
|
||||
'traits': trait1}),
|
||||
ResponseObj({'message_id': '3676d6d4-5c65-4442-9eda-b78d750ea91f',
|
||||
'event_type': 'compute.instance.update',
|
||||
'generated': '2014-09-30T04:54:45.395522',
|
||||
'traits': trait2}),
|
||||
ResponseObj({'message_id': 'fae7b03d-b5b7-4b4f-b2ef-06d2af03f21e',
|
||||
'event_type': 'telemetry.api',
|
||||
'generated': '2015-09-02T10:12:50.338919',
|
||||
'traits': trait3})]
|
||||
|
||||
self.driver._translate_events(events_data)
|
||||
events_set = self.driver.state['events']
|
||||
expected_events = {('6834861c-ccb3-4c6f-ac00-fe8fe1ad4ed4',
|
||||
'image.create', '2014-09-29T08:19:45.556301'),
|
||||
('3676d6d4-5c65-4442-9eda-b78d750ea91f',
|
||||
'compute.instance.update',
|
||||
'2014-09-30T04:54:45.395522'),
|
||||
('fae7b03d-b5b7-4b4f-b2ef-06d2af03f21e',
|
||||
'telemetry.api', '2015-09-02T10:12:50.338919')}
|
||||
self.assertEqual(expected_events, events_set)
|
||||
|
||||
event_traits_set = self.driver.state['events.traits']
|
||||
expected_traits = {('6834861c-ccb3-4c6f-ac00-fe8fe1ad4ed4',
|
||||
'value1', 'value2', 'value3'),
|
||||
('6834861c-ccb3-4c6f-ac00-fe8fe1ad4ed4',
|
||||
'value7', 'value8', 'value9'),
|
||||
('3676d6d4-5c65-4442-9eda-b78d750ea91f',
|
||||
'value4', 'value5', 'value6')}
|
||||
self.assertEqual(expected_traits, event_traits_set)
|
||||
|
||||
def test_list_statistics(self):
|
||||
statistics_data = [
|
||||
{'meter_name': 'network',
|
||||
'period': 0, 'groupby':
|
||||
{'resource_id': '2fdef98a-8a00-4094-b6b8-b3f742076417'},
|
||||
'period_start': '2014-12-09T12:52:39.366015',
|
||||
'period_end': '2014-12-09T12:52:56.478338',
|
||||
'max': 0.0, 'min': 0.0, 'avg': 0.0, 'sum': 0.0,
|
||||
'count': 10, 'duration': 17.112323, 'unit': 'GB',
|
||||
'duration_start': '2014-12-09T12:52:39.366015',
|
||||
'duration_end': '2014-12-09T12:52:56.478338'},
|
||||
{'meter_name': 'instance',
|
||||
'period': 0, 'groupby':
|
||||
{'resource_id': '8a1340fa-fd43-4376-9deb-37c872c47e38'},
|
||||
'period_start': '2014-12-09T12:52:39.366015',
|
||||
'period_end': '2014-12-09T13:04:34',
|
||||
'max': 1.0, 'min': 1.0, 'avg': 1.0, 'sum': 13.0,
|
||||
'count': 13, 'duration': 714.633985,
|
||||
'unit': 'instance',
|
||||
'duration_start': '2014-12-09T12:52:39.366015',
|
||||
'duration_end': '2014-12-09T13:04:34'}]
|
||||
|
||||
self.driver._translate_statistics(statistics_data)
|
||||
statistics_list = list(self.driver.state['statistics'])
|
||||
self.assertIsNotNone(statistics_list)
|
||||
self.assertEqual(2, len(statistics_list))
|
||||
|
||||
# Verifying individual tuple data
|
||||
s1 = next(x for x in statistics_list if x[0] == 'network')
|
||||
s2 = next(x for x in statistics_list if x[0] == 'instance')
|
||||
|
||||
self.assertEqual(('network',
|
||||
'2fdef98a-8a00-4094-b6b8-b3f742076417',
|
||||
0.0, 10, 17.112323,
|
||||
'2014-12-09T12:52:39.366015',
|
||||
'2014-12-09T12:52:56.478338',
|
||||
0.0, 0.0, 0,
|
||||
'2014-12-09T12:52:56.478338',
|
||||
'2014-12-09T12:52:39.366015',
|
||||
0.0, 'GB'), s1)
|
||||
self.assertEqual(('instance',
|
||||
'8a1340fa-fd43-4376-9deb-37c872c47e38',
|
||||
1.0, 13, 714.633985,
|
||||
'2014-12-09T12:52:39.366015',
|
||||
'2014-12-09T13:04:34',
|
||||
1.0, 1.0, 0,
|
||||
'2014-12-09T13:04:34',
|
||||
'2014-12-09T12:52:39.366015',
|
||||
13.0, 'instance'), s2)
|
||||
|
||||
def test_execute(self):
|
||||
class CeilometerClient(object):
|
||||
def __init__(self):
|
||||
self.testkey = None
|
||||
|
||||
def setAlarm(self, arg1):
|
||||
self.testkey = 'arg1=%s' % arg1
|
||||
|
||||
ceilometer_client = CeilometerClient()
|
||||
self.driver.ceilometer_client = ceilometer_client
|
||||
api_args = {
|
||||
'positional': ['1']
|
||||
}
|
||||
expected_ans = 'arg1=1'
|
||||
|
||||
self.driver.execute('setAlarm', api_args)
|
||||
|
||||
self.assertEqual(ceilometer_client.testkey, expected_ans)
|
|
@ -1,85 +0,0 @@
|
|||
# Copyright 2014 OpenStack Foundation
|
||||
# All Rights Reserved.
|
||||
#
|
||||
# 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 tempest import config
|
||||
from tempest.lib.common.utils import test_utils
|
||||
from tempest.lib import decorators
|
||||
from tempest.lib import exceptions
|
||||
|
||||
from congress_tempest_tests.tests.scenario import manager_congress
|
||||
|
||||
|
||||
CONF = config.CONF
|
||||
|
||||
|
||||
class TestCeilometerDriver(manager_congress.ScenarioPolicyBase):
|
||||
|
||||
@classmethod
|
||||
def skip_checks(cls):
|
||||
super(TestCeilometerDriver, cls).skip_checks()
|
||||
if not getattr(CONF.service_available, 'ceilometer', False):
|
||||
msg = ("%s skipped as ceilometer is not available" %
|
||||
cls.__class__.__name__)
|
||||
raise cls.skipException(msg)
|
||||
|
||||
def setUp(self):
|
||||
super(TestCeilometerDriver, self).setUp()
|
||||
self.telemetry_client = self.os_admin.telemetry_client
|
||||
self.datasource_id = manager_congress.get_datasource_id(
|
||||
self.os_admin.congress_client, 'ceilometer')
|
||||
|
||||
@decorators.attr(type='smoke')
|
||||
def test_ceilometer_meters_table(self):
|
||||
meter_schema = (
|
||||
self.os_admin.congress_client.show_datasource_table_schema(
|
||||
self.datasource_id, 'meters')['columns'])
|
||||
meter_id_col = next(i for i, c in enumerate(meter_schema)
|
||||
if c['name'] == 'meter_id')
|
||||
|
||||
def _check_data_table_ceilometer_meters():
|
||||
# Fetch data from ceilometer each time, because this test may start
|
||||
# before ceilometer has all the users.
|
||||
meters = self.telemetry_client.list_meters()
|
||||
meter_map = {}
|
||||
for meter in meters:
|
||||
meter_map[meter['meter_id']] = meter
|
||||
|
||||
results = (
|
||||
self.os_admin.congress_client.list_datasource_rows(
|
||||
self.datasource_id, 'meters'))
|
||||
for row in results['results']:
|
||||
try:
|
||||
meter_row = meter_map[row['data'][meter_id_col]]
|
||||
except KeyError:
|
||||
return False
|
||||
for index in range(len(meter_schema)):
|
||||
if (str(row['data'][index]) !=
|
||||
str(meter_row[meter_schema[index]['name']])):
|
||||
return False
|
||||
return True
|
||||
|
||||
if not test_utils.call_until_true(
|
||||
func=_check_data_table_ceilometer_meters,
|
||||
duration=100, sleep_for=5):
|
||||
raise exceptions.TimeoutException("Data did not converge in time "
|
||||
"or failure in server")
|
||||
|
||||
@decorators.attr(type='smoke')
|
||||
def test_update_no_error(self):
|
||||
if not test_utils.call_until_true(
|
||||
func=lambda: self.check_datasource_no_error('ceilometer'),
|
||||
duration=30, sleep_for=5):
|
||||
raise exceptions.TimeoutException('Datasource could not poll '
|
||||
'without error.')
|
|
@ -75,7 +75,6 @@ function configure_congress {
|
|||
CONGRESS_DRIVERS+="congress.datasources.glancev2_driver.GlanceV2Driver,"
|
||||
CONGRESS_DRIVERS+="congress.datasources.nova_driver.NovaDriver,"
|
||||
CONGRESS_DRIVERS+="congress.datasources.keystonev3_driver.KeystoneV3Driver,"
|
||||
CONGRESS_DRIVERS+="congress.datasources.ceilometer_driver.CeilometerDriver,"
|
||||
CONGRESS_DRIVERS+="congress.datasources.cinder_driver.CinderDriver,"
|
||||
CONGRESS_DRIVERS+="congress.datasources.swift_driver.SwiftDriver,"
|
||||
CONGRESS_DRIVERS+="congress.datasources.plexxi_driver.PlexxiDriver,"
|
||||
|
@ -100,7 +99,6 @@ function configure_congress_datasources {
|
|||
_configure_service neutron neutronv2_qos
|
||||
_configure_service nova nova
|
||||
_configure_service key keystonev3
|
||||
_configure_service ceilometer ceilometer
|
||||
_configure_service cinder cinder
|
||||
_configure_service swift swift
|
||||
_configure_service glance glancev2
|
||||
|
|
|
@ -121,7 +121,7 @@ Add drivers:
|
|||
|
||||
.. code-block:: text
|
||||
|
||||
drivers = congress.datasources.neutronv2_driver.NeutronV2Driver,congress.datasources.glancev2_driver.GlanceV2Driver,congress.datasources.nova_driver.NovaDriver,congress.datasources.keystone_driver.KeystoneDriver,congress.datasources.ceilometer_driver.CeilometerDriver,congress.datasources.cinder_driver.CinderDriver,congress.datasources.swift_driver.SwiftDriver,congress.datasources.plexxi_driver.PlexxiDriver,congress.datasources.vCenter_driver.VCenterDriver,congress.datasources.murano_driver.MuranoDriver,congress.datasources.ironic_driver.IronicDriver
|
||||
drivers = congress.datasources.neutronv2_driver.NeutronV2Driver,congress.datasources.glancev2_driver.GlanceV2Driver,congress.datasources.nova_driver.NovaDriver,congress.datasources.keystone_driver.KeystoneDriver,congress.datasources.cinder_driver.CinderDriver,congress.datasources.swift_driver.SwiftDriver,congress.datasources.plexxi_driver.PlexxiDriver,congress.datasources.vCenter_driver.VCenterDriver,congress.datasources.murano_driver.MuranoDriver,congress.datasources.ironic_driver.IronicDriver
|
||||
|
||||
|
||||
The default auth_strategy is keystone. To set Congress to use no authorization strategy:
|
||||
|
|
|
@ -1,19 +0,0 @@
|
|||
---
|
||||
name: ServerUtilization
|
||||
description: "Rules related to server utilization. For example, identifying underutilized servers."
|
||||
rules:
|
||||
-
|
||||
comment: >
|
||||
Identify all virtual machines whose CPU utilization averages less than 10%.
|
||||
Affectionately called, the "deadbeat detector", this policy helps operators understand
|
||||
whether a request for increased quota is warranted or not.
|
||||
rule: >
|
||||
underutilized_servers(server_id) :-
|
||||
ceilometer:statistics(meter_name='cpu_util',resource_id=server_id, avg=avg),
|
||||
builtin:lt(avg, 10)
|
||||
-
|
||||
comment: "User should customize this. Permitted flavors."
|
||||
rule: >
|
||||
warning(server_id, server_name, user_id) :-
|
||||
underutilized_servers(server_id),
|
||||
nova:servers(id=server_id, name=server_name, user_id=user_id)
|
|
@ -0,0 +1,6 @@
|
|||
---
|
||||
deprecations:
|
||||
- |
|
||||
Ceilometer datasource is no longer supported in congress as the ceilometer API
|
||||
has been deprecated in Ocata and removed in Queens release. So, congress
|
||||
no longer supports retreiving data from ceilometer.
|
Loading…
Reference in New Issue