From bdee91bd27dfdb49311414b3158403c551bd67fa Mon Sep 17 00:00:00 2001 From: Yan Ning Date: Mon, 1 Jun 2015 14:48:23 -0600 Subject: [PATCH] Add validate monasca service to authenticate.py * enable monascaclient call in Rally infra only in this patch Co-Authored-By: Kun Huang Change-Id: Ib97831f025bdf87ee7504211f26d067b982c507a --- optional-requirements.txt | 1 + rally/consts.py | 3 ++ rally/osclients.py | 20 +++++++++++++ .../scenarios/authenticate/authenticate.py | 18 ++++++++++++ .../authenticate/token_validate_monasca.json | 20 +++++++++++++ .../authenticate/token_validate_monasca.yaml | 13 +++++++++ tests/unit/fakes.py | 21 +++++++++++++- .../authenticate/test_authenticate.py | 8 +++++ tests/unit/test_osclients.py | 29 ++++++++++++++++++- 9 files changed, 131 insertions(+), 2 deletions(-) create mode 100644 samples/tasks/scenarios/authenticate/token_validate_monasca.json create mode 100644 samples/tasks/scenarios/authenticate/token_validate_monasca.yaml diff --git a/optional-requirements.txt b/optional-requirements.txt index 5c03a2a4a6..b93ebc514d 100644 --- a/optional-requirements.txt +++ b/optional-requirements.txt @@ -1,3 +1,4 @@ python-mistralclient python-fuelclient==6.1.0 python-muranoclient>=0.5.5 +python-monascaclient>=1.0.22 diff --git a/rally/consts.py b/rally/consts.py index 826146f097..e2359546bf 100644 --- a/rally/consts.py +++ b/rally/consts.py @@ -104,6 +104,7 @@ class _Service(utils.ImmutableMixin, utils.EnumMixin): NEUTRON = "neutron" DESIGNATE = "designate" CEILOMETER = "ceilometer" + MONASCA = "monasca" S3 = "s3" TROVE = "trove" SAHARA = "sahara" @@ -130,6 +131,7 @@ class _ServiceType(utils.ImmutableMixin, utils.EnumMixin): NETWORK = "network" DNS = "dns" METERING = "metering" + MONITORING = "monitoring" S3 = "s3" DATABASE = "database" DATA_PROCESSING = "data_processing" @@ -154,6 +156,7 @@ class _ServiceType(utils.ImmutableMixin, utils.EnumMixin): self.NETWORK: _Service.NEUTRON, self.DNS: _Service.DESIGNATE, self.METERING: _Service.CEILOMETER, + self.MONITORING: _Service.MONASCA, self.S3: _Service.S3, self.DATABASE: _Service.TROVE, self.DATA_PROCESSING: _Service.SAHARA, diff --git a/rally/osclients.py b/rally/osclients.py index 85afcdd855..533053bdfb 100644 --- a/rally/osclients.py +++ b/rally/osclients.py @@ -282,6 +282,26 @@ class Clients(object): **self._get_auth_info(project_name_key="tenant_name")) return client + @cached + def monasca(self, version="2_0"): + """Return monasca client.""" + from monascaclient import client as monasca + kc = self.keystone() + monitoring_api_url = kc.service_catalog.url_for( + service_type="monitoring", + endpoint_type=self.endpoint.endpoint_type, + region_name=self.endpoint.region_name) + auth_token = kc.auth_token + client = monasca.Client( + version, + monitoring_api_url, + token=auth_token, + timeout=CONF.openstack_client_http_timeout, + insecure=self.endpoint.insecure, + cacert=self.endpoint.cacert, + **self._get_auth_info(project_name_key="tenant_name")) + return client + @cached def ironic(self, version="1"): """Return Ironic client.""" diff --git a/rally/plugins/openstack/scenarios/authenticate/authenticate.py b/rally/plugins/openstack/scenarios/authenticate/authenticate.py index a556730457..2e2866a02c 100644 --- a/rally/plugins/openstack/scenarios/authenticate/authenticate.py +++ b/rally/plugins/openstack/scenarios/authenticate/authenticate.py @@ -12,6 +12,7 @@ # License for the specific language governing permissions and limitations # under the License. +from rally import consts from rally.plugins.openstack import scenario from rally.task import atomic from rally.task import validation @@ -111,3 +112,20 @@ class Authenticate(scenario.OpenStackScenario): for i in range(repetitions): with atomic.ActionTimer(self, "authenticate.validate_heat"): list(heat_client.stacks.list(limit=0)) + + @validation.number("repetitions", minval=1) + @validation.required_openstack(users=True) + @validation.required_services(consts.Service.MONASCA) + @scenario.configure() + def validate_monasca(self, repetitions): + """Check Monasca Client to ensure validation of token. + + Creation of the client does not ensure validation of the token. + We have to do some minimal operation to make sure token gets validated. + + :param repetitions: number of times to validate + """ + monasca_client = self.clients("monasca") + for i in range(repetitions): + with atomic.ActionTimer(self, "authenticate.validate_monasca"): + list(monasca_client.metrics.list(limit=0)) diff --git a/samples/tasks/scenarios/authenticate/token_validate_monasca.json b/samples/tasks/scenarios/authenticate/token_validate_monasca.json new file mode 100644 index 0000000000..8164824d19 --- /dev/null +++ b/samples/tasks/scenarios/authenticate/token_validate_monasca.json @@ -0,0 +1,20 @@ +{ + "Authenticate.validate_monasca": [ + { + "args": { + "repetitions": 2 + }, + "runner": { + "type": "constant", + "times": 10, + "concurrency": 5 + }, + "context": { + "users": { + "tenants": 3, + "users_per_tenant": 5 + } + } + } + ] +} diff --git a/samples/tasks/scenarios/authenticate/token_validate_monasca.yaml b/samples/tasks/scenarios/authenticate/token_validate_monasca.yaml new file mode 100644 index 0000000000..ccd67b5e60 --- /dev/null +++ b/samples/tasks/scenarios/authenticate/token_validate_monasca.yaml @@ -0,0 +1,13 @@ +--- + Authenticate.validate_monasca: + - + args: + repetitions: 2 + runner: + type: "constant" + times: 10 + concurrency: 5 + context: + users: + tenants: 3 + users_per_tenant: 5 diff --git a/tests/unit/fakes.py b/tests/unit/fakes.py index b4335e6f4a..d28c3594a0 100644 --- a/tests/unit/fakes.py +++ b/tests/unit/fakes.py @@ -768,6 +768,12 @@ class FakeMeterManager(FakeManager): return ["fake-meter"] +class FakeMetricsManager(FakeManager): + + def list(self): + return ["fake-metric"] + + class FakeCeilometerResourceManager(FakeManager): def get(self, resource_id): @@ -916,7 +922,8 @@ class FakeObjectManager(FakeManager): class FakeServiceCatalog(object): def get_endpoints(self): return {"image": [{"publicURL": "http://fake.to"}], - "metering": [{"publicURL": "http://fake.to"}]} + "metering": [{"publicURL": "http://fake.to"}], + "monitoring": [{"publicURL": "http://fake.to"}]} def url_for(self, **kwargs): return "http://fake.to" @@ -1027,6 +1034,12 @@ class FakeCeilometerClient(object): self.query_alarm_history = FakeQueryManager() +class FakeMonascaClient(object): + + def __init__(self): + self.metrics = FakeMetricsManager() + + class FakeNeutronClient(object): def __init__(self, **kwargs): @@ -1453,6 +1466,7 @@ class FakeClients(object): self._mistral = None self._swift = None self._murano = None + self._monasca = None self._ec2 = None self._endpoint = endpoint_ or objects.Endpoint( "http://fake.example.org:5000/v2.0/", @@ -1508,6 +1522,11 @@ class FakeClients(object): self._ceilometer = FakeCeilometerClient() return self._ceilometer + def monasca(self): + if not self._monasca: + self._monasca = FakeMonascaClient() + return self._monasca + def zaqar(self): if not self._zaqar: self._zaqar = FakeZaqarClient() diff --git a/tests/unit/plugins/openstack/scenarios/authenticate/test_authenticate.py b/tests/unit/plugins/openstack/scenarios/authenticate/test_authenticate.py index 806878b860..5787a09d2e 100644 --- a/tests/unit/plugins/openstack/scenarios/authenticate/test_authenticate.py +++ b/tests/unit/plugins/openstack/scenarios/authenticate/test_authenticate.py @@ -67,3 +67,11 @@ class AuthenticateTestCase(test.ScenarioTestCase): scenario_inst.validate_heat(5) self.clients("heat").stacks.list.assert_called_with(limit=0) self.assertEqual(self.clients("heat").stacks.list.call_count, 5) + + def test_validate_monasca(self): + scenario_inst = authenticate.Authenticate() + with atomic.ActionTimer(scenario_inst, + "authenticate.validate_monasca"): + scenario_inst.validate_monasca(5) + self.clients("monasca").metrics.list.assert_called_with(limit=0) + self.assertEqual(self.clients("monasca").metrics.list.call_count, 5) diff --git a/tests/unit/test_osclients.py b/tests/unit/test_osclients.py index baf3001680..df5105832c 100644 --- a/tests/unit/test_osclients.py +++ b/tests/unit/test_osclients.py @@ -13,7 +13,6 @@ # License for the specific language governing permissions and limitations # under the License. - from keystoneclient import exceptions as keystone_exceptions import mock from oslo_config import cfg @@ -326,6 +325,34 @@ class OSClientsTestCase(test.TestCase): self.assertEqual(fake_ceilometer, self.clients.cache["ceilometer"]) + def test_monasca(self): + fake_monasca = fakes.FakeMonascaClient() + mock_monasca = mock.MagicMock() + mock_monasca.client.Client.return_value = fake_monasca + self.assertNotIn("monasca", self.clients.cache) + with mock.patch.dict("sys.modules", + {"monascaclient": mock_monasca}): + client = self.clients.monasca() + self.assertEqual(fake_monasca, client) + self.service_catalog.url_for.assert_called_once_with( + service_type="monitoring", + endpoint_type=consts.EndpointType.PUBLIC, + region_name=self.endpoint.region_name) + os_endpoint = self.service_catalog.url_for.return_value + kw = {"token": self.fake_keystone.auth_token, + "timeout": cfg.CONF.openstack_client_http_timeout, + "insecure": False, "cacert": None, + "username": self.endpoint.username, + "password": self.endpoint.password, + "tenant_name": self.endpoint.tenant_name, + "auth_url": self.endpoint.auth_url + } + mock_monasca.client.Client.assert_called_once_with("2_0", + os_endpoint, + **kw) + self.assertEqual(mock_monasca.client.Client.return_value, + self.clients.cache["monasca"]) + def test_ironic(self): fake_ironic = fakes.FakeIronicClient() mock_ironic = mock.MagicMock()