Add watcher audit template context and 2 scenarios

This patch set adds audit template context with two scenarios:
list_audit_templates
create_audit_and_delete

Change-Id: I2d3adef7893fbef1b90e69f56818fbe4d3ce4366
This commit is contained in:
Alexander Chadin 2016-07-13 17:48:23 +03:00
parent 7d640d2312
commit 27604462c4
18 changed files with 621 additions and 11 deletions

View File

@ -509,6 +509,11 @@
# Time to wait for a VM to become pingable (floating point value)
#vm_ping_timeout = 120.0
# Watcher audit launch interval (floating point value)
#watcher_audit_launch_poll_interval = 2.0
# Watcher audit launch timeout (integer value)
#watcher_audit_launch_timeout = 300
[cleanup]
@ -712,4 +717,4 @@
#project_domain = default
# ID of domain in which users will be created. (string value)
#user_domain = default
#user_domain = default

View File

@ -1,4 +1,27 @@
---
Watcher.create_audit_and_delete:
-
runner:
type: "constant"
times: 10
concurrency: 2
context:
users:
tenants: 2
users_per_tenant: 2
audit_templates:
audit_templates_per_admin: 5
fill_strategy: "round_robin"
params:
- goal:
name: "dummy"
strategy:
name: "dummy"
extra: {}
sla:
failure_rate:
max: 0
Watcher.create_audit_template_and_delete:
-
args:
@ -7,14 +30,38 @@
strategy:
name: "dummy"
extra: {}
runner:
type: "constant"
times: 10
concurrency: 2
sla:
failure_rate:
max: 0
Watcher.list_audit_templates:
-
runner:
type: "constant"
times: 10
concurrency: 2
context:
users:
tenants: 3
tenants: 2
users_per_tenant: 2
audit_templates:
audit_templates_per_admin: 5
fill_strategy: "random"
params:
- goal:
name: "workload_balancing"
strategy:
name: "workload_stabilization"
extra: {}
- goal:
name: "dummy"
strategy:
name: "dummy"
extra: {}
sla:
failure_rate:
max: 0

View File

@ -29,6 +29,7 @@ from rally.plugins.openstack.scenarios.murano import utils as murano_utils
from rally.plugins.openstack.scenarios.nova import utils as nova_utils
from rally.plugins.openstack.scenarios.sahara import utils as sahara_utils
from rally.plugins.openstack.scenarios.vm import utils as vm_utils
from rally.plugins.openstack.scenarios.watcher import utils as watcher_utils
from rally.plugins.openstack.wrappers import glance as glance_utils
from rally.verification.tempest import config as tempest_conf
@ -49,7 +50,8 @@ def list_opts():
murano_utils.MURANO_BENCHMARK_OPTS,
nova_utils.NOVA_BENCHMARK_OPTS,
sahara_utils.SAHARA_BENCHMARK_OPTS,
vm_utils.VM_BENCHMARK_OPTS)),
vm_utils.VM_BENCHMARK_OPTS,
watcher_utils.WATCHER_BENCHMARK_OPTS)),
("tempest",
itertools.chain(tempest_conf.TEMPEST_OPTS)),
("roles_context", itertools.chain(roles.ROLES_CONTEXT_OPTS)),

View File

@ -722,13 +722,17 @@ class FuelEnvironment(base.ResourceManager):
# WATCHER
@base.resource("watcher", "audit_template", order=1500,
admin_required=True, tenant_resource=True)
class WatcherTemplate(SynchronizedDeletion, base.ResourceManager):
_watcher_order = get_order(1500)
class WatcherMixin(SynchronizedDeletion, base.ResourceManager):
def id(self):
return self.raw_resource.uuid
def list(self):
return self._manager().list(limit=0)
def is_deleted(self):
from watcherclient.common.apiclient import exceptions
try:
@ -737,8 +741,27 @@ class WatcherTemplate(SynchronizedDeletion, base.ResourceManager):
except exceptions.NotFound:
return True
def list(self):
return self._manager().list(limit=0)
@base.resource("watcher", "audit_template", order=next(_watcher_order),
admin_required=True, perform_for_admin_only=True)
class WatcherTemplate(WatcherMixin):
pass
@base.resource("watcher", "action_plan", order=next(_watcher_order),
admin_required=True, perform_for_admin_only=True)
class WatcherActionPlan(WatcherMixin):
def name(self):
return self.raw_resource.uuid
@base.resource("watcher", "audit", order=next(_watcher_order),
admin_required=True, perform_for_admin_only=True)
class WatcherAudit(WatcherMixin):
def name(self):
return self.raw_resource.uuid
# KEYSTONE

View File

@ -0,0 +1,113 @@
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import random
import six
from rally.common.i18n import _
from rally.common import logging
from rally import consts
from rally import osclients
from rally.plugins.openstack.cleanup import manager as resource_manager
from rally.plugins.openstack.scenarios.watcher import utils as watcher_utils
from rally.plugins.openstack import types
from rally.task import context
LOG = logging.getLogger(__name__)
@context.configure(name="audit_templates", order=550)
class AuditTemplateGenerator(context.Context):
"""Context class for adding temporary audit template for benchmarks."""
CONFIG_SCHEMA = {
"type": "object",
"$schema": consts.JSON_SCHEMA,
"fill_strategy": {"enum": ["round_robin", "random", None]},
"params": {
"type": "array",
"minItems": 1,
"uniqueItems": True,
"items": {
"type": "object",
"properties": {
"goal": {
"type": "object",
"properties": {
"name": {
"type": "string"
}
}
},
"strategy": {
"type": "object",
"properties": {
"name": {
"type": "string"
}
}
},
"extra": {
"type": "object"
},
},
},
},
"additionalProperties": True,
"required": ["params"]
}
DEFAULT_CONFIG = {
"audit_templates_per_admin": 1,
"fill_strategy": "round_robin"
}
@logging.log_task_wrapper(LOG.info, _("Enter context: `Audit Templates`"))
def setup(self):
watcher_scenario = watcher_utils.WatcherScenario(
{"admin": self.context["admin"], "task": self.context["task"],
"config": {
"api_versions": self.context["config"].get(
"api_versions", [])}
})
clients = osclients.Clients(self.context["admin"]["credential"])
self.context["audit_templates"] = []
for i in six.moves.range(self.config["audit_templates_per_admin"]):
cfg_size = len(self.config["params"])
if self.config["fill_strategy"] == "round_robin":
audit_params = self.config["params"][i % cfg_size]
elif self.config["fill_strategy"] == "random":
audit_params = random.choice(self.config["params"])
goal_id = types.WatcherGoal.transform(
clients=clients,
resource_config=audit_params["goal"])
strategy_id = types.WatcherStrategy.transform(
clients=clients,
resource_config=audit_params["strategy"])
extra = audit_params.get("extra") or {}
audit_template = watcher_scenario._create_audit_template(
goal_id, strategy_id, extra)
self.context["audit_templates"].append(audit_template.uuid)
@logging.log_task_wrapper(LOG.info, _("Exit context: `Audit Templates`"))
def cleanup(self):
resource_manager.cleanup(names=["watcher.action_plan",
"watcher.audit_template"],
admin=self.context.get("admin", []))

View File

@ -38,3 +38,47 @@ class Watcher(utils.WatcherScenario):
extra = extra or {}
audit_template = self._create_audit_template(goal, strategy, extra)
self._delete_audit_template(audit_template.uuid)
@validation.required_services(consts.Service.WATCHER)
@scenario.configure()
def list_audit_templates(self, name=None, goal=None, strategy=None,
limit=None, sort_key=None, sort_dir=None,
detail=False):
"""List existing audit templates.
Audit templates are being created by Audit Template Context.
:param name: Name of the audit template
:param goal: Name of the goal
:param strategy: Name of the strategy
:param limit: The maximum number of results to return per
request, if:
1) limit > 0, the maximum number of audit templates to return.
2) limit == 0, return the entire list of audit_templates.
3) limit param is NOT specified (None), the number of items
returned respect the maximum imposed by the Watcher API
(see Watcher's api.max_limit option).
:param sort_key: Optional, field used for sorting.
:param sort_dir: Optional, direction of sorting, either 'asc' (the
default) or 'desc'.
:param detail: Optional, boolean whether to return detailed information
about audit_templates.
"""
self._list_audit_templates(name=name, goal=goal, strategy=strategy,
limit=limit, sort_key=sort_key,
sort_dir=sort_dir, detail=detail)
@validation.required_services(consts.Service.WATCHER)
@validation.required_contexts("audit_templates")
@scenario.configure(context={"admin_cleanup": ["watcher"]})
def create_audit_and_delete(self):
"""Create and delete audit.
Create Audit, wait until whether Audit is in SUCCEEDED state or in
FAILED and delete audit.
"""
audit_template_uuid = self.context["audit_templates"][0]
audit = self._create_audit(audit_template_uuid)
self._delete_audit(audit)

View File

@ -10,8 +10,24 @@
# License for the specific language governing permissions and limitations
# under the License.
from oslo_config import cfg
from rally.plugins.openstack import scenario
from rally.task import atomic
from rally.task import utils
CONF = cfg.CONF
WATCHER_BENCHMARK_OPTS = [
cfg.FloatOpt("watcher_audit_launch_poll_interval", default=2.0,
help="Watcher audit launch interval"),
cfg.IntOpt("watcher_audit_launch_timeout", default=300,
help="Watcher audit launch timeout")
]
benchmark_group = cfg.OptGroup(name="benchmark", title="benchmark options")
CONF.register_opts(WATCHER_BENCHMARK_OPTS, group=benchmark_group)
class WatcherScenario(scenario.OpenStackScenario):
@ -39,3 +55,32 @@ class WatcherScenario(scenario.OpenStackScenario):
:param audit_template: Audit Template object
"""
self.admin_clients("watcher").audit_template.delete(audit_template)
@atomic.action_timer("watcher.list_audit_templates")
def _list_audit_templates(self, name=None, goal=None, strategy=None,
limit=None, sort_key=None, sort_dir=None,
detail=False):
return self.admin_clients("watcher").audit_template.list(
name=name, goal=goal, strategy=strategy, limit=limit,
sort_key=sort_key, sort_dir=sort_dir, detail=detail)
@atomic.action_timer("watcher.create_audit")
def _create_audit(self, audit_template_uuid):
audit = self.admin_clients("watcher").audit.create(
audit_template_uuid=audit_template_uuid,
audit_type="ONESHOT")
utils.wait_for_status(
audit,
ready_statuses=["SUCCEEDED"],
failure_statuses=["FAILED"],
status_attr="state",
update_resource=utils.get_from_manager(),
timeout=CONF.benchmark.watcher_audit_launch_timeout,
check_interval=CONF.benchmark.watcher_audit_launch_poll_interval,
id_attr="uuid"
)
return audit
@atomic.action_timer("watcher.delete_audit")
def _delete_audit(self, audit):
self.admin_clients("watcher").audit.delete(audit.uuid)

View File

@ -0,0 +1,32 @@
{
"Watcher.create_audit_and_delete": [
{
"runner": {
"type": "constant",
"times": 10,
"concurrency": 2
},
"context": {
"users": {
"tenants": 2,
"users_per_tenant": 2
},
"audit_templates": {
"audit_templates_per_admin": 5,
"fill_strategy": "round_robin",
"params": [
{
"goal": {
"name": "dummy"
},
"strategy": {
"name": "dummy"
},
"extra": {}
}
]
}
}
}
]
}

View File

@ -0,0 +1,20 @@
---
Watcher.create_audit_and_delete:
-
runner:
type: "constant"
times: 10
concurrency: 2
context:
users:
tenants: 2
users_per_tenant: 2
audit_templates:
audit_templates_per_admin: 5
fill_strategy: "round_robin"
params:
- goal:
name: "dummy"
strategy:
name: "dummy"
extra: {}

View File

@ -0,0 +1,37 @@
{
"Watcher.list_audit_templates": [
{
"runner": {
"type": "constant",
"times": 10,
"concurrency": 1
},
"context": {
"audit_templates": {
"audit_templates_per_admin": 5,
"fill_strategy": "random",
"params": [
{
"goal": {
"name": "workload_balancing"
},
"strategy": {
"name": "workload_stabilization"
},
"extra": {}
},
{
"goal": {
"name": "dummy"
},
"strategy": {
"name": "dummy"
},
"extra": {}
}
]
}
}
}
]
}

View File

@ -0,0 +1,22 @@
---
Watcher.list_audit_templates:
-
runner:
type: "constant"
times: 10
concurrency: 1
context:
audit_templates:
audit_templates_per_admin: 5
fill_strategy: "random"
params:
- goal:
name: "workload_balancing"
strategy:
name: "workload_stabilization"
extra: {}
- goal:
name: "dummy"
strategy:
name: "dummy"
extra: {}

View File

@ -212,6 +212,8 @@ class Watcher(ResourceManager):
REQUIRED_SERVICE = consts.Service.WATCHER
REPR_KEYS = ("uuid", "name")
def list_audits(self):
return self.client.audit.list()
@ -221,12 +223,12 @@ class Watcher(ResourceManager):
def list_goals(self):
return self.client.goal.list()
def list_strategies(self):
return self.client.strategy.list()
def list_action_plans(self):
return self.client.action_plan.list()
def list_actions(self):
return self.client.action.list()
class CloudResources(object):
"""List and compare cloud resources.

View File

@ -780,3 +780,65 @@ class WatcherTemplateTestCase(test.TestCase):
self.assertEqual("audit_template", watcher._resource)
watcher._manager().list.assert_called_once_with(limit=0)
class WatcherAuditTestCase(test.TestCase):
def test_id(self):
watcher = resources.WatcherAudit()
watcher.raw_resource = mock.MagicMock(uuid=100)
self.assertEqual(100, watcher.id())
def test_name(self):
watcher = resources.WatcherAudit()
watcher.raw_resource = mock.MagicMock(uuid="name")
self.assertEqual("name", watcher.name())
@mock.patch("%s.WatcherAudit._manager" % BASE)
def test_is_deleted(self, mock__manager):
mock__manager.return_value.get.return_value = None
watcher = resources.WatcherAudit()
watcher.id = mock.Mock()
self.assertFalse(watcher.is_deleted())
mock__manager.side_effect = [watcher_exceptions.NotFound()]
self.assertTrue(watcher.is_deleted())
def test_list(self):
watcher = resources.WatcherAudit()
watcher._manager = mock.MagicMock()
watcher.list()
self.assertEqual("audit", watcher._resource)
watcher._manager().list.assert_called_once_with(limit=0)
class WatcherActionPlanTestCase(test.TestCase):
def test_id(self):
watcher = resources.WatcherActionPlan()
watcher.raw_resource = mock.MagicMock(uuid=100)
self.assertEqual(100, watcher.id())
def test_name(self):
watcher = resources.WatcherActionPlan()
watcher.raw_resource = mock.MagicMock(uuid="name")
self.assertEqual("name", watcher.name())
@mock.patch("%s.WatcherActionPlan._manager" % BASE)
def test_is_deleted(self, mock__manager):
mock__manager.return_value.get.return_value = None
watcher = resources.WatcherActionPlan()
watcher.id = mock.Mock()
self.assertFalse(watcher.is_deleted())
mock__manager.side_effect = [watcher_exceptions.NotFound()]
self.assertTrue(watcher.is_deleted())
def test_list(self):
watcher = resources.WatcherActionPlan()
watcher._manager = mock.MagicMock()
watcher.list()
self.assertEqual("action_plan", watcher._resource)
watcher._manager().list.assert_called_once_with(limit=0)

View File

@ -0,0 +1,96 @@
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import mock
from rally.plugins.openstack.context.watcher import audit_templates
from tests.unit import fakes
from tests.unit import test
CTX = "rally.plugins.openstack.context.watcher"
SCN = "rally.plugins.openstack.scenarios.watcher"
TYP = "rally.plugins.openstack.types"
class AuditTemplateTestCase(test.ScenarioTestCase):
@mock.patch("%s.utils.WatcherScenario._create_audit_template" % SCN,
return_value=mock.MagicMock())
@mock.patch("%s.WatcherStrategy.transform" % TYP,
return_value=mock.MagicMock())
@mock.patch("%s.WatcherGoal.transform" % TYP,
return_value=mock.MagicMock())
@mock.patch("%s.audit_templates.osclients" % CTX,
return_value=fakes.FakeClients())
def test_setup(self, mock_osclients, mock_watcher_goal_transform,
mock_watcher_strategy_transform,
mock_watcher_scenario__create_audit_template):
users = [{"id": 1, "tenant_id": 1, "credential": mock.MagicMock()}]
self.context.update({
"config": {
"audit_templates": {
"audit_templates_per_admin": 1,
"fill_strategy": "random",
"params": [
{
"goal": {
"name": "workload_balancing"
},
"strategy": {
"name": "workload_stabilization"
},
"extra": {}
},
{
"goal": {
"name": "workload_balancing"
},
"strategy": {
"name": "workload_stabilization"
},
"extra": {}
}
]
},
},
"admin": {
"credential": mock.MagicMock()
},
"users": users
})
audit_template = audit_templates.AuditTemplateGenerator(self.context)
audit_template.setup()
goal_id = mock_watcher_goal_transform.return_value
strategy_id = mock_watcher_strategy_transform.return_value
mock_calls = [mock.call(goal_id, strategy_id, {})]
mock_watcher_scenario__create_audit_template.assert_has_calls(
mock_calls)
@mock.patch("%s.audit_templates.resource_manager.cleanup" % CTX)
def test_cleanup(self, mock_cleanup):
audit_templates_mocks = [mock.Mock() for i in range(2)]
self.context.update({
"admin": {
"credential": mock.MagicMock()
},
"audit_templates": audit_templates_mocks
})
audit_templates_ctx = audit_templates.AuditTemplateGenerator(
self.context)
audit_templates_ctx.cleanup()
mock_cleanup.assert_called_once_with(
names=["watcher.action_plan", "watcher.audit_template"],
admin=self.context["admin"])

View File

@ -33,3 +33,22 @@ class WatcherTestCase(test.ScenarioTestCase):
{})
scenario._delete_audit_template.assert_called_once_with(
audit_template.uuid)
def test_list_audit_template(self):
scenario = basic.Watcher(self.context)
scenario._list_audit_templates = mock.MagicMock()
scenario.list_audit_templates()
scenario._list_audit_templates.assert_called_once_with(
detail=False, goal=None, limit=None, name=None, sort_dir=None,
sort_key=None, strategy=None)
def test_create_audit_and_delete(self):
mock_audit = mock.MagicMock()
scenario = basic.Watcher(self.context)
scenario.context = mock.MagicMock()
scenario._create_audit = mock.MagicMock(return_value=mock_audit)
scenario.sleep_between = mock.MagicMock()
scenario._delete_audit = mock.MagicMock()
scenario.create_audit_and_delete()
scenario._create_audit.assert_called_once_with(mock.ANY)
scenario._delete_audit.assert_called_once_with(mock_audit)

View File

@ -14,10 +14,13 @@
# under the License.
import mock
from oslo_config import cfg
from rally.plugins.openstack.scenarios.watcher import utils
from tests.unit import test
CONF = cfg.CONF
class WatcherScenarioTestCase(test.ScenarioTestCase):
@ -37,6 +40,16 @@ class WatcherScenarioTestCase(test.ScenarioTestCase):
self._test_atomic_action_timer(watcher_scenario.atomic_actions(),
"watcher.create_audit_template")
def test_list_audit_templates(self):
audit_templates_list = []
watcher_scenario = utils.WatcherScenario(self.context)
self.admin_clients(
"watcher").audit_template.list.return_value = audit_templates_list
return_audit_templates_list = watcher_scenario._list_audit_templates()
self.assertEqual(audit_templates_list, return_audit_templates_list)
self._test_atomic_action_timer(watcher_scenario.atomic_actions(),
"watcher.list_audit_templates")
def test_delete_audit_template(self):
watcher_scenario = utils.WatcherScenario(self.context)
watcher_scenario._delete_audit_template("fake_audit_template")
@ -45,3 +58,31 @@ class WatcherScenarioTestCase(test.ScenarioTestCase):
"fake_audit_template")
self._test_atomic_action_timer(watcher_scenario.atomic_actions(),
"watcher.delete_audit_template")
def test_create_audit(self):
mock_audit_template = mock.Mock()
watcher_scenario = utils.WatcherScenario(self.context)
audit = watcher_scenario._create_audit(mock_audit_template)
self.mock_wait_for_status.mock.assert_called_once_with(
audit,
ready_statuses=["SUCCEEDED"],
failure_statuses=["FAILED"],
status_attr="state",
update_resource=self.mock_get_from_manager.mock.return_value,
check_interval=CONF.benchmark.watcher_audit_launch_poll_interval,
timeout=CONF.benchmark.watcher_audit_launch_timeout,
id_attr="uuid")
self.mock_get_from_manager.mock.assert_called_once_with()
self.admin_clients("watcher").audit.create.assert_called_once_with(
audit_template_uuid=mock_audit_template, audit_type="ONESHOT")
self._test_atomic_action_timer(watcher_scenario.atomic_actions(),
"watcher.create_audit")
def test_delete_audit(self):
mock_audit = mock.Mock()
watcher_scenario = utils.WatcherScenario(self.context)
watcher_scenario._delete_audit(mock_audit)
self.admin_clients("watcher").audit.delete.assert_called_once_with(
mock_audit.uuid)
self._test_atomic_action_timer(watcher_scenario.atomic_actions(),
"watcher.delete_audit")