Compare commits
23 Commits
victoria-e
...
rocky-eol
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7c90c9c752 | ||
|
|
4c56eba5be | ||
|
|
a8974556ec | ||
|
|
6a4a9af538 | ||
|
|
214ee82e45 | ||
|
|
5c7fcc22c0 | ||
|
|
4db5a58d0d | ||
|
|
0a20d27860 | ||
|
|
dc9dba2fda | ||
|
|
6203a280ce | ||
|
|
294c3cd760 | ||
|
|
d226c5d0fb | ||
|
|
abbe182cf1 | ||
|
|
c1c0a472dd | ||
|
|
bb0e959bd2 | ||
|
|
41bfba5cac | ||
|
|
ef66e75b77 | ||
|
|
f517cc662a | ||
|
|
d99e8f33da | ||
|
|
ef14aec225 | ||
|
|
546012bed4 | ||
|
|
9be780b2b9 | ||
|
|
f80e7098fd |
@@ -1,4 +1,5 @@
|
||||
[gerrit]
|
||||
host=review.openstack.org
|
||||
host=review.opendev.org
|
||||
port=29418
|
||||
project=openstack/watcher.git
|
||||
defaultbranch=stable/rocky
|
||||
|
||||
49
.zuul.yaml
49
.zuul.yaml
@@ -1,4 +1,10 @@
|
||||
- project:
|
||||
templates:
|
||||
- openstack-python-jobs
|
||||
- openstack-python35-jobs
|
||||
- publish-openstack-sphinx-docs
|
||||
- check-requirements
|
||||
- release-notes-jobs
|
||||
check:
|
||||
jobs:
|
||||
- watcher-tempest-functional
|
||||
@@ -10,6 +16,7 @@
|
||||
- watcher-tempest-zone_migration
|
||||
- openstack-tox-lower-constraints
|
||||
gate:
|
||||
queue: watcher
|
||||
jobs:
|
||||
- watcher-tempest-functional
|
||||
- openstack-tox-lower-constraints
|
||||
@@ -19,35 +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'
|
||||
tempest_test_regex: watcher_tempest_plugin.tests.scenario.test_execute_zone_migration
|
||||
|
||||
- job:
|
||||
name: watcher-tempest-multinode
|
||||
@@ -63,7 +70,7 @@
|
||||
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
|
||||
@@ -91,14 +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
|
||||
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:
|
||||
@@ -107,15 +114,16 @@
|
||||
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
|
||||
parent: devstack-tempest
|
||||
voting: false
|
||||
timeout: 7200
|
||||
required-projects:
|
||||
- openstack/ceilometer
|
||||
- openstack-infra/devstack-gate
|
||||
- openstack/devstack-gate
|
||||
- openstack/python-openstackclient
|
||||
- openstack/python-watcherclient
|
||||
- openstack/watcher
|
||||
@@ -123,7 +131,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
|
||||
@@ -135,8 +143,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
|
||||
@@ -148,9 +156,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.
|
||||
|
||||
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
|
||||
|
||||
@@ -148,18 +148,23 @@ class AuditTemplatePostType(wtypes.Base):
|
||||
"included and excluded together"))
|
||||
|
||||
if audit_template.strategy:
|
||||
available_strategies = objects.Strategy.list(
|
||||
AuditTemplatePostType._ctx)
|
||||
available_strategies_map = {
|
||||
s.uuid: s for s in available_strategies}
|
||||
if audit_template.strategy not in available_strategies_map:
|
||||
try:
|
||||
if (common_utils.is_uuid_like(audit_template.strategy) or
|
||||
common_utils.is_int_like(audit_template.strategy)):
|
||||
strategy = objects.Strategy.get(
|
||||
AuditTemplatePostType._ctx, audit_template.strategy)
|
||||
else:
|
||||
strategy = objects.Strategy.get_by_name(
|
||||
AuditTemplatePostType._ctx, audit_template.strategy)
|
||||
except Exception:
|
||||
raise exception.InvalidStrategy(
|
||||
strategy=audit_template.strategy)
|
||||
|
||||
strategy = available_strategies_map[audit_template.strategy]
|
||||
# Check that the strategy we indicate is actually related to the
|
||||
# specified goal
|
||||
if strategy.goal_id != goal.id:
|
||||
available_strategies = objects.Strategy.list(
|
||||
AuditTemplatePostType._ctx)
|
||||
choices = ["'%s' (%s)" % (s.uuid, s.name)
|
||||
for s in available_strategies]
|
||||
raise exception.InvalidStrategy(
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -74,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})
|
||||
@@ -704,8 +705,9 @@ 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'))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 []
|
||||
|
||||
|
||||
@@ -254,7 +254,7 @@ class WorkloadStabilization(base.WorkloadStabilizationBaseStrategy):
|
||||
:param instance: instance for which statistic is gathered.
|
||||
:return: dict
|
||||
"""
|
||||
LOG.debug('get_instance_load started')
|
||||
LOG.debug('Getting load for %s', instance.uuid)
|
||||
instance_load = {'uuid': instance.uuid, 'vcpus': instance.vcpus}
|
||||
for meter in self.metrics:
|
||||
avg_meter = self.datasource_backend.statistic_aggregation(
|
||||
@@ -269,6 +269,10 @@ class WorkloadStabilization(base.WorkloadStabilizationBaseStrategy):
|
||||
return
|
||||
if meter == 'cpu_util':
|
||||
avg_meter /= float(100)
|
||||
LOG.debug('Load of %(metric)s for %(instance)s is %(value)s',
|
||||
{'metric': meter,
|
||||
'instance': instance.uuid,
|
||||
'value': avg_meter})
|
||||
instance_load[meter] = avg_meter
|
||||
return instance_load
|
||||
|
||||
@@ -293,6 +297,7 @@ class WorkloadStabilization(base.WorkloadStabilizationBaseStrategy):
|
||||
for node_id, node in self.get_available_nodes().items():
|
||||
hosts_load[node_id] = {}
|
||||
hosts_load[node_id]['vcpus'] = node.vcpus
|
||||
LOG.debug('Getting load for %s', node_id)
|
||||
for metric in self.metrics:
|
||||
resource_id = ''
|
||||
avg_meter = None
|
||||
@@ -315,6 +320,10 @@ class WorkloadStabilization(base.WorkloadStabilizationBaseStrategy):
|
||||
avg_meter /= oslo_utils.units.Ki
|
||||
if meter_name == 'compute.node.cpu.percent':
|
||||
avg_meter /= 100
|
||||
LOG.debug('Load of %(metric)s for %(node)s is %(value)s',
|
||||
{'metric': metric,
|
||||
'node': node_id,
|
||||
'value': avg_meter})
|
||||
hosts_load[node_id][metric] = avg_meter
|
||||
return hosts_load
|
||||
|
||||
@@ -442,12 +451,15 @@ class WorkloadStabilization(base.WorkloadStabilizationBaseStrategy):
|
||||
normalized_load = self.normalize_hosts_load(hosts_load)
|
||||
for metric in self.metrics:
|
||||
metric_sd = self.get_sd(normalized_load, metric)
|
||||
LOG.info("Standard deviation for %s is %s.",
|
||||
(metric, metric_sd))
|
||||
LOG.info("Standard deviation for %(metric)s is %(sd)s.",
|
||||
{'metric': metric, 'sd': metric_sd})
|
||||
if metric_sd > float(self.thresholds[metric]):
|
||||
LOG.info("Standard deviation of %s exceeds"
|
||||
" appropriate threshold %s.",
|
||||
(metric, metric_sd))
|
||||
LOG.info("Standard deviation of %(metric)s exceeds"
|
||||
" appropriate threshold %(threshold)s by %(sd)s.",
|
||||
{'metric': metric,
|
||||
'threshold': float(self.thresholds[metric]),
|
||||
'sd': metric_sd})
|
||||
LOG.info("Launching workload optimization...")
|
||||
return self.simulate_migrations(hosts_load)
|
||||
|
||||
def add_migration(self,
|
||||
@@ -523,12 +535,23 @@ class WorkloadStabilization(base.WorkloadStabilizationBaseStrategy):
|
||||
if weighted_sd < min_sd:
|
||||
min_sd = weighted_sd
|
||||
hosts_load = instance_load[-1]
|
||||
LOG.info("Migration of %(instance_uuid)s from %(s_host)s "
|
||||
"to %(host)s reduces standard deviation to "
|
||||
"%(min_sd)s.",
|
||||
{'instance_uuid': instance_host['instance'],
|
||||
's_host': instance_host['s_host'],
|
||||
'host': instance_host['host'],
|
||||
'min_sd': min_sd})
|
||||
self.migrate(instance_host['instance'],
|
||||
instance_host['s_host'],
|
||||
instance_host['host'])
|
||||
|
||||
for metric, value in zip(self.metrics, instance_load[:-1]):
|
||||
if value < float(self.thresholds[metric]):
|
||||
LOG.info("At least one of metrics' values fell "
|
||||
"below the threshold values. "
|
||||
"Workload Stabilization has successfully "
|
||||
"completed optimization process.")
|
||||
balanced = True
|
||||
break
|
||||
if balanced:
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -555,6 +555,35 @@ class TestPost(FunctionalTestWithSetup):
|
||||
response.json['created_at']).replace(tzinfo=None)
|
||||
self.assertEqual(test_time, return_created_at)
|
||||
|
||||
@mock.patch.object(timeutils, 'utcnow')
|
||||
def test_create_audit_template_with_strategy_name(self, mock_utcnow):
|
||||
audit_template_dict = post_get_test_audit_template(
|
||||
goal=self.fake_goal1.uuid,
|
||||
strategy=self.fake_strategy1.name)
|
||||
test_time = datetime.datetime(2000, 1, 1, 0, 0)
|
||||
mock_utcnow.return_value = test_time
|
||||
|
||||
response = self.post_json('/audit_templates', audit_template_dict)
|
||||
self.assertEqual('application/json', response.content_type)
|
||||
self.assertEqual(201, response.status_int)
|
||||
# Check location header
|
||||
self.assertIsNotNone(response.location)
|
||||
expected_location = \
|
||||
'/v1/audit_templates/%s' % response.json['uuid']
|
||||
self.assertEqual(urlparse.urlparse(response.location).path,
|
||||
expected_location)
|
||||
self.assertTrue(utils.is_uuid_like(response.json['uuid']))
|
||||
self.assertNotIn('updated_at', response.json.keys)
|
||||
self.assertNotIn('deleted_at', response.json.keys)
|
||||
self.assertEqual(self.fake_goal1.uuid, response.json['goal_uuid'])
|
||||
self.assertEqual(self.fake_strategy1.uuid,
|
||||
response.json['strategy_uuid'])
|
||||
self.assertEqual(self.fake_strategy1.name,
|
||||
response.json['strategy_name'])
|
||||
return_created_at = timeutils.parse_isotime(
|
||||
response.json['created_at']).replace(tzinfo=None)
|
||||
self.assertEqual(test_time, return_created_at)
|
||||
|
||||
def test_create_audit_template_validation_with_aggregates(self):
|
||||
scope = [{'compute': [{'host_aggregates': [{'id': '*'}]},
|
||||
{'availability_zones': [{'name': 'AZ1'},
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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