diff --git a/.gitignore b/.gitignore index d311e9b9c5..3a8cb664d4 100644 --- a/.gitignore +++ b/.gitignore @@ -46,3 +46,6 @@ doc/source/_build/ .idea .pydevproject *.swp + +# Mac Desktop Service Store +*.DS_Store diff --git a/rally/consts.py b/rally/consts.py index 3b15251d00..dab791f259 100644 --- a/rally/consts.py +++ b/rally/consts.py @@ -113,6 +113,7 @@ class _Service(utils.ImmutableMixin, utils.EnumMixin): IRONIC = "ironic" GNOCCHI = "gnocchi" MAGNUM = "magnum" + WATCHER = "watcher" class _ServiceType(utils.ImmutableMixin, utils.EnumMixin): @@ -141,6 +142,7 @@ class _ServiceType(utils.ImmutableMixin, utils.EnumMixin): BARE_METAL = "baremetal" METRIC = "metric" CONTAINER_INFRA = "container-infra" + INFRA_OPTIM = "infra-optim" def __init__(self): self.__names = { @@ -167,6 +169,7 @@ class _ServiceType(utils.ImmutableMixin, utils.EnumMixin): self.BARE_METAL: _Service.IRONIC, self.METRIC: _Service.GNOCCHI, self.CONTAINER_INFRA: _Service.MAGNUM, + self.INFRA_OPTIM: _Service.WATCHER, } def __getitem__(self, service_type): diff --git a/rally/osclients.py b/rally/osclients.py index 233bdb75c9..10b9dc519b 100644 --- a/rally/osclients.py +++ b/rally/osclients.py @@ -744,6 +744,25 @@ class Magnum(OSClient): return magnum.Client(session=session, interface=endpoint_type[0]) +@configure("watcher", default_version="1", default_service_type="infra-optim", + supported_versions=["1"]) +class Watcher(OSClient): + def create_client(self, version=None, service_type=None): + """Return watcher client.""" + from watcherclient import client as watcher_client + kc = self.keystone() + watcher_api_url = self._get_endpoint( + self.choose_service_type(service_type)) + client = watcher_client.Client( + self.choose_version(version), + watcher_api_url, + token=kc.auth_token, + timeout=CONF.openstack_client_http_timeout, + insecure=self.credential.insecure, + ca_file=self.credential.cacert) + return client + + class Clients(object): """This class simplify and unify work with OpenStack python clients.""" diff --git a/rally/plugins/openstack/cleanup/resources.py b/rally/plugins/openstack/cleanup/resources.py index 5161370a90..37fca765f0 100644 --- a/rally/plugins/openstack/cleanup/resources.py +++ b/rally/plugins/openstack/cleanup/resources.py @@ -720,6 +720,27 @@ class FuelEnvironment(base.ResourceManager): futils.FuelScenario)] +# WATCHER + +@base.resource("watcher", "audit_template", order=1500, + admin_required=True, tenant_resource=True) +class WatcherTemplate(SynchronizedDeletion, base.ResourceManager): + + def id(self): + return self.raw_resource.uuid + + def is_deleted(self): + from watcherclient.common.apiclient import exceptions + try: + self._manager().get(self.id()) + return False + except exceptions.NotFound: + return True + + def list(self): + return self._manager().list(limit=0) + + # KEYSTONE _keystone_order = get_order(9000) diff --git a/requirements.txt b/requirements.txt index 2c35c73e64..997fe78b2b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -32,6 +32,7 @@ python-saharaclient>=0.13.0 # Apache-2.0 python-troveclient>=2.2.0 # Apache-2.0 python-zaqarclient>=1.0.0 # Apache-2.0 python-swiftclient>=2.2.0 # Apache-2.0 +python-watcherclient>=0.23.0 # Apache-2.0 python-subunit>=0.0.18 # Apache-2.0/BSD requests>=2.10.0 # Apache-2.0 SQLAlchemy<1.1.0,>=1.0.10 # MIT diff --git a/tests/ci/osresources.py b/tests/ci/osresources.py index 898ae8bf5c..14c6be74ae 100755 --- a/tests/ci/osresources.py +++ b/tests/ci/osresources.py @@ -208,6 +208,26 @@ class Cinder(ResourceManager): search_opts={"all_tenants": True}) +class Watcher(ResourceManager): + + REQUIRED_SERVICE = consts.Service.WATCHER + + def list_audits(self): + return self.client.audit.list() + + def list_audit_templates(self): + return self.client.audit_template.list() + + def list_goals(self): + return self.client.goal.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. diff --git a/tests/unit/fakes.py b/tests/unit/fakes.py index c273e900b8..8e6949f83c 100644 --- a/tests/unit/fakes.py +++ b/tests/unit/fakes.py @@ -127,6 +127,14 @@ class FakeImage(FakeResource): self.update = mock.MagicMock() +class FakeStrategy(FakeResource): + pass + + +class FakeGoal(FakeResource): + pass + + class FakeMurano(FakeResource): pass @@ -425,6 +433,18 @@ class FakeImageManager(FakeManager): self.resources_order.remove(resource) +class FakeStrategyManager(FakeManager): + + def create(self): + return FakeStrategy(self) + + +class FakeGoalManager(FakeManager): + + def create(self): + return FakeGoal(self) + + class FakePackageManager(FakeManager): def create(self, package_descr, package_arch, package_class=FakeMurano): @@ -1493,6 +1513,13 @@ class FakeMagnumClient(object): pass +class FakeWatcherClient(object): + + def __init__(self): + self.strategy = FakeStrategyManager() + self.goal = FakeGoalManager() + + class FakeClients(object): def __init__(self, credential_=None): @@ -1513,6 +1540,7 @@ class FakeClients(object): self._monasca = None self._ec2 = None self._senlin = None + self._watcher = None self._credential = credential_ or objects.Credential( "http://fake.example.org:5000/v2.0/", "fake_username", @@ -1607,6 +1635,11 @@ class FakeClients(object): self._senlin = FakeSenlinClient() return self._senlin + def watcher(self): + if not self._watcher: + self._watcher = FakeWatcherClient() + return self._watcher + class FakeRunner(object): diff --git a/tests/unit/plugins/openstack/cleanup/test_resources.py b/tests/unit/plugins/openstack/cleanup/test_resources.py index 15d15c494a..ad509ae98f 100644 --- a/tests/unit/plugins/openstack/cleanup/test_resources.py +++ b/tests/unit/plugins/openstack/cleanup/test_resources.py @@ -18,6 +18,7 @@ import ddt import mock from neutronclient.common import exceptions as neutron_exceptions from novaclient import exceptions as nova_exc +from watcherclient.common.apiclient import exceptions as watcher_exceptions from rally.common import utils from rally.plugins.openstack.cleanup import resources @@ -753,3 +754,29 @@ class FuelEnvironmentTestCase(test.TestCase): fres = resources.FuelEnvironment() self.assertEqual(envs[:-1], fres.list()) + + +class WatcherTemplateTestCase(test.TestCase): + + def test_id(self): + watcher = resources.WatcherTemplate() + watcher.raw_resource = mock.MagicMock(uuid=100) + self.assertEqual(100, watcher.id()) + + @mock.patch("%s.WatcherTemplate._manager" % BASE) + def test_is_deleted(self, mock__manager): + mock__manager.return_value.get.return_value = None + watcher = resources.WatcherTemplate() + 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.WatcherTemplate() + watcher._manager = mock.MagicMock() + + watcher.list() + + self.assertEqual("audit_template", watcher._resource) + watcher._manager().list.assert_called_once_with(limit=0) diff --git a/tests/unit/test_osclients.py b/tests/unit/test_osclients.py index 16ba3ff1ca..88cce985a2 100644 --- a/tests/unit/test_osclients.py +++ b/tests/unit/test_osclients.py @@ -856,3 +856,28 @@ class OSClientsTestCase(test.TestCase): session=self.fake_keystone.session) self.assertEqual(fake_magnum, self.clients.cache["magnum"]) + + def test_watcher(self): + fake_watcher = fakes.FakeWatcherClient() + mock_watcher = mock.MagicMock() + mock_watcher.client.Client.return_value = fake_watcher + self.assertNotIn("watcher", self.clients.cache) + with mock.patch.dict("sys.modules", {"watcherclient": mock_watcher}): + client = self.clients.watcher() + + self.assertEqual(fake_watcher, client) + + self.service_catalog.url_for.assert_called_once_with( + service_type="infra-optim", + endpoint_type=consts.EndpointType.PUBLIC, + region_name=self.credential.region_name) + + mock_watcher.client.Client.assert_called_once_with( + "1", + self.service_catalog.url_for.return_value, + token=self.fake_keystone.auth_token, + ca_file=None, + insecure=False, + timeout=180.0) + + self.assertEqual(fake_watcher, self.clients.cache["watcher"])