Compare commits

...

2 Commits

Author SHA1 Message Date
limin0801
7c90c9c752 Watcher API supports strategy name when creating audit template
when directly using the `curl` command to create audit template,
strategy name can be accepted.

Closes-Bug: #1884174

Change-Id: I7c0ca760a7fa414faca03c5293df34a84aad6fac
(cherry picked from commit 3f7a508a2e)
2020-08-03 09:41:59 +00:00
Alexander Chadin
4c56eba5be Improve logs of Workload Stabilization strategy
This patch set refactors logs of workload stabilization
strategy to make them more readable and sensible.

Related-Bug: #1874416
Change-Id: I408988712bb7560728157f3b4e4f2b37572128c4
2020-05-14 03:31:22 +00:00
4 changed files with 70 additions and 12 deletions

View File

@@ -119,6 +119,7 @@
- job: - job:
name: watcher-tempest-functional name: watcher-tempest-functional
parent: devstack-tempest parent: devstack-tempest
voting: false
timeout: 7200 timeout: 7200
required-projects: required-projects:
- openstack/ceilometer - openstack/ceilometer

View File

@@ -148,18 +148,23 @@ class AuditTemplatePostType(wtypes.Base):
"included and excluded together")) "included and excluded together"))
if audit_template.strategy: if audit_template.strategy:
available_strategies = objects.Strategy.list( try:
AuditTemplatePostType._ctx) if (common_utils.is_uuid_like(audit_template.strategy) or
available_strategies_map = { common_utils.is_int_like(audit_template.strategy)):
s.uuid: s for s in available_strategies} strategy = objects.Strategy.get(
if audit_template.strategy not in available_strategies_map: AuditTemplatePostType._ctx, audit_template.strategy)
else:
strategy = objects.Strategy.get_by_name(
AuditTemplatePostType._ctx, audit_template.strategy)
except Exception:
raise exception.InvalidStrategy( raise exception.InvalidStrategy(
strategy=audit_template.strategy) strategy=audit_template.strategy)
strategy = available_strategies_map[audit_template.strategy]
# Check that the strategy we indicate is actually related to the # Check that the strategy we indicate is actually related to the
# specified goal # specified goal
if strategy.goal_id != goal.id: if strategy.goal_id != goal.id:
available_strategies = objects.Strategy.list(
AuditTemplatePostType._ctx)
choices = ["'%s' (%s)" % (s.uuid, s.name) choices = ["'%s' (%s)" % (s.uuid, s.name)
for s in available_strategies] for s in available_strategies]
raise exception.InvalidStrategy( raise exception.InvalidStrategy(

View File

@@ -254,7 +254,7 @@ class WorkloadStabilization(base.WorkloadStabilizationBaseStrategy):
:param instance: instance for which statistic is gathered. :param instance: instance for which statistic is gathered.
:return: dict :return: dict
""" """
LOG.debug('get_instance_load started') LOG.debug('Getting load for %s', instance.uuid)
instance_load = {'uuid': instance.uuid, 'vcpus': instance.vcpus} instance_load = {'uuid': instance.uuid, 'vcpus': instance.vcpus}
for meter in self.metrics: for meter in self.metrics:
avg_meter = self.datasource_backend.statistic_aggregation( avg_meter = self.datasource_backend.statistic_aggregation(
@@ -269,6 +269,10 @@ class WorkloadStabilization(base.WorkloadStabilizationBaseStrategy):
return return
if meter == 'cpu_util': if meter == 'cpu_util':
avg_meter /= float(100) 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 instance_load[meter] = avg_meter
return instance_load return instance_load
@@ -293,6 +297,7 @@ class WorkloadStabilization(base.WorkloadStabilizationBaseStrategy):
for node_id, node in self.get_available_nodes().items(): for node_id, node in self.get_available_nodes().items():
hosts_load[node_id] = {} hosts_load[node_id] = {}
hosts_load[node_id]['vcpus'] = node.vcpus hosts_load[node_id]['vcpus'] = node.vcpus
LOG.debug('Getting load for %s', node_id)
for metric in self.metrics: for metric in self.metrics:
resource_id = '' resource_id = ''
avg_meter = None avg_meter = None
@@ -315,6 +320,10 @@ class WorkloadStabilization(base.WorkloadStabilizationBaseStrategy):
avg_meter /= oslo_utils.units.Ki avg_meter /= oslo_utils.units.Ki
if meter_name == 'compute.node.cpu.percent': if meter_name == 'compute.node.cpu.percent':
avg_meter /= 100 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 hosts_load[node_id][metric] = avg_meter
return hosts_load return hosts_load
@@ -442,12 +451,15 @@ class WorkloadStabilization(base.WorkloadStabilizationBaseStrategy):
normalized_load = self.normalize_hosts_load(hosts_load) normalized_load = self.normalize_hosts_load(hosts_load)
for metric in self.metrics: for metric in self.metrics:
metric_sd = self.get_sd(normalized_load, metric) metric_sd = self.get_sd(normalized_load, metric)
LOG.info("Standard deviation for %s is %s.", LOG.info("Standard deviation for %(metric)s is %(sd)s.",
(metric, metric_sd)) {'metric': metric, 'sd': metric_sd})
if metric_sd > float(self.thresholds[metric]): if metric_sd > float(self.thresholds[metric]):
LOG.info("Standard deviation of %s exceeds" LOG.info("Standard deviation of %(metric)s exceeds"
" appropriate threshold %s.", " appropriate threshold %(threshold)s by %(sd)s.",
(metric, metric_sd)) {'metric': metric,
'threshold': float(self.thresholds[metric]),
'sd': metric_sd})
LOG.info("Launching workload optimization...")
return self.simulate_migrations(hosts_load) return self.simulate_migrations(hosts_load)
def add_migration(self, def add_migration(self,
@@ -523,12 +535,23 @@ class WorkloadStabilization(base.WorkloadStabilizationBaseStrategy):
if weighted_sd < min_sd: if weighted_sd < min_sd:
min_sd = weighted_sd min_sd = weighted_sd
hosts_load = instance_load[-1] 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'], self.migrate(instance_host['instance'],
instance_host['s_host'], instance_host['s_host'],
instance_host['host']) instance_host['host'])
for metric, value in zip(self.metrics, instance_load[:-1]): for metric, value in zip(self.metrics, instance_load[:-1]):
if value < float(self.thresholds[metric]): 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 balanced = True
break break
if balanced: if balanced:

View File

@@ -555,6 +555,35 @@ class TestPost(FunctionalTestWithSetup):
response.json['created_at']).replace(tzinfo=None) response.json['created_at']).replace(tzinfo=None)
self.assertEqual(test_time, return_created_at) 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): def test_create_audit_template_validation_with_aggregates(self):
scope = [{'compute': [{'host_aggregates': [{'id': '*'}]}, scope = [{'compute': [{'host_aggregates': [{'id': '*'}]},
{'availability_zones': [{'name': 'AZ1'}, {'availability_zones': [{'name': 'AZ1'},