Compare commits
45 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a8974556ec | ||
|
|
6a4a9af538 | ||
|
|
214ee82e45 | ||
|
|
5c7fcc22c0 | ||
|
|
4db5a58d0d | ||
|
|
0a20d27860 | ||
|
|
dc9dba2fda | ||
|
|
6203a280ce | ||
|
|
294c3cd760 | ||
|
|
d226c5d0fb | ||
|
|
abbe182cf1 | ||
|
|
c1c0a472dd | ||
|
|
bb0e959bd2 | ||
|
|
41bfba5cac | ||
|
|
ef66e75b77 | ||
|
|
f517cc662a | ||
|
|
d99e8f33da | ||
|
|
ef14aec225 | ||
|
|
546012bed4 | ||
|
|
9be780b2b9 | ||
|
|
f80e7098fd | ||
|
|
b471b4ca36 | ||
|
|
2be5bd1c3f | ||
|
|
d79edb93d6 | ||
|
|
0c41f20df2 | ||
|
|
249e3c9515 | ||
|
|
a229fec4a6 | ||
|
|
5c2b3f0025 | ||
|
|
cf9b158713 | ||
|
|
2cb7871df0 | ||
|
|
7c83042aa1 | ||
|
|
7103e60786 | ||
|
|
343128fcb9 | ||
|
|
a739f81bfb | ||
|
|
d690b2b598 | ||
|
|
4d1b9c1f04 | ||
|
|
927d094907 | ||
|
|
57a4aae92b | ||
|
|
abd129002c | ||
|
|
b92a26345f | ||
|
|
843cd493c2 | ||
|
|
bad257f402 | ||
|
|
c4821ceedf | ||
|
|
abbb1317d3 | ||
|
|
4a5175cbad |
@@ -1,4 +1,5 @@
|
||||
[gerrit]
|
||||
host=review.openstack.org
|
||||
host=review.opendev.org
|
||||
port=29418
|
||||
project=openstack/watcher.git
|
||||
defaultbranch=stable/rocky
|
||||
|
||||
64
.zuul.yaml
64
.zuul.yaml
@@ -1,18 +1,24 @@
|
||||
- project:
|
||||
templates:
|
||||
- openstack-python-jobs
|
||||
- openstack-python35-jobs
|
||||
- publish-openstack-sphinx-docs
|
||||
- check-requirements
|
||||
- release-notes-jobs
|
||||
check:
|
||||
jobs:
|
||||
- watcher-tempest-functional:
|
||||
voting: false
|
||||
- watcher-tempest-functional
|
||||
- watcher-tempest-dummy_optim
|
||||
- watcher-tempest-actuator
|
||||
- watcher-tempest-basic_optim
|
||||
- watcher-tempest-workload_balancing
|
||||
- watcherclient-tempest-functional:
|
||||
voting: false
|
||||
- watcherclient-tempest-functional
|
||||
- watcher-tempest-zone_migration
|
||||
- openstack-tox-lower-constraints
|
||||
gate:
|
||||
queue: watcher
|
||||
jobs:
|
||||
# - watcher-tempest-functional
|
||||
- watcher-tempest-functional
|
||||
- openstack-tox-lower-constraints
|
||||
|
||||
- job:
|
||||
@@ -20,28 +26,35 @@
|
||||
parent: watcher-tempest-multinode
|
||||
voting: false
|
||||
vars:
|
||||
tempest_test_regex: 'watcher_tempest_plugin.tests.scenario.test_execute_dummy_optim'
|
||||
tempest_test_regex: watcher_tempest_plugin.tests.scenario.test_execute_dummy_optim
|
||||
|
||||
- job:
|
||||
name: watcher-tempest-actuator
|
||||
parent: watcher-tempest-multinode
|
||||
voting: false
|
||||
vars:
|
||||
tempest_test_regex: 'watcher_tempest_plugin.tests.scenario.test_execute_actuator'
|
||||
tempest_test_regex: watcher_tempest_plugin.tests.scenario.test_execute_actuator
|
||||
|
||||
- job:
|
||||
name: watcher-tempest-basic_optim
|
||||
parent: watcher-tempest-multinode
|
||||
voting: false
|
||||
vars:
|
||||
tempest_test_regex: 'watcher_tempest_plugin.tests.scenario.test_execute_basic_optim'
|
||||
tempest_test_regex: watcher_tempest_plugin.tests.scenario.test_execute_basic_optim
|
||||
|
||||
- job:
|
||||
name: watcher-tempest-workload_balancing
|
||||
parent: watcher-tempest-multinode
|
||||
voting: false
|
||||
vars:
|
||||
tempest_test_regex: 'watcher_tempest_plugin.tests.scenario.test_execute_workload_balancing'
|
||||
tempest_test_regex: watcher_tempest_plugin.tests.scenario.test_execute_workload_balancing
|
||||
|
||||
- job:
|
||||
name: watcher-tempest-zone_migration
|
||||
parent: watcher-tempest-multinode
|
||||
voting: false
|
||||
vars:
|
||||
tempest_test_regex: watcher_tempest_plugin.tests.scenario.test_execute_zone_migration
|
||||
|
||||
- job:
|
||||
name: watcher-tempest-multinode
|
||||
@@ -57,7 +70,14 @@
|
||||
post-config:
|
||||
$NOVA_CONF:
|
||||
libvirt:
|
||||
live_migration_uri: 'qemu+ssh://root@%s/system'
|
||||
live_migration_uri: qemu+ssh://root@%s/system
|
||||
$WATCHER_CONF:
|
||||
watcher_cluster_data_model_collectors.compute:
|
||||
period: 120
|
||||
watcher_cluster_data_model_collectors.baremetal:
|
||||
period: 120
|
||||
watcher_cluster_data_model_collectors.storage:
|
||||
period: 120
|
||||
devstack_services:
|
||||
watcher-api: false
|
||||
watcher-decision-engine: true
|
||||
@@ -78,7 +98,14 @@
|
||||
post-config:
|
||||
$NOVA_CONF:
|
||||
libvirt:
|
||||
live_migration_uri: 'qemu+ssh://root@%s/system'
|
||||
live_migration_uri: qemu+ssh://root@%s/system
|
||||
$WATCHER_CONF:
|
||||
watcher_cluster_data_model_collectors.compute:
|
||||
period: 120
|
||||
watcher_cluster_data_model_collectors.baremetal:
|
||||
period: 120
|
||||
watcher_cluster_data_model_collectors.storage:
|
||||
period: 120
|
||||
test-config:
|
||||
$TEMPEST_CONFIG:
|
||||
compute:
|
||||
@@ -87,7 +114,7 @@
|
||||
live_migration: true
|
||||
block_migration_for_live_migration: true
|
||||
devstack_plugins:
|
||||
ceilometer: https://git.openstack.org/openstack/ceilometer
|
||||
ceilometer: https://opendev.org/openstack/ceilometer
|
||||
|
||||
- job:
|
||||
name: watcher-tempest-functional
|
||||
@@ -95,7 +122,7 @@
|
||||
timeout: 7200
|
||||
required-projects:
|
||||
- openstack/ceilometer
|
||||
- openstack-infra/devstack-gate
|
||||
- openstack/devstack-gate
|
||||
- openstack/python-openstackclient
|
||||
- openstack/python-watcherclient
|
||||
- openstack/watcher
|
||||
@@ -103,7 +130,7 @@
|
||||
- openstack/tempest
|
||||
vars:
|
||||
devstack_plugins:
|
||||
watcher: https://git.openstack.org/openstack/watcher
|
||||
watcher: https://opendev.org/openstack/watcher
|
||||
devstack_services:
|
||||
tls-proxy: false
|
||||
watcher-api: true
|
||||
@@ -115,8 +142,8 @@
|
||||
s-object: false
|
||||
s-proxy: false
|
||||
devstack_localrc:
|
||||
TEMPEST_PLUGINS: '/opt/stack/watcher-tempest-plugin'
|
||||
tempest_test_regex: 'watcher_tempest_plugin.tests.api'
|
||||
TEMPEST_PLUGINS: /opt/stack/watcher-tempest-plugin
|
||||
tempest_test_regex: watcher_tempest_plugin.tests.api
|
||||
tox_envlist: all
|
||||
tox_environment:
|
||||
# Do we really need to set this? It's cargo culted
|
||||
@@ -128,9 +155,10 @@
|
||||
# This job is used in python-watcherclient repo
|
||||
name: watcherclient-tempest-functional
|
||||
parent: watcher-tempest-functional
|
||||
voting: false
|
||||
timeout: 4200
|
||||
vars:
|
||||
tempest_concurrency: 1
|
||||
devstack_localrc:
|
||||
TEMPEST_PLUGINS: '/opt/stack/python-watcherclient'
|
||||
tempest_test_regex: 'watcherclient.tests.functional'
|
||||
TEMPEST_PLUGINS: /opt/stack/python-watcherclient
|
||||
tempest_test_regex: watcherclient.tests.functional
|
||||
|
||||
@@ -317,6 +317,7 @@ function start_watcher {
|
||||
function stop_watcher {
|
||||
if [[ "$WATCHER_USE_MOD_WSGI" == "True" ]]; then
|
||||
disable_apache_site watcher-api
|
||||
restart_apache_server
|
||||
else
|
||||
stop_process watcher-api
|
||||
fi
|
||||
|
||||
@@ -35,7 +35,7 @@ VNCSERVER_PROXYCLIENT_ADDRESS=$HOST_IP
|
||||
NOVA_INSTANCES_PATH=/opt/stack/data/instances
|
||||
|
||||
# Enable the Ceilometer plugin for the compute agent
|
||||
enable_plugin ceilometer git://git.openstack.org/openstack/ceilometer
|
||||
enable_plugin ceilometer https://git.openstack.org/openstack/ceilometer
|
||||
disable_service ceilometer-acentral,ceilometer-collector,ceilometer-api
|
||||
|
||||
LOGFILE=$DEST/logs/stack.sh.log
|
||||
|
||||
@@ -25,13 +25,13 @@ MULTI_HOST=1
|
||||
disable_service n-cpu
|
||||
|
||||
# Enable the Watcher Dashboard plugin
|
||||
enable_plugin watcher-dashboard git://git.openstack.org/openstack/watcher-dashboard
|
||||
enable_plugin watcher-dashboard https://git.openstack.org/openstack/watcher-dashboard
|
||||
|
||||
# Enable the Watcher plugin
|
||||
enable_plugin watcher git://git.openstack.org/openstack/watcher
|
||||
enable_plugin watcher https://git.openstack.org/openstack/watcher
|
||||
|
||||
# Enable the Ceilometer plugin
|
||||
enable_plugin ceilometer git://git.openstack.org/openstack/ceilometer
|
||||
enable_plugin ceilometer https://git.openstack.org/openstack/ceilometer
|
||||
|
||||
# This is the controller node, so disable the ceilometer compute agent
|
||||
disable_service ceilometer-acompute
|
||||
|
||||
@@ -178,7 +178,7 @@ You can easily generate and update a sample configuration file
|
||||
named :ref:`watcher.conf.sample <watcher_sample_configuration_files>` by using
|
||||
these following commands::
|
||||
|
||||
$ git clone git://git.openstack.org/openstack/watcher
|
||||
$ git clone https://git.openstack.org/openstack/watcher
|
||||
$ cd watcher/
|
||||
$ tox -e genconfig
|
||||
$ vi etc/watcher/watcher.conf.sample
|
||||
@@ -239,10 +239,6 @@ so that the watcher service is configured for your needs.
|
||||
|
||||
[DEFAULT]
|
||||
|
||||
# The messaging driver to use, defaults to rabbit. Other drivers
|
||||
# include qpid and zmq. (string value)
|
||||
#rpc_backend = rabbit
|
||||
|
||||
# The default exchange under which topics are scoped. May be
|
||||
# overridden by an exchange name specified in the transport_url
|
||||
# option. (string value)
|
||||
|
||||
@@ -19,7 +19,7 @@ model. To enable the Watcher plugin with DevStack, add the following to the
|
||||
`[[local|localrc]]` section of your controller's `local.conf` to enable the
|
||||
Watcher plugin::
|
||||
|
||||
enable_plugin watcher git://git.openstack.org/openstack/watcher
|
||||
enable_plugin watcher https://git.openstack.org/openstack/watcher
|
||||
|
||||
For more detailed instructions, see `Detailed DevStack Instructions`_. Check
|
||||
out the `DevStack documentation`_ for more information regarding DevStack.
|
||||
|
||||
@@ -241,10 +241,9 @@ purge
|
||||
The maximum number of database objects we expect to be deleted. If exceeded,
|
||||
this will prevent any deletion.
|
||||
|
||||
.. option:: -t, --audit-template
|
||||
.. option:: -t, --goal
|
||||
|
||||
Either the UUID or name of the soft deleted audit template to purge. This
|
||||
will also include any related objects with it.
|
||||
Either the UUID or name of the goal to purge.
|
||||
|
||||
.. option:: -e, --exclude-orphans
|
||||
|
||||
|
||||
97
doc/source/strategies/noisy_neighbor.rst
Normal file
97
doc/source/strategies/noisy_neighbor.rst
Normal file
@@ -0,0 +1,97 @@
|
||||
==============
|
||||
Noisy neighbor
|
||||
==============
|
||||
|
||||
Synopsis
|
||||
--------
|
||||
|
||||
**display name**: ``Noisy Neighbor``
|
||||
|
||||
**goal**: ``noisy_neighbor``
|
||||
|
||||
.. watcher-term:: watcher.decision_engine.strategy.strategies.noisy_neighbor.NoisyNeighbor
|
||||
|
||||
Requirements
|
||||
------------
|
||||
|
||||
Metrics
|
||||
*******
|
||||
|
||||
The *noisy_neighbor* strategy requires the following metrics:
|
||||
|
||||
============================ ============ ======= =======================
|
||||
metric service name plugins comment
|
||||
============================ ============ ======= =======================
|
||||
``cpu_l3_cache`` ceilometer_ none Intel CMT_ is required
|
||||
============================ ============ ======= =======================
|
||||
|
||||
.. _CMT: http://www.intel.com/content/www/us/en/architecture-and-technology/resource-director-technology.html
|
||||
.. _ceilometer: https://docs.openstack.org/ceilometer/latest/admin/telemetry-measurements.html#openstack-compute
|
||||
|
||||
Cluster data model
|
||||
******************
|
||||
|
||||
Default Watcher's Compute cluster data model:
|
||||
|
||||
.. watcher-term:: watcher.decision_engine.model.collector.nova.NovaClusterDataModelCollector
|
||||
|
||||
Actions
|
||||
*******
|
||||
|
||||
Default Watcher's actions:
|
||||
|
||||
.. list-table::
|
||||
:widths: 30 30
|
||||
:header-rows: 1
|
||||
|
||||
* - action
|
||||
- description
|
||||
* - ``migration``
|
||||
- .. watcher-term:: watcher.applier.actions.migration.Migrate
|
||||
|
||||
Planner
|
||||
*******
|
||||
|
||||
Default Watcher's planner:
|
||||
|
||||
.. watcher-term:: watcher.decision_engine.planner.weight.WeightPlanner
|
||||
|
||||
Configuration
|
||||
-------------
|
||||
|
||||
Strategy parameter is:
|
||||
|
||||
==================== ====== ============= ============================
|
||||
parameter type default Value description
|
||||
==================== ====== ============= ============================
|
||||
``cache_threshold`` Number 35.0 Performance drop in L3_cache
|
||||
threshold for migration
|
||||
==================== ====== ============= ============================
|
||||
|
||||
|
||||
Efficacy Indicator
|
||||
------------------
|
||||
|
||||
None
|
||||
|
||||
Algorithm
|
||||
---------
|
||||
|
||||
For more information on the noisy neighbor strategy please refer to:
|
||||
http://specs.openstack.org/openstack/watcher-specs/specs/pike/implemented/noisy_neighbor_strategy.html
|
||||
|
||||
How to use it ?
|
||||
---------------
|
||||
|
||||
.. code-block:: shell
|
||||
|
||||
$ openstack optimize audittemplate create \
|
||||
at1 noisy_neighbor --strategy noisy_neighbor
|
||||
|
||||
$ openstack optimize audit create -a at1 \
|
||||
-p cache_threshold=45.0
|
||||
|
||||
External Links
|
||||
--------------
|
||||
|
||||
None
|
||||
@@ -155,7 +155,6 @@ ujson==1.35
|
||||
unittest2==1.1.0
|
||||
urllib3==1.22
|
||||
vine==1.1.4
|
||||
voluptuous==0.11.1
|
||||
waitress==1.1.0
|
||||
warlock==1.3.0
|
||||
WebOb==1.7.4
|
||||
|
||||
@@ -28,7 +28,6 @@ PasteDeploy>=1.5.2 # MIT
|
||||
pbr>=3.1.1 # Apache-2.0
|
||||
pecan>=1.2.1 # BSD
|
||||
PrettyTable<0.8,>=0.7.2 # BSD
|
||||
voluptuous>=0.11.1 # BSD License
|
||||
gnocchiclient>=7.0.1 # Apache-2.0
|
||||
python-ceilometerclient>=2.9.0 # Apache-2.0
|
||||
python-cinderclient>=3.5.0 # Apache-2.0
|
||||
|
||||
2
tox.ini
2
tox.ini
@@ -7,7 +7,7 @@ skipsdist = True
|
||||
usedevelop = True
|
||||
whitelist_externals = find
|
||||
rm
|
||||
install_command = pip install -c{env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt} {opts} {packages}
|
||||
install_command = pip install -c{env:UPPER_CONSTRAINTS_FILE:https://git.openstack.org/cgit/openstack/requirements/plain/upper-constraints.txt?h=stable/rocky} {opts} {packages}
|
||||
setenv =
|
||||
VIRTUAL_ENV={envdir}
|
||||
deps = -r{toxinidir}/test-requirements.txt
|
||||
|
||||
@@ -581,7 +581,7 @@ class ActionPlansController(rest.RestController):
|
||||
|
||||
if action_plan_to_start['state'] != \
|
||||
objects.action_plan.State.RECOMMENDED:
|
||||
raise Exception.StartError(
|
||||
raise exception.StartError(
|
||||
state=action_plan_to_start.state)
|
||||
|
||||
action_plan_to_start['state'] = objects.action_plan.State.PENDING
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
|
||||
|
||||
from oslo_config import cfg
|
||||
from oslo_utils import importutils
|
||||
from pecan import hooks
|
||||
from six.moves import http_client
|
||||
|
||||
@@ -60,14 +59,8 @@ class ContextHook(hooks.PecanHook):
|
||||
roles = (headers.get('X-Roles', None) and
|
||||
headers.get('X-Roles').split(','))
|
||||
|
||||
auth_url = headers.get('X-Auth-Url')
|
||||
if auth_url is None:
|
||||
importutils.import_module('keystonemiddleware.auth_token')
|
||||
auth_url = cfg.CONF.keystone_authtoken.www_authenticate_uri
|
||||
|
||||
state.request.context = context.make_context(
|
||||
auth_token=auth_token,
|
||||
auth_url=auth_url,
|
||||
auth_token_info=auth_token_info,
|
||||
user=user,
|
||||
user_id=user_id,
|
||||
|
||||
@@ -52,7 +52,8 @@ class APISchedulingService(scheduling.BackgroundSchedulerService):
|
||||
self.services_status[service.id] = result
|
||||
notifications.service.send_service_update(context, service,
|
||||
state=result)
|
||||
if result == failed_s:
|
||||
if (result == failed_s) and (
|
||||
service.name == 'watcher-decision-engine'):
|
||||
audit_filters = {
|
||||
'audit_type': objects.audit.AuditType.CONTINUOUS.value,
|
||||
'state': objects.audit.State.ONGOING,
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
from ceilometerclient import client as ceclient
|
||||
|
||||
from cinderclient import client as ciclient
|
||||
from glanceclient import client as glclient
|
||||
from gnocchiclient import client as gnclient
|
||||
@@ -25,6 +25,12 @@ from watcher.common import exception
|
||||
|
||||
from watcher import conf
|
||||
|
||||
try:
|
||||
from ceilometerclient import client as ceclient
|
||||
HAS_CEILCLIENT = True
|
||||
except ImportError:
|
||||
HAS_CEILCLIENT = False
|
||||
|
||||
CONF = conf.CONF
|
||||
|
||||
_CLIENTS_AUTH_GROUP = 'watcher_clients_auth'
|
||||
@@ -83,8 +89,10 @@ class OpenStackClients(object):
|
||||
|
||||
novaclient_version = self._get_client_option('nova', 'api_version')
|
||||
nova_endpoint_type = self._get_client_option('nova', 'endpoint_type')
|
||||
nova_region_name = self._get_client_option('nova', 'region_name')
|
||||
self._nova = nvclient.Client(novaclient_version,
|
||||
endpoint_type=nova_endpoint_type,
|
||||
region_name=nova_region_name,
|
||||
session=self.session)
|
||||
return self._nova
|
||||
|
||||
@@ -96,8 +104,10 @@ class OpenStackClients(object):
|
||||
glanceclient_version = self._get_client_option('glance', 'api_version')
|
||||
glance_endpoint_type = self._get_client_option('glance',
|
||||
'endpoint_type')
|
||||
glance_region_name = self._get_client_option('glance', 'region_name')
|
||||
self._glance = glclient.Client(glanceclient_version,
|
||||
interface=glance_endpoint_type,
|
||||
region_name=glance_region_name,
|
||||
session=self.session)
|
||||
return self._glance
|
||||
|
||||
@@ -110,8 +120,11 @@ class OpenStackClients(object):
|
||||
'api_version')
|
||||
gnocchiclient_interface = self._get_client_option('gnocchi',
|
||||
'endpoint_type')
|
||||
gnocchiclient_region_name = self._get_client_option('gnocchi',
|
||||
'region_name')
|
||||
adapter_options = {
|
||||
"interface": gnocchiclient_interface
|
||||
"interface": gnocchiclient_interface,
|
||||
"region_name": gnocchiclient_region_name
|
||||
}
|
||||
|
||||
self._gnocchi = gnclient.Client(gnocchiclient_version,
|
||||
@@ -127,8 +140,10 @@ class OpenStackClients(object):
|
||||
cinderclient_version = self._get_client_option('cinder', 'api_version')
|
||||
cinder_endpoint_type = self._get_client_option('cinder',
|
||||
'endpoint_type')
|
||||
cinder_region_name = self._get_client_option('cinder', 'region_name')
|
||||
self._cinder = ciclient.Client(cinderclient_version,
|
||||
endpoint_type=cinder_endpoint_type,
|
||||
region_name=cinder_region_name,
|
||||
session=self.session)
|
||||
return self._cinder
|
||||
|
||||
@@ -141,9 +156,12 @@ class OpenStackClients(object):
|
||||
'api_version')
|
||||
ceilometer_endpoint_type = self._get_client_option('ceilometer',
|
||||
'endpoint_type')
|
||||
ceilometer_region_name = self._get_client_option('ceilometer',
|
||||
'region_name')
|
||||
self._ceilometer = ceclient.get_client(
|
||||
ceilometerclient_version,
|
||||
endpoint_type=ceilometer_endpoint_type,
|
||||
region_name=ceilometer_region_name,
|
||||
session=self.session)
|
||||
return self._ceilometer
|
||||
|
||||
@@ -156,6 +174,8 @@ class OpenStackClients(object):
|
||||
'monasca', 'api_version')
|
||||
monascaclient_interface = self._get_client_option(
|
||||
'monasca', 'interface')
|
||||
monascaclient_region = self._get_client_option(
|
||||
'monasca', 'region_name')
|
||||
token = self.session.get_token()
|
||||
watcher_clients_auth_config = CONF.get(_CLIENTS_AUTH_GROUP)
|
||||
service_type = 'monitoring'
|
||||
@@ -172,7 +192,8 @@ class OpenStackClients(object):
|
||||
'password': watcher_clients_auth_config.password,
|
||||
}
|
||||
endpoint = self.session.get_endpoint(service_type=service_type,
|
||||
interface=monascaclient_interface)
|
||||
interface=monascaclient_interface,
|
||||
region_name=monascaclient_region)
|
||||
|
||||
self._monasca = monclient.Client(
|
||||
monascaclient_version, endpoint, **monasca_kwargs)
|
||||
@@ -188,9 +209,11 @@ class OpenStackClients(object):
|
||||
'api_version')
|
||||
neutron_endpoint_type = self._get_client_option('neutron',
|
||||
'endpoint_type')
|
||||
neutron_region_name = self._get_client_option('neutron', 'region_name')
|
||||
|
||||
self._neutron = netclient.Client(neutronclient_version,
|
||||
endpoint_type=neutron_endpoint_type,
|
||||
region_name=neutron_region_name,
|
||||
session=self.session)
|
||||
self._neutron.format = 'json'
|
||||
return self._neutron
|
||||
@@ -202,7 +225,9 @@ class OpenStackClients(object):
|
||||
|
||||
ironicclient_version = self._get_client_option('ironic', 'api_version')
|
||||
endpoint_type = self._get_client_option('ironic', 'endpoint_type')
|
||||
ironic_region_name = self._get_client_option('ironic', 'region_name')
|
||||
self._ironic = irclient.get_client(ironicclient_version,
|
||||
os_endpoint_type=endpoint_type,
|
||||
region_name=ironic_region_name,
|
||||
session=self.session)
|
||||
return self._ironic
|
||||
|
||||
@@ -21,12 +21,15 @@ from watcher.common import rpc
|
||||
from watcher import version
|
||||
|
||||
|
||||
def parse_args(argv, default_config_files=None):
|
||||
def parse_args(argv, default_config_files=None, default_config_dirs=None):
|
||||
default_config_files = (default_config_files or
|
||||
cfg.find_config_files(project='watcher'))
|
||||
default_config_dirs = (default_config_dirs or
|
||||
cfg.find_config_dirs(project='watcher'))
|
||||
rpc.set_defaults(control_exchange='watcher')
|
||||
cfg.CONF(argv[1:],
|
||||
project='python-watcher',
|
||||
version=version.version_info.release_string(),
|
||||
default_config_dirs=default_config_dirs,
|
||||
default_config_files=default_config_files)
|
||||
rpc.init(cfg.CONF)
|
||||
|
||||
@@ -23,9 +23,9 @@ class RequestContext(context.RequestContext):
|
||||
|
||||
def __init__(self, user_id=None, project_id=None, is_admin=None,
|
||||
roles=None, timestamp=None, request_id=None, auth_token=None,
|
||||
auth_url=None, overwrite=True, user_name=None,
|
||||
project_name=None, domain_name=None, domain_id=None,
|
||||
auth_token_info=None, **kwargs):
|
||||
overwrite=True, user_name=None, project_name=None,
|
||||
domain_name=None, domain_id=None, auth_token_info=None,
|
||||
**kwargs):
|
||||
"""Stores several additional request parameters:
|
||||
|
||||
:param domain_id: The ID of the domain.
|
||||
@@ -70,7 +70,6 @@ class RequestContext(context.RequestContext):
|
||||
# FIXME(dims): user_id and project_id duplicate information that is
|
||||
# already present in the oslo_context's RequestContext. We need to
|
||||
# get rid of them.
|
||||
self.auth_url = auth_url
|
||||
self.domain_name = domain_name
|
||||
self.domain_id = domain_id
|
||||
self.auth_token_info = auth_token_info
|
||||
|
||||
@@ -150,7 +150,7 @@ class ResourceNotFound(ObjectNotFound):
|
||||
|
||||
|
||||
class InvalidParameter(Invalid):
|
||||
msg_fmt = _("%(parameter)s has to be of type %(parameter_type)s")
|
||||
msg_fmt = _("%(parameter)s has to be of type %(parameter_type)s")
|
||||
|
||||
|
||||
class InvalidIdentity(Invalid):
|
||||
@@ -514,9 +514,9 @@ class NegativeLimitError(WatcherException):
|
||||
|
||||
|
||||
class NotificationPayloadError(WatcherException):
|
||||
_msg_fmt = _("Payload not populated when trying to send notification "
|
||||
"\"%(class_name)s\"")
|
||||
msg_fmt = _("Payload not populated when trying to send notification "
|
||||
"\"%(class_name)s\"")
|
||||
|
||||
|
||||
class InvalidPoolAttributeValue(Invalid):
|
||||
msg_fmt = _("The %(name)s pool %(attribute)s is not integer")
|
||||
msg_fmt = _("The %(name)s pool %(attribute)s is not integer")
|
||||
|
||||
@@ -22,7 +22,6 @@ import time
|
||||
from novaclient import api_versions
|
||||
from oslo_log import log
|
||||
|
||||
import cinderclient.exceptions as ciexceptions
|
||||
import glanceclient.exc as glexceptions
|
||||
import novaclient.exceptions as nvexceptions
|
||||
|
||||
@@ -75,7 +74,8 @@ class NovaHelper(object):
|
||||
raise exception.ComputeNodeNotFound(name=node_hostname)
|
||||
|
||||
def get_instance_list(self):
|
||||
return self.nova.servers.list(search_opts={'all_tenants': True})
|
||||
return self.nova.servers.list(search_opts={'all_tenants': True},
|
||||
limit=-1)
|
||||
|
||||
def get_flavor_list(self):
|
||||
return self.nova.flavors.list(**{'is_public': None})
|
||||
@@ -705,31 +705,13 @@ class NovaHelper(object):
|
||||
|
||||
def get_instances_by_node(self, host):
|
||||
return [instance for instance in
|
||||
self.nova.servers.list(search_opts={"all_tenants": True})
|
||||
if self.get_hostname(instance) == host]
|
||||
self.nova.servers.list(search_opts={"all_tenants": True,
|
||||
"host": host},
|
||||
limit=-1)]
|
||||
|
||||
def get_hostname(self, instance):
|
||||
return str(getattr(instance, 'OS-EXT-SRV-ATTR:host'))
|
||||
|
||||
def get_flavor_instance(self, instance, cache):
|
||||
fid = instance.flavor['id']
|
||||
if fid in cache:
|
||||
flavor = cache.get(fid)
|
||||
else:
|
||||
try:
|
||||
flavor = self.nova.flavors.get(fid)
|
||||
except ciexceptions.NotFound:
|
||||
flavor = None
|
||||
cache[fid] = flavor
|
||||
attr_defaults = [('name', 'unknown-id-%s' % fid),
|
||||
('vcpus', 0), ('ram', 0), ('disk', 0),
|
||||
('ephemeral', 0), ('extra_specs', {})]
|
||||
for attr, default in attr_defaults:
|
||||
if not flavor:
|
||||
instance.flavor[attr] = default
|
||||
continue
|
||||
instance.flavor[attr] = getattr(flavor, attr, default)
|
||||
|
||||
def get_running_migration(self, instance_id):
|
||||
return self.nova.server_migrations.list(server=instance_id)
|
||||
|
||||
|
||||
@@ -265,8 +265,7 @@ class Service(service.ServiceBase):
|
||||
allow_requeue=False, pool=CONF.host)
|
||||
|
||||
def start(self):
|
||||
LOG.debug("Connecting to '%s' (%s)",
|
||||
CONF.transport_url, CONF.rpc_backend)
|
||||
LOG.debug("Connecting to '%s'", CONF.transport_url)
|
||||
if self.conductor_topic_handler:
|
||||
self.conductor_topic_handler.start()
|
||||
if self.notification_handler:
|
||||
@@ -275,8 +274,7 @@ class Service(service.ServiceBase):
|
||||
self.heartbeat.start()
|
||||
|
||||
def stop(self):
|
||||
LOG.debug("Disconnecting from '%s' (%s)",
|
||||
CONF.transport_url, CONF.rpc_backend)
|
||||
LOG.debug("Disconnecting from '%s' (%s)'", CONF.transport_url)
|
||||
if self.conductor_topic_handler:
|
||||
self.conductor_topic_handler.stop()
|
||||
if self.notification_handler:
|
||||
|
||||
@@ -30,7 +30,10 @@ CEILOMETER_CLIENT_OPTS = [
|
||||
default='internalURL',
|
||||
help='Type of endpoint to use in ceilometerclient.'
|
||||
'Supported values: internalURL, publicURL, adminURL'
|
||||
'The default is internalURL.')]
|
||||
'The default is internalURL.'),
|
||||
cfg.StrOpt('region_name',
|
||||
help='Region in Identity service catalog to use for '
|
||||
'communication with the OpenStack service.')]
|
||||
|
||||
|
||||
def register_opts(conf):
|
||||
|
||||
@@ -29,7 +29,10 @@ CINDER_CLIENT_OPTS = [
|
||||
default='publicURL',
|
||||
help='Type of endpoint to use in cinderclient.'
|
||||
'Supported values: internalURL, publicURL, adminURL'
|
||||
'The default is publicURL.')]
|
||||
'The default is publicURL.'),
|
||||
cfg.StrOpt('region_name',
|
||||
help='Region in Identity service catalog to use for '
|
||||
'communication with the OpenStack service.')]
|
||||
|
||||
|
||||
def register_opts(conf):
|
||||
|
||||
@@ -29,7 +29,10 @@ GLANCE_CLIENT_OPTS = [
|
||||
default='publicURL',
|
||||
help='Type of endpoint to use in glanceclient.'
|
||||
'Supported values: internalURL, publicURL, adminURL'
|
||||
'The default is publicURL.')]
|
||||
'The default is publicURL.'),
|
||||
cfg.StrOpt('region_name',
|
||||
help='Region in Identity service catalog to use for '
|
||||
'communication with the OpenStack service.')]
|
||||
|
||||
|
||||
def register_opts(conf):
|
||||
|
||||
@@ -30,6 +30,9 @@ GNOCCHI_CLIENT_OPTS = [
|
||||
help='Type of endpoint to use in gnocchi client.'
|
||||
'Supported values: internal, public, admin'
|
||||
'The default is public.'),
|
||||
cfg.StrOpt('region_name',
|
||||
help='Region in Identity service catalog to use for '
|
||||
'communication with the OpenStack service.'),
|
||||
cfg.IntOpt('query_max_retries',
|
||||
default=10,
|
||||
mutable=True,
|
||||
|
||||
@@ -29,7 +29,10 @@ IRONIC_CLIENT_OPTS = [
|
||||
default='publicURL',
|
||||
help='Type of endpoint to use in ironicclient.'
|
||||
'Supported values: internalURL, publicURL, adminURL'
|
||||
'The default is publicURL.')]
|
||||
'The default is publicURL.'),
|
||||
cfg.StrOpt('region_name',
|
||||
help='Region in Identity service catalog to use for '
|
||||
'communication with the OpenStack service.')]
|
||||
|
||||
|
||||
def register_opts(conf):
|
||||
|
||||
@@ -29,7 +29,10 @@ MONASCA_CLIENT_OPTS = [
|
||||
default='internal',
|
||||
help='Type of interface used for monasca endpoint.'
|
||||
'Supported values: internal, public, admin'
|
||||
'The default is internal.')]
|
||||
'The default is internal.'),
|
||||
cfg.StrOpt('region_name',
|
||||
help='Region in Identity service catalog to use for '
|
||||
'communication with the OpenStack service.')]
|
||||
|
||||
|
||||
def register_opts(conf):
|
||||
|
||||
@@ -29,7 +29,10 @@ NEUTRON_CLIENT_OPTS = [
|
||||
default='publicURL',
|
||||
help='Type of endpoint to use in neutronclient.'
|
||||
'Supported values: internalURL, publicURL, adminURL'
|
||||
'The default is publicURL.')]
|
||||
'The default is publicURL.'),
|
||||
cfg.StrOpt('region_name',
|
||||
help='Region in Identity service catalog to use for '
|
||||
'communication with the OpenStack service.')]
|
||||
|
||||
|
||||
def register_opts(conf):
|
||||
|
||||
@@ -29,7 +29,10 @@ NOVA_CLIENT_OPTS = [
|
||||
default='publicURL',
|
||||
help='Type of endpoint to use in novaclient.'
|
||||
'Supported values: internalURL, publicURL, adminURL'
|
||||
'The default is publicURL.')]
|
||||
'The default is publicURL.'),
|
||||
cfg.StrOpt('region_name',
|
||||
help='Region in Identity service catalog to use for '
|
||||
'communication with the OpenStack service.')]
|
||||
|
||||
|
||||
def register_opts(conf):
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
import datetime
|
||||
|
||||
from ceilometerclient import exc
|
||||
from oslo_log import log
|
||||
from oslo_utils import timeutils
|
||||
|
||||
from watcher._i18n import _
|
||||
@@ -26,6 +27,8 @@ from watcher.common import clients
|
||||
from watcher.common import exception
|
||||
from watcher.datasource import base
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
|
||||
class CeilometerHelper(base.DataSourceBase):
|
||||
|
||||
@@ -112,15 +115,15 @@ class CeilometerHelper(base.DataSourceBase):
|
||||
self.osc.reset_clients()
|
||||
self.ceilometer = self.osc.ceilometer()
|
||||
return f(*args, **kargs)
|
||||
except Exception:
|
||||
raise
|
||||
except Exception as e:
|
||||
LOG.exception(e)
|
||||
|
||||
def check_availability(self):
|
||||
try:
|
||||
self.query_retry(self.ceilometer.resources.list)
|
||||
except Exception:
|
||||
status = self.query_retry(self.ceilometer.resources.list)
|
||||
if status:
|
||||
return 'available'
|
||||
else:
|
||||
return 'not available'
|
||||
return 'available'
|
||||
|
||||
def query_sample(self, meter_name, query, limit=1):
|
||||
return self.query_retry(f=self.ceilometer.samples.list,
|
||||
@@ -138,9 +141,8 @@ class CeilometerHelper(base.DataSourceBase):
|
||||
|
||||
def list_metrics(self):
|
||||
"""List the user's meters."""
|
||||
try:
|
||||
meters = self.query_retry(f=self.ceilometer.meters.list)
|
||||
except Exception:
|
||||
meters = self.query_retry(f=self.ceilometer.meters.list)
|
||||
if not meters:
|
||||
return set()
|
||||
else:
|
||||
return meters
|
||||
|
||||
@@ -24,7 +24,6 @@ from oslo_config import cfg
|
||||
from oslo_log import log
|
||||
|
||||
from watcher.common import clients
|
||||
from watcher.common import exception
|
||||
from watcher.common import utils as common_utils
|
||||
from watcher.datasource import base
|
||||
|
||||
@@ -49,27 +48,25 @@ class GnocchiHelper(base.DataSourceBase):
|
||||
except Exception as e:
|
||||
LOG.exception(e)
|
||||
time.sleep(CONF.gnocchi_client.query_timeout)
|
||||
raise exception.DataSourceNotAvailable(datasource='gnocchi')
|
||||
|
||||
def check_availability(self):
|
||||
try:
|
||||
self.query_retry(self.gnocchi.status.get)
|
||||
except Exception:
|
||||
status = self.query_retry(self.gnocchi.status.get)
|
||||
if status:
|
||||
return 'available'
|
||||
else:
|
||||
return 'not available'
|
||||
return 'available'
|
||||
|
||||
def list_metrics(self):
|
||||
"""List the user's meters."""
|
||||
try:
|
||||
response = self.query_retry(f=self.gnocchi.metric.list)
|
||||
except Exception:
|
||||
response = self.query_retry(f=self.gnocchi.metric.list)
|
||||
if not response:
|
||||
return set()
|
||||
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='*'):
|
||||
aggregation='mean', group_by='*'):
|
||||
"""Representing a statistic aggregate by operators
|
||||
|
||||
:param resource_id: id of resource to list statistics for.
|
||||
@@ -95,7 +92,9 @@ class GnocchiHelper(base.DataSourceBase):
|
||||
f=self.gnocchi.resource.search, **kwargs)
|
||||
|
||||
if not resources:
|
||||
raise exception.ResourceNotFound(name=resource_id)
|
||||
LOG.warning("The {0} resource {1} could not be "
|
||||
"found".format(self.NAME, resource_id))
|
||||
return
|
||||
|
||||
resource_id = resources[0]['id']
|
||||
|
||||
|
||||
@@ -29,7 +29,12 @@ class DataSourceManager(object):
|
||||
self._monasca = None
|
||||
self._gnocchi = None
|
||||
self.metric_map = base.DataSourceBase.METRIC_MAP
|
||||
self.datasources = self.config.datasources
|
||||
if hasattr(self.config, 'datasources'):
|
||||
self.datasources = self.config.datasources
|
||||
elif hasattr(self.config, 'datasource'):
|
||||
self.datasources = [self.config.datasource]
|
||||
else:
|
||||
self.datasources = []
|
||||
|
||||
@property
|
||||
def ceilometer(self):
|
||||
|
||||
@@ -19,11 +19,14 @@
|
||||
import datetime
|
||||
|
||||
from monascaclient import exc
|
||||
from oslo_log import log
|
||||
|
||||
from watcher.common import clients
|
||||
from watcher.common import exception
|
||||
from watcher.datasource import base
|
||||
|
||||
LOG = log.getLogger(__name__)
|
||||
|
||||
|
||||
class MonascaHelper(base.DataSourceBase):
|
||||
|
||||
@@ -42,8 +45,8 @@ class MonascaHelper(base.DataSourceBase):
|
||||
self.osc.reset_clients()
|
||||
self.monasca = self.osc.monasca()
|
||||
return f(*args, **kwargs)
|
||||
except Exception:
|
||||
raise
|
||||
except Exception as e:
|
||||
LOG.exception(e)
|
||||
|
||||
def _format_time_params(self, start_time, end_time, period):
|
||||
"""Format time-related params to the correct Monasca format
|
||||
@@ -67,11 +70,11 @@ class MonascaHelper(base.DataSourceBase):
|
||||
return start_timestamp, end_timestamp, period
|
||||
|
||||
def check_availability(self):
|
||||
try:
|
||||
self.query_retry(self.monasca.metrics.list)
|
||||
except Exception:
|
||||
status = self.query_retry(self.monasca.metrics.list)
|
||||
if status:
|
||||
return 'available'
|
||||
else:
|
||||
return 'not available'
|
||||
return 'available'
|
||||
|
||||
def list_metrics(self):
|
||||
# TODO(alexchadin): this method should be implemented in accordance to
|
||||
|
||||
@@ -23,8 +23,10 @@ from sqlalchemy import Boolean
|
||||
from sqlalchemy import Column
|
||||
from sqlalchemy import DateTime
|
||||
from sqlalchemy.ext.declarative import declarative_base
|
||||
from sqlalchemy import Float
|
||||
from sqlalchemy import ForeignKey
|
||||
from sqlalchemy import Integer
|
||||
from sqlalchemy import LargeBinary
|
||||
from sqlalchemy import Numeric
|
||||
from sqlalchemy import orm
|
||||
from sqlalchemy import String
|
||||
@@ -296,3 +298,23 @@ class ActionDescription(Base):
|
||||
id = Column(Integer, primary_key=True)
|
||||
action_type = Column(String(255), nullable=False)
|
||||
description = Column(String(255), nullable=False)
|
||||
|
||||
|
||||
class APScheulerJob(Base):
|
||||
"""Represents apscheduler jobs"""
|
||||
|
||||
__tablename__ = 'apscheduler_jobs'
|
||||
__table_args__ = (
|
||||
UniqueConstraint('id',
|
||||
name="uniq_apscheduler_jobs0id"),
|
||||
table_args()
|
||||
)
|
||||
id = Column(String(191), nullable=False, primary_key=True)
|
||||
next_run_time = Column(Float(25), index=True)
|
||||
job_state = Column(LargeBinary, nullable=False)
|
||||
tag = Column(JSONEncodedDict(), nullable=True)
|
||||
service_id = Column(Integer, ForeignKey('services.id'),
|
||||
nullable=False)
|
||||
|
||||
service = orm.relationship(
|
||||
Service, foreign_keys=service_id, lazy=None)
|
||||
|
||||
@@ -230,21 +230,17 @@ class ModelBuilder(object):
|
||||
"free_capacity_gb", "provisioned_capacity_gb",
|
||||
"allocated_capacity_gb"]
|
||||
|
||||
node_attributes = {"name": pool.name}
|
||||
for attr in attrs:
|
||||
try:
|
||||
int(getattr(pool, attr))
|
||||
node_attributes[attr] = int(getattr(pool, attr))
|
||||
except AttributeError:
|
||||
LOG.debug("Attribute %s for pool %s is not provided",
|
||||
attr, pool.name)
|
||||
except ValueError:
|
||||
raise exception.InvalidPoolAttributeValue(
|
||||
name=pool.name, attribute=attr)
|
||||
|
||||
node_attributes = {
|
||||
"name": pool.name,
|
||||
"total_volumes": pool.total_volumes,
|
||||
"total_capacity_gb": pool.total_capacity_gb,
|
||||
"free_capacity_gb": pool.free_capacity_gb,
|
||||
"provisioned_capacity_gb": pool.provisioned_capacity_gb,
|
||||
"allocated_capacity_gb": pool.allocated_capacity_gb}
|
||||
|
||||
storage_pool = element.Pool(**node_attributes)
|
||||
return storage_pool
|
||||
|
||||
|
||||
@@ -279,7 +279,7 @@ class ChangeNovaServiceStateActionValidator(BaseActionValidator):
|
||||
|
||||
def validate_parents(self, resource_action_map, action):
|
||||
host_name = action['input_parameters']['resource_id']
|
||||
self._mapping(resource_action_map, host_name, action.uuid,
|
||||
self._mapping(resource_action_map, host_name, action['uuid'],
|
||||
'change_nova_service_state')
|
||||
return []
|
||||
|
||||
|
||||
@@ -31,6 +31,8 @@ LOG = log.getLogger(__name__)
|
||||
class SavingEnergy(base.SavingEnergyBaseStrategy):
|
||||
"""Saving Energy Strategy
|
||||
|
||||
*Description*
|
||||
|
||||
Saving Energy Strategy together with VM Workload Consolidation Strategy
|
||||
can perform the Dynamic Power Management (DPM) functionality, which tries
|
||||
to save power by dynamically consolidating workloads even further during
|
||||
@@ -51,19 +53,29 @@ class SavingEnergy(base.SavingEnergyBaseStrategy):
|
||||
the given number and there are spare unused nodes(in poweroff state),
|
||||
randomly select some nodes(unused,poweroff) and power on them.
|
||||
|
||||
*Requirements*
|
||||
|
||||
In this policy, in order to calculate the min_free_hosts_num,
|
||||
users must provide two parameters:
|
||||
|
||||
* One parameter("min_free_hosts_num") is a constant int number.
|
||||
This number should be int type and larger than zero.
|
||||
* One parameter("min_free_hosts_num") is a constant int number.
|
||||
This number should be int type and larger than zero.
|
||||
|
||||
* The other parameter("free_used_percent") is a percentage number, which
|
||||
describes the quotient of min_free_hosts_num/nodes_with_VMs_num,
|
||||
where nodes_with_VMs_num is the number of nodes with VMs running on it.
|
||||
This parameter is used to calculate a dynamic min_free_hosts_num.
|
||||
The nodes with VMs refer to those nodes with VMs running on it.
|
||||
* The other parameter("free_used_percent") is a percentage number, which
|
||||
describes the quotient of min_free_hosts_num/nodes_with_VMs_num,
|
||||
where nodes_with_VMs_num is the number of nodes with VMs running on it.
|
||||
This parameter is used to calculate a dynamic min_free_hosts_num.
|
||||
The nodes with VMs refer to those nodes with VMs running on it.
|
||||
|
||||
Then choose the larger one as the final min_free_hosts_num.
|
||||
|
||||
*Limitations*
|
||||
|
||||
* at least 2 physical compute hosts
|
||||
|
||||
*Spec URL*
|
||||
|
||||
http://specs.openstack.org/openstack/watcher-specs/specs/pike/implemented/energy-saving-strategy.html
|
||||
"""
|
||||
|
||||
def __init__(self, config, osc=None):
|
||||
@@ -113,16 +125,16 @@ class SavingEnergy(base.SavingEnergyBaseStrategy):
|
||||
"properties": {
|
||||
"free_used_percent": {
|
||||
"description": ("a rational number, which describes the"
|
||||
"quotient of"
|
||||
" quotient of"
|
||||
" min_free_hosts_num/nodes_with_VMs_num"
|
||||
"where nodes_with_VMs_num is the number"
|
||||
"of nodes with VMs"),
|
||||
" where nodes_with_VMs_num is the number"
|
||||
" of nodes with VMs"),
|
||||
"type": "number",
|
||||
"default": 10.0
|
||||
},
|
||||
"min_free_hosts_num": {
|
||||
"description": ("minimum number of hosts without VMs"
|
||||
"but still powered on"),
|
||||
" but still powered on"),
|
||||
"type": "number",
|
||||
"default": 1
|
||||
},
|
||||
|
||||
@@ -41,6 +41,15 @@ class StorageCapacityBalance(base.WorkloadStabilizationBaseStrategy):
|
||||
|
||||
* You must have at least 2 cinder volume pools to run
|
||||
this strategy.
|
||||
|
||||
*Limitations*
|
||||
|
||||
* Volume migration depends on the storage device.
|
||||
It may take a long time.
|
||||
|
||||
*Spec URL*
|
||||
|
||||
http://specs.openstack.org/openstack/watcher-specs/specs/queens/implemented/storage-capacity-balance.html
|
||||
"""
|
||||
|
||||
def __init__(self, config, osc=None):
|
||||
|
||||
@@ -309,10 +309,10 @@ class ZoneMigration(base.ZoneMigrationBaseStrategy):
|
||||
else:
|
||||
self.instances_migration(targets, action_counter)
|
||||
|
||||
LOG.debug("action total: %s, pools: %s, nodes %s ", (
|
||||
LOG.debug("action total: %s, pools: %s, nodes %s ",
|
||||
action_counter.total_count,
|
||||
action_counter.per_pool_count,
|
||||
action_counter.per_node_count))
|
||||
action_counter.per_node_count)
|
||||
|
||||
def post_execute(self):
|
||||
"""Post-execution phase
|
||||
@@ -416,7 +416,7 @@ class ZoneMigration(base.ZoneMigrationBaseStrategy):
|
||||
src_type = volume.volume_type
|
||||
dst_pool, dst_type = self.get_dst_pool_and_type(pool, src_type)
|
||||
LOG.debug(src_type)
|
||||
LOG.debug("%s %s", (dst_pool, dst_type))
|
||||
LOG.debug("%s %s", dst_pool, dst_type)
|
||||
|
||||
if self.is_available(volume):
|
||||
if src_type == dst_type:
|
||||
@@ -640,8 +640,8 @@ class ActionCounter(object):
|
||||
if not self.is_total_max() and not self.is_pool_max(pool):
|
||||
self.per_pool_count[pool] += 1
|
||||
self.total_count += 1
|
||||
LOG.debug("total: %s, per_pool: %s", (
|
||||
self.total_count, self.per_pool_count))
|
||||
LOG.debug("total: %s, per_pool: %s",
|
||||
self.total_count, self.per_pool_count)
|
||||
return True
|
||||
return False
|
||||
|
||||
@@ -657,8 +657,8 @@ class ActionCounter(object):
|
||||
if not self.is_total_max() and not self.is_node_max(node):
|
||||
self.per_node_count[node] += 1
|
||||
self.total_count += 1
|
||||
LOG.debug("total: %s, per_node: %s", (
|
||||
self.total_count, self.per_node_count))
|
||||
LOG.debug("total: %s, per_node: %s",
|
||||
self.total_count, self.per_node_count)
|
||||
return True
|
||||
return False
|
||||
|
||||
@@ -677,7 +677,7 @@ class ActionCounter(object):
|
||||
if pool not in self.per_pool_count:
|
||||
self.per_pool_count[pool] = 0
|
||||
LOG.debug("the number of parallel per pool %s is %s ",
|
||||
(pool, self.per_pool_count[pool]))
|
||||
pool, self.per_pool_count[pool])
|
||||
LOG.debug("per pool limit is %s", self.per_pool_limit)
|
||||
return self.per_pool_count[pool] >= self.per_pool_limit
|
||||
|
||||
@@ -721,7 +721,7 @@ class BaseFilter(object):
|
||||
for k, v in six.iteritems(targets):
|
||||
if not self.is_allowed(k):
|
||||
continue
|
||||
LOG.debug("filter:%s with the key: %s", (cond, k))
|
||||
LOG.debug("filter:%s with the key: %s", cond, k)
|
||||
targets[k] = self.exec_filter(v, cond)
|
||||
|
||||
LOG.debug(targets)
|
||||
@@ -775,7 +775,7 @@ class ProjectSortFilter(SortMovingToFrontFilter):
|
||||
"""
|
||||
|
||||
project_id = self.get_project_id(item)
|
||||
LOG.debug("project_id: %s, sort_key: %s", (project_id, sort_key))
|
||||
LOG.debug("project_id: %s, sort_key: %s", project_id, sort_key)
|
||||
return project_id == sort_key
|
||||
|
||||
def get_project_id(self, item):
|
||||
@@ -809,7 +809,7 @@ class ComputeHostSortFilter(SortMovingToFrontFilter):
|
||||
"""
|
||||
|
||||
host = self.get_host(item)
|
||||
LOG.debug("host: %s, sort_key: %s", (host, sort_key))
|
||||
LOG.debug("host: %s, sort_key: %s", host, sort_key)
|
||||
return host == sort_key
|
||||
|
||||
def get_host(self, item):
|
||||
@@ -837,7 +837,7 @@ class StorageHostSortFilter(SortMovingToFrontFilter):
|
||||
"""
|
||||
|
||||
host = self.get_host(item)
|
||||
LOG.debug("host: %s, sort_key: %s", (host, sort_key))
|
||||
LOG.debug("host: %s, sort_key: %s", host, sort_key)
|
||||
return host == sort_key
|
||||
|
||||
def get_host(self, item):
|
||||
@@ -909,9 +909,9 @@ class ComputeSpecSortFilter(BaseFilter):
|
||||
:returns: memory size of item
|
||||
"""
|
||||
|
||||
LOG.debug("item: %s, flavors: %s", (item, flavors))
|
||||
LOG.debug("item: %s, flavors: %s", item, flavors)
|
||||
for flavor in flavors:
|
||||
LOG.debug("item.flavor: %s, flavor: %s", (item.flavor, flavor))
|
||||
LOG.debug("item.flavor: %s, flavor: %s", item.flavor, flavor)
|
||||
if item.flavor.get('id') == flavor.id:
|
||||
LOG.debug("flavor.ram: %s", flavor.ram)
|
||||
return flavor.ram
|
||||
@@ -924,9 +924,9 @@ class ComputeSpecSortFilter(BaseFilter):
|
||||
:returns: vcpu number of item
|
||||
"""
|
||||
|
||||
LOG.debug("item: %s, flavors: %s", (item, flavors))
|
||||
LOG.debug("item: %s, flavors: %s", item, flavors)
|
||||
for flavor in flavors:
|
||||
LOG.debug("item.flavor: %s, flavor: %s", (item.flavor, flavor))
|
||||
LOG.debug("item.flavor: %s, flavor: %s", item.flavor, flavor)
|
||||
if item.flavor.get('id') == flavor.id:
|
||||
LOG.debug("flavor.vcpus: %s", flavor.vcpus)
|
||||
return flavor.vcpus
|
||||
@@ -939,9 +939,9 @@ class ComputeSpecSortFilter(BaseFilter):
|
||||
:returns: disk size of item
|
||||
"""
|
||||
|
||||
LOG.debug("item: %s, flavors: %s", (item, flavors))
|
||||
LOG.debug("item: %s, flavors: %s", item, flavors)
|
||||
for flavor in flavors:
|
||||
LOG.debug("item.flavor: %s, flavor: %s", (item.flavor, flavor))
|
||||
LOG.debug("item.flavor: %s, flavor: %s", item.flavor, flavor)
|
||||
if item.flavor.get('id') == flavor.id:
|
||||
LOG.debug("flavor.disk: %s", flavor.disk)
|
||||
return flavor.disk
|
||||
|
||||
@@ -222,7 +222,6 @@ class TestContextHook(base.FunctionalTest):
|
||||
user_id=headers['X-User-Id'],
|
||||
domain_id=headers['X-User-Domain-Id'],
|
||||
domain_name=headers['X-User-Domain-Name'],
|
||||
auth_url=cfg.CONF.keystone_authtoken.www_authenticate_uri,
|
||||
project=headers['X-Project-Name'],
|
||||
project_id=headers['X-Project-Id'],
|
||||
show_deleted=None,
|
||||
@@ -243,7 +242,6 @@ class TestContextHook(base.FunctionalTest):
|
||||
user_id=headers['X-User-Id'],
|
||||
domain_id=headers['X-User-Domain-Id'],
|
||||
domain_name=headers['X-User-Domain-Name'],
|
||||
auth_url=cfg.CONF.keystone_authtoken.www_authenticate_uri,
|
||||
project=headers['X-Project-Name'],
|
||||
project_id=headers['X-Project-Id'],
|
||||
show_deleted=None,
|
||||
@@ -265,7 +263,6 @@ class TestContextHook(base.FunctionalTest):
|
||||
user_id=headers['X-User-Id'],
|
||||
domain_id=headers['X-User-Domain-Id'],
|
||||
domain_name=headers['X-User-Domain-Name'],
|
||||
auth_url=cfg.CONF.keystone_authtoken.www_authenticate_uri,
|
||||
project=headers['X-Project-Name'],
|
||||
project_id=headers['X-Project-Id'],
|
||||
show_deleted=None,
|
||||
|
||||
@@ -60,9 +60,6 @@ class TestCase(BaseTestCase):
|
||||
|
||||
cfg.CONF.set_override("auth_type", "admin_token",
|
||||
group='keystone_authtoken')
|
||||
cfg.CONF.set_override("www_authenticate_uri",
|
||||
"http://127.0.0.1/identity",
|
||||
group='keystone_authtoken')
|
||||
|
||||
app_config_path = os.path.join(os.path.dirname(__file__), 'config.py')
|
||||
self.app = testing.load_test_app(app_config_path)
|
||||
|
||||
@@ -120,6 +120,7 @@ class TestClients(base.TestCase):
|
||||
mock_call.assert_called_once_with(
|
||||
CONF.nova_client.api_version,
|
||||
endpoint_type=CONF.nova_client.endpoint_type,
|
||||
region_name=CONF.nova_client.region_name,
|
||||
session=mock_session)
|
||||
|
||||
@mock.patch.object(clients.OpenStackClients, 'session')
|
||||
@@ -155,6 +156,7 @@ class TestClients(base.TestCase):
|
||||
mock_call.assert_called_once_with(
|
||||
CONF.glance_client.api_version,
|
||||
interface=CONF.glance_client.endpoint_type,
|
||||
region_name=CONF.glance_client.region_name,
|
||||
session=mock_session)
|
||||
|
||||
@mock.patch.object(clients.OpenStackClients, 'session')
|
||||
@@ -191,7 +193,8 @@ class TestClients(base.TestCase):
|
||||
mock_call.assert_called_once_with(
|
||||
CONF.gnocchi_client.api_version,
|
||||
adapter_options={
|
||||
"interface": CONF.gnocchi_client.endpoint_type},
|
||||
"interface": CONF.gnocchi_client.endpoint_type,
|
||||
"region_name": CONF.gnocchi_client.region_name},
|
||||
session=mock_session)
|
||||
|
||||
@mock.patch.object(clients.OpenStackClients, 'session')
|
||||
@@ -229,6 +232,7 @@ class TestClients(base.TestCase):
|
||||
mock_call.assert_called_once_with(
|
||||
CONF.cinder_client.api_version,
|
||||
endpoint_type=CONF.cinder_client.endpoint_type,
|
||||
region_name=CONF.cinder_client.region_name,
|
||||
session=mock_session)
|
||||
|
||||
@mock.patch.object(clients.OpenStackClients, 'session')
|
||||
@@ -266,6 +270,7 @@ class TestClients(base.TestCase):
|
||||
CONF.ceilometer_client.api_version,
|
||||
None,
|
||||
endpoint_type=CONF.ceilometer_client.endpoint_type,
|
||||
region_name=CONF.ceilometer_client.region_name,
|
||||
session=mock_session)
|
||||
|
||||
@mock.patch.object(clients.OpenStackClients, 'session')
|
||||
@@ -314,6 +319,7 @@ class TestClients(base.TestCase):
|
||||
mock_call.assert_called_once_with(
|
||||
CONF.neutron_client.api_version,
|
||||
endpoint_type=CONF.neutron_client.endpoint_type,
|
||||
region_name=CONF.neutron_client.region_name,
|
||||
session=mock_session)
|
||||
|
||||
@mock.patch.object(clients.OpenStackClients, 'session')
|
||||
@@ -404,6 +410,7 @@ class TestClients(base.TestCase):
|
||||
mock_call.assert_called_once_with(
|
||||
CONF.ironic_client.api_version,
|
||||
endpoint_override=ironic_url,
|
||||
interface='publicURL',
|
||||
max_retries=None,
|
||||
os_ironic_api_version=None,
|
||||
retry_interval=None,
|
||||
|
||||
@@ -321,19 +321,6 @@ class TestNovaHelper(base.TestCase):
|
||||
instance = nova_util.create_instance(self.source_node)
|
||||
self.assertIsNotNone(instance)
|
||||
|
||||
def test_get_flavor_instance(self, mock_glance, mock_cinder,
|
||||
mock_neutron, mock_nova):
|
||||
nova_util = nova_helper.NovaHelper()
|
||||
instance = self.fake_server(self.instance_uuid)
|
||||
flavor = {'id': 1, 'name': 'm1.tiny', 'ram': 512, 'vcpus': 1,
|
||||
'disk': 0, 'ephemeral': 0}
|
||||
instance.flavor = flavor
|
||||
nova_util.nova.flavors.get.return_value = flavor
|
||||
cache = flavor
|
||||
|
||||
nova_util.get_flavor_instance(instance, cache)
|
||||
self.assertEqual(instance.flavor['name'], cache['name'])
|
||||
|
||||
@staticmethod
|
||||
def fake_volume(**kwargs):
|
||||
volume = mock.MagicMock()
|
||||
|
||||
@@ -385,11 +385,10 @@ class TestContinuousAuditHandler(base.DbTestCase):
|
||||
audit_handler = continuous.ContinuousAuditHandler()
|
||||
self.audits[0].next_run_time = (datetime.datetime.now() -
|
||||
datetime.timedelta(seconds=1800))
|
||||
m_is_inactive.return_value = False
|
||||
m_get_jobs.return_value = None
|
||||
m_is_inactive.return_value = True
|
||||
m_get_jobs.return_value = []
|
||||
|
||||
audit_handler.execute_audit(self.audits[0], self.context)
|
||||
m_execute.assert_called_once_with(self.audits[0], self.context)
|
||||
self.assertIsNotNone(self.audits[0].next_run_time)
|
||||
|
||||
@mock.patch.object(objects.service.Service, 'list')
|
||||
|
||||
@@ -451,11 +451,10 @@ class TestSyncer(base.DbTestCase):
|
||||
self._find_created_modified_unmodified_ids(
|
||||
before_action_plans, after_action_plans))
|
||||
|
||||
dummy_1_spec = [
|
||||
{'description': 'Dummy indicator', 'name': 'dummy',
|
||||
'schema': jsonutils.dumps({'minimum': 0, 'type': 'integer'}),
|
||||
'unit': '%'}]
|
||||
dummy_2_spec = []
|
||||
dummy_1_spec = jsonutils.loads(
|
||||
self.goal1_spec.serialize_indicators_specs())
|
||||
dummy_2_spec = jsonutils.loads(
|
||||
self.goal2_spec.serialize_indicators_specs())
|
||||
self.assertEqual(
|
||||
[dummy_1_spec, dummy_2_spec],
|
||||
[g.efficacy_specification for g in after_goals])
|
||||
|
||||
@@ -20,7 +20,6 @@ fakeAuthTokenHeaders = {'X-User-Id': u'773a902f022949619b5c2f32cd89d419',
|
||||
'X-Auth-Token': u'5588aebbcdc24e17a061595f80574376',
|
||||
'X-Forwarded-For': u'10.10.10.10, 11.11.11.11',
|
||||
'X-Service-Catalog': u'{test: 12345}',
|
||||
'X-Auth-Url': 'fake_auth_url',
|
||||
'X-Identity-Status': 'Confirmed',
|
||||
'X-User-Domain-Name': 'domain',
|
||||
'X-Project-Domain-Id': 'project_domain_id',
|
||||
|
||||
Reference in New Issue
Block a user