Andrey Kurilin fda172a4ce Fix the order of imports
Change-Id: I99a6f09bd5e4385f9a7710f374a1eb41bad28c74
2018-02-20 15:25:02 +00:00

468 lines
18 KiB
Python

# 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.
import datetime as dt
import uuid
from rally import exceptions
from rally.task import atomic
from rally.task import utils as bench_utils
import six
from rally_openstack import scenario
class CeilometerScenario(scenario.OpenStackScenario):
"""Base class for Ceilometer scenarios with basic atomic actions."""
def _make_samples(self, count=1, interval=0, counter_name="cpu_util",
counter_type="gauge", counter_unit="%", counter_volume=1,
project_id=None, user_id=None, source=None,
timestamp=None, metadata_list=None, batch_size=None):
"""Prepare and return a list of samples.
:param count: specifies number of samples in array
:param interval: specifies interval between timestamps of near-by
samples
:param counter_name: specifies name of the counter
:param counter_type: specifies type of the counter
:param counter_unit: specifies unit of the counter
:param counter_volume: specifies volume of the counter
:param project_id: specifies project id for samples
:param user_id: specifies user id for samples
:param source: specifies source for samples
:param timestamp: specifies timestamp for samples
:param metadata_list: specifies list of resource metadata
:param batch_size: specifies number of samples to store in one query
:returns: generator that produces lists of samples
"""
batch_size = batch_size or count
sample = {
"counter_name": counter_name,
"counter_type": counter_type,
"counter_unit": counter_unit,
"counter_volume": counter_volume,
"resource_id": str(uuid.uuid4())
}
opt_fields = {
"project_id": project_id,
"user_id": user_id,
"source": source,
"timestamp": timestamp,
}
for k, v in opt_fields.items():
if v:
sample.update({k: v})
len_meta = len(metadata_list) if metadata_list else 0
now = timestamp or dt.datetime.utcnow()
samples = []
for i in six.moves.xrange(count):
if i and not (i % batch_size):
yield samples
samples = []
sample_item = dict(sample)
sample_item["timestamp"] = (
now - dt.timedelta(seconds=(interval * i))
).isoformat()
if metadata_list:
# NOTE(idegtiarov): Adding more than one template of metadata
# required it's proportional distribution among whole samples.
sample_item["resource_metadata"] = metadata_list[
i * len_meta // count
]
samples.append(sample_item)
yield samples
def _make_query_item(self, field, op="eq", value=None):
"""Create a SimpleQuery item for requests.
:param field: filtered field
:param op: operator for filtering
:param value: matched value
:returns: dict with field, op and value keys for query
"""
return {"field": field, "op": op, "value": value}
def _make_general_query(self, filter_by_project_id=None,
filter_by_user_id=None,
filter_by_resource_id=None,
metadata_query=None):
"""Create a SimpleQuery used by samples list API.
:param filter_by_project_id: add a project id to query
:param filter_by_user_id: add a user id to query
:param filter_by_resource_id: add a resource id to query
:param metadata_query: metadata dict that will add to query
:returns: SimpleQuery with specified items
"""
query = []
metadata_query = metadata_query or {}
if filter_by_user_id:
query.append(self._make_query_item("user_id", "eq",
self.context["user"]["id"]))
if filter_by_project_id:
query.append(self._make_query_item(
"project_id", "eq", self.context["tenant"]["id"]))
if filter_by_resource_id:
query.append(self._make_query_item(
"resource_id", "eq", self.context["tenant"]["resources"][0]))
for key, value in metadata_query.items():
query.append(self._make_query_item("metadata.%s" % key,
value=value))
return query
def _make_timestamp_query(self, start_time=None, end_time=None):
"""Create ceilometer query for timestamp range.
:param start_time: start datetime in isoformat
:param end_time: end datetime in isoformat
:returns: query with timestamp range
"""
query = []
if end_time and start_time and end_time < start_time:
msg = "End time should be great or equal than start time"
raise exceptions.InvalidArgumentsException(msg)
if start_time:
query.append(self._make_query_item("timestamp", ">=", start_time))
if end_time:
query.append(self._make_query_item("timestamp", "<=", end_time))
return query
def _make_profiler_key(self, method, query=None, limit=None):
"""Create key for profiling method with query.
:param method: Original profiler tag for method
:param query: ceilometer query which fields will be added to key
:param limit: if it exists `limit` will be added to key
:returns: profiler key that includes method and queried fields
"""
query = query or []
limit_line = limit and "limit" or ""
fields_line = "&".join("%s" % a["field"] for a in query)
key_identifiers = "&".join(x for x in (limit_line, fields_line) if x)
key = ":".join(x for x in (method, key_identifiers) if x)
return key
def _get_alarm_dict(self, **kwargs):
"""Prepare and return an alarm dict for creating an alarm.
:param kwargs: optional parameters to create alarm
:returns: alarm dictionary used to create an alarm
"""
alarm_id = self.generate_random_name()
alarm = {"alarm_id": alarm_id,
"name": alarm_id,
"description": "Test Alarm"}
alarm.update(kwargs)
return alarm
@atomic.action_timer("ceilometer.list_alarms")
def _list_alarms(self, alarm_id=None):
"""List alarms.
List alarm matching alarm_id. It fetches all alarms
if alarm_id is None.
:param alarm_id: specifies id of the alarm
:returns: list of alarms
"""
if alarm_id:
return self.clients("ceilometer").alarms.get(alarm_id)
else:
return self.clients("ceilometer").alarms.list()
@atomic.action_timer("ceilometer.get_alarm")
def _get_alarm(self, alarm_id):
"""Get detailed information of an alarm.
:param alarm_id: Specifies id of the alarm
:returns: If alarm_id is existed and correct, returns
detailed information of an alarm, else returns None
"""
return self.clients("ceilometer").alarms.get(alarm_id)
@atomic.action_timer("ceilometer.create_alarm")
def _create_alarm(self, meter_name, threshold, kwargs):
"""Create an alarm.
:param meter_name: specifies meter name of the alarm
:param threshold: specifies alarm threshold
:param kwargs: contains optional features of alarm to be created
:returns: alarm
"""
alarm_dict = self._get_alarm_dict(**kwargs)
alarm_dict.update({"meter_name": meter_name,
"threshold": threshold})
alarm = self.clients("ceilometer").alarms.create(**alarm_dict)
return alarm
@atomic.action_timer("ceilometer.delete_alarm")
def _delete_alarm(self, alarm_id):
"""Delete an alarm.
:param alarm_id: specifies id of the alarm
"""
self.clients("ceilometer").alarms.delete(alarm_id)
@atomic.action_timer("ceilometer.update_alarm")
def _update_alarm(self, alarm_id, alarm_dict_delta):
"""Update an alarm.
:param alarm_id: specifies id of the alarm
:param alarm_dict_delta: features of alarm to be updated
"""
self.clients("ceilometer").alarms.update(alarm_id, **alarm_dict_delta)
@atomic.action_timer("ceilometer.get_alarm_history")
def _get_alarm_history(self, alarm_id):
"""Assemble the alarm history requested.
:param alarm_id: specifies id of the alarm
:returns: list of alarm changes
"""
return self.clients("ceilometer").alarms.get_history(alarm_id)
@atomic.action_timer("ceilometer.get_alarm_state")
def _get_alarm_state(self, alarm_id):
"""Get the state of the alarm.
:param alarm_id: specifies id of the alarm
:returns: state of the alarm
"""
return self.clients("ceilometer").alarms.get_state(alarm_id)
@atomic.action_timer("ceilometer.set_alarm_state")
def _set_alarm_state(self, alarm, state, timeout):
"""Set the state of the alarm.
:param alarm: alarm instance
:param state: an alarm state to be set
:param timeout: The number of seconds for which to attempt a
successful check of the alarm state.
:returns: alarm in the set state
"""
self.clients("ceilometer").alarms.set_state(alarm.alarm_id, state)
return bench_utils.wait_for_status(alarm,
ready_statuses=[state],
update_resource=bench_utils
.get_from_manager(),
timeout=timeout, check_interval=1)
@atomic.action_timer("ceilometer.list_events")
def _list_events(self):
"""Get list of user's events.
It fetches all events.
:returns: list of events
"""
return self.admin_clients("ceilometer").events.list()
@atomic.action_timer("ceilometer.get_event")
def _get_event(self, event_id):
"""Get event with specific id.
Get event matching event_id.
:param event_id: specifies id of the event
:returns: event
"""
return self.admin_clients("ceilometer").events.get(event_id)
@atomic.action_timer("ceilometer.list_event_types")
def _list_event_types(self):
"""Get list of all event types.
:returns: list of event types
"""
return self.admin_clients("ceilometer").event_types.list()
@atomic.action_timer("ceilometer.list_event_traits")
def _list_event_traits(self, event_type, trait_name):
"""Get list of event traits.
:param event_type: specifies the type of event
:param trait_name: specifies trait name
:returns: list of event traits
"""
return self.admin_clients("ceilometer").traits.list(event_type,
trait_name)
@atomic.action_timer("ceilometer.list_event_trait_descriptions")
def _list_event_trait_descriptions(self, event_type):
"""Get list of event trait descriptions.
:param event_type: specifies the type of event
:returns: list of event trait descriptions
"""
return self.admin_clients("ceilometer").trait_descriptions.list(
event_type)
def _list_samples(self, query=None, limit=None):
"""List all Samples.
:param query: optional param that specify query
:param limit: optional param for maximum number of samples returned
:returns: list of samples
"""
key = self._make_profiler_key("ceilometer.list_samples", query,
limit)
with atomic.ActionTimer(self, key):
return self.clients("ceilometer").new_samples.list(q=query,
limit=limit)
@atomic.action_timer("ceilometer.get_resource")
def _get_resource(self, resource_id):
"""Retrieve details about one resource."""
return self.clients("ceilometer").resources.get(resource_id)
@atomic.action_timer("ceilometer.get_stats")
def _get_stats(self, meter_name, query=None, period=None, groupby=None,
aggregates=None):
"""Get stats for a specific meter.
:param meter_name: Name of ceilometer meter
:param query: list of queries
:param period: the length of the time range covered by these stats
:param groupby: the fields used to group the samples
:param aggregates: function for samples aggregation
:returns: list of statistics data
"""
return self.clients("ceilometer").statistics.list(meter_name, q=query,
period=period,
groupby=groupby,
aggregates=aggregates
)
@atomic.action_timer("ceilometer.create_meter")
def _create_meter(self, **kwargs):
"""Create a new meter.
:param kwargs: Contains the optional attributes for meter creation
:returns: Newly created meter
"""
name = self.generate_random_name()
samples = self.clients("ceilometer").samples.create(
counter_name=name, **kwargs)
return samples[0]
@atomic.action_timer("ceilometer.query_alarms")
def _query_alarms(self, filter, orderby, limit):
"""Query alarms with specific parameters.
If no input params are provided, it returns all the results
in the database.
:param limit: optional param for maximum number of results returned
:param orderby: optional param for specifying ordering of results
:param filter: optional filter query
:returns: queried alarms
"""
return self.clients("ceilometer").query_alarms.query(
filter, orderby, limit)
@atomic.action_timer("ceilometer.query_alarm_history")
def _query_alarm_history(self, filter, orderby, limit):
"""Query history of an alarm.
If no input params are provided, it returns all the results
in the database.
:param limit: optional param for maximum number of results returned
:param orderby: optional param for specifying ordering of results
:param filter: optional filter query
:returns: alarm history
"""
return self.clients("ceilometer").query_alarm_history.query(
filter, orderby, limit)
@atomic.action_timer("ceilometer.create_sample")
def _create_sample(self, counter_name, counter_type, counter_unit,
counter_volume, resource_id=None, **kwargs):
"""Create a Sample with specified parameters.
:param counter_name: specifies name of the counter
:param counter_type: specifies type of the counter
:param counter_unit: specifies unit of the counter
:param counter_volume: specifies volume of the counter
:param resource_id: specifies resource id for the sample created
:param kwargs: contains optional parameters for creating a sample
:returns: created sample
"""
kwargs.update({"counter_name": counter_name,
"counter_type": counter_type,
"counter_unit": counter_unit,
"counter_volume": counter_volume,
"resource_id": resource_id if resource_id
else self.generate_random_name()})
return self.clients("ceilometer").samples.create(**kwargs)
@atomic.action_timer("ceilometer.create_samples")
def _create_samples(self, samples):
"""Create Samples with specified parameters.
:param samples: a list of samples to create
:returns: created list samples
"""
return self.clients("ceilometer").samples.create_list(samples)
@atomic.action_timer("ceilometer.query_samples")
def _query_samples(self, filter, orderby, limit):
"""Query samples with specified parameters.
If no input params are provided, it returns all the results
in the database.
:param limit: optional param for maximum number of results returned
:param orderby: optional param for specifying ordering of results
:param filter: optional filter query
:returns: queried samples
"""
return self.clients("ceilometer").query_samples.query(
filter, orderby, limit)
def _list_resources(self, query=None, limit=None):
"""List all resources.
:param query: query list for Ceilometer api
:param limit: count of returned resources
:returns: list of all resources
"""
key = self._make_profiler_key("ceilometer.list_resources", query,
limit)
with atomic.ActionTimer(self, key):
return self.clients("ceilometer").resources.list(q=query,
limit=limit)
def _list_meters(self, query=None, limit=None):
"""Get list of user's meters.
:param query: query list for Ceilometer api
:param limit: count of returned meters
:returns: list of all meters
"""
key = self._make_profiler_key("ceilometer.list_meters", query,
limit)
with atomic.ActionTimer(self, key):
return self.clients("ceilometer").meters.list(q=query,
limit=limit)