Compare commits
26 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
40a653215f | ||
|
|
1492f5d8dc | ||
|
|
76263f149a | ||
|
|
028006d15d | ||
|
|
d27ba8cc2a | ||
|
|
33750ce7a9 | ||
|
|
cb8d1a98d6 | ||
|
|
f32252d510 | ||
|
|
4849f8dde9 | ||
|
|
0cafdcdee9 | ||
|
|
3a70225164 | ||
|
|
892c766ac4 | ||
|
|
63a3fd84ae | ||
|
|
287ace1dcc | ||
|
|
4b302e415e | ||
|
|
f24744c910 | ||
|
|
d9a85eda2c | ||
|
|
82c8633e42 | ||
|
|
d3f23795f5 | ||
|
|
e7f4456a80 | ||
|
|
a36a309e2e | ||
|
|
8e3affd9ac | ||
|
|
71e979cae0 | ||
|
|
6edfd34a53 | ||
|
|
0c8c32e69e | ||
|
|
9138b7bacb |
@@ -1,5 +1,4 @@
|
|||||||
- project:
|
- project:
|
||||||
name: openstack/watcher
|
|
||||||
check:
|
check:
|
||||||
jobs:
|
jobs:
|
||||||
- watcher-tempest-multinode
|
- watcher-tempest-multinode
|
||||||
|
|||||||
@@ -267,7 +267,7 @@ the same goal and same workload of the :ref:`Cluster <cluster_definition>`.
|
|||||||
Project
|
Project
|
||||||
=======
|
=======
|
||||||
|
|
||||||
:ref:`Projects <project_definition>` represent the base unit of “ownership”
|
:ref:`Projects <project_definition>` represent the base unit of "ownership"
|
||||||
in OpenStack, in that all :ref:`resources <managed_resource_definition>` in
|
in OpenStack, in that all :ref:`resources <managed_resource_definition>` in
|
||||||
OpenStack should be owned by a specific :ref:`project <project_definition>`.
|
OpenStack should be owned by a specific :ref:`project <project_definition>`.
|
||||||
In OpenStack Identity, a :ref:`project <project_definition>` must be owned by a
|
In OpenStack Identity, a :ref:`project <project_definition>` must be owned by a
|
||||||
|
|||||||
86
doc/source/strategies/actuation.rst
Normal file
86
doc/source/strategies/actuation.rst
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
=============
|
||||||
|
Actuator
|
||||||
|
=============
|
||||||
|
|
||||||
|
Synopsis
|
||||||
|
--------
|
||||||
|
|
||||||
|
**display name**: ``Actuator``
|
||||||
|
|
||||||
|
**goal**: ``unclassified``
|
||||||
|
|
||||||
|
.. watcher-term:: watcher.decision_engine.strategy.strategies.actuation
|
||||||
|
|
||||||
|
Requirements
|
||||||
|
------------
|
||||||
|
|
||||||
|
Metrics
|
||||||
|
*******
|
||||||
|
|
||||||
|
None
|
||||||
|
|
||||||
|
Cluster data model
|
||||||
|
******************
|
||||||
|
|
||||||
|
None
|
||||||
|
|
||||||
|
Actions
|
||||||
|
*******
|
||||||
|
|
||||||
|
Default Watcher's actions.
|
||||||
|
|
||||||
|
Planner
|
||||||
|
*******
|
||||||
|
|
||||||
|
Default Watcher's planner:
|
||||||
|
|
||||||
|
.. watcher-term:: watcher.decision_engine.planner.weight.WeightPlanner
|
||||||
|
|
||||||
|
Configuration
|
||||||
|
-------------
|
||||||
|
|
||||||
|
Strategy parameters are:
|
||||||
|
|
||||||
|
==================== ====== ===================== =============================
|
||||||
|
parameter type default Value description
|
||||||
|
==================== ====== ===================== =============================
|
||||||
|
``actions`` array None Actions to be executed.
|
||||||
|
==================== ====== ===================== =============================
|
||||||
|
|
||||||
|
The elements of actions array are:
|
||||||
|
|
||||||
|
==================== ====== ===================== =============================
|
||||||
|
parameter type default Value description
|
||||||
|
==================== ====== ===================== =============================
|
||||||
|
``action_type`` string None Action name defined in
|
||||||
|
setup.cfg(mandatory)
|
||||||
|
``resource_id`` string None Resource_id of the action.
|
||||||
|
``input_parameters`` object None Input_parameters of the
|
||||||
|
action(mandatory).
|
||||||
|
==================== ====== ===================== =============================
|
||||||
|
|
||||||
|
Efficacy Indicator
|
||||||
|
------------------
|
||||||
|
|
||||||
|
None
|
||||||
|
|
||||||
|
Algorithm
|
||||||
|
---------
|
||||||
|
|
||||||
|
This strategy create an action plan with a predefined set of actions.
|
||||||
|
|
||||||
|
How to use it ?
|
||||||
|
---------------
|
||||||
|
|
||||||
|
.. code-block:: shell
|
||||||
|
|
||||||
|
$ openstack optimize audittemplate create \
|
||||||
|
at1 unclassified --strategy actuator
|
||||||
|
|
||||||
|
$ openstack optimize audit create -a at1 \
|
||||||
|
-p actions='[{"action_type": "migrate", "resource_id": "56a40802-6fde-4b59-957c-c84baec7eaed", "input_parameters": {"migration_type": "live", "source_node": "s01"}}]'
|
||||||
|
|
||||||
|
External Links
|
||||||
|
--------------
|
||||||
|
|
||||||
|
None
|
||||||
154
doc/source/strategies/zone_migration.rst
Normal file
154
doc/source/strategies/zone_migration.rst
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
==============
|
||||||
|
Zone migration
|
||||||
|
==============
|
||||||
|
|
||||||
|
Synopsis
|
||||||
|
--------
|
||||||
|
|
||||||
|
**display name**: ``Zone migration``
|
||||||
|
|
||||||
|
**goal**: ``hardware_maintenance``
|
||||||
|
|
||||||
|
.. watcher-term:: watcher.decision_engine.strategy.strategies.zone_migration
|
||||||
|
|
||||||
|
Requirements
|
||||||
|
------------
|
||||||
|
|
||||||
|
Metrics
|
||||||
|
*******
|
||||||
|
|
||||||
|
None
|
||||||
|
|
||||||
|
Cluster data model
|
||||||
|
******************
|
||||||
|
|
||||||
|
Default Watcher's Compute cluster data model:
|
||||||
|
|
||||||
|
.. watcher-term:: watcher.decision_engine.model.collector.nova.NovaClusterDataModelCollector
|
||||||
|
|
||||||
|
Storage cluster data model is also required:
|
||||||
|
|
||||||
|
.. watcher-term:: watcher.decision_engine.model.collector.cinder.CinderClusterDataModelCollector
|
||||||
|
|
||||||
|
Actions
|
||||||
|
*******
|
||||||
|
|
||||||
|
|
||||||
|
Default Watcher's actions:
|
||||||
|
|
||||||
|
.. list-table::
|
||||||
|
:widths: 30 30
|
||||||
|
:header-rows: 1
|
||||||
|
|
||||||
|
* - action
|
||||||
|
- description
|
||||||
|
* - ``migrate``
|
||||||
|
- .. watcher-term:: watcher.applier.actions.migration.Migrate
|
||||||
|
* - ``volume_migrate``
|
||||||
|
- .. watcher-term:: watcher.applier.actions.volume_migration.VolumeMigrate
|
||||||
|
|
||||||
|
Planner
|
||||||
|
*******
|
||||||
|
|
||||||
|
Default Watcher's planner:
|
||||||
|
|
||||||
|
.. watcher-term:: watcher.decision_engine.planner.weight.WeightPlanner
|
||||||
|
|
||||||
|
Configuration
|
||||||
|
-------------
|
||||||
|
|
||||||
|
Strategy parameters are:
|
||||||
|
|
||||||
|
======================== ======== ============= ==============================
|
||||||
|
parameter type default Value description
|
||||||
|
======================== ======== ============= ==============================
|
||||||
|
``compute_nodes`` array None Compute nodes to migrate.
|
||||||
|
``storage_pools`` array None Storage pools to migrate.
|
||||||
|
``parallel_total`` integer 6 The number of actions to be
|
||||||
|
run in parallel in total.
|
||||||
|
``parallel_per_node`` integer 2 The number of actions to be
|
||||||
|
run in parallel per compute
|
||||||
|
node.
|
||||||
|
``parallel_per_pool`` integer 2 The number of actions to be
|
||||||
|
run in parallel per storage
|
||||||
|
pool.
|
||||||
|
``priority`` object None List prioritizes instances
|
||||||
|
and volumes.
|
||||||
|
``with_attached_volume`` boolean False False: Instances will migrate
|
||||||
|
after all volumes migrate.
|
||||||
|
True: An instance will migrate
|
||||||
|
after the attached volumes
|
||||||
|
migrate.
|
||||||
|
======================== ======== ============= ==============================
|
||||||
|
|
||||||
|
The elements of compute_nodes array are:
|
||||||
|
|
||||||
|
============= ======= =============== =============================
|
||||||
|
parameter type default Value description
|
||||||
|
============= ======= =============== =============================
|
||||||
|
``src_node`` string None Compute node from which
|
||||||
|
instances migrate(mandatory).
|
||||||
|
``dst_node`` string None Compute node to which
|
||||||
|
instances migrate.
|
||||||
|
============= ======= =============== =============================
|
||||||
|
|
||||||
|
The elements of storage_pools array are:
|
||||||
|
|
||||||
|
============= ======= =============== ==============================
|
||||||
|
parameter type default Value description
|
||||||
|
============= ======= =============== ==============================
|
||||||
|
``src_pool`` string None Storage pool from which
|
||||||
|
volumes migrate(mandatory).
|
||||||
|
``dst_pool`` string None Storage pool to which
|
||||||
|
volumes migrate.
|
||||||
|
``src_type`` string None Source volume type(mandatory).
|
||||||
|
``dst_type`` string None Destination volume type
|
||||||
|
(mandatory).
|
||||||
|
============= ======= =============== ==============================
|
||||||
|
|
||||||
|
The elements of priority object are:
|
||||||
|
|
||||||
|
================ ======= =============== ======================
|
||||||
|
parameter type default Value description
|
||||||
|
================ ======= =============== ======================
|
||||||
|
``project`` array None Project names.
|
||||||
|
``compute_node`` array None Compute node names.
|
||||||
|
``storage_pool`` array None Storage pool names.
|
||||||
|
``compute`` enum None Instance attributes.
|
||||||
|
|compute|
|
||||||
|
``storage`` enum None Volume attributes.
|
||||||
|
|storage|
|
||||||
|
================ ======= =============== ======================
|
||||||
|
|
||||||
|
.. |compute| replace:: ["vcpu_num", "mem_size", "disk_size", "created_at"]
|
||||||
|
.. |storage| replace:: ["size", "created_at"]
|
||||||
|
|
||||||
|
Efficacy Indicator
|
||||||
|
------------------
|
||||||
|
|
||||||
|
.. watcher-func::
|
||||||
|
:format: literal_block
|
||||||
|
|
||||||
|
watcher.decision_engine.goal.efficacy.specs.HardwareMaintenance.get_global_efficacy_indicator
|
||||||
|
|
||||||
|
Algorithm
|
||||||
|
---------
|
||||||
|
|
||||||
|
For more information on the zone migration strategy please refer
|
||||||
|
to: http://specs.openstack.org/openstack/watcher-specs/specs/queens/implemented/zone-migration-strategy.html
|
||||||
|
|
||||||
|
How to use it ?
|
||||||
|
---------------
|
||||||
|
|
||||||
|
.. code-block:: shell
|
||||||
|
|
||||||
|
$ openstack optimize audittemplate create \
|
||||||
|
at1 hardware_maintenance --strategy zone_migration
|
||||||
|
|
||||||
|
$ openstack optimize audit create -a at1 \
|
||||||
|
-p compute_nodes='[{"src_node": "s01", "dst_node": "d01"}]'
|
||||||
|
|
||||||
|
External Links
|
||||||
|
--------------
|
||||||
|
|
||||||
|
None
|
||||||
@@ -4,11 +4,11 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: watcher\n"
|
"Project-Id-Version: watcher\n"
|
||||||
"Report-Msgid-Bugs-To: \n"
|
"Report-Msgid-Bugs-To: \n"
|
||||||
"POT-Creation-Date: 2018-01-19 11:46+0000\n"
|
"POT-Creation-Date: 2018-01-26 00:18+0000\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"PO-Revision-Date: 2018-01-19 07:16+0000\n"
|
"PO-Revision-Date: 2018-01-27 12:50+0000\n"
|
||||||
"Last-Translator: Andi Chandler <andi@gowling.com>\n"
|
"Last-Translator: Andi Chandler <andi@gowling.com>\n"
|
||||||
"Language-Team: English (United Kingdom)\n"
|
"Language-Team: English (United Kingdom)\n"
|
||||||
"Language: en-GB\n"
|
"Language: en-GB\n"
|
||||||
@@ -42,8 +42,8 @@ msgstr "1.5.0"
|
|||||||
msgid "1.6.0"
|
msgid "1.6.0"
|
||||||
msgstr "1.6.0"
|
msgstr "1.6.0"
|
||||||
|
|
||||||
msgid "1.6.0-32"
|
msgid "1.7.0"
|
||||||
msgstr "1.6.0-32"
|
msgstr "1.7.0"
|
||||||
|
|
||||||
msgid "Add a service supervisor to watch Watcher deamons."
|
msgid "Add a service supervisor to watch Watcher deamons."
|
||||||
msgstr "Add a service supervisor to watch Watcher daemons."
|
msgstr "Add a service supervisor to watch Watcher daemons."
|
||||||
@@ -136,6 +136,17 @@ msgstr ""
|
|||||||
"Added a way to add a new action without having to amend the source code of "
|
"Added a way to add a new action without having to amend the source code of "
|
||||||
"the default planner."
|
"the default planner."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Added a way to check state of strategy before audit's execution. "
|
||||||
|
"Administrator can use \"watcher strategy state <strategy_name>\" command to "
|
||||||
|
"get information about metrics' availability, datasource's availability and "
|
||||||
|
"CDM's availability."
|
||||||
|
msgstr ""
|
||||||
|
"Added a way to check state of strategy before audit's execution. "
|
||||||
|
"Administrator can use \"watcher strategy state <strategy_name>\" command to "
|
||||||
|
"get information about metrics' availability, datasource's availability and "
|
||||||
|
"CDM's availability."
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Added a way to compare the efficacy of different strategies for a give "
|
"Added a way to compare the efficacy of different strategies for a give "
|
||||||
"optimization goal."
|
"optimization goal."
|
||||||
@@ -186,6 +197,18 @@ msgstr ""
|
|||||||
msgid "Added policies to handle user rights to access Watcher API."
|
msgid "Added policies to handle user rights to access Watcher API."
|
||||||
msgstr "Added policies to handle user rights to access Watcher API."
|
msgstr "Added policies to handle user rights to access Watcher API."
|
||||||
|
|
||||||
|
msgid "Added storage capacity balance strategy."
|
||||||
|
msgstr "Added storage capacity balance strategy."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Added strategy \"Zone migration\" and it's goal \"Hardware maintenance\". "
|
||||||
|
"The strategy migrates many instances and volumes efficiently with minimum "
|
||||||
|
"downtime automatically."
|
||||||
|
msgstr ""
|
||||||
|
"Added strategy \"Zone migration\" and it's goal \"Hardware maintenance\". "
|
||||||
|
"The strategy migrates many instances and volumes efficiently with minimum "
|
||||||
|
"downtime automatically."
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Added strategy to identify and migrate a Noisy Neighbor - a low priority VM "
|
"Added strategy to identify and migrate a Noisy Neighbor - a low priority VM "
|
||||||
"that negatively affects peformance of a high priority VM by over utilizing "
|
"that negatively affects peformance of a high priority VM by over utilizing "
|
||||||
@@ -212,6 +235,13 @@ msgstr "Added using of JSONSchema instead of voluptuous to validate Actions."
|
|||||||
msgid "Added volume migrate action"
|
msgid "Added volume migrate action"
|
||||||
msgstr "Added volume migrate action"
|
msgstr "Added volume migrate action"
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Adds audit scoper for storage data model, now watcher users can specify "
|
||||||
|
"audit scope for storage CDM in the same manner as compute scope."
|
||||||
|
msgstr ""
|
||||||
|
"Adds audit scoper for storage data model, now watcher users can specify "
|
||||||
|
"audit scope for storage CDM in the same manner as compute scope."
|
||||||
|
|
||||||
msgid "Adds baremetal data model in Watcher"
|
msgid "Adds baremetal data model in Watcher"
|
||||||
msgstr "Adds baremetal data model in Watcher"
|
msgstr "Adds baremetal data model in Watcher"
|
||||||
|
|
||||||
|
|||||||
@@ -23,7 +23,7 @@ oslo.reports>=1.18.0 # Apache-2.0
|
|||||||
oslo.serialization!=2.19.1,>=2.18.0 # Apache-2.0
|
oslo.serialization!=2.19.1,>=2.18.0 # Apache-2.0
|
||||||
oslo.service!=1.28.1,>=1.24.0 # Apache-2.0
|
oslo.service!=1.28.1,>=1.24.0 # Apache-2.0
|
||||||
oslo.utils>=3.33.0 # Apache-2.0
|
oslo.utils>=3.33.0 # Apache-2.0
|
||||||
oslo.versionedobjects>=1.28.0 # Apache-2.0
|
oslo.versionedobjects>=1.31.2 # Apache-2.0
|
||||||
PasteDeploy>=1.5.0 # MIT
|
PasteDeploy>=1.5.0 # MIT
|
||||||
pbr!=2.1.0,>=2.0.0 # Apache-2.0
|
pbr!=2.1.0,>=2.0.0 # Apache-2.0
|
||||||
pecan!=1.0.2,!=1.0.3,!=1.0.4,!=1.2,>=1.0.0 # BSD
|
pecan!=1.0.2,!=1.0.3,!=1.0.4,!=1.2,>=1.0.0 # BSD
|
||||||
@@ -38,7 +38,7 @@ python-monascaclient>=1.7.0 # Apache-2.0
|
|||||||
python-neutronclient>=6.3.0 # Apache-2.0
|
python-neutronclient>=6.3.0 # Apache-2.0
|
||||||
python-novaclient>=9.1.0 # Apache-2.0
|
python-novaclient>=9.1.0 # Apache-2.0
|
||||||
python-openstackclient>=3.12.0 # Apache-2.0
|
python-openstackclient>=3.12.0 # Apache-2.0
|
||||||
python-ironicclient>=1.14.0 # Apache-2.0
|
python-ironicclient>=2.2.0 # Apache-2.0
|
||||||
six>=1.10.0 # MIT
|
six>=1.10.0 # MIT
|
||||||
SQLAlchemy!=1.1.5,!=1.1.6,!=1.1.7,!=1.1.8,>=1.0.10 # MIT
|
SQLAlchemy!=1.1.5,!=1.1.6,!=1.1.7,!=1.1.8,>=1.0.10 # MIT
|
||||||
stevedore>=1.20.0 # Apache-2.0
|
stevedore>=1.20.0 # Apache-2.0
|
||||||
|
|||||||
@@ -52,14 +52,21 @@ class NovaHelper(object):
|
|||||||
return self.nova.hypervisors.get(utils.Struct(id=node_id))
|
return self.nova.hypervisors.get(utils.Struct(id=node_id))
|
||||||
|
|
||||||
def get_compute_node_by_hostname(self, node_hostname):
|
def get_compute_node_by_hostname(self, node_hostname):
|
||||||
"""Get compute node by ID (*not* UUID)"""
|
"""Get compute node by hostname"""
|
||||||
# We need to pass an object with an 'id' attribute to make it work
|
|
||||||
try:
|
try:
|
||||||
compute_nodes = self.nova.hypervisors.search(node_hostname)
|
hypervisors = [hv for hv in self.get_compute_node_list()
|
||||||
if len(compute_nodes) != 1:
|
if hv.service['host'] == node_hostname]
|
||||||
|
if len(hypervisors) != 1:
|
||||||
|
# TODO(hidekazu)
|
||||||
|
# this may occur if VMware vCenter driver is used
|
||||||
raise exception.ComputeNodeNotFound(name=node_hostname)
|
raise exception.ComputeNodeNotFound(name=node_hostname)
|
||||||
|
else:
|
||||||
|
compute_nodes = self.nova.hypervisors.search(
|
||||||
|
hypervisors[0].hypervisor_hostname)
|
||||||
|
if len(compute_nodes) != 1:
|
||||||
|
raise exception.ComputeNodeNotFound(name=node_hostname)
|
||||||
|
|
||||||
return self.get_compute_node_by_id(compute_nodes[0].id)
|
return self.get_compute_node_by_id(compute_nodes[0].id)
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
LOG.exception(exc)
|
LOG.exception(exc)
|
||||||
raise exception.ComputeNodeNotFound(name=node_hostname)
|
raise exception.ComputeNodeNotFound(name=node_hostname)
|
||||||
|
|||||||
@@ -57,6 +57,12 @@ class DataSourceBase(object):
|
|||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@abc.abstractmethod
|
||||||
|
def statistic_aggregation(self, resource_id=None, meter_name=None,
|
||||||
|
period=300, granularity=300, dimensions=None,
|
||||||
|
aggregation='avg', group_by='*'):
|
||||||
|
pass
|
||||||
|
|
||||||
@abc.abstractmethod
|
@abc.abstractmethod
|
||||||
def list_metrics(self):
|
def list_metrics(self):
|
||||||
pass
|
pass
|
||||||
|
|||||||
@@ -145,24 +145,28 @@ class CeilometerHelper(base.DataSourceBase):
|
|||||||
else:
|
else:
|
||||||
return meters
|
return meters
|
||||||
|
|
||||||
def statistic_aggregation(self,
|
def statistic_aggregation(self, resource_id=None, meter_name=None,
|
||||||
resource_id,
|
period=300, granularity=300, dimensions=None,
|
||||||
meter_name,
|
aggregation='avg', group_by='*'):
|
||||||
period,
|
|
||||||
aggregate='avg'):
|
|
||||||
"""Representing a statistic aggregate by operators
|
"""Representing a statistic aggregate by operators
|
||||||
|
|
||||||
:param resource_id: id of resource to list statistics for.
|
:param resource_id: id of resource to list statistics for.
|
||||||
:param meter_name: Name of meter to list statistics for.
|
:param meter_name: Name of meter to list statistics for.
|
||||||
:param period: Period in seconds over which to group samples.
|
:param period: Period in seconds over which to group samples.
|
||||||
:param aggregate: Available aggregates are: count, cardinality,
|
:param granularity: frequency of marking metric point, in seconds.
|
||||||
min, max, sum, stddev, avg. Defaults to avg.
|
This param isn't used in Ceilometer datasource.
|
||||||
|
:param dimensions: dimensions (dict). This param isn't used in
|
||||||
|
Ceilometer datasource.
|
||||||
|
:param aggregation: Available aggregates are: count, cardinality,
|
||||||
|
min, max, sum, stddev, avg. Defaults to avg.
|
||||||
|
:param group_by: list of columns to group the metrics to be returned.
|
||||||
|
This param isn't used in Ceilometer datasource.
|
||||||
:return: Return the latest statistical data, None if no data.
|
:return: Return the latest statistical data, None if no data.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
end_time = datetime.datetime.utcnow()
|
end_time = datetime.datetime.utcnow()
|
||||||
if aggregate == 'mean':
|
if aggregation == 'mean':
|
||||||
aggregate = 'avg'
|
aggregation = 'avg'
|
||||||
start_time = end_time - datetime.timedelta(seconds=int(period))
|
start_time = end_time - datetime.timedelta(seconds=int(period))
|
||||||
query = self.build_query(
|
query = self.build_query(
|
||||||
resource_id=resource_id, start_time=start_time, end_time=end_time)
|
resource_id=resource_id, start_time=start_time, end_time=end_time)
|
||||||
@@ -171,11 +175,11 @@ class CeilometerHelper(base.DataSourceBase):
|
|||||||
q=query,
|
q=query,
|
||||||
period=period,
|
period=period,
|
||||||
aggregates=[
|
aggregates=[
|
||||||
{'func': aggregate}])
|
{'func': aggregation}])
|
||||||
|
|
||||||
item_value = None
|
item_value = None
|
||||||
if statistic:
|
if statistic:
|
||||||
item_value = statistic[-1]._info.get('aggregate').get(aggregate)
|
item_value = statistic[-1]._info.get('aggregate').get(aggregation)
|
||||||
return item_value
|
return item_value
|
||||||
|
|
||||||
def get_last_sample_values(self, resource_id, meter_name, limit=1):
|
def get_last_sample_values(self, resource_id, meter_name, limit=1):
|
||||||
@@ -204,64 +208,64 @@ class CeilometerHelper(base.DataSourceBase):
|
|||||||
granularity=None):
|
granularity=None):
|
||||||
meter_name = self.METRIC_MAP.get('host_cpu_usage')
|
meter_name = self.METRIC_MAP.get('host_cpu_usage')
|
||||||
return self.statistic_aggregation(resource_id, meter_name, period,
|
return self.statistic_aggregation(resource_id, meter_name, period,
|
||||||
aggregate=aggregate)
|
granularity, aggregate=aggregate)
|
||||||
|
|
||||||
def get_instance_cpu_usage(self, resource_id, period, aggregate,
|
def get_instance_cpu_usage(self, resource_id, period, aggregate,
|
||||||
granularity=None):
|
granularity=None):
|
||||||
meter_name = self.METRIC_MAP.get('instance_cpu_usage')
|
meter_name = self.METRIC_MAP.get('instance_cpu_usage')
|
||||||
return self.statistic_aggregation(resource_id, meter_name, period,
|
return self.statistic_aggregation(resource_id, meter_name, period,
|
||||||
aggregate=aggregate)
|
granularity, aggregate=aggregate)
|
||||||
|
|
||||||
def get_host_memory_usage(self, resource_id, period, aggregate,
|
def get_host_memory_usage(self, resource_id, period, aggregate,
|
||||||
granularity=None):
|
granularity=None):
|
||||||
meter_name = self.METRIC_MAP.get('host_memory_usage')
|
meter_name = self.METRIC_MAP.get('host_memory_usage')
|
||||||
return self.statistic_aggregation(resource_id, meter_name, period,
|
return self.statistic_aggregation(resource_id, meter_name, period,
|
||||||
aggregate=aggregate)
|
granularity, aggregate=aggregate)
|
||||||
|
|
||||||
def get_instance_memory_usage(self, resource_id, period, aggregate,
|
def get_instance_memory_usage(self, resource_id, period, aggregate,
|
||||||
granularity=None):
|
granularity=None):
|
||||||
meter_name = self.METRIC_MAP.get('instance_ram_usage')
|
meter_name = self.METRIC_MAP.get('instance_ram_usage')
|
||||||
return self.statistic_aggregation(resource_id, meter_name, period,
|
return self.statistic_aggregation(resource_id, meter_name, period,
|
||||||
aggregate=aggregate)
|
granularity, aggregate=aggregate)
|
||||||
|
|
||||||
def get_instance_l3_cache_usage(self, resource_id, period, aggregate,
|
def get_instance_l3_cache_usage(self, resource_id, period, aggregate,
|
||||||
granularity=None):
|
granularity=None):
|
||||||
meter_name = self.METRIC_MAP.get('instance_l3_cache_usage')
|
meter_name = self.METRIC_MAP.get('instance_l3_cache_usage')
|
||||||
return self.statistic_aggregation(resource_id, meter_name, period,
|
return self.statistic_aggregation(resource_id, meter_name, period,
|
||||||
aggregate=aggregate)
|
granularity, aggregate=aggregate)
|
||||||
|
|
||||||
def get_instance_ram_allocated(self, resource_id, period, aggregate,
|
def get_instance_ram_allocated(self, resource_id, period, aggregate,
|
||||||
granularity=None):
|
granularity=None):
|
||||||
meter_name = self.METRIC_MAP.get('instance_ram_allocated')
|
meter_name = self.METRIC_MAP.get('instance_ram_allocated')
|
||||||
return self.statistic_aggregation(resource_id, meter_name, period,
|
return self.statistic_aggregation(resource_id, meter_name, period,
|
||||||
aggregate=aggregate)
|
granularity, aggregate=aggregate)
|
||||||
|
|
||||||
def get_instance_root_disk_allocated(self, resource_id, period, aggregate,
|
def get_instance_root_disk_allocated(self, resource_id, period, aggregate,
|
||||||
granularity=None):
|
granularity=None):
|
||||||
meter_name = self.METRIC_MAP.get('instance_root_disk_size')
|
meter_name = self.METRIC_MAP.get('instance_root_disk_size')
|
||||||
return self.statistic_aggregation(resource_id, meter_name, period,
|
return self.statistic_aggregation(resource_id, meter_name, period,
|
||||||
aggregate=aggregate)
|
granularity, aggregate=aggregate)
|
||||||
|
|
||||||
def get_host_outlet_temperature(self, resource_id, period, aggregate,
|
def get_host_outlet_temperature(self, resource_id, period, aggregate,
|
||||||
granularity=None):
|
granularity=None):
|
||||||
meter_name = self.METRIC_MAP.get('host_outlet_temp')
|
meter_name = self.METRIC_MAP.get('host_outlet_temp')
|
||||||
return self.statistic_aggregation(resource_id, meter_name, period,
|
return self.statistic_aggregation(resource_id, meter_name, period,
|
||||||
aggregate=aggregate)
|
granularity, aggregate=aggregate)
|
||||||
|
|
||||||
def get_host_inlet_temperature(self, resource_id, period, aggregate,
|
def get_host_inlet_temperature(self, resource_id, period, aggregate,
|
||||||
granularity=None):
|
granularity=None):
|
||||||
meter_name = self.METRIC_MAP.get('host_inlet_temp')
|
meter_name = self.METRIC_MAP.get('host_inlet_temp')
|
||||||
return self.statistic_aggregation(resource_id, meter_name, period,
|
return self.statistic_aggregation(resource_id, meter_name, period,
|
||||||
aggregate=aggregate)
|
granularity, aggregate=aggregate)
|
||||||
|
|
||||||
def get_host_airflow(self, resource_id, period, aggregate,
|
def get_host_airflow(self, resource_id, period, aggregate,
|
||||||
granularity=None):
|
granularity=None):
|
||||||
meter_name = self.METRIC_MAP.get('host_airflow')
|
meter_name = self.METRIC_MAP.get('host_airflow')
|
||||||
return self.statistic_aggregation(resource_id, meter_name, period,
|
return self.statistic_aggregation(resource_id, meter_name, period,
|
||||||
aggregate=aggregate)
|
granularity, aggregate=aggregate)
|
||||||
|
|
||||||
def get_host_power(self, resource_id, period, aggregate,
|
def get_host_power(self, resource_id, period, aggregate,
|
||||||
granularity=None):
|
granularity=None):
|
||||||
meter_name = self.METRIC_MAP.get('host_power')
|
meter_name = self.METRIC_MAP.get('host_power')
|
||||||
return self.statistic_aggregation(resource_id, meter_name, period,
|
return self.statistic_aggregation(resource_id, meter_name, period,
|
||||||
aggregate=aggregate)
|
granularity, aggregate=aggregate)
|
||||||
|
|||||||
@@ -58,32 +58,35 @@ class GnocchiHelper(base.DataSourceBase):
|
|||||||
return 'not available'
|
return 'not available'
|
||||||
return 'available'
|
return 'available'
|
||||||
|
|
||||||
def _statistic_aggregation(self,
|
def list_metrics(self):
|
||||||
resource_id,
|
"""List the user's meters."""
|
||||||
metric,
|
try:
|
||||||
granularity,
|
response = self.query_retry(f=self.gnocchi.metric.list)
|
||||||
start_time=None,
|
except Exception:
|
||||||
stop_time=None,
|
return set()
|
||||||
aggregation='mean'):
|
else:
|
||||||
|
return set([metric['name'] for metric in response])
|
||||||
|
|
||||||
|
def statistic_aggregation(self, resource_id=None, meter_name=None,
|
||||||
|
period=300, granularity=300, dimensions=None,
|
||||||
|
aggregation='avg', group_by='*'):
|
||||||
"""Representing a statistic aggregate by operators
|
"""Representing a statistic aggregate by operators
|
||||||
|
|
||||||
:param metric: metric name of which we want the statistics
|
:param resource_id: id of resource to list statistics for.
|
||||||
:param resource_id: id of resource to list statistics for
|
:param meter_name: meter name of which we want the statistics.
|
||||||
:param start_time: Start datetime from which metrics will be used
|
:param period: Period in seconds over which to group samples.
|
||||||
:param stop_time: End datetime from which metrics will be used
|
:param granularity: frequency of marking metric point, in seconds.
|
||||||
:param granularity: frequency of marking metric point, in seconds
|
:param dimensions: dimensions (dict). This param isn't used in
|
||||||
|
Gnocchi datasource.
|
||||||
:param aggregation: Should be chosen in accordance with policy
|
:param aggregation: Should be chosen in accordance with policy
|
||||||
aggregations
|
aggregations.
|
||||||
|
:param group_by: list of columns to group the metrics to be returned.
|
||||||
|
This param isn't used in Gnocchi datasource.
|
||||||
:return: value of aggregated metric
|
:return: value of aggregated metric
|
||||||
"""
|
"""
|
||||||
|
|
||||||
if start_time is not None and not isinstance(start_time, datetime):
|
stop_time = datetime.utcnow()
|
||||||
raise exception.InvalidParameter(parameter='start_time',
|
start_time = stop_time - timedelta(seconds=(int(period)))
|
||||||
parameter_type=datetime)
|
|
||||||
|
|
||||||
if stop_time is not None and not isinstance(stop_time, datetime):
|
|
||||||
raise exception.InvalidParameter(parameter='stop_time',
|
|
||||||
parameter_type=datetime)
|
|
||||||
|
|
||||||
if not common_utils.is_uuid_like(resource_id):
|
if not common_utils.is_uuid_like(resource_id):
|
||||||
kwargs = dict(query={"=": {"original_resource_id": resource_id}},
|
kwargs = dict(query={"=": {"original_resource_id": resource_id}},
|
||||||
@@ -97,7 +100,7 @@ class GnocchiHelper(base.DataSourceBase):
|
|||||||
resource_id = resources[0]['id']
|
resource_id = resources[0]['id']
|
||||||
|
|
||||||
raw_kwargs = dict(
|
raw_kwargs = dict(
|
||||||
metric=metric,
|
metric=meter_name,
|
||||||
start=start_time,
|
start=start_time,
|
||||||
stop=stop_time,
|
stop=stop_time,
|
||||||
resource_id=resource_id,
|
resource_id=resource_id,
|
||||||
@@ -115,27 +118,6 @@ class GnocchiHelper(base.DataSourceBase):
|
|||||||
# measure has structure [time, granularity, value]
|
# measure has structure [time, granularity, value]
|
||||||
return statistics[-1][2]
|
return statistics[-1][2]
|
||||||
|
|
||||||
def list_metrics(self):
|
|
||||||
"""List the user's meters."""
|
|
||||||
try:
|
|
||||||
response = self.query_retry(f=self.gnocchi.metric.list)
|
|
||||||
except Exception:
|
|
||||||
return set()
|
|
||||||
else:
|
|
||||||
return set([metric['name'] for metric in response])
|
|
||||||
|
|
||||||
def statistic_aggregation(self, resource_id, metric, period, granularity,
|
|
||||||
aggregation='mean'):
|
|
||||||
stop_time = datetime.utcnow()
|
|
||||||
start_time = stop_time - timedelta(seconds=(int(period)))
|
|
||||||
return self._statistic_aggregation(
|
|
||||||
resource_id=resource_id,
|
|
||||||
metric=metric,
|
|
||||||
granularity=granularity,
|
|
||||||
start_time=start_time,
|
|
||||||
stop_time=stop_time,
|
|
||||||
aggregation=aggregation)
|
|
||||||
|
|
||||||
def get_host_cpu_usage(self, resource_id, period, aggregate,
|
def get_host_cpu_usage(self, resource_id, period, aggregate,
|
||||||
granularity=300):
|
granularity=300):
|
||||||
meter_name = self.METRIC_MAP.get('host_cpu_usage')
|
meter_name = self.METRIC_MAP.get('host_cpu_usage')
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ import datetime
|
|||||||
from monascaclient import exc
|
from monascaclient import exc
|
||||||
|
|
||||||
from watcher.common import clients
|
from watcher.common import clients
|
||||||
|
from watcher.common import exception
|
||||||
from watcher.datasource import base
|
from watcher.datasource import base
|
||||||
|
|
||||||
|
|
||||||
@@ -97,41 +98,42 @@ class MonascaHelper(base.DataSourceBase):
|
|||||||
|
|
||||||
return statistics
|
return statistics
|
||||||
|
|
||||||
def statistic_aggregation(self,
|
def statistic_aggregation(self, resource_id=None, meter_name=None,
|
||||||
meter_name,
|
period=300, granularity=300, dimensions=None,
|
||||||
dimensions,
|
aggregation='avg', group_by='*'):
|
||||||
start_time=None,
|
|
||||||
end_time=None,
|
|
||||||
period=None,
|
|
||||||
aggregate='avg',
|
|
||||||
group_by='*'):
|
|
||||||
"""Representing a statistic aggregate by operators
|
"""Representing a statistic aggregate by operators
|
||||||
|
|
||||||
:param meter_name: meter names of which we want the statistics
|
:param resource_id: id of resource to list statistics for.
|
||||||
:param dimensions: dimensions (dict)
|
This param isn't used in Monasca datasource.
|
||||||
:param start_time: Start datetime from which metrics will be used
|
:param meter_name: meter names of which we want the statistics.
|
||||||
:param end_time: End datetime from which metrics will be used
|
|
||||||
:param period: Sampling `period`: In seconds. If no period is given,
|
:param period: Sampling `period`: In seconds. If no period is given,
|
||||||
only one aggregate statistic is returned. If given, a
|
only one aggregate statistic is returned. If given, a
|
||||||
faceted result will be returned, divided into given
|
faceted result will be returned, divided into given
|
||||||
periods. Periods with no data are ignored.
|
periods. Periods with no data are ignored.
|
||||||
:param aggregate: Should be either 'avg', 'count', 'min' or 'max'
|
:param granularity: frequency of marking metric point, in seconds.
|
||||||
|
This param isn't used in Ceilometer datasource.
|
||||||
|
:param dimensions: dimensions (dict).
|
||||||
|
:param aggregation: Should be either 'avg', 'count', 'min' or 'max'.
|
||||||
|
:param group_by: list of columns to group the metrics to be returned.
|
||||||
:return: A list of dict with each dict being a distinct result row
|
:return: A list of dict with each dict being a distinct result row
|
||||||
"""
|
"""
|
||||||
start_timestamp, end_timestamp, period = self._format_time_params(
|
|
||||||
start_time, end_time, period
|
|
||||||
)
|
|
||||||
|
|
||||||
if aggregate == 'mean':
|
if dimensions is None:
|
||||||
aggregate = 'avg'
|
raise exception.UnsupportedDataSource(datasource='Monasca')
|
||||||
|
|
||||||
|
stop_time = datetime.datetime.utcnow()
|
||||||
|
start_time = stop_time - datetime.timedelta(seconds=(int(period)))
|
||||||
|
|
||||||
|
if aggregation == 'mean':
|
||||||
|
aggregation = 'avg'
|
||||||
|
|
||||||
raw_kwargs = dict(
|
raw_kwargs = dict(
|
||||||
name=meter_name,
|
name=meter_name,
|
||||||
start_time=start_timestamp,
|
start_time=start_time.isoformat(),
|
||||||
end_time=end_timestamp,
|
end_time=stop_time.isoformat(),
|
||||||
dimensions=dimensions,
|
dimensions=dimensions,
|
||||||
period=period,
|
period=period,
|
||||||
statistics=aggregate,
|
statistics=aggregation,
|
||||||
group_by=group_by,
|
group_by=group_by,
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -140,45 +142,36 @@ class MonascaHelper(base.DataSourceBase):
|
|||||||
statistics = self.query_retry(
|
statistics = self.query_retry(
|
||||||
f=self.monasca.metrics.list_statistics, **kwargs)
|
f=self.monasca.metrics.list_statistics, **kwargs)
|
||||||
|
|
||||||
return statistics
|
cpu_usage = None
|
||||||
|
for stat in statistics:
|
||||||
|
avg_col_idx = stat['columns'].index(aggregation)
|
||||||
|
values = [r[avg_col_idx] for r in stat['statistics']]
|
||||||
|
value = float(sum(values)) / len(values)
|
||||||
|
cpu_usage = value
|
||||||
|
|
||||||
|
return cpu_usage
|
||||||
|
|
||||||
def get_host_cpu_usage(self, resource_id, period, aggregate,
|
def get_host_cpu_usage(self, resource_id, period, aggregate,
|
||||||
granularity=None):
|
granularity=None):
|
||||||
metric_name = self.METRIC_MAP.get('host_cpu_usage')
|
metric_name = self.METRIC_MAP.get('host_cpu_usage')
|
||||||
node_uuid = resource_id.split('_')[0]
|
node_uuid = resource_id.split('_')[0]
|
||||||
statistics = self.statistic_aggregation(
|
return self.statistic_aggregation(
|
||||||
meter_name=metric_name,
|
meter_name=metric_name,
|
||||||
dimensions=dict(hostname=node_uuid),
|
dimensions=dict(hostname=node_uuid),
|
||||||
period=period,
|
period=period,
|
||||||
aggregate=aggregate
|
aggregation=aggregate
|
||||||
)
|
)
|
||||||
cpu_usage = None
|
|
||||||
for stat in statistics:
|
|
||||||
avg_col_idx = stat['columns'].index('avg')
|
|
||||||
values = [r[avg_col_idx] for r in stat['statistics']]
|
|
||||||
value = float(sum(values)) / len(values)
|
|
||||||
cpu_usage = value
|
|
||||||
|
|
||||||
return cpu_usage
|
|
||||||
|
|
||||||
def get_instance_cpu_usage(self, resource_id, period, aggregate,
|
def get_instance_cpu_usage(self, resource_id, period, aggregate,
|
||||||
granularity=None):
|
granularity=None):
|
||||||
metric_name = self.METRIC_MAP.get('instance_cpu_usage')
|
metric_name = self.METRIC_MAP.get('instance_cpu_usage')
|
||||||
|
|
||||||
statistics = self.statistic_aggregation(
|
return self.statistic_aggregation(
|
||||||
meter_name=metric_name,
|
meter_name=metric_name,
|
||||||
dimensions=dict(resource_id=resource_id),
|
dimensions=dict(resource_id=resource_id),
|
||||||
period=period,
|
period=period,
|
||||||
aggregate=aggregate
|
aggregation=aggregate
|
||||||
)
|
)
|
||||||
cpu_usage = None
|
|
||||||
for stat in statistics:
|
|
||||||
avg_col_idx = stat['columns'].index('avg')
|
|
||||||
values = [r[avg_col_idx] for r in stat['statistics']]
|
|
||||||
value = float(sum(values)) / len(values)
|
|
||||||
cpu_usage = value
|
|
||||||
|
|
||||||
return cpu_usage
|
|
||||||
|
|
||||||
def get_host_memory_usage(self, resource_id, period, aggregate,
|
def get_host_memory_usage(self, resource_id, period, aggregate,
|
||||||
granularity=None):
|
granularity=None):
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ class StrategyEndpoint(object):
|
|||||||
ds_metrics = datasource.list_metrics()
|
ds_metrics = datasource.list_metrics()
|
||||||
if ds_metrics is None:
|
if ds_metrics is None:
|
||||||
raise exception.DataSourceNotAvailable(
|
raise exception.DataSourceNotAvailable(
|
||||||
datasource=strategy.config.datasource)
|
datasource=datasource.NAME)
|
||||||
else:
|
else:
|
||||||
for metric in strategy.DATASOURCE_METRICS:
|
for metric in strategy.DATASOURCE_METRICS:
|
||||||
original_metric_name = datasource.METRIC_MAP.get(metric)
|
original_metric_name = datasource.METRIC_MAP.get(metric)
|
||||||
@@ -81,7 +81,7 @@ class StrategyEndpoint(object):
|
|||||||
if not datasource:
|
if not datasource:
|
||||||
state = "Datasource is not presented for this strategy"
|
state = "Datasource is not presented for this strategy"
|
||||||
else:
|
else:
|
||||||
state = "%s: %s" % (strategy.config.datasource,
|
state = "%s: %s" % (datasource.NAME,
|
||||||
datasource.check_availability())
|
datasource.check_availability())
|
||||||
return {'type': 'Datasource',
|
return {'type': 'Datasource',
|
||||||
'state': state,
|
'state': state,
|
||||||
@@ -104,7 +104,7 @@ class StrategyEndpoint(object):
|
|||||||
try:
|
try:
|
||||||
is_datasources = getattr(strategy.config, 'datasources', None)
|
is_datasources = getattr(strategy.config, 'datasources', None)
|
||||||
if is_datasources:
|
if is_datasources:
|
||||||
datasource = is_datasources[0]
|
datasource = getattr(strategy, 'datasource_backend')
|
||||||
else:
|
else:
|
||||||
datasource = getattr(strategy, strategy.config.datasource)
|
datasource = getattr(strategy, strategy.config.datasource)
|
||||||
except (AttributeError, IndexError):
|
except (AttributeError, IndexError):
|
||||||
@@ -272,7 +272,7 @@ class BaseStrategy(loadable.Loadable):
|
|||||||
collector = self.collector_manager.get_cluster_model_collector(
|
collector = self.collector_manager.get_cluster_model_collector(
|
||||||
'storage', osc=self.osc)
|
'storage', osc=self.osc)
|
||||||
audit_scope_handler = collector.get_audit_scope_handler(
|
audit_scope_handler = collector.get_audit_scope_handler(
|
||||||
audit_scope=self.audit.scope)
|
audit_scope=self.audit_scope)
|
||||||
self._storage_model = audit_scope_handler.get_scoped_model(
|
self._storage_model = audit_scope_handler.get_scoped_model(
|
||||||
collector.get_latest_cluster_data_model())
|
collector.get_latest_cluster_data_model())
|
||||||
|
|
||||||
|
|||||||
@@ -149,8 +149,10 @@ class BasicConsolidation(base.ServerConsolidationBaseStrategy):
|
|||||||
def get_config_opts(cls):
|
def get_config_opts(cls):
|
||||||
return [
|
return [
|
||||||
cfg.ListOpt(
|
cfg.ListOpt(
|
||||||
"datasource",
|
"datasources",
|
||||||
help="Data source to use in order to query the needed metrics",
|
help="Datasources to use in order to query the needed metrics."
|
||||||
|
" If one of strategy metric isn't available in the first"
|
||||||
|
" datasource, the next datasource will be chosen.",
|
||||||
item_type=cfg.types.String(choices=['gnocchi', 'ceilometer',
|
item_type=cfg.types.String(choices=['gnocchi', 'ceilometer',
|
||||||
'monasca']),
|
'monasca']),
|
||||||
default=['gnocchi', 'ceilometer', 'monasca']),
|
default=['gnocchi', 'ceilometer', 'monasca']),
|
||||||
|
|||||||
@@ -86,8 +86,10 @@ class NoisyNeighbor(base.NoisyNeighborBaseStrategy):
|
|||||||
def get_config_opts(cls):
|
def get_config_opts(cls):
|
||||||
return [
|
return [
|
||||||
cfg.ListOpt(
|
cfg.ListOpt(
|
||||||
"datasource",
|
"datasources",
|
||||||
help="Data source to use in order to query the needed metrics",
|
help="Datasources to use in order to query the needed metrics."
|
||||||
|
" If one of strategy metric isn't available in the first"
|
||||||
|
" datasource, the next datasource will be chosen.",
|
||||||
item_type=cfg.types.String(choices=['gnocchi', 'ceilometer',
|
item_type=cfg.types.String(choices=['gnocchi', 'ceilometer',
|
||||||
'monasca']),
|
'monasca']),
|
||||||
default=['gnocchi', 'ceilometer', 'monasca'])
|
default=['gnocchi', 'ceilometer', 'monasca'])
|
||||||
|
|||||||
@@ -28,15 +28,11 @@ Outlet (Exhaust Air) Temperature is one of the important thermal
|
|||||||
telemetries to measure thermal/workload status of server.
|
telemetries to measure thermal/workload status of server.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import datetime
|
|
||||||
|
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_log import log
|
from oslo_log import log
|
||||||
|
|
||||||
from watcher._i18n import _
|
from watcher._i18n import _
|
||||||
from watcher.common import exception as wexc
|
from watcher.common import exception as wexc
|
||||||
from watcher.datasource import ceilometer as ceil
|
|
||||||
from watcher.datasource import gnocchi as gnoc
|
|
||||||
from watcher.decision_engine.model import element
|
from watcher.decision_engine.model import element
|
||||||
from watcher.decision_engine.strategy.strategies import base
|
from watcher.decision_engine.strategy.strategies import base
|
||||||
|
|
||||||
@@ -95,8 +91,6 @@ class OutletTempControl(base.ThermalOptimizationBaseStrategy):
|
|||||||
:type osc: :py:class:`~.OpenStackClients` instance, optional
|
:type osc: :py:class:`~.OpenStackClients` instance, optional
|
||||||
"""
|
"""
|
||||||
super(OutletTempControl, self).__init__(config, osc)
|
super(OutletTempControl, self).__init__(config, osc)
|
||||||
self._ceilometer = None
|
|
||||||
self._gnocchi = None
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_name(cls):
|
def get_name(cls):
|
||||||
@@ -139,26 +133,6 @@ class OutletTempControl(base.ThermalOptimizationBaseStrategy):
|
|||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@property
|
|
||||||
def ceilometer(self):
|
|
||||||
if self._ceilometer is None:
|
|
||||||
self.ceilometer = ceil.CeilometerHelper(osc=self.osc)
|
|
||||||
return self._ceilometer
|
|
||||||
|
|
||||||
@ceilometer.setter
|
|
||||||
def ceilometer(self, c):
|
|
||||||
self._ceilometer = c
|
|
||||||
|
|
||||||
@property
|
|
||||||
def gnocchi(self):
|
|
||||||
if self._gnocchi is None:
|
|
||||||
self.gnocchi = gnoc.GnocchiHelper(osc=self.osc)
|
|
||||||
return self._gnocchi
|
|
||||||
|
|
||||||
@gnocchi.setter
|
|
||||||
def gnocchi(self, g):
|
|
||||||
self._gnocchi = g
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def granularity(self):
|
def granularity(self):
|
||||||
return self.input_parameters.get('granularity', 300)
|
return self.input_parameters.get('granularity', 300)
|
||||||
@@ -208,25 +182,13 @@ class OutletTempControl(base.ThermalOptimizationBaseStrategy):
|
|||||||
resource_id = node.uuid
|
resource_id = node.uuid
|
||||||
outlet_temp = None
|
outlet_temp = None
|
||||||
|
|
||||||
if self.config.datasource == "ceilometer":
|
outlet_temp = self.datasource_backend.statistic_aggregation(
|
||||||
outlet_temp = self.ceilometer.statistic_aggregation(
|
resource_id=resource_id,
|
||||||
resource_id=resource_id,
|
meter_name=metric_name,
|
||||||
meter_name=metric_name,
|
period=self.period,
|
||||||
period=self.period,
|
granularity=self.granularity,
|
||||||
aggregate='avg'
|
)
|
||||||
)
|
|
||||||
elif self.config.datasource == "gnocchi":
|
|
||||||
stop_time = datetime.datetime.utcnow()
|
|
||||||
start_time = stop_time - datetime.timedelta(
|
|
||||||
seconds=int(self.period))
|
|
||||||
outlet_temp = self.gnocchi.statistic_aggregation(
|
|
||||||
resource_id=resource_id,
|
|
||||||
metric=metric_name,
|
|
||||||
granularity=self.granularity,
|
|
||||||
start_time=start_time,
|
|
||||||
stop_time=stop_time,
|
|
||||||
aggregation='mean'
|
|
||||||
)
|
|
||||||
# some hosts may not have outlet temp meters, remove from target
|
# some hosts may not have outlet temp meters, remove from target
|
||||||
if outlet_temp is None:
|
if outlet_temp is None:
|
||||||
LOG.warning("%s: no outlet temp data", resource_id)
|
LOG.warning("%s: no outlet temp data", resource_id)
|
||||||
|
|||||||
@@ -42,15 +42,11 @@ airflow is higher than the specified threshold.
|
|||||||
- It assumes that live migrations are possible.
|
- It assumes that live migrations are possible.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import datetime
|
|
||||||
|
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_log import log
|
from oslo_log import log
|
||||||
|
|
||||||
from watcher._i18n import _
|
from watcher._i18n import _
|
||||||
from watcher.common import exception as wexc
|
from watcher.common import exception as wexc
|
||||||
from watcher.datasource import ceilometer as ceil
|
|
||||||
from watcher.datasource import gnocchi as gnoc
|
|
||||||
from watcher.decision_engine.model import element
|
from watcher.decision_engine.model import element
|
||||||
from watcher.decision_engine.strategy.strategies import base
|
from watcher.decision_engine.strategy.strategies import base
|
||||||
|
|
||||||
@@ -125,30 +121,8 @@ class UniformAirflow(base.BaseStrategy):
|
|||||||
self.config.datasource]['host_inlet_temp']
|
self.config.datasource]['host_inlet_temp']
|
||||||
self.meter_name_power = self.METRIC_NAMES[
|
self.meter_name_power = self.METRIC_NAMES[
|
||||||
self.config.datasource]['host_power']
|
self.config.datasource]['host_power']
|
||||||
self._ceilometer = None
|
|
||||||
self._gnocchi = None
|
|
||||||
self._period = self.PERIOD
|
self._period = self.PERIOD
|
||||||
|
|
||||||
@property
|
|
||||||
def ceilometer(self):
|
|
||||||
if self._ceilometer is None:
|
|
||||||
self.ceilometer = ceil.CeilometerHelper(osc=self.osc)
|
|
||||||
return self._ceilometer
|
|
||||||
|
|
||||||
@ceilometer.setter
|
|
||||||
def ceilometer(self, c):
|
|
||||||
self._ceilometer = c
|
|
||||||
|
|
||||||
@property
|
|
||||||
def gnocchi(self):
|
|
||||||
if self._gnocchi is None:
|
|
||||||
self.gnocchi = gnoc.GnocchiHelper(osc=self.osc)
|
|
||||||
return self._gnocchi
|
|
||||||
|
|
||||||
@gnocchi.setter
|
|
||||||
def gnocchi(self, g):
|
|
||||||
self._gnocchi = g
|
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def get_name(cls):
|
def get_name(cls):
|
||||||
return "uniform_airflow"
|
return "uniform_airflow"
|
||||||
@@ -247,35 +221,16 @@ class UniformAirflow(base.BaseStrategy):
|
|||||||
source_instances = self.compute_model.get_node_instances(
|
source_instances = self.compute_model.get_node_instances(
|
||||||
source_node)
|
source_node)
|
||||||
if source_instances:
|
if source_instances:
|
||||||
if self.config.datasource == "ceilometer":
|
inlet_t = self.datasource_backend.statistic_aggregation(
|
||||||
inlet_t = self.ceilometer.statistic_aggregation(
|
resource_id=source_node.uuid,
|
||||||
resource_id=source_node.uuid,
|
meter_name=self.meter_name_inlet_t,
|
||||||
meter_name=self.meter_name_inlet_t,
|
period=self._period,
|
||||||
period=self._period,
|
granularity=self.granularity)
|
||||||
aggregate='avg')
|
power = self.datasource_backend.statistic_aggregation(
|
||||||
power = self.ceilometer.statistic_aggregation(
|
resource_id=source_node.uuid,
|
||||||
resource_id=source_node.uuid,
|
meter_name=self.meter_name_power,
|
||||||
meter_name=self.meter_name_power,
|
period=self._period,
|
||||||
period=self._period,
|
granularity=self.granularity)
|
||||||
aggregate='avg')
|
|
||||||
elif self.config.datasource == "gnocchi":
|
|
||||||
stop_time = datetime.datetime.utcnow()
|
|
||||||
start_time = stop_time - datetime.timedelta(
|
|
||||||
seconds=int(self._period))
|
|
||||||
inlet_t = self.gnocchi.statistic_aggregation(
|
|
||||||
resource_id=source_node.uuid,
|
|
||||||
metric=self.meter_name_inlet_t,
|
|
||||||
granularity=self.granularity,
|
|
||||||
start_time=start_time,
|
|
||||||
stop_time=stop_time,
|
|
||||||
aggregation='mean')
|
|
||||||
power = self.gnocchi.statistic_aggregation(
|
|
||||||
resource_id=source_node.uuid,
|
|
||||||
metric=self.meter_name_power,
|
|
||||||
granularity=self.granularity,
|
|
||||||
start_time=start_time,
|
|
||||||
stop_time=stop_time,
|
|
||||||
aggregation='mean')
|
|
||||||
if (power < self.threshold_power and
|
if (power < self.threshold_power and
|
||||||
inlet_t < self.threshold_inlet_t):
|
inlet_t < self.threshold_inlet_t):
|
||||||
# hardware issue, migrate all instances from this node
|
# hardware issue, migrate all instances from this node
|
||||||
@@ -353,23 +308,11 @@ class UniformAirflow(base.BaseStrategy):
|
|||||||
node = self.compute_model.get_node_by_uuid(
|
node = self.compute_model.get_node_by_uuid(
|
||||||
node_id)
|
node_id)
|
||||||
resource_id = node.uuid
|
resource_id = node.uuid
|
||||||
if self.config.datasource == "ceilometer":
|
airflow = self.datasource_backend.statistic_aggregation(
|
||||||
airflow = self.ceilometer.statistic_aggregation(
|
resource_id=resource_id,
|
||||||
resource_id=resource_id,
|
meter_name=self.meter_name_airflow,
|
||||||
meter_name=self.meter_name_airflow,
|
period=self._period,
|
||||||
period=self._period,
|
granularity=self.granularity)
|
||||||
aggregate='avg')
|
|
||||||
elif self.config.datasource == "gnocchi":
|
|
||||||
stop_time = datetime.datetime.utcnow()
|
|
||||||
start_time = stop_time - datetime.timedelta(
|
|
||||||
seconds=int(self._period))
|
|
||||||
airflow = self.gnocchi.statistic_aggregation(
|
|
||||||
resource_id=resource_id,
|
|
||||||
metric=self.meter_name_airflow,
|
|
||||||
granularity=self.granularity,
|
|
||||||
start_time=start_time,
|
|
||||||
stop_time=stop_time,
|
|
||||||
aggregation='mean')
|
|
||||||
# some hosts may not have airflow meter, remove from target
|
# some hosts may not have airflow meter, remove from target
|
||||||
if airflow is None:
|
if airflow is None:
|
||||||
LOG.warning("%s: no airflow data", resource_id)
|
LOG.warning("%s: no airflow data", resource_id)
|
||||||
|
|||||||
@@ -52,7 +52,6 @@ correctly on all compute nodes within the cluster.
|
|||||||
This strategy assumes it is possible to live migrate any VM from
|
This strategy assumes it is possible to live migrate any VM from
|
||||||
an active compute node to any other active compute node.
|
an active compute node to any other active compute node.
|
||||||
"""
|
"""
|
||||||
import datetime
|
|
||||||
|
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_log import log
|
from oslo_log import log
|
||||||
@@ -60,8 +59,6 @@ import six
|
|||||||
|
|
||||||
from watcher._i18n import _
|
from watcher._i18n import _
|
||||||
from watcher.common import exception
|
from watcher.common import exception
|
||||||
from watcher.datasource import ceilometer as ceil
|
|
||||||
from watcher.datasource import gnocchi as gnoc
|
|
||||||
from watcher.decision_engine.model import element
|
from watcher.decision_engine.model import element
|
||||||
from watcher.decision_engine.strategy.strategies import base
|
from watcher.decision_engine.strategy.strategies import base
|
||||||
|
|
||||||
@@ -118,26 +115,6 @@ class VMWorkloadConsolidation(base.ServerConsolidationBaseStrategy):
|
|||||||
def period(self):
|
def period(self):
|
||||||
return self.input_parameters.get('period', 3600)
|
return self.input_parameters.get('period', 3600)
|
||||||
|
|
||||||
@property
|
|
||||||
def ceilometer(self):
|
|
||||||
if self._ceilometer is None:
|
|
||||||
self.ceilometer = ceil.CeilometerHelper(osc=self.osc)
|
|
||||||
return self._ceilometer
|
|
||||||
|
|
||||||
@ceilometer.setter
|
|
||||||
def ceilometer(self, ceilometer):
|
|
||||||
self._ceilometer = ceilometer
|
|
||||||
|
|
||||||
@property
|
|
||||||
def gnocchi(self):
|
|
||||||
if self._gnocchi is None:
|
|
||||||
self.gnocchi = gnoc.GnocchiHelper(osc=self.osc)
|
|
||||||
return self._gnocchi
|
|
||||||
|
|
||||||
@gnocchi.setter
|
|
||||||
def gnocchi(self, gnocchi):
|
|
||||||
self._gnocchi = gnocchi
|
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def granularity(self):
|
def granularity(self):
|
||||||
return self.input_parameters.get('granularity', 300)
|
return self.input_parameters.get('granularity', 300)
|
||||||
@@ -315,57 +292,28 @@ class VMWorkloadConsolidation(base.ServerConsolidationBaseStrategy):
|
|||||||
disk_alloc_metric = self.METRIC_NAMES[
|
disk_alloc_metric = self.METRIC_NAMES[
|
||||||
self.config.datasource]['disk_alloc_metric']
|
self.config.datasource]['disk_alloc_metric']
|
||||||
|
|
||||||
if self.config.datasource == "ceilometer":
|
instance_cpu_util = self.datasource_backend.statistic_aggregation(
|
||||||
instance_cpu_util = self.ceilometer.statistic_aggregation(
|
resource_id=instance.uuid,
|
||||||
resource_id=instance.uuid, meter_name=cpu_util_metric,
|
meter_name=cpu_util_metric,
|
||||||
period=self.period, aggregate='avg')
|
period=self.period,
|
||||||
instance_ram_util = self.ceilometer.statistic_aggregation(
|
granularity=self.granularity)
|
||||||
resource_id=instance.uuid, meter_name=ram_util_metric,
|
instance_ram_util = self.datasource_backend.statistic_aggregation(
|
||||||
period=self.period, aggregate='avg')
|
resource_id=instance.uuid,
|
||||||
if not instance_ram_util:
|
meter_name=ram_util_metric,
|
||||||
instance_ram_util = self.ceilometer.statistic_aggregation(
|
period=self.period,
|
||||||
resource_id=instance.uuid, meter_name=ram_alloc_metric,
|
granularity=self.granularity)
|
||||||
period=self.period, aggregate='avg')
|
if not instance_ram_util:
|
||||||
instance_disk_util = self.ceilometer.statistic_aggregation(
|
instance_ram_util = self.datasource_backend.statistic_aggregation(
|
||||||
resource_id=instance.uuid, meter_name=disk_alloc_metric,
|
|
||||||
period=self.period, aggregate='avg')
|
|
||||||
elif self.config.datasource == "gnocchi":
|
|
||||||
stop_time = datetime.datetime.utcnow()
|
|
||||||
start_time = stop_time - datetime.timedelta(
|
|
||||||
seconds=int(self.period))
|
|
||||||
instance_cpu_util = self.gnocchi.statistic_aggregation(
|
|
||||||
resource_id=instance.uuid,
|
resource_id=instance.uuid,
|
||||||
metric=cpu_util_metric,
|
meter_name=ram_alloc_metric,
|
||||||
granularity=self.granularity,
|
period=self.period,
|
||||||
start_time=start_time,
|
granularity=self.granularity)
|
||||||
stop_time=stop_time,
|
instance_disk_util = self.datasource_backend.statistic_aggregation(
|
||||||
aggregation='mean'
|
resource_id=instance.uuid,
|
||||||
)
|
meter_name=disk_alloc_metric,
|
||||||
instance_ram_util = self.gnocchi.statistic_aggregation(
|
period=self.period,
|
||||||
resource_id=instance.uuid,
|
granularity=self.granularity)
|
||||||
metric=ram_util_metric,
|
|
||||||
granularity=self.granularity,
|
|
||||||
start_time=start_time,
|
|
||||||
stop_time=stop_time,
|
|
||||||
aggregation='mean'
|
|
||||||
)
|
|
||||||
if not instance_ram_util:
|
|
||||||
instance_ram_util = self.gnocchi.statistic_aggregation(
|
|
||||||
resource_id=instance.uuid,
|
|
||||||
metric=ram_alloc_metric,
|
|
||||||
granularity=self.granularity,
|
|
||||||
start_time=start_time,
|
|
||||||
stop_time=stop_time,
|
|
||||||
aggregation='mean'
|
|
||||||
)
|
|
||||||
instance_disk_util = self.gnocchi.statistic_aggregation(
|
|
||||||
resource_id=instance.uuid,
|
|
||||||
metric=disk_alloc_metric,
|
|
||||||
granularity=self.granularity,
|
|
||||||
start_time=start_time,
|
|
||||||
stop_time=stop_time,
|
|
||||||
aggregation='mean'
|
|
||||||
)
|
|
||||||
if instance_cpu_util:
|
if instance_cpu_util:
|
||||||
total_cpu_utilization = (
|
total_cpu_utilization = (
|
||||||
instance.vcpus * (instance_cpu_util / 100.0))
|
instance.vcpus * (instance_cpu_util / 100.0))
|
||||||
|
|||||||
@@ -290,8 +290,9 @@ class WorkloadBalance(base.WorkloadStabilizationBaseStrategy):
|
|||||||
util = None
|
util = None
|
||||||
try:
|
try:
|
||||||
util = self.datasource_backend.statistic_aggregation(
|
util = self.datasource_backend.statistic_aggregation(
|
||||||
instance.uuid, self._meter, self._period, 'mean',
|
instance.uuid, self._meter, self._period,
|
||||||
granularity=self.granularity)
|
self._granularity, aggregation='mean',
|
||||||
|
dimensions=dict(resource_id=instance.uuid))
|
||||||
except Exception as exc:
|
except Exception as exc:
|
||||||
LOG.exception(exc)
|
LOG.exception(exc)
|
||||||
LOG.error("Can not get %s from %s", self._meter,
|
LOG.error("Can not get %s from %s", self._meter,
|
||||||
@@ -352,6 +353,7 @@ class WorkloadBalance(base.WorkloadStabilizationBaseStrategy):
|
|||||||
self.threshold = self.input_parameters.threshold
|
self.threshold = self.input_parameters.threshold
|
||||||
self._period = self.input_parameters.period
|
self._period = self.input_parameters.period
|
||||||
self._meter = self.input_parameters.metrics
|
self._meter = self.input_parameters.metrics
|
||||||
|
self._granularity = self.input_parameters.granularity
|
||||||
source_nodes, target_nodes, avg_workload, workload_cache = (
|
source_nodes, target_nodes, avg_workload, workload_cache = (
|
||||||
self.group_hosts_by_cpu_or_ram_util())
|
self.group_hosts_by_cpu_or_ram_util())
|
||||||
|
|
||||||
|
|||||||
@@ -198,8 +198,8 @@ class WorkloadStabilization(base.WorkloadStabilizationBaseStrategy):
|
|||||||
instance_load = {'uuid': instance.uuid, 'vcpus': instance.vcpus}
|
instance_load = {'uuid': instance.uuid, 'vcpus': instance.vcpus}
|
||||||
for meter in self.metrics:
|
for meter in self.metrics:
|
||||||
avg_meter = self.datasource_backend.statistic_aggregation(
|
avg_meter = self.datasource_backend.statistic_aggregation(
|
||||||
instance.uuid, meter, self.periods['instance'], 'mean',
|
instance.uuid, meter, self.periods['instance'],
|
||||||
granularity=self.granularity)
|
self.granularity, aggregation='mean')
|
||||||
if avg_meter is None:
|
if avg_meter is None:
|
||||||
LOG.warning(
|
LOG.warning(
|
||||||
"No values returned by %(resource_id)s "
|
"No values returned by %(resource_id)s "
|
||||||
@@ -242,8 +242,7 @@ class WorkloadStabilization(base.WorkloadStabilizationBaseStrategy):
|
|||||||
resource_id = node_id
|
resource_id = node_id
|
||||||
avg_meter = self.datasource_backend.statistic_aggregation(
|
avg_meter = self.datasource_backend.statistic_aggregation(
|
||||||
resource_id, self.instance_metrics[metric],
|
resource_id, self.instance_metrics[metric],
|
||||||
self.periods['node'], 'mean', granularity=self.granularity)
|
self.periods['node'], self.granularity, aggregation='mean')
|
||||||
|
|
||||||
if avg_meter is None:
|
if avg_meter is None:
|
||||||
LOG.warning('No values returned by node %s for %s',
|
LOG.warning('No values returned by node %s for %s',
|
||||||
node_id, meter_name)
|
node_id, meter_name)
|
||||||
|
|||||||
@@ -10,6 +10,14 @@
|
|||||||
# implied.
|
# implied.
|
||||||
# See the License for the specific language governing permissions and
|
# See the License for the specific language governing permissions and
|
||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
|
#
|
||||||
|
"""
|
||||||
|
*Zone migration using instance and volume migration*
|
||||||
|
|
||||||
|
This is zone migration strategy to migrate many instances and volumes
|
||||||
|
efficiently with minimum downtime for hardware maintenance.
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
from dateutil.parser import parse
|
from dateutil.parser import parse
|
||||||
import six
|
import six
|
||||||
@@ -40,6 +48,7 @@ IN_USE = "in-use"
|
|||||||
|
|
||||||
|
|
||||||
class ZoneMigration(base.ZoneMigrationBaseStrategy):
|
class ZoneMigration(base.ZoneMigrationBaseStrategy):
|
||||||
|
"""Zone migration using instance and volume migration"""
|
||||||
|
|
||||||
def __init__(self, config, osc=None):
|
def __init__(self, config, osc=None):
|
||||||
|
|
||||||
@@ -371,15 +380,6 @@ class ZoneMigration(base.ZoneMigrationBaseStrategy):
|
|||||||
:param pool: pool name
|
:param pool: pool name
|
||||||
:returns: host name
|
:returns: host name
|
||||||
"""
|
"""
|
||||||
|
|
||||||
# TODO(hidekazu) use this
|
|
||||||
# mapping = zonemgr.get_host_pool_mapping()
|
|
||||||
# for host, pools in six.iteritems(mapping):
|
|
||||||
# for _pool in pools:
|
|
||||||
# if pool == _pool:
|
|
||||||
# return host
|
|
||||||
# LOG.warning(self.msg_not_exist_corresponding_host % pool)
|
|
||||||
# return pool
|
|
||||||
return pool.split('@')[0]
|
return pool.split('@')[0]
|
||||||
|
|
||||||
def get_dst_node(self, src_node):
|
def get_dst_node(self, src_node):
|
||||||
|
|||||||
@@ -60,6 +60,7 @@ log_warn = re.compile(
|
|||||||
r"(.)*LOG\.(warn)\(\s*('|\"|_)")
|
r"(.)*LOG\.(warn)\(\s*('|\"|_)")
|
||||||
unittest_imports_dot = re.compile(r"\bimport[\s]+unittest\b")
|
unittest_imports_dot = re.compile(r"\bimport[\s]+unittest\b")
|
||||||
unittest_imports_from = re.compile(r"\bfrom[\s]+unittest\b")
|
unittest_imports_from = re.compile(r"\bfrom[\s]+unittest\b")
|
||||||
|
re_redundant_import_alias = re.compile(r".*import (.+) as \1$")
|
||||||
|
|
||||||
|
|
||||||
@flake8ext
|
@flake8ext
|
||||||
@@ -271,6 +272,18 @@ def check_builtins_gettext(logical_line, tokens, filename, lines, noqa):
|
|||||||
yield (0, msg)
|
yield (0, msg)
|
||||||
|
|
||||||
|
|
||||||
|
@flake8ext
|
||||||
|
def no_redundant_import_alias(logical_line):
|
||||||
|
"""Checking no redundant import alias.
|
||||||
|
|
||||||
|
https://bugs.launchpad.net/watcher/+bug/1745527
|
||||||
|
|
||||||
|
N342
|
||||||
|
"""
|
||||||
|
if re.match(re_redundant_import_alias, logical_line):
|
||||||
|
yield(0, "N342: No redundant import alias.")
|
||||||
|
|
||||||
|
|
||||||
def factory(register):
|
def factory(register):
|
||||||
register(use_jsonutils)
|
register(use_jsonutils)
|
||||||
register(check_assert_called_once_with)
|
register(check_assert_called_once_with)
|
||||||
@@ -286,3 +299,4 @@ def factory(register):
|
|||||||
register(check_log_warn_deprecated)
|
register(check_log_warn_deprecated)
|
||||||
register(check_oslo_i18n_wrapper)
|
register(check_oslo_i18n_wrapper)
|
||||||
register(check_builtins_gettext)
|
register(check_builtins_gettext)
|
||||||
|
register(no_redundant_import_alias)
|
||||||
|
|||||||
@@ -4,11 +4,11 @@ msgid ""
|
|||||||
msgstr ""
|
msgstr ""
|
||||||
"Project-Id-Version: watcher VERSION\n"
|
"Project-Id-Version: watcher VERSION\n"
|
||||||
"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n"
|
"Report-Msgid-Bugs-To: https://bugs.launchpad.net/openstack-i18n/\n"
|
||||||
"POT-Creation-Date: 2018-01-19 11:46+0000\n"
|
"POT-Creation-Date: 2018-01-26 00:18+0000\n"
|
||||||
"MIME-Version: 1.0\n"
|
"MIME-Version: 1.0\n"
|
||||||
"Content-Type: text/plain; charset=UTF-8\n"
|
"Content-Type: text/plain; charset=UTF-8\n"
|
||||||
"Content-Transfer-Encoding: 8bit\n"
|
"Content-Transfer-Encoding: 8bit\n"
|
||||||
"PO-Revision-Date: 2018-01-19 08:01+0000\n"
|
"PO-Revision-Date: 2018-01-27 12:51+0000\n"
|
||||||
"Last-Translator: Andi Chandler <andi@gowling.com>\n"
|
"Last-Translator: Andi Chandler <andi@gowling.com>\n"
|
||||||
"Language-Team: English (United Kingdom)\n"
|
"Language-Team: English (United Kingdom)\n"
|
||||||
"Language: en-GB\n"
|
"Language: en-GB\n"
|
||||||
@@ -280,6 +280,10 @@ msgstr "Couldn't apply patch '%(patch)s'. Reason: %(reason)s"
|
|||||||
msgid "Couldn't delete when state is '%(state)s'."
|
msgid "Couldn't delete when state is '%(state)s'."
|
||||||
msgstr "Couldn't delete when state is '%(state)s'."
|
msgstr "Couldn't delete when state is '%(state)s'."
|
||||||
|
|
||||||
|
#, python-format
|
||||||
|
msgid "Datasource %(datasource)s is not available."
|
||||||
|
msgstr "Datasource %(datasource)s is not available."
|
||||||
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Datasource %(datasource)s is not supported by strategy %(strategy)s"
|
msgid "Datasource %(datasource)s is not supported by strategy %(strategy)s"
|
||||||
msgstr "Datasource %(datasource)s is not supported by strategy %(strategy)s"
|
msgstr "Datasource %(datasource)s is not supported by strategy %(strategy)s"
|
||||||
@@ -369,6 +373,9 @@ msgstr "Goal %(goal)s is invalid"
|
|||||||
msgid "Goals"
|
msgid "Goals"
|
||||||
msgstr "Goals"
|
msgstr "Goals"
|
||||||
|
|
||||||
|
msgid "Hardware Maintenance"
|
||||||
|
msgstr "Hardware Maintenance"
|
||||||
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid "Here below is a table containing the objects that can be purged%s:"
|
msgid "Here below is a table containing the objects that can be purged%s:"
|
||||||
msgstr "Here below is a table containing the objects that can be purged%s:"
|
msgstr "Here below is a table containing the objects that can be purged%s:"
|
||||||
@@ -506,6 +513,30 @@ msgstr "Provided cron is invalid: %(message)s"
|
|||||||
msgid "Purge results summary%s:"
|
msgid "Purge results summary%s:"
|
||||||
msgstr "Purge results summary%s:"
|
msgstr "Purge results summary%s:"
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Ratio of actual attached volumes migrated to planned attached volumes "
|
||||||
|
"migrate."
|
||||||
|
msgstr ""
|
||||||
|
"Ratio of actual attached volumes migrated to planned attached volumes "
|
||||||
|
"migrate."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Ratio of actual cold migrated instances to planned cold migrate instances."
|
||||||
|
msgstr ""
|
||||||
|
"Ratio of actual cold migrated instances to planned cold migrate instances."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Ratio of actual detached volumes migrated to planned detached volumes "
|
||||||
|
"migrate."
|
||||||
|
msgstr ""
|
||||||
|
"Ratio of actual detached volumes migrated to planned detached volumes "
|
||||||
|
"migrate."
|
||||||
|
|
||||||
|
msgid ""
|
||||||
|
"Ratio of actual live migrated instances to planned live migrate instances."
|
||||||
|
msgstr ""
|
||||||
|
"Ratio of actual live migrated instances to planned live migrate instances."
|
||||||
|
|
||||||
msgid ""
|
msgid ""
|
||||||
"Ratio of released compute nodes divided by the total number of enabled "
|
"Ratio of released compute nodes divided by the total number of enabled "
|
||||||
"compute nodes."
|
"compute nodes."
|
||||||
@@ -561,6 +592,9 @@ msgstr ""
|
|||||||
msgid "State transition not allowed: (%(initial_state)s -> %(new_state)s)"
|
msgid "State transition not allowed: (%(initial_state)s -> %(new_state)s)"
|
||||||
msgstr "State transition not allowed: (%(initial_state)s -> %(new_state)s)"
|
msgstr "State transition not allowed: (%(initial_state)s -> %(new_state)s)"
|
||||||
|
|
||||||
|
msgid "Storage Capacity Balance Strategy"
|
||||||
|
msgstr "Storage Capacity Balance Strategy"
|
||||||
|
|
||||||
msgid "Strategies"
|
msgid "Strategies"
|
||||||
msgstr "Strategies"
|
msgstr "Strategies"
|
||||||
|
|
||||||
@@ -644,15 +678,42 @@ msgstr "The Ironic node %(uuid)s could not be found"
|
|||||||
msgid "The list of compute node(s) in the cluster is empty"
|
msgid "The list of compute node(s) in the cluster is empty"
|
||||||
msgstr "The list of compute node(s) in the cluster is empty"
|
msgstr "The list of compute node(s) in the cluster is empty"
|
||||||
|
|
||||||
|
msgid "The list of storage node(s) in the cluster is empty"
|
||||||
|
msgstr "The list of storage node(s) in the cluster is empty"
|
||||||
|
|
||||||
msgid "The metrics resource collector is not defined"
|
msgid "The metrics resource collector is not defined"
|
||||||
msgstr "The metrics resource collector is not defined"
|
msgstr "The metrics resource collector is not defined"
|
||||||
|
|
||||||
msgid "The number of VM migrations to be performed."
|
msgid "The number of VM migrations to be performed."
|
||||||
msgstr "The number of VM migrations to be performed."
|
msgstr "The number of VM migrations to be performed."
|
||||||
|
|
||||||
|
msgid "The number of attached volumes actually migrated."
|
||||||
|
msgstr "The number of attached volumes actually migrated."
|
||||||
|
|
||||||
|
msgid "The number of attached volumes planned to migrate."
|
||||||
|
msgstr "The number of attached volumes planned to migrate."
|
||||||
|
|
||||||
msgid "The number of compute nodes to be released."
|
msgid "The number of compute nodes to be released."
|
||||||
msgstr "The number of compute nodes to be released."
|
msgstr "The number of compute nodes to be released."
|
||||||
|
|
||||||
|
msgid "The number of detached volumes actually migrated."
|
||||||
|
msgstr "The number of detached volumes actually migrated."
|
||||||
|
|
||||||
|
msgid "The number of detached volumes planned to migrate."
|
||||||
|
msgstr "The number of detached volumes planned to migrate."
|
||||||
|
|
||||||
|
msgid "The number of instances actually cold migrated."
|
||||||
|
msgstr "The number of instances actually cold migrated."
|
||||||
|
|
||||||
|
msgid "The number of instances actually live migrated."
|
||||||
|
msgstr "The number of instances actually live migrated."
|
||||||
|
|
||||||
|
msgid "The number of instances planned to cold migrate."
|
||||||
|
msgstr "The number of instances planned to cold migrate."
|
||||||
|
|
||||||
|
msgid "The number of instances planned to live migrate."
|
||||||
|
msgstr "The number of instances planned to live migrate."
|
||||||
|
|
||||||
#, python-format
|
#, python-format
|
||||||
msgid ""
|
msgid ""
|
||||||
"The number of objects (%(num)s) to delete from the database exceeds the "
|
"The number of objects (%(num)s) to delete from the database exceeds the "
|
||||||
@@ -766,6 +827,9 @@ msgstr ""
|
|||||||
"You shouldn't use any other IDs of %(resource)s if you use wildcard "
|
"You shouldn't use any other IDs of %(resource)s if you use wildcard "
|
||||||
"character."
|
"character."
|
||||||
|
|
||||||
|
msgid "Zone migration"
|
||||||
|
msgstr "Zone migration"
|
||||||
|
|
||||||
msgid "destination type is required when migration type is swap"
|
msgid "destination type is required when migration type is swap"
|
||||||
msgstr "destination type is required when migration type is swap"
|
msgstr "destination type is required when migration type is swap"
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ import sys
|
|||||||
import six
|
import six
|
||||||
|
|
||||||
from watcher.notifications import base as notificationbase
|
from watcher.notifications import base as notificationbase
|
||||||
from watcher.objects import base as base
|
from watcher.objects import base
|
||||||
from watcher.objects import fields as wfields
|
from watcher.objects import fields as wfields
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -55,7 +55,8 @@ class TestCeilometerHelper(base.BaseTestCase):
|
|||||||
val = cm.statistic_aggregation(
|
val = cm.statistic_aggregation(
|
||||||
resource_id="INSTANCE_ID",
|
resource_id="INSTANCE_ID",
|
||||||
meter_name="cpu_util",
|
meter_name="cpu_util",
|
||||||
period="7300"
|
period="7300",
|
||||||
|
granularity=None
|
||||||
)
|
)
|
||||||
self.assertEqual(expected_result, val)
|
self.assertEqual(expected_result, val)
|
||||||
|
|
||||||
@@ -100,7 +101,7 @@ class TestCeilometerHelper(base.BaseTestCase):
|
|||||||
helper = ceilometer_helper.CeilometerHelper()
|
helper = ceilometer_helper.CeilometerHelper()
|
||||||
helper.get_host_cpu_usage('compute1', 600, 'mean')
|
helper.get_host_cpu_usage('compute1', 600, 'mean')
|
||||||
mock_aggregation.assert_called_once_with(
|
mock_aggregation.assert_called_once_with(
|
||||||
'compute1', helper.METRIC_MAP['host_cpu_usage'], 600,
|
'compute1', helper.METRIC_MAP['host_cpu_usage'], 600, None,
|
||||||
aggregate='mean')
|
aggregate='mean')
|
||||||
|
|
||||||
@mock.patch.object(ceilometer_helper.CeilometerHelper,
|
@mock.patch.object(ceilometer_helper.CeilometerHelper,
|
||||||
@@ -109,7 +110,7 @@ class TestCeilometerHelper(base.BaseTestCase):
|
|||||||
helper = ceilometer_helper.CeilometerHelper()
|
helper = ceilometer_helper.CeilometerHelper()
|
||||||
helper.get_instance_cpu_usage('compute1', 600, 'mean')
|
helper.get_instance_cpu_usage('compute1', 600, 'mean')
|
||||||
mock_aggregation.assert_called_once_with(
|
mock_aggregation.assert_called_once_with(
|
||||||
'compute1', helper.METRIC_MAP['instance_cpu_usage'], 600,
|
'compute1', helper.METRIC_MAP['instance_cpu_usage'], 600, None,
|
||||||
aggregate='mean')
|
aggregate='mean')
|
||||||
|
|
||||||
@mock.patch.object(ceilometer_helper.CeilometerHelper,
|
@mock.patch.object(ceilometer_helper.CeilometerHelper,
|
||||||
@@ -118,7 +119,7 @@ class TestCeilometerHelper(base.BaseTestCase):
|
|||||||
helper = ceilometer_helper.CeilometerHelper()
|
helper = ceilometer_helper.CeilometerHelper()
|
||||||
helper.get_host_memory_usage('compute1', 600, 'mean')
|
helper.get_host_memory_usage('compute1', 600, 'mean')
|
||||||
mock_aggregation.assert_called_once_with(
|
mock_aggregation.assert_called_once_with(
|
||||||
'compute1', helper.METRIC_MAP['host_memory_usage'], 600,
|
'compute1', helper.METRIC_MAP['host_memory_usage'], 600, None,
|
||||||
aggregate='mean')
|
aggregate='mean')
|
||||||
|
|
||||||
@mock.patch.object(ceilometer_helper.CeilometerHelper,
|
@mock.patch.object(ceilometer_helper.CeilometerHelper,
|
||||||
@@ -128,7 +129,7 @@ class TestCeilometerHelper(base.BaseTestCase):
|
|||||||
helper = ceilometer_helper.CeilometerHelper()
|
helper = ceilometer_helper.CeilometerHelper()
|
||||||
helper.get_instance_memory_usage('compute1', 600, 'mean')
|
helper.get_instance_memory_usage('compute1', 600, 'mean')
|
||||||
mock_aggregation.assert_called_once_with(
|
mock_aggregation.assert_called_once_with(
|
||||||
'compute1', helper.METRIC_MAP['instance_ram_usage'], 600,
|
'compute1', helper.METRIC_MAP['instance_ram_usage'], 600, None,
|
||||||
aggregate='mean')
|
aggregate='mean')
|
||||||
|
|
||||||
@mock.patch.object(ceilometer_helper.CeilometerHelper,
|
@mock.patch.object(ceilometer_helper.CeilometerHelper,
|
||||||
@@ -139,7 +140,7 @@ class TestCeilometerHelper(base.BaseTestCase):
|
|||||||
helper.get_instance_l3_cache_usage('compute1', 600, 'mean')
|
helper.get_instance_l3_cache_usage('compute1', 600, 'mean')
|
||||||
mock_aggregation.assert_called_once_with(
|
mock_aggregation.assert_called_once_with(
|
||||||
'compute1', helper.METRIC_MAP['instance_l3_cache_usage'], 600,
|
'compute1', helper.METRIC_MAP['instance_l3_cache_usage'], 600,
|
||||||
aggregate='mean')
|
None, aggregate='mean')
|
||||||
|
|
||||||
@mock.patch.object(ceilometer_helper.CeilometerHelper,
|
@mock.patch.object(ceilometer_helper.CeilometerHelper,
|
||||||
'statistic_aggregation')
|
'statistic_aggregation')
|
||||||
@@ -148,7 +149,7 @@ class TestCeilometerHelper(base.BaseTestCase):
|
|||||||
helper = ceilometer_helper.CeilometerHelper()
|
helper = ceilometer_helper.CeilometerHelper()
|
||||||
helper.get_instance_ram_allocated('compute1', 600, 'mean')
|
helper.get_instance_ram_allocated('compute1', 600, 'mean')
|
||||||
mock_aggregation.assert_called_once_with(
|
mock_aggregation.assert_called_once_with(
|
||||||
'compute1', helper.METRIC_MAP['instance_ram_allocated'], 600,
|
'compute1', helper.METRIC_MAP['instance_ram_allocated'], 600, None,
|
||||||
aggregate='mean')
|
aggregate='mean')
|
||||||
|
|
||||||
@mock.patch.object(ceilometer_helper.CeilometerHelper,
|
@mock.patch.object(ceilometer_helper.CeilometerHelper,
|
||||||
@@ -159,7 +160,7 @@ class TestCeilometerHelper(base.BaseTestCase):
|
|||||||
helper.get_instance_root_disk_allocated('compute1', 600, 'mean')
|
helper.get_instance_root_disk_allocated('compute1', 600, 'mean')
|
||||||
mock_aggregation.assert_called_once_with(
|
mock_aggregation.assert_called_once_with(
|
||||||
'compute1', helper.METRIC_MAP['instance_root_disk_size'], 600,
|
'compute1', helper.METRIC_MAP['instance_root_disk_size'], 600,
|
||||||
aggregate='mean')
|
None, aggregate='mean')
|
||||||
|
|
||||||
@mock.patch.object(ceilometer_helper.CeilometerHelper,
|
@mock.patch.object(ceilometer_helper.CeilometerHelper,
|
||||||
'statistic_aggregation')
|
'statistic_aggregation')
|
||||||
@@ -168,7 +169,7 @@ class TestCeilometerHelper(base.BaseTestCase):
|
|||||||
helper = ceilometer_helper.CeilometerHelper()
|
helper = ceilometer_helper.CeilometerHelper()
|
||||||
helper.get_host_outlet_temperature('compute1', 600, 'mean')
|
helper.get_host_outlet_temperature('compute1', 600, 'mean')
|
||||||
mock_aggregation.assert_called_once_with(
|
mock_aggregation.assert_called_once_with(
|
||||||
'compute1', helper.METRIC_MAP['host_outlet_temp'], 600,
|
'compute1', helper.METRIC_MAP['host_outlet_temp'], 600, None,
|
||||||
aggregate='mean')
|
aggregate='mean')
|
||||||
|
|
||||||
@mock.patch.object(ceilometer_helper.CeilometerHelper,
|
@mock.patch.object(ceilometer_helper.CeilometerHelper,
|
||||||
@@ -178,7 +179,7 @@ class TestCeilometerHelper(base.BaseTestCase):
|
|||||||
helper = ceilometer_helper.CeilometerHelper()
|
helper = ceilometer_helper.CeilometerHelper()
|
||||||
helper.get_host_inlet_temperature('compute1', 600, 'mean')
|
helper.get_host_inlet_temperature('compute1', 600, 'mean')
|
||||||
mock_aggregation.assert_called_once_with(
|
mock_aggregation.assert_called_once_with(
|
||||||
'compute1', helper.METRIC_MAP['host_inlet_temp'], 600,
|
'compute1', helper.METRIC_MAP['host_inlet_temp'], 600, None,
|
||||||
aggregate='mean')
|
aggregate='mean')
|
||||||
|
|
||||||
@mock.patch.object(ceilometer_helper.CeilometerHelper,
|
@mock.patch.object(ceilometer_helper.CeilometerHelper,
|
||||||
@@ -187,7 +188,7 @@ class TestCeilometerHelper(base.BaseTestCase):
|
|||||||
helper = ceilometer_helper.CeilometerHelper()
|
helper = ceilometer_helper.CeilometerHelper()
|
||||||
helper.get_host_airflow('compute1', 600, 'mean')
|
helper.get_host_airflow('compute1', 600, 'mean')
|
||||||
mock_aggregation.assert_called_once_with(
|
mock_aggregation.assert_called_once_with(
|
||||||
'compute1', helper.METRIC_MAP['host_airflow'], 600,
|
'compute1', helper.METRIC_MAP['host_airflow'], 600, None,
|
||||||
aggregate='mean')
|
aggregate='mean')
|
||||||
|
|
||||||
@mock.patch.object(ceilometer_helper.CeilometerHelper,
|
@mock.patch.object(ceilometer_helper.CeilometerHelper,
|
||||||
@@ -196,7 +197,7 @@ class TestCeilometerHelper(base.BaseTestCase):
|
|||||||
helper = ceilometer_helper.CeilometerHelper()
|
helper = ceilometer_helper.CeilometerHelper()
|
||||||
helper.get_host_power('compute1', 600, 'mean')
|
helper.get_host_power('compute1', 600, 'mean')
|
||||||
mock_aggregation.assert_called_once_with(
|
mock_aggregation.assert_called_once_with(
|
||||||
'compute1', helper.METRIC_MAP['host_power'], 600,
|
'compute1', helper.METRIC_MAP['host_power'], 600, None,
|
||||||
aggregate='mean')
|
aggregate='mean')
|
||||||
|
|
||||||
def test_check_availability(self, mock_ceilometer):
|
def test_check_availability(self, mock_ceilometer):
|
||||||
|
|||||||
@@ -16,10 +16,8 @@
|
|||||||
|
|
||||||
import mock
|
import mock
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_utils import timeutils
|
|
||||||
|
|
||||||
from watcher.common import clients
|
from watcher.common import clients
|
||||||
from watcher.common import exception
|
|
||||||
from watcher.datasource import gnocchi as gnocchi_helper
|
from watcher.datasource import gnocchi as gnocchi_helper
|
||||||
from watcher.tests import base
|
from watcher.tests import base
|
||||||
|
|
||||||
@@ -39,34 +37,17 @@ class TestGnocchiHelper(base.BaseTestCase):
|
|||||||
mock_gnocchi.return_value = gnocchi
|
mock_gnocchi.return_value = gnocchi
|
||||||
|
|
||||||
helper = gnocchi_helper.GnocchiHelper()
|
helper = gnocchi_helper.GnocchiHelper()
|
||||||
result = helper._statistic_aggregation(
|
result = helper.statistic_aggregation(
|
||||||
resource_id='16a86790-327a-45f9-bc82-45839f062fdc',
|
resource_id='16a86790-327a-45f9-bc82-45839f062fdc',
|
||||||
metric='cpu_util',
|
meter_name='cpu_util',
|
||||||
|
period=300,
|
||||||
granularity=360,
|
granularity=360,
|
||||||
start_time=timeutils.parse_isotime("2017-02-02T09:00:00.000000"),
|
dimensions=None,
|
||||||
stop_time=timeutils.parse_isotime("2017-02-02T10:00:00.000000"),
|
aggregation='mean',
|
||||||
aggregation='mean'
|
group_by='*'
|
||||||
)
|
)
|
||||||
self.assertEqual(expected_result, result)
|
self.assertEqual(expected_result, result)
|
||||||
|
|
||||||
def test_gnocchi_wrong_datetime(self, mock_gnocchi):
|
|
||||||
gnocchi = mock.MagicMock()
|
|
||||||
|
|
||||||
expected_measures = [["2017-02-02T09:00:00.000000", 360, 5.5]]
|
|
||||||
|
|
||||||
gnocchi.metric.get_measures.return_value = expected_measures
|
|
||||||
mock_gnocchi.return_value = gnocchi
|
|
||||||
|
|
||||||
helper = gnocchi_helper.GnocchiHelper()
|
|
||||||
self.assertRaises(
|
|
||||||
exception.InvalidParameter, helper._statistic_aggregation,
|
|
||||||
resource_id='16a86790-327a-45f9-bc82-45839f062fdc',
|
|
||||||
metric='cpu_util',
|
|
||||||
granularity=360,
|
|
||||||
start_time="2017-02-02T09:00:00.000000",
|
|
||||||
stop_time=timeutils.parse_isotime("2017-02-02T10:00:00.000000"),
|
|
||||||
aggregation='mean')
|
|
||||||
|
|
||||||
@mock.patch.object(gnocchi_helper.GnocchiHelper, 'statistic_aggregation')
|
@mock.patch.object(gnocchi_helper.GnocchiHelper, 'statistic_aggregation')
|
||||||
def test_get_host_cpu_usage(self, mock_aggregation, mock_gnocchi):
|
def test_get_host_cpu_usage(self, mock_aggregation, mock_gnocchi):
|
||||||
helper = gnocchi_helper.GnocchiHelper()
|
helper = gnocchi_helper.GnocchiHelper()
|
||||||
|
|||||||
@@ -16,7 +16,6 @@
|
|||||||
|
|
||||||
import mock
|
import mock
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
from oslo_utils import timeutils
|
|
||||||
|
|
||||||
from watcher.common import clients
|
from watcher.common import clients
|
||||||
from watcher.datasource import monasca as monasca_helper
|
from watcher.datasource import monasca as monasca_helper
|
||||||
@@ -30,7 +29,7 @@ class TestMonascaHelper(base.BaseTestCase):
|
|||||||
|
|
||||||
def test_monasca_statistic_aggregation(self, mock_monasca):
|
def test_monasca_statistic_aggregation(self, mock_monasca):
|
||||||
monasca = mock.MagicMock()
|
monasca = mock.MagicMock()
|
||||||
expected_result = [{
|
expected_stat = [{
|
||||||
'columns': ['timestamp', 'avg'],
|
'columns': ['timestamp', 'avg'],
|
||||||
'dimensions': {
|
'dimensions': {
|
||||||
'hostname': 'rdev-indeedsrv001',
|
'hostname': 'rdev-indeedsrv001',
|
||||||
@@ -39,23 +38,23 @@ class TestMonascaHelper(base.BaseTestCase):
|
|||||||
'name': 'cpu.percent',
|
'name': 'cpu.percent',
|
||||||
'statistics': [
|
'statistics': [
|
||||||
['2016-07-29T12:45:00Z', 0.0],
|
['2016-07-29T12:45:00Z', 0.0],
|
||||||
['2016-07-29T12:50:00Z', 0.9100000000000001],
|
['2016-07-29T12:50:00Z', 0.9],
|
||||||
['2016-07-29T12:55:00Z', 0.9111111111111112]]}]
|
['2016-07-29T12:55:00Z', 0.9]]}]
|
||||||
|
|
||||||
monasca.metrics.list_statistics.return_value = expected_result
|
monasca.metrics.list_statistics.return_value = expected_stat
|
||||||
mock_monasca.return_value = monasca
|
mock_monasca.return_value = monasca
|
||||||
|
|
||||||
helper = monasca_helper.MonascaHelper()
|
helper = monasca_helper.MonascaHelper()
|
||||||
result = helper.statistic_aggregation(
|
result = helper.statistic_aggregation(
|
||||||
|
resource_id=None,
|
||||||
meter_name='cpu.percent',
|
meter_name='cpu.percent',
|
||||||
dimensions={'hostname': 'NODE_UUID'},
|
|
||||||
start_time=timeutils.parse_isotime("2016-06-06T10:33:22.063176"),
|
|
||||||
end_time=None,
|
|
||||||
period=7200,
|
period=7200,
|
||||||
aggregate='avg',
|
granularity=300,
|
||||||
|
dimensions={'hostname': 'NODE_UUID'},
|
||||||
|
aggregation='avg',
|
||||||
group_by='*',
|
group_by='*',
|
||||||
)
|
)
|
||||||
self.assertEqual(expected_result, result)
|
self.assertEqual(0.6, result)
|
||||||
|
|
||||||
def test_check_availability(self, mock_monasca):
|
def test_check_availability(self, mock_monasca):
|
||||||
monasca = mock.MagicMock()
|
monasca = mock.MagicMock()
|
||||||
@@ -117,34 +116,14 @@ class TestMonascaHelper(base.BaseTestCase):
|
|||||||
@mock.patch.object(monasca_helper.MonascaHelper, 'statistic_aggregation')
|
@mock.patch.object(monasca_helper.MonascaHelper, 'statistic_aggregation')
|
||||||
def test_get_host_cpu_usage(self, mock_aggregation, mock_monasca):
|
def test_get_host_cpu_usage(self, mock_aggregation, mock_monasca):
|
||||||
node = "compute1_compute1"
|
node = "compute1_compute1"
|
||||||
mock_aggregation.return_value = [{
|
mock_aggregation.return_value = 0.6
|
||||||
'columns': ['timestamp', 'avg'],
|
|
||||||
'dimensions': {
|
|
||||||
'hostname': 'rdev-indeedsrv001',
|
|
||||||
'service': 'monasca'},
|
|
||||||
'id': '0',
|
|
||||||
'name': 'cpu.percent',
|
|
||||||
'statistics': [
|
|
||||||
['2016-07-29T12:45:00Z', 0.0],
|
|
||||||
['2016-07-29T12:50:00Z', 0.9],
|
|
||||||
['2016-07-29T12:55:00Z', 0.9]]}]
|
|
||||||
helper = monasca_helper.MonascaHelper()
|
helper = monasca_helper.MonascaHelper()
|
||||||
cpu_usage = helper.get_host_cpu_usage(node, 600, 'mean')
|
cpu_usage = helper.get_host_cpu_usage(node, 600, 'mean')
|
||||||
self.assertEqual(0.6, cpu_usage)
|
self.assertEqual(0.6, cpu_usage)
|
||||||
|
|
||||||
@mock.patch.object(monasca_helper.MonascaHelper, 'statistic_aggregation')
|
@mock.patch.object(monasca_helper.MonascaHelper, 'statistic_aggregation')
|
||||||
def test_get_instance_cpu_usage(self, mock_aggregation, mock_monasca):
|
def test_get_instance_cpu_usage(self, mock_aggregation, mock_monasca):
|
||||||
mock_aggregation.return_value = [{
|
mock_aggregation.return_value = 0.6
|
||||||
'columns': ['timestamp', 'avg'],
|
|
||||||
'dimensions': {
|
|
||||||
'name': 'vm1',
|
|
||||||
'service': 'monasca'},
|
|
||||||
'id': '0',
|
|
||||||
'name': 'cpu.percent',
|
|
||||||
'statistics': [
|
|
||||||
['2016-07-29T12:45:00Z', 0.0],
|
|
||||||
['2016-07-29T12:50:00Z', 0.9],
|
|
||||||
['2016-07-29T12:55:00Z', 0.9]]}]
|
|
||||||
helper = monasca_helper.MonascaHelper()
|
helper = monasca_helper.MonascaHelper()
|
||||||
cpu_usage = helper.get_instance_cpu_usage('vm1', 600, 'mean')
|
cpu_usage = helper.get_instance_cpu_usage('vm1', 600, 'mean')
|
||||||
self.assertEqual(0.6, cpu_usage)
|
self.assertEqual(0.6, cpu_usage)
|
||||||
|
|||||||
@@ -26,14 +26,9 @@ class FakeCeilometerMetrics(object):
|
|||||||
def empty_one_metric(self, emptytype):
|
def empty_one_metric(self, emptytype):
|
||||||
self.emptytype = emptytype
|
self.emptytype = emptytype
|
||||||
|
|
||||||
# TODO(alexchadin): This method is added as temporary solution until
|
def mock_get_statistics(self, resource_id=None, meter_name=None,
|
||||||
# all strategies use datasource_backend property.
|
period=None, granularity=None, dimensions=None,
|
||||||
def temp_mock_get_statistics(self, resource_id, meter_name, period,
|
aggregation='avg', group_by='*'):
|
||||||
aggregate, granularity=300):
|
|
||||||
return self.mock_get_statistics(resource_id, meter_name, period)
|
|
||||||
|
|
||||||
def mock_get_statistics(self, resource_id, meter_name, period,
|
|
||||||
aggregate='avg'):
|
|
||||||
result = 0
|
result = 0
|
||||||
if meter_name == "hardware.cpu.util":
|
if meter_name == "hardware.cpu.util":
|
||||||
result = self.get_usage_node_cpu(resource_id)
|
result = self.get_usage_node_cpu(resource_id)
|
||||||
@@ -56,7 +51,8 @@ class FakeCeilometerMetrics(object):
|
|||||||
return result
|
return result
|
||||||
|
|
||||||
def mock_get_statistics_wb(self, resource_id, meter_name, period,
|
def mock_get_statistics_wb(self, resource_id, meter_name, period,
|
||||||
aggregate, granularity=300):
|
granularity, dimensions=None,
|
||||||
|
aggregation='avg', group_by='*'):
|
||||||
result = 0.0
|
result = 0.0
|
||||||
if meter_name == "cpu_util":
|
if meter_name == "cpu_util":
|
||||||
result = self.get_average_usage_instance_cpu_wb(resource_id)
|
result = self.get_average_usage_instance_cpu_wb(resource_id)
|
||||||
|
|||||||
@@ -84,8 +84,9 @@ class FakeCeilometerMetrics(object):
|
|||||||
def __init__(self, model):
|
def __init__(self, model):
|
||||||
self.model = model
|
self.model = model
|
||||||
|
|
||||||
def mock_get_statistics(self, resource_id, meter_name, period=3600,
|
def mock_get_statistics(self, resource_id=None, meter_name=None,
|
||||||
aggregate='avg'):
|
period=300, granularity=300, dimensions=None,
|
||||||
|
aggregation='avg', group_by='*'):
|
||||||
if meter_name == "compute.node.cpu.percent":
|
if meter_name == "compute.node.cpu.percent":
|
||||||
return self.get_node_cpu_util(resource_id)
|
return self.get_node_cpu_util(resource_id)
|
||||||
elif meter_name == "cpu_util":
|
elif meter_name == "cpu_util":
|
||||||
@@ -166,15 +167,16 @@ class FakeGnocchiMetrics(object):
|
|||||||
def __init__(self, model):
|
def __init__(self, model):
|
||||||
self.model = model
|
self.model = model
|
||||||
|
|
||||||
def mock_get_statistics(self, resource_id, metric, granularity,
|
def mock_get_statistics(self, resource_id=None, meter_name=None,
|
||||||
start_time, stop_time, aggregation='mean'):
|
period=300, granularity=300, dimensions=None,
|
||||||
if metric == "compute.node.cpu.percent":
|
aggregation='avg', group_by='*'):
|
||||||
|
if meter_name == "compute.node.cpu.percent":
|
||||||
return self.get_node_cpu_util(resource_id)
|
return self.get_node_cpu_util(resource_id)
|
||||||
elif metric == "cpu_util":
|
elif meter_name == "cpu_util":
|
||||||
return self.get_instance_cpu_util(resource_id)
|
return self.get_instance_cpu_util(resource_id)
|
||||||
elif metric == "memory.resident":
|
elif meter_name == "memory.resident":
|
||||||
return self.get_instance_ram_util(resource_id)
|
return self.get_instance_ram_util(resource_id)
|
||||||
elif metric == "disk.root.size":
|
elif meter_name == "disk.root.size":
|
||||||
return self.get_instance_disk_root_size(resource_id)
|
return self.get_instance_disk_root_size(resource_id)
|
||||||
|
|
||||||
def get_node_cpu_util(self, r_id):
|
def get_node_cpu_util(self, r_id):
|
||||||
|
|||||||
@@ -21,17 +21,10 @@ class FakeGnocchiMetrics(object):
|
|||||||
def empty_one_metric(self, emptytype):
|
def empty_one_metric(self, emptytype):
|
||||||
self.emptytype = emptytype
|
self.emptytype = emptytype
|
||||||
|
|
||||||
# TODO(alexchadin): This method is added as temporary solution until
|
def mock_get_statistics(self, resource_id=None, meter_name=None,
|
||||||
# all strategies use datasource_backend property.
|
period=None, granularity=None, dimensions=None,
|
||||||
def temp_mock_get_statistics(self, resource_id, metric, period, aggregate,
|
aggregation='avg', group_by='*'):
|
||||||
granularity=300):
|
|
||||||
return self.mock_get_statistics(resource_id, metric, granularity,
|
|
||||||
0, 0, aggregation='mean')
|
|
||||||
|
|
||||||
def mock_get_statistics(self, resource_id, metric, granularity,
|
|
||||||
start_time, stop_time, aggregation='mean'):
|
|
||||||
result = 0
|
result = 0
|
||||||
meter_name = metric
|
|
||||||
if meter_name == "hardware.cpu.util":
|
if meter_name == "hardware.cpu.util":
|
||||||
result = self.get_usage_node_cpu(resource_id)
|
result = self.get_usage_node_cpu(resource_id)
|
||||||
elif meter_name == "compute.node.cpu.percent":
|
elif meter_name == "compute.node.cpu.percent":
|
||||||
@@ -87,12 +80,13 @@ class FakeGnocchiMetrics(object):
|
|||||||
mock[uuid] = 25 * oslo_utils.units.Ki
|
mock[uuid] = 25 * oslo_utils.units.Ki
|
||||||
return mock[str(uuid)]
|
return mock[str(uuid)]
|
||||||
|
|
||||||
def mock_get_statistics_wb(self, resource_id, metric, period, aggregate,
|
def mock_get_statistics_wb(self, resource_id, meter_name, period,
|
||||||
granularity=300):
|
granularity, dimensions=None,
|
||||||
|
aggregation='avg', group_by='*'):
|
||||||
result = 0.0
|
result = 0.0
|
||||||
if metric == "cpu_util":
|
if meter_name == "cpu_util":
|
||||||
result = self.get_average_usage_instance_cpu_wb(resource_id)
|
result = self.get_average_usage_instance_cpu_wb(resource_id)
|
||||||
elif metric == "memory.resident":
|
elif meter_name == "memory.resident":
|
||||||
result = self.get_average_usage_instance_memory_wb(resource_id)
|
result = self.get_average_usage_instance_memory_wb(resource_id)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
|
|||||||
@@ -26,15 +26,9 @@ class FakeMonascaMetrics(object):
|
|||||||
def empty_one_metric(self, emptytype):
|
def empty_one_metric(self, emptytype):
|
||||||
self.emptytype = emptytype
|
self.emptytype = emptytype
|
||||||
|
|
||||||
# This method is added as temporary solution until all strategies use
|
def mock_get_statistics(self, resource_id=None, meter_name=None,
|
||||||
# datasource_backend property
|
period=None, granularity=None, dimensions=None,
|
||||||
def temp_mock_get_statistics(self, metric, dimensions, period,
|
aggregation='avg', group_by='*'):
|
||||||
aggregate='avg', granularity=300):
|
|
||||||
return self.mock_get_statistics(metric, dimensions,
|
|
||||||
period, aggregate='avg')
|
|
||||||
|
|
||||||
def mock_get_statistics(self, meter_name, dimensions, period,
|
|
||||||
aggregate='avg'):
|
|
||||||
resource_id = dimensions.get(
|
resource_id = dimensions.get(
|
||||||
"resource_id") or dimensions.get("hostname")
|
"resource_id") or dimensions.get("hostname")
|
||||||
result = 0.0
|
result = 0.0
|
||||||
|
|||||||
@@ -17,7 +17,6 @@
|
|||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
#
|
#
|
||||||
import collections
|
import collections
|
||||||
import datetime
|
|
||||||
import mock
|
import mock
|
||||||
|
|
||||||
from watcher.applier.loading import default
|
from watcher.applier.loading import default
|
||||||
@@ -57,7 +56,7 @@ class TestOutletTempControl(base.TestCase):
|
|||||||
self.addCleanup(p_model.stop)
|
self.addCleanup(p_model.stop)
|
||||||
|
|
||||||
p_datasource = mock.patch.object(
|
p_datasource = mock.patch.object(
|
||||||
strategies.OutletTempControl, self.datasource,
|
strategies.OutletTempControl, 'datasource_backend',
|
||||||
new_callable=mock.PropertyMock)
|
new_callable=mock.PropertyMock)
|
||||||
self.m_datasource = p_datasource.start()
|
self.m_datasource = p_datasource.start()
|
||||||
self.addCleanup(p_datasource.stop)
|
self.addCleanup(p_datasource.stop)
|
||||||
@@ -164,44 +163,3 @@ class TestOutletTempControl(base.TestCase):
|
|||||||
loaded_action = loader.load(action['action_type'])
|
loaded_action = loader.load(action['action_type'])
|
||||||
loaded_action.input_parameters = action['input_parameters']
|
loaded_action.input_parameters = action['input_parameters']
|
||||||
loaded_action.validate_parameters()
|
loaded_action.validate_parameters()
|
||||||
|
|
||||||
def test_periods(self):
|
|
||||||
model = self.fake_cluster.generate_scenario_3_with_2_nodes()
|
|
||||||
self.m_model.return_value = model
|
|
||||||
p_ceilometer = mock.patch.object(
|
|
||||||
strategies.OutletTempControl, "ceilometer")
|
|
||||||
m_ceilometer = p_ceilometer.start()
|
|
||||||
self.addCleanup(p_ceilometer.stop)
|
|
||||||
p_gnocchi = mock.patch.object(strategies.OutletTempControl, "gnocchi")
|
|
||||||
m_gnocchi = p_gnocchi.start()
|
|
||||||
self.addCleanup(p_gnocchi.stop)
|
|
||||||
datetime_patcher = mock.patch.object(
|
|
||||||
datetime, 'datetime',
|
|
||||||
mock.Mock(wraps=datetime.datetime)
|
|
||||||
)
|
|
||||||
mocked_datetime = datetime_patcher.start()
|
|
||||||
mocked_datetime.utcnow.return_value = datetime.datetime(
|
|
||||||
2017, 3, 19, 18, 53, 11, 657417)
|
|
||||||
self.addCleanup(datetime_patcher.stop)
|
|
||||||
m_ceilometer.statistic_aggregation = mock.Mock(
|
|
||||||
side_effect=self.fake_metrics.mock_get_statistics)
|
|
||||||
m_gnocchi.statistic_aggregation = mock.Mock(
|
|
||||||
side_effect=self.fake_metrics.mock_get_statistics)
|
|
||||||
node = model.get_node_by_uuid('Node_0')
|
|
||||||
self.strategy.input_parameters.update({'threshold': 35.0})
|
|
||||||
self.strategy.threshold = 35.0
|
|
||||||
self.strategy.group_hosts_by_outlet_temp()
|
|
||||||
if self.strategy.config.datasource == "ceilometer":
|
|
||||||
m_ceilometer.statistic_aggregation.assert_any_call(
|
|
||||||
aggregate='avg',
|
|
||||||
meter_name='hardware.ipmi.node.outlet_temperature',
|
|
||||||
period=30, resource_id=node.uuid)
|
|
||||||
elif self.strategy.config.datasource == "gnocchi":
|
|
||||||
stop_time = datetime.datetime.utcnow()
|
|
||||||
start_time = stop_time - datetime.timedelta(
|
|
||||||
seconds=int('30'))
|
|
||||||
m_gnocchi.statistic_aggregation.assert_called_with(
|
|
||||||
resource_id=mock.ANY,
|
|
||||||
metric='hardware.ipmi.node.outlet_temperature',
|
|
||||||
granularity=300, start_time=start_time, stop_time=stop_time,
|
|
||||||
aggregation='mean')
|
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ class TestStrategyEndpoint(base.BaseTestCase):
|
|||||||
def test_get_datasource_status(self):
|
def test_get_datasource_status(self):
|
||||||
strategy = mock.MagicMock()
|
strategy = mock.MagicMock()
|
||||||
datasource = mock.MagicMock()
|
datasource = mock.MagicMock()
|
||||||
strategy.config.datasource = "gnocchi"
|
datasource.NAME = 'gnocchi'
|
||||||
datasource.check_availability.return_value = "available"
|
datasource.check_availability.return_value = "available"
|
||||||
se = strategy_base.StrategyEndpoint(mock.MagicMock())
|
se = strategy_base.StrategyEndpoint(mock.MagicMock())
|
||||||
result = se._get_datasource_status(strategy, datasource)
|
result = se._get_datasource_status(strategy, datasource)
|
||||||
|
|||||||
@@ -17,7 +17,6 @@
|
|||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
#
|
#
|
||||||
import collections
|
import collections
|
||||||
import datetime
|
|
||||||
import mock
|
import mock
|
||||||
|
|
||||||
from watcher.applier.loading import default
|
from watcher.applier.loading import default
|
||||||
@@ -56,7 +55,7 @@ class TestUniformAirflow(base.TestCase):
|
|||||||
self.addCleanup(p_model.stop)
|
self.addCleanup(p_model.stop)
|
||||||
|
|
||||||
p_datasource = mock.patch.object(
|
p_datasource = mock.patch.object(
|
||||||
strategies.UniformAirflow, self.datasource,
|
strategies.UniformAirflow, 'datasource_backend',
|
||||||
new_callable=mock.PropertyMock)
|
new_callable=mock.PropertyMock)
|
||||||
self.m_datasource = p_datasource.start()
|
self.m_datasource = p_datasource.start()
|
||||||
self.addCleanup(p_datasource.stop)
|
self.addCleanup(p_datasource.stop)
|
||||||
@@ -211,39 +210,3 @@ class TestUniformAirflow(base.TestCase):
|
|||||||
loaded_action = loader.load(action['action_type'])
|
loaded_action = loader.load(action['action_type'])
|
||||||
loaded_action.input_parameters = action['input_parameters']
|
loaded_action.input_parameters = action['input_parameters']
|
||||||
loaded_action.validate_parameters()
|
loaded_action.validate_parameters()
|
||||||
|
|
||||||
def test_periods(self):
|
|
||||||
model = self.fake_cluster.generate_scenario_7_with_2_nodes()
|
|
||||||
self.m_model.return_value = model
|
|
||||||
p_ceilometer = mock.patch.object(
|
|
||||||
strategies.UniformAirflow, "ceilometer")
|
|
||||||
m_ceilometer = p_ceilometer.start()
|
|
||||||
self.addCleanup(p_ceilometer.stop)
|
|
||||||
p_gnocchi = mock.patch.object(strategies.UniformAirflow, "gnocchi")
|
|
||||||
m_gnocchi = p_gnocchi.start()
|
|
||||||
self.addCleanup(p_gnocchi.stop)
|
|
||||||
datetime_patcher = mock.patch.object(
|
|
||||||
datetime, 'datetime',
|
|
||||||
mock.Mock(wraps=datetime.datetime)
|
|
||||||
)
|
|
||||||
mocked_datetime = datetime_patcher.start()
|
|
||||||
mocked_datetime.utcnow.return_value = datetime.datetime(
|
|
||||||
2017, 3, 19, 18, 53, 11, 657417)
|
|
||||||
self.addCleanup(datetime_patcher.stop)
|
|
||||||
m_ceilometer.statistic_aggregation = mock.Mock(
|
|
||||||
side_effect=self.fake_metrics.mock_get_statistics)
|
|
||||||
m_gnocchi.statistic_aggregation = mock.Mock(
|
|
||||||
side_effect=self.fake_metrics.mock_get_statistics)
|
|
||||||
self.strategy.group_hosts_by_airflow()
|
|
||||||
if self.strategy.config.datasource == "ceilometer":
|
|
||||||
m_ceilometer.statistic_aggregation.assert_any_call(
|
|
||||||
aggregate='avg', meter_name='hardware.ipmi.node.airflow',
|
|
||||||
period=300, resource_id=mock.ANY)
|
|
||||||
elif self.strategy.config.datasource == "gnocchi":
|
|
||||||
stop_time = datetime.datetime.utcnow()
|
|
||||||
start_time = stop_time - datetime.timedelta(
|
|
||||||
seconds=int('300'))
|
|
||||||
m_gnocchi.statistic_aggregation.assert_called_with(
|
|
||||||
resource_id=mock.ANY, metric='hardware.ipmi.node.airflow',
|
|
||||||
granularity=300, start_time=start_time, stop_time=stop_time,
|
|
||||||
aggregation='mean')
|
|
||||||
|
|||||||
@@ -18,7 +18,6 @@
|
|||||||
# limitations under the License.
|
# limitations under the License.
|
||||||
#
|
#
|
||||||
|
|
||||||
import datetime
|
|
||||||
import mock
|
import mock
|
||||||
|
|
||||||
from watcher.common import exception
|
from watcher.common import exception
|
||||||
@@ -55,7 +54,7 @@ class TestVMWorkloadConsolidation(base.TestCase):
|
|||||||
self.addCleanup(p_model.stop)
|
self.addCleanup(p_model.stop)
|
||||||
|
|
||||||
p_datasource = mock.patch.object(
|
p_datasource = mock.patch.object(
|
||||||
strategies.VMWorkloadConsolidation, self.datasource,
|
strategies.VMWorkloadConsolidation, 'datasource_backend',
|
||||||
new_callable=mock.PropertyMock)
|
new_callable=mock.PropertyMock)
|
||||||
self.m_datasource = p_datasource.start()
|
self.m_datasource = p_datasource.start()
|
||||||
self.addCleanup(p_datasource.stop)
|
self.addCleanup(p_datasource.stop)
|
||||||
@@ -333,41 +332,3 @@ class TestVMWorkloadConsolidation(base.TestCase):
|
|||||||
del expected[3]
|
del expected[3]
|
||||||
del expected[1]
|
del expected[1]
|
||||||
self.assertEqual(expected, self.strategy.solution.actions)
|
self.assertEqual(expected, self.strategy.solution.actions)
|
||||||
|
|
||||||
def test_periods(self):
|
|
||||||
model = self.fake_cluster.generate_scenario_1()
|
|
||||||
self.m_model.return_value = model
|
|
||||||
p_ceilometer = mock.patch.object(
|
|
||||||
strategies.VMWorkloadConsolidation, "ceilometer")
|
|
||||||
m_ceilometer = p_ceilometer.start()
|
|
||||||
self.addCleanup(p_ceilometer.stop)
|
|
||||||
p_gnocchi = mock.patch.object(
|
|
||||||
strategies.VMWorkloadConsolidation, "gnocchi")
|
|
||||||
m_gnocchi = p_gnocchi.start()
|
|
||||||
self.addCleanup(p_gnocchi.stop)
|
|
||||||
datetime_patcher = mock.patch.object(
|
|
||||||
datetime, 'datetime',
|
|
||||||
mock.Mock(wraps=datetime.datetime)
|
|
||||||
)
|
|
||||||
mocked_datetime = datetime_patcher.start()
|
|
||||||
mocked_datetime.utcnow.return_value = datetime.datetime(
|
|
||||||
2017, 3, 19, 18, 53, 11, 657417)
|
|
||||||
self.addCleanup(datetime_patcher.stop)
|
|
||||||
m_ceilometer.return_value = mock.Mock(
|
|
||||||
statistic_aggregation=self.fake_metrics.mock_get_statistics)
|
|
||||||
m_gnocchi.return_value = mock.Mock(
|
|
||||||
statistic_aggregation=self.fake_metrics.mock_get_statistics)
|
|
||||||
instance0 = model.get_instance_by_uuid("INSTANCE_0")
|
|
||||||
self.strategy.get_instance_utilization(instance0)
|
|
||||||
if self.strategy.config.datasource == "ceilometer":
|
|
||||||
m_ceilometer.statistic_aggregation.assert_any_call(
|
|
||||||
aggregate='avg', meter_name='disk.root.size',
|
|
||||||
period=3600, resource_id=instance0.uuid)
|
|
||||||
elif self.strategy.config.datasource == "gnocchi":
|
|
||||||
stop_time = datetime.datetime.utcnow()
|
|
||||||
start_time = stop_time - datetime.timedelta(
|
|
||||||
seconds=int('3600'))
|
|
||||||
m_gnocchi.statistic_aggregation.assert_called_with(
|
|
||||||
resource_id=instance0.uuid, metric='disk.root.size',
|
|
||||||
granularity=300, start_time=start_time, stop_time=stop_time,
|
|
||||||
aggregation='mean')
|
|
||||||
|
|||||||
@@ -75,10 +75,12 @@ class TestWorkloadBalance(base.TestCase):
|
|||||||
self.strategy.input_parameters = utils.Struct()
|
self.strategy.input_parameters = utils.Struct()
|
||||||
self.strategy.input_parameters.update({'metrics': 'cpu_util',
|
self.strategy.input_parameters.update({'metrics': 'cpu_util',
|
||||||
'threshold': 25.0,
|
'threshold': 25.0,
|
||||||
'period': 300})
|
'period': 300,
|
||||||
|
'granularity': 300})
|
||||||
self.strategy.threshold = 25.0
|
self.strategy.threshold = 25.0
|
||||||
self.strategy._period = 300
|
self.strategy._period = 300
|
||||||
self.strategy._meter = "cpu_util"
|
self.strategy._meter = "cpu_util"
|
||||||
|
self.strategy._granularity = 300
|
||||||
|
|
||||||
def test_calc_used_resource(self):
|
def test_calc_used_resource(self):
|
||||||
model = self.fake_cluster.generate_scenario_6_with_2_nodes()
|
model = self.fake_cluster.generate_scenario_6_with_2_nodes()
|
||||||
|
|||||||
@@ -83,7 +83,7 @@ class TestWorkloadStabilization(base.TestCase):
|
|||||||
self.m_model.return_value = model_root.ModelRoot()
|
self.m_model.return_value = model_root.ModelRoot()
|
||||||
self.m_audit_scope.return_value = mock.Mock()
|
self.m_audit_scope.return_value = mock.Mock()
|
||||||
self.m_datasource.return_value = mock.Mock(
|
self.m_datasource.return_value = mock.Mock(
|
||||||
statistic_aggregation=self.fake_metrics.temp_mock_get_statistics)
|
statistic_aggregation=self.fake_metrics.mock_get_statistics)
|
||||||
|
|
||||||
self.strategy = strategies.WorkloadStabilization(
|
self.strategy = strategies.WorkloadStabilization(
|
||||||
config=mock.Mock(datasource=self.datasource))
|
config=mock.Mock(datasource=self.datasource))
|
||||||
|
|||||||
Reference in New Issue
Block a user