Add Senlin plugin for profile and cluster
This patch add Senlin plugin for profile and cluster resources. It also adds a sample scenario job to test cluster creating/deleting performance. Change-Id: I87e7a2bc5ce3bc859bb2ebd9b2f6c6e08833f397 Partial-bp: add-support-for-clustering-service-senlin
This commit is contained in:
parent
788f2220a8
commit
bffc116628
27
rally-jobs/rally-senlin.yaml
Normal file
27
rally-jobs/rally-senlin.yaml
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
---
|
||||||
|
SenlinClusters.create_and_delete_profile_cluster:
|
||||||
|
-
|
||||||
|
args:
|
||||||
|
profile_spec:
|
||||||
|
type: os.nova.server
|
||||||
|
version: 1.0
|
||||||
|
properties:
|
||||||
|
name: cirros_server
|
||||||
|
flavor: 1
|
||||||
|
image: "cirros-0.3.4-x86_64-uec"
|
||||||
|
networks:
|
||||||
|
- network: private
|
||||||
|
desired_capacity: 3
|
||||||
|
min_size: 0
|
||||||
|
max_size: 5
|
||||||
|
runner:
|
||||||
|
type: "constant"
|
||||||
|
times: 3
|
||||||
|
concurrency: 2
|
||||||
|
context:
|
||||||
|
users:
|
||||||
|
tenants: 2
|
||||||
|
users_per_tenant: 2
|
||||||
|
sla:
|
||||||
|
failure_rate:
|
||||||
|
max: 0
|
@ -74,6 +74,37 @@ class HeatStack(base.ResourceManager):
|
|||||||
return self.raw_resource.stack_name
|
return self.raw_resource.stack_name
|
||||||
|
|
||||||
|
|
||||||
|
# SENLIN
|
||||||
|
|
||||||
|
_senlin_order = get_order(150)
|
||||||
|
|
||||||
|
|
||||||
|
@base.resource(service=None, resource=None, admin_required=True)
|
||||||
|
class SenlinMixin(base.ResourceManager):
|
||||||
|
|
||||||
|
def _manager(self):
|
||||||
|
client = self._admin_required and self.admin or self.user
|
||||||
|
return getattr(client, self._service)()
|
||||||
|
|
||||||
|
def list(self):
|
||||||
|
return getattr(self._manager(), self._resource)()
|
||||||
|
|
||||||
|
def delete(self):
|
||||||
|
# make singular form of resource name from plural form
|
||||||
|
res_name = self._resource[:-1]
|
||||||
|
return getattr(self._manager(), "delete_%s" % res_name)(self.id)
|
||||||
|
|
||||||
|
|
||||||
|
@base.resource("senlin", "clusters", order=next(_senlin_order))
|
||||||
|
class SenlinCluster(SenlinMixin):
|
||||||
|
"""Resource class for Senlin Cluster."""
|
||||||
|
|
||||||
|
|
||||||
|
@base.resource("senlin", "profiles", order=next(_senlin_order))
|
||||||
|
class SenlinProfile(SenlinMixin):
|
||||||
|
"""Resource class for Senlin Profile."""
|
||||||
|
|
||||||
|
|
||||||
# NOVA
|
# NOVA
|
||||||
|
|
||||||
_nova_order = get_order(200)
|
_nova_order = get_order(200)
|
||||||
|
48
rally/plugins/openstack/scenarios/senlin/clusters.py
Normal file
48
rally/plugins/openstack/scenarios/senlin/clusters.py
Normal file
@ -0,0 +1,48 @@
|
|||||||
|
# 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.
|
||||||
|
|
||||||
|
from rally import consts
|
||||||
|
from rally.plugins.openstack import scenario
|
||||||
|
from rally.plugins.openstack.scenarios.senlin import utils
|
||||||
|
from rally.task import validation
|
||||||
|
|
||||||
|
|
||||||
|
class SenlinClusters(utils.SenlinScenario):
|
||||||
|
"""Benchmark scenarios for Senlin clusters."""
|
||||||
|
|
||||||
|
@validation.required_openstack(admin=True)
|
||||||
|
@validation.required_services(consts.Service.SENLIN)
|
||||||
|
@scenario.configure(context={"cleanup": ["senlin"]})
|
||||||
|
def create_and_delete_profile_cluster(self, profile_spec,
|
||||||
|
desired_capacity=0, min_size=0,
|
||||||
|
max_size=-1, timeout=3600,
|
||||||
|
metadata=None):
|
||||||
|
"""Create a profile and a cluster and then delete them.
|
||||||
|
|
||||||
|
Measure the "senlin profile-create", "senlin profile-delete",
|
||||||
|
"senlin cluster-create" and "senlin cluster-delete" commands
|
||||||
|
performance.
|
||||||
|
|
||||||
|
:param profile_spec: spec dictionary used to create profile
|
||||||
|
:param desired_capacity: The capacity or initial number of nodes
|
||||||
|
owned by the cluster
|
||||||
|
:param min_size: The minimum number of nodes owned by the cluster
|
||||||
|
:param max_size: The maximum number of nodes owned by the cluster.
|
||||||
|
-1 means no limit
|
||||||
|
:param timeout: The timeout value in seconds for cluster creation
|
||||||
|
:param metadata: A set of key value pairs to associate with the cluster
|
||||||
|
"""
|
||||||
|
profile = self._create_profile(profile_spec)
|
||||||
|
cluster = self._create_cluster(profile.id, desired_capacity,
|
||||||
|
min_size, max_size, timeout, metadata)
|
||||||
|
self._delete_cluster(cluster)
|
||||||
|
self._delete_profile(profile)
|
153
rally/plugins/openstack/scenarios/senlin/utils.py
Normal file
153
rally/plugins/openstack/scenarios/senlin/utils.py
Normal file
@ -0,0 +1,153 @@
|
|||||||
|
# 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.
|
||||||
|
|
||||||
|
from oslo_config import cfg
|
||||||
|
|
||||||
|
from rally import exceptions
|
||||||
|
from rally.plugins.openstack import scenario
|
||||||
|
from rally.task import atomic
|
||||||
|
from rally.task import utils
|
||||||
|
|
||||||
|
SENLIN_BENCHMARK_OPTS = [
|
||||||
|
cfg.FloatOpt("senlin_action_timeout",
|
||||||
|
default=3600,
|
||||||
|
help="Time in seconds to wait for senlin action to finish."),
|
||||||
|
]
|
||||||
|
|
||||||
|
CONF = cfg.CONF
|
||||||
|
benchmark_group = cfg.OptGroup(name="benchmark", title="benchmark options")
|
||||||
|
CONF.register_opts(SENLIN_BENCHMARK_OPTS, group=benchmark_group)
|
||||||
|
|
||||||
|
|
||||||
|
class SenlinScenario(scenario.OpenStackScenario):
|
||||||
|
"""Base class for Senlin scenarios with basic atomic actions."""
|
||||||
|
|
||||||
|
@atomic.action_timer("senlin.list_clusters")
|
||||||
|
def _list_clusters(self, **queries):
|
||||||
|
"""Return user cluster list.
|
||||||
|
|
||||||
|
:param kwargs \*\*queries: Optional query parameters to be sent to
|
||||||
|
restrict the clusters to be returned. Available parameters include:
|
||||||
|
|
||||||
|
* name: The name of a cluster.
|
||||||
|
* status: The current status of a cluster.
|
||||||
|
* sort: A list of sorting keys separated by commas. Each sorting
|
||||||
|
key can optionally be attached with a sorting direction
|
||||||
|
modifier which can be ``asc`` or ``desc``.
|
||||||
|
* limit: Requests a specified size of returned items from the
|
||||||
|
query. Returns a number of items up to the specified limit
|
||||||
|
value.
|
||||||
|
* marker: Specifies the ID of the last-seen item. Use the limit
|
||||||
|
parameter to make an initial limited request and use the ID of
|
||||||
|
the last-seen item from the response as the marker parameter
|
||||||
|
value in a subsequent limited request.
|
||||||
|
* global_project: A boolean value indicating whether clusters
|
||||||
|
from all projects will be returned.
|
||||||
|
|
||||||
|
:returns: list of clusters according to query.
|
||||||
|
"""
|
||||||
|
return list(self.admin_clients("senlin").clusters(**queries))
|
||||||
|
|
||||||
|
@atomic.action_timer("senlin.create_cluster")
|
||||||
|
def _create_cluster(self, profile_id, desired_capacity=0, min_size=0,
|
||||||
|
max_size=-1, timeout=60, metadata=None):
|
||||||
|
"""Create a new cluster from attributes.
|
||||||
|
|
||||||
|
:param profile_id: ID of profile used to create cluster
|
||||||
|
:param desired_capacity: The capacity or initial number of nodes
|
||||||
|
owned by the cluster
|
||||||
|
:param min_size: The minimum number of nodes owned by the cluster
|
||||||
|
:param max_size: The maximum number of nodes owned by the cluster.
|
||||||
|
-1 means no limit
|
||||||
|
:param timeout: The timeout value in minutes for cluster creation
|
||||||
|
:param metadata: A set of key value pairs to associate with the cluster
|
||||||
|
|
||||||
|
:returns: object of cluster created.
|
||||||
|
"""
|
||||||
|
attrs = {
|
||||||
|
"profile_id": profile_id,
|
||||||
|
"name": self.generate_random_name(),
|
||||||
|
"desired_capacity": desired_capacity,
|
||||||
|
"min_size": min_size,
|
||||||
|
"max_size": max_size,
|
||||||
|
"metadata": metadata,
|
||||||
|
"timeout": timeout
|
||||||
|
}
|
||||||
|
|
||||||
|
cluster = self.admin_clients("senlin").create_cluster(**attrs)
|
||||||
|
cluster = utils.wait_for_status(
|
||||||
|
cluster,
|
||||||
|
ready_statuses=["ACTIVE"],
|
||||||
|
failure_statuses=["ERROR"],
|
||||||
|
update_resource=self._get_cluster,
|
||||||
|
timeout=CONF.benchmark.senlin_action_timeout)
|
||||||
|
|
||||||
|
return cluster
|
||||||
|
|
||||||
|
def _get_cluster(self, cluster):
|
||||||
|
"""Get cluster details.
|
||||||
|
|
||||||
|
:param cluster: cluster to get
|
||||||
|
|
||||||
|
:returns: object of cluster
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
return self.admin_clients("senlin").get_cluster(cluster.id)
|
||||||
|
except Exception as e:
|
||||||
|
if getattr(e, "code", getattr(e, "http_status", 400)) == 404:
|
||||||
|
raise exceptions.GetResourceNotFound(resource=cluster.id)
|
||||||
|
raise exceptions.GetResourceFailure(resource=cluster.id, err=e)
|
||||||
|
|
||||||
|
@atomic.action_timer("senlin.delete_cluster")
|
||||||
|
def _delete_cluster(self, cluster):
|
||||||
|
"""Delete given cluster.
|
||||||
|
|
||||||
|
Returns after the cluster is successfully deleted.
|
||||||
|
|
||||||
|
:param cluster: cluster object to delete
|
||||||
|
"""
|
||||||
|
self.admin_clients("senlin").delete_cluster(cluster)
|
||||||
|
utils.wait_for_status(
|
||||||
|
cluster,
|
||||||
|
ready_statuses=["DELETED"],
|
||||||
|
failure_statuses=["ERROR"],
|
||||||
|
check_deletion=True,
|
||||||
|
update_resource=self._get_cluster,
|
||||||
|
timeout=CONF.benchmark.senlin_action_timeout)
|
||||||
|
|
||||||
|
@atomic.action_timer("senlin.create_profile")
|
||||||
|
def _create_profile(self, spec, metadata=None):
|
||||||
|
"""Create a new profile from attributes.
|
||||||
|
|
||||||
|
:param spec: spec dictionary used to create profile
|
||||||
|
:param metadata: A set of key value pairs to associate with the
|
||||||
|
profile
|
||||||
|
|
||||||
|
:returns: object of profile created
|
||||||
|
"""
|
||||||
|
attrs = {}
|
||||||
|
attrs["spec"] = spec
|
||||||
|
attrs["name"] = self.generate_random_name()
|
||||||
|
if metadata:
|
||||||
|
attrs["metadata"] = metadata
|
||||||
|
|
||||||
|
return self.admin_clients("senlin").create_profile(**attrs)
|
||||||
|
|
||||||
|
@atomic.action_timer("senlin.delete_profile")
|
||||||
|
def _delete_profile(self, profile):
|
||||||
|
"""Delete given profile.
|
||||||
|
|
||||||
|
Returns after the profile is successfully deleted.
|
||||||
|
|
||||||
|
:param profile: profile object to be deleted
|
||||||
|
"""
|
||||||
|
self.admin_clients("senlin").delete_profile(profile)
|
@ -0,0 +1,34 @@
|
|||||||
|
{
|
||||||
|
"SenlinClusters.create_and_delete_profile_cluster": [
|
||||||
|
{
|
||||||
|
"args": {
|
||||||
|
"profile_spec": {
|
||||||
|
"type": "os.nova.server",
|
||||||
|
"version": "1.0",
|
||||||
|
"properties": {
|
||||||
|
"name": "cirros_server",
|
||||||
|
"flavor": 1,
|
||||||
|
"image": "cirros-0.3.4-x86_64-uec",
|
||||||
|
"networks": [
|
||||||
|
{ "network": "private" }
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"desired_capacity": 3,
|
||||||
|
"min_size": 0,
|
||||||
|
"max_size": 5
|
||||||
|
},
|
||||||
|
"runner": {
|
||||||
|
"type": "constant",
|
||||||
|
"times": 3,
|
||||||
|
"concurrency": 1
|
||||||
|
},
|
||||||
|
"context": {
|
||||||
|
"users": {
|
||||||
|
"tenants": 1,
|
||||||
|
"users_per_tenant": 1
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
---
|
||||||
|
SenlinClusters.create_and_delete_profile_cluster:
|
||||||
|
-
|
||||||
|
args:
|
||||||
|
profile_spec:
|
||||||
|
type: os.nova.server
|
||||||
|
version: "1.0"
|
||||||
|
properties:
|
||||||
|
name: cirros_server
|
||||||
|
flavor: 1
|
||||||
|
image: "cirros-0.3.4-x86_64-uec"
|
||||||
|
networks:
|
||||||
|
- network: private
|
||||||
|
desired_capacity: 3
|
||||||
|
min_size: 0
|
||||||
|
max_size: 5
|
||||||
|
runner:
|
||||||
|
type: "constant"
|
||||||
|
times: 3
|
||||||
|
concurrency: 1
|
||||||
|
context:
|
||||||
|
users:
|
||||||
|
tenants: 1
|
||||||
|
users_per_tenant: 1
|
@ -208,6 +208,17 @@ class Cinder(ResourceManager):
|
|||||||
search_opts={"all_tenants": True})
|
search_opts={"all_tenants": True})
|
||||||
|
|
||||||
|
|
||||||
|
class Senlin(ResourceManager):
|
||||||
|
|
||||||
|
REQUIRED_SERVICE = consts.Service.SENLIN
|
||||||
|
|
||||||
|
def list_clusters(self):
|
||||||
|
return self.client.clusters()
|
||||||
|
|
||||||
|
def list_profiles(self):
|
||||||
|
return self.client.profiles()
|
||||||
|
|
||||||
|
|
||||||
class Watcher(ResourceManager):
|
class Watcher(ResourceManager):
|
||||||
|
|
||||||
REQUIRED_SERVICE = consts.Service.WATCHER
|
REQUIRED_SERVICE = consts.Service.WATCHER
|
||||||
|
@ -756,6 +756,39 @@ class FuelEnvironmentTestCase(test.TestCase):
|
|||||||
self.assertEqual(envs[:-1], fres.list())
|
self.assertEqual(envs[:-1], fres.list())
|
||||||
|
|
||||||
|
|
||||||
|
class SenlinMixinTestCase(test.TestCase):
|
||||||
|
|
||||||
|
def test__manager(self):
|
||||||
|
senlin = resources.SenlinMixin()
|
||||||
|
senlin._service = "senlin"
|
||||||
|
senlin.user = mock.MagicMock()
|
||||||
|
self.assertEqual(senlin.user.senlin.return_value, senlin._manager())
|
||||||
|
|
||||||
|
def test_list(self):
|
||||||
|
senlin = resources.SenlinMixin()
|
||||||
|
senlin._service = "senlin"
|
||||||
|
senlin.user = mock.MagicMock()
|
||||||
|
senlin._resource = "some_resources"
|
||||||
|
|
||||||
|
some_resources = [{"name": "resource1"}, {"name": "resource2"}]
|
||||||
|
senlin.user.senlin().some_resources.return_value = some_resources
|
||||||
|
|
||||||
|
self.assertEqual(some_resources, senlin.list())
|
||||||
|
senlin.user.senlin().some_resources.assert_called_once_with()
|
||||||
|
|
||||||
|
def test_delete(self):
|
||||||
|
senlin = resources.SenlinMixin()
|
||||||
|
senlin._service = "senlin"
|
||||||
|
senlin.user = mock.MagicMock()
|
||||||
|
senlin._resource = "some_resources"
|
||||||
|
senlin.id = "TEST_ID"
|
||||||
|
senlin.user.senlin().delete_some_resource.return_value = None
|
||||||
|
|
||||||
|
senlin.delete()
|
||||||
|
senlin.user.senlin().delete_some_resource.assert_called_once_with(
|
||||||
|
"TEST_ID")
|
||||||
|
|
||||||
|
|
||||||
class WatcherTemplateTestCase(test.TestCase):
|
class WatcherTemplateTestCase(test.TestCase):
|
||||||
|
|
||||||
def test_id(self):
|
def test_id(self):
|
||||||
|
@ -0,0 +1,43 @@
|
|||||||
|
# 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.scenarios.senlin import clusters
|
||||||
|
from tests.unit import test
|
||||||
|
|
||||||
|
|
||||||
|
class SenlinClustersTestCase(test.ScenarioTestCase):
|
||||||
|
|
||||||
|
def test_create_and_delete_cluster(self):
|
||||||
|
profile_spec = {"k1": "v1"}
|
||||||
|
mock_profile = mock.Mock(id="fake_profile_id")
|
||||||
|
mock_cluster = mock.Mock()
|
||||||
|
scenario = clusters.SenlinClusters(self.context)
|
||||||
|
scenario._create_cluster = mock.Mock(return_value=mock_cluster)
|
||||||
|
scenario._create_profile = mock.Mock(return_value=mock_profile)
|
||||||
|
scenario._delete_cluster = mock.Mock()
|
||||||
|
scenario._delete_profile = mock.Mock()
|
||||||
|
|
||||||
|
scenario.create_and_delete_profile_cluster(profile_spec,
|
||||||
|
desired_capacity=1,
|
||||||
|
min_size=0,
|
||||||
|
max_size=3,
|
||||||
|
timeout=60,
|
||||||
|
metadata={"k2": "v2"})
|
||||||
|
|
||||||
|
scenario._create_profile.assert_called_once_with(profile_spec)
|
||||||
|
scenario._create_cluster.assert_called_once_with("fake_profile_id",
|
||||||
|
1, 0, 3, 60,
|
||||||
|
{"k2": "v2"})
|
||||||
|
scenario._delete_cluster.assert_called_once_with(mock_cluster)
|
||||||
|
scenario._delete_profile.assert_called_once_with(mock_profile)
|
152
tests/unit/plugins/openstack/scenarios/senlin/test_utils.py
Normal file
152
tests/unit/plugins/openstack/scenarios/senlin/test_utils.py
Normal file
@ -0,0 +1,152 @@
|
|||||||
|
# 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 oslo_config import cfg
|
||||||
|
|
||||||
|
from rally import exceptions
|
||||||
|
from rally.plugins.openstack.scenarios.senlin import utils
|
||||||
|
from tests.unit import test
|
||||||
|
|
||||||
|
SENLIN_UTILS = "rally.plugins.openstack.scenarios.senlin.utils."
|
||||||
|
CONF = cfg.CONF
|
||||||
|
|
||||||
|
|
||||||
|
class SenlinScenarioTestCase(test.ScenarioTestCase):
|
||||||
|
|
||||||
|
def test_list_cluster(self):
|
||||||
|
fake_cluster_list = ["cluster1", "cluster2"]
|
||||||
|
self.admin_clients("senlin").clusters.return_value = fake_cluster_list
|
||||||
|
scenario = utils.SenlinScenario(self.context)
|
||||||
|
result = scenario._list_clusters()
|
||||||
|
|
||||||
|
self.assertEqual(list(fake_cluster_list), result)
|
||||||
|
self.admin_clients("senlin").clusters.assert_called_once_with()
|
||||||
|
|
||||||
|
def test_list_cluster_with_queries(self):
|
||||||
|
fake_cluster_list = ["cluster1", "cluster2"]
|
||||||
|
self.admin_clients("senlin").clusters.return_value = fake_cluster_list
|
||||||
|
scenario = utils.SenlinScenario(self.context)
|
||||||
|
result = scenario._list_clusters(status="ACTIVE")
|
||||||
|
|
||||||
|
self.assertEqual(list(fake_cluster_list), result)
|
||||||
|
self.admin_clients("senlin").clusters.assert_called_once_with(
|
||||||
|
status="ACTIVE")
|
||||||
|
|
||||||
|
@mock.patch(SENLIN_UTILS + "SenlinScenario.generate_random_name",
|
||||||
|
return_value="test_cluster")
|
||||||
|
def test_create_cluster(self, mock_generate_random_name):
|
||||||
|
fake_cluster = mock.Mock(id="fake_cluster_id")
|
||||||
|
res_cluster = mock.Mock()
|
||||||
|
self.admin_clients("senlin").create_cluster.return_value = fake_cluster
|
||||||
|
self.mock_wait_for_status.mock.return_value = res_cluster
|
||||||
|
scenario = utils.SenlinScenario(self.context)
|
||||||
|
result = scenario._create_cluster("fake_profile_id",
|
||||||
|
desired_capacity=1,
|
||||||
|
min_size=0,
|
||||||
|
max_size=3,
|
||||||
|
metadata={"k1": "v1"},
|
||||||
|
timeout=60)
|
||||||
|
|
||||||
|
self.assertEqual(res_cluster, result)
|
||||||
|
self.admin_clients("senlin").create_cluster.assert_called_once_with(
|
||||||
|
profile_id="fake_profile_id", name="test_cluster",
|
||||||
|
desired_capacity=1, min_size=0, max_size=3, metadata={"k1": "v1"},
|
||||||
|
timeout=60)
|
||||||
|
self.mock_wait_for_status.mock.assert_called_once_with(
|
||||||
|
fake_cluster, ready_statuses=["ACTIVE"],
|
||||||
|
failure_statuses=["ERROR"],
|
||||||
|
update_resource=scenario._get_cluster,
|
||||||
|
timeout=CONF.benchmark.senlin_action_timeout)
|
||||||
|
mock_generate_random_name.assert_called_once_with()
|
||||||
|
self._test_atomic_action_timer(scenario.atomic_actions(),
|
||||||
|
"senlin.create_cluster")
|
||||||
|
|
||||||
|
def test_get_cluster(self):
|
||||||
|
fake_cluster = mock.Mock(id="fake_cluster_id")
|
||||||
|
scenario = utils.SenlinScenario(context=self.context)
|
||||||
|
scenario._get_cluster(fake_cluster)
|
||||||
|
|
||||||
|
self.admin_clients("senlin").get_cluster.assert_called_once_with(
|
||||||
|
"fake_cluster_id")
|
||||||
|
|
||||||
|
def test_get_cluster_notfound(self):
|
||||||
|
fake_cluster = mock.Mock(id="fake_cluster_id")
|
||||||
|
ex = Exception()
|
||||||
|
ex.code = 404
|
||||||
|
self.admin_clients("senlin").get_cluster.side_effect = ex
|
||||||
|
scenario = utils.SenlinScenario(context=self.context)
|
||||||
|
|
||||||
|
self.assertRaises(exceptions.GetResourceNotFound,
|
||||||
|
scenario._get_cluster,
|
||||||
|
fake_cluster)
|
||||||
|
self.admin_clients("senlin").get_cluster.assert_called_once_with(
|
||||||
|
"fake_cluster_id")
|
||||||
|
|
||||||
|
def test_get_cluster_failed(self):
|
||||||
|
fake_cluster = mock.Mock(id="fake_cluster_id")
|
||||||
|
ex = Exception()
|
||||||
|
ex.code = 500
|
||||||
|
self.admin_clients("senlin").get_cluster.side_effect = ex
|
||||||
|
scenario = utils.SenlinScenario(context=self.context)
|
||||||
|
|
||||||
|
self.assertRaises(exceptions.GetResourceFailure,
|
||||||
|
scenario._get_cluster,
|
||||||
|
fake_cluster)
|
||||||
|
self.admin_clients("senlin").get_cluster.assert_called_once_with(
|
||||||
|
"fake_cluster_id")
|
||||||
|
|
||||||
|
def test_delete_cluster(self):
|
||||||
|
fake_cluster = mock.Mock()
|
||||||
|
scenario = utils.SenlinScenario(context=self.context)
|
||||||
|
scenario._delete_cluster(fake_cluster)
|
||||||
|
|
||||||
|
self.admin_clients("senlin").delete_cluster.assert_called_once_with(
|
||||||
|
fake_cluster)
|
||||||
|
self.mock_wait_for_status.mock.assert_called_once_with(
|
||||||
|
fake_cluster, ready_statuses=["DELETED"],
|
||||||
|
failure_statuses=["ERROR"], check_deletion=True,
|
||||||
|
update_resource=scenario._get_cluster,
|
||||||
|
timeout=CONF.benchmark.senlin_action_timeout)
|
||||||
|
self._test_atomic_action_timer(scenario.atomic_actions(),
|
||||||
|
"senlin.delete_cluster")
|
||||||
|
|
||||||
|
@mock.patch(SENLIN_UTILS + "SenlinScenario.generate_random_name",
|
||||||
|
return_value="test_profile")
|
||||||
|
def test_create_profile(self, mock_generate_random_name):
|
||||||
|
test_spec = {
|
||||||
|
"version": "1.0",
|
||||||
|
"type": "test_type",
|
||||||
|
"properties": {
|
||||||
|
"key1": "value1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
scenario = utils.SenlinScenario(self.context)
|
||||||
|
result = scenario._create_profile(test_spec, metadata={"k2": "v2"})
|
||||||
|
|
||||||
|
self.assertEqual(
|
||||||
|
self.admin_clients("senlin").create_profile.return_value, result)
|
||||||
|
self.admin_clients("senlin").create_profile.assert_called_once_with(
|
||||||
|
spec=test_spec, name="test_profile", metadata={"k2": "v2"})
|
||||||
|
mock_generate_random_name.assert_called_once_with()
|
||||||
|
self._test_atomic_action_timer(scenario.atomic_actions(),
|
||||||
|
"senlin.create_profile")
|
||||||
|
|
||||||
|
def test_delete_profile(self):
|
||||||
|
fake_profile = mock.Mock()
|
||||||
|
scenario = utils.SenlinScenario(context=self.context)
|
||||||
|
scenario._delete_profile(fake_profile)
|
||||||
|
|
||||||
|
self.admin_clients("senlin").delete_profile.assert_called_once_with(
|
||||||
|
fake_profile)
|
||||||
|
self._test_atomic_action_timer(scenario.atomic_actions(),
|
||||||
|
"senlin.delete_profile")
|
Loading…
x
Reference in New Issue
Block a user