Add Designate API V2 support - part 1

This commit adds basic support for Rally > Designate V2 with the RecordSet and
Zone resources. More functionality will be added later.

Change-Id: I42456a404a8c8733103228f3b1e83215da9ae641
This commit is contained in:
Endre Karlson 2015-11-24 13:43:31 +01:00
parent 2b120d3022
commit cb09982b96
15 changed files with 436 additions and 13 deletions

View File

@ -115,3 +115,44 @@
failure_rate:
max: 0
DesignateBasic.create_and_list_zones:
-
runner:
type: "constant"
times: 10
concurrency: 1
context:
users:
tenants: 2
users_per_tenant: 2
sla:
failure_rate:
max: 0
DesignateBasic.create_and_delete_zone:
-
runner:
type: "constant"
times: 10
concurrency: 2
context:
users:
tenants: 2
users_per_tenant: 2
sla:
failure_rate:
max: 0
DesignateBasic.list_zones:
-
runner:
type: "constant"
times: 4
concurrency: 2
context:
users:
tenants: 2
users_per_tenant: 2
sla:
failure_rate:
max: 0

View File

@ -462,14 +462,27 @@ class ZaqarQueues(SynchronizedDeletion, base.ResourceManager):
_designate_order = get_order(900)
@base.resource("designate", "domains", order=next(_designate_order))
class Designate(SynchronizedDeletion, base.ResourceManager):
class DesignateResource(SynchronizedDeletion, base.ResourceManager):
def _manager(self):
# NOTE: service name contains version, so we should split them
service_name, version = self._service.split("_v")
return getattr(getattr(self.user, service_name)(version),
self._resource)
@base.resource("designate_v1", "domains", order=next(_designate_order))
class DesignateDomain(DesignateResource):
pass
@base.resource("designate", "servers", order=next(_designate_order),
@base.resource("designate_v2", "zones", order=next(_designate_order))
class DesignateZones(DesignateResource):
pass
@base.resource("designate_v1", "servers", order=next(_designate_order),
admin_required=True, perform_for_admin_only=True)
class DesignateServer(SynchronizedDeletion, base.ResourceManager):
class DesignateServer(DesignateResource):
pass

View File

@ -26,7 +26,7 @@ class DesignateBasic(utils.DesignateScenario):
@validation.required_services(consts.Service.DESIGNATE)
@validation.required_openstack(users=True)
@scenario.configure(context={"cleanup": ["designate"]})
@scenario.configure(context={"cleanup": ["designate_v1"]})
def create_and_list_domains(self):
"""Create a domain and list all domains.
@ -43,7 +43,7 @@ class DesignateBasic(utils.DesignateScenario):
@validation.required_services(consts.Service.DESIGNATE)
@validation.required_openstack(users=True)
@scenario.configure(context={"cleanup": ["designate"]})
@scenario.configure(context={"cleanup": ["designate_v1"]})
def list_domains(self):
"""List Designate domains.
@ -59,7 +59,7 @@ class DesignateBasic(utils.DesignateScenario):
@validation.required_services(consts.Service.DESIGNATE)
@validation.required_openstack(users=True)
@scenario.configure(context={"cleanup": ["designate"]})
@scenario.configure(context={"cleanup": ["designate_v1"]})
def create_and_delete_domain(self):
"""Create and then delete a domain.
@ -71,7 +71,7 @@ class DesignateBasic(utils.DesignateScenario):
@validation.required_services(consts.Service.DESIGNATE)
@validation.required_openstack(users=True)
@scenario.configure(context={"cleanup": ["designate"]})
@scenario.configure(context={"cleanup": ["designate_v1"]})
def create_and_delete_records(self, records_per_domain=5):
"""Create and then delete records.
@ -98,7 +98,7 @@ class DesignateBasic(utils.DesignateScenario):
@validation.required_services(consts.Service.DESIGNATE)
@validation.required_openstack(users=True)
@scenario.configure(context={"cleanup": ["designate"]})
@scenario.configure(context={"cleanup": ["designate_v1"]})
def list_records(self, domain_id):
"""List Designate records.
@ -116,7 +116,7 @@ class DesignateBasic(utils.DesignateScenario):
@validation.required_services(consts.Service.DESIGNATE)
@validation.required_openstack(users=True)
@scenario.configure(context={"cleanup": ["designate"]})
@scenario.configure(context={"cleanup": ["designate_v1"]})
def create_and_list_records(self, records_per_domain=5):
"""Create and then list records.
@ -139,7 +139,7 @@ class DesignateBasic(utils.DesignateScenario):
@validation.required_services(consts.Service.DESIGNATE)
@validation.required_openstack(admin=True)
@scenario.configure(context={"cleanup": ["designate"]})
@scenario.configure(context={"cleanup": ["designate_v1"]})
def create_and_list_servers(self):
"""Create a Designate server and list all servers.
@ -154,7 +154,7 @@ class DesignateBasic(utils.DesignateScenario):
@validation.required_services(consts.Service.DESIGNATE)
@validation.required_openstack(admin=True)
@scenario.configure(context={"cleanup": ["designate"]})
@scenario.configure(context={"cleanup": ["designate_v1"]})
def create_and_delete_server(self):
"""Create and then delete a server.
@ -166,7 +166,7 @@ class DesignateBasic(utils.DesignateScenario):
@validation.required_services(consts.Service.DESIGNATE)
@validation.required_openstack(admin=True)
@scenario.configure(context={"cleanup": ["designate"]})
@scenario.configure(context={"cleanup": ["designate_v1"]})
def list_servers(self):
"""List Designate servers.
@ -174,3 +174,59 @@ class DesignateBasic(utils.DesignateScenario):
all the servers.
"""
self._list_servers()
# NOTE: API V2
@validation.required_services(consts.Service.DESIGNATE)
@validation.required_openstack(users=True)
@scenario.configure(context={"cleanup": ["designate_v2"]})
def create_and_list_zones(self):
"""Create a zone and list all zones.
Measure the "openstack zone list" command performance.
If you have only 1 user in your context, you will
add 1 zone on every iteration. So you will have more
and more zone and will be able to measure the
performance of the "openstack zone list" command depending on
the number of zones owned by users.
"""
self._create_zone()
self._list_zones()
@validation.required_services(consts.Service.DESIGNATE)
@validation.required_openstack(users=True)
@scenario.configure(context={"cleanup": ["designate_v2"]})
def list_zones(self):
"""List Designate zones.
This simple scenario tests the openstack zone list command by listing
all the zones.
"""
self._list_zones()
@validation.required_services(consts.Service.DESIGNATE)
@validation.required_openstack(users=True)
@scenario.configure(context={"cleanup": ["designate_v2"]})
def create_and_delete_zone(self):
"""Create and then delete a zone.
Measure the performance of creating and deleting zones
with different level of load.
"""
zone = self._create_zone()
self._delete_zone(zone["id"])
@validation.required_services(consts.Service.DESIGNATE)
@validation.required_openstack(users=True)
@scenario.configure(context={"cleanup": ["designate_v2"]})
def list_recordsets(self, zone_id):
"""List Designate recordsets.
This simple scenario tests the openstack recordset list command by
listing all the recordsets in a zone.
:param zone_id: Zone ID
"""
self._list_recordsets(zone_id)

View File

@ -115,3 +115,64 @@ class DesignateScenario(scenario.OpenStackScenario):
:param server_id: unicode server ID
"""
self.admin_clients("designate").servers.delete(server_id)
# NOTE: API V2
@atomic.action_timer("designate.create_zone")
def _create_zone(self, name=None, type_=None, email=None, description=None,
ttl=None):
"""Create zone.
:param name: Zone name
:param type_: Zone type, PRIMARY or SECONDARY
:param email: Zone owner email
:param description: Zone description
:param ttl: Zone ttl - Time to live in seconds
:returns: designate zone dict
"""
type_ = type_ or "PRIMARY"
if type_ == "PRIMARY":
email = email or "root@random.name"
# Name is only useful to be random for PRIMARY
name = name or "%s.name." % self.generate_random_name()
return self.clients("designate", version="2").zones.create(
name=name,
type_=type_,
email=email,
description=description,
ttl=ttl
)
@atomic.action_timer("designate.list_zones")
def _list_zones(self, criterion=None, marker=None, limit=None):
"""Return user zone list.
:param criterion: API Criterion to filter by
:param marker: UUID marker of the item to start the page from
:param limit: How many items to return in the page.
: returns: list of designate zones
"""
return self.clients("designate", version="2").zones.list()
@atomic.action_timer("designate.delete_zone")
def _delete_zone(self, zone_id):
"""Delete designate zone.
:param zone_id: Zone ID
"""
self.clients("designate", version="2").zones.delete(zone_id)
@atomic.action_timer("designate.list_recordsets")
def _list_recordsets(self, zone_id, criterion=None, marker=None,
limit=None):
"""List zone recordsets.
:param zone_id: Zone ID
:param criterion: API Criterion to filter by
:param marker: UUID marker of the item to start the page from
:param limit: How many items to return in the page.
:returns: zone recordsets list
"""
return self.clients("designate", version="2").recordsets.list(
zone_id, criterion=criterion, marker=marker, limit=limit)

View File

@ -0,0 +1,25 @@
{
"DesignateBasic.create_and_delete_zone": [
{
"runner": {
"type": "constant",
"times": 10,
"concurrency": 10
},
"context": {
"quotas": {
"designate": {
"domains": 100,
"domain_recordsets": 500,
"domain_records": 2000,
"recordset_records": 2000
}
},
"users": {
"tenants": 2,
"users_per_tenant": 2
}
}
}
]
}

View File

@ -0,0 +1,17 @@
---
DesignateBasic.create_and_delete_zone:
-
runner:
type: "constant"
times: 10
concurrency: 10
context:
quotas:
designate:
domains: 100
domain_recordsets: 500
domain_records: 2000
recordset_records: 2000
users:
tenants: 2
users_per_tenant: 2

View File

@ -0,0 +1,25 @@
{
"DesignateBasic.create_and_list_zones": [
{
"runner": {
"type": "constant",
"times": 10,
"concurrency": 10
},
"context": {
"quotas": {
"designate": {
"domains": 100,
"domain_recordsets": 500,
"domain_records": 2000,
"recordset_records": 2000
}
},
"users": {
"tenants": 2,
"users_per_tenant": 2
}
}
}
]
}

View File

@ -0,0 +1,17 @@
---
DesignateBasic.create_and_list_zones:
-
runner:
type: "constant"
times: 10
concurrency: 10
context:
quotas:
designate:
domains: 100
domain_recordsets: 500
domain_records: 2000
recordset_records: 2000
users:
tenants: 2
users_per_tenant: 2

View File

@ -0,0 +1,20 @@
{
"DesignateBasic.list_recordsets": [
{
"args": {
"zone_id": "<uuid>"
},
"runner": {
"type": "constant",
"times": 3,
"concurrency": 2
},
"context": {
"users": {
"tenants": 2,
"users_per_tenant": 2
}
}
}
]
}

View File

@ -0,0 +1,13 @@
---
DesignateBasic.list_recordsets:
-
args:
zone_id: <uuid>
runner:
type: "constant"
times: 3
concurrency: 2
context:
users:
tenants: 2
users_per_tenant: 2

View File

@ -0,0 +1,17 @@
{
"DesignateBasic.list_zones": [
{
"runner": {
"type": "constant",
"times": 3,
"concurrency": 2
},
"context": {
"users": {
"tenants": 2,
"users_per_tenant": 2
}
}
}
]
}

View File

@ -0,0 +1,11 @@
---
DesignateBasic.list_zones:
-
runner:
type: "constant"
times: 3
concurrency: 2
context:
users:
tenants: 2
users_per_tenant: 2

View File

@ -155,3 +155,47 @@ class DesignateBasicTestCase(test.ScenarioTestCase):
# Default options
scenario.list_servers()
mock_designate_basic__list_servers.assert_called_once_with()
# NOTE: API V2
@mock.patch(DESIGNATE_BASIC + "._list_zones")
@mock.patch(DESIGNATE_BASIC + "._create_zone")
def test_create_and_list_zones(self, mock_designate_basic__create_zone,
mock_designate_basic__list_zones):
scenario = basic.DesignateBasic(self.context)
# Default options
scenario.create_and_list_zones()
mock_designate_basic__create_zone.assert_called_once_with()
mock_designate_basic__list_zones.assert_called_once_with()
@mock.patch(DESIGNATE_BASIC + "._delete_zone")
@mock.patch(DESIGNATE_BASIC + "._create_zone")
def test_create_and_delete_zone(
self, mock_designate_basic__create_zone,
mock_designate_basic__delete_zone):
scenario = basic.DesignateBasic(self.context)
mock_designate_basic__create_zone.return_value = {"id": "123"}
# Default options
scenario.create_and_delete_zone()
mock_designate_basic__create_zone.assert_called_once_with()
mock_designate_basic__delete_zone.assert_called_once_with("123")
@mock.patch(DESIGNATE_BASIC + "._list_zones")
def test_list_zones(self, mock_designate_basic__list_zones):
scenario = basic.DesignateBasic(self.context)
# Default options
scenario.list_zones()
mock_designate_basic__list_zones.assert_called_once_with()
@mock.patch(DESIGNATE_BASIC + "._list_recordsets")
def test_list_recordsets(self, mock_designate_basic__list_recordsets):
scenario = basic.DesignateBasic(self.context)
# Default options
scenario.list_recordsets("123")
mock_designate_basic__list_recordsets.assert_called_once_with("123")

View File

@ -29,8 +29,11 @@ class DesignateScenarioTestCase(test.ScenarioTestCase):
def setUp(self):
super(DesignateScenarioTestCase, self).setUp()
self.domain = mock.Mock()
self.zone = mock.Mock()
self.server = mock.Mock()
self.client = self.clients("designate", version="2")
@ddt.data(
{},
{"email": "root@zone.name"})
@ -147,3 +150,63 @@ class DesignateScenarioTestCase(test.ScenarioTestCase):
"foo_id")
self._test_atomic_action_timer(scenario.atomic_actions(),
"designate.delete_server")
# NOTE: API V2
@ddt.data(
{},
{"email": "root@zone.name"},
{"name": "example.name."},
{
"email": "root@zone.name",
"name": "example.name."
})
def test_create_zone(self, zone_data):
scenario = utils.DesignateScenario()
random_name = "foo"
scenario = utils.DesignateScenario(context=self.context)
scenario.generate_random_name = mock.Mock(return_value=random_name)
self.client.zones.create.return_value = self.zone
expected = {
"email": "root@random.name",
"name": "%s.name." % random_name,
"type_": "PRIMARY"
}
expected.update(zone_data)
# Check that the defaults / randoms are used if nothing is specified
zone = scenario._create_zone(**zone_data)
self.client.zones.create.assert_called_once_with(
description=None,
ttl=None,
**expected)
self.assertEqual(self.zone, zone)
self._test_atomic_action_timer(scenario.atomic_actions(),
"designate.create_zone")
def test_list_zones(self):
scenario = utils.DesignateScenario(context=self.context)
return_zones_list = scenario._list_zones()
self.assertEqual(self.client.zones.list.return_value,
return_zones_list)
self._test_atomic_action_timer(scenario.atomic_actions(),
"designate.list_zones")
def test_delete_zone(self):
scenario = utils.DesignateScenario(context=self.context)
zone = scenario._create_zone()
scenario._delete_zone(zone["id"])
self._test_atomic_action_timer(scenario.atomic_actions(),
"designate.delete_zone")
def test_list_recordsets(self):
scenario = utils.DesignateScenario(context=self.context)
return_recordsets_list = scenario._list_recordsets("123")
self.assertEqual(
self.client.recordsets.list.return_value,
return_recordsets_list)
self._test_atomic_action_timer(scenario.atomic_actions(),
"designate.list_recordsets")