Add Nova lock and unlock scenario

Add scenario to boot a server, lock it, unlock it, and delete
it.

Change-Id: Ifd29211914ff264738e1ff0371629d33b5f55f36
This commit is contained in:
Chris St. Pierre 2015-04-17 14:27:18 -05:00
parent cadc3d0d3d
commit 889f2e9b17
10 changed files with 177 additions and 2 deletions

View File

@ -1278,6 +1278,25 @@
failure_rate:
max: 0
NovaServers.boot_lock_unlock_and_delete:
-
args:
flavor:
name: "m1.tiny"
image:
name: {{image_name}}
runner:
type: "constant"
times: 4
concurrency: 4
context:
users:
tenants: 2
users_per_tenant: 1
sla:
failure_rate:
max: 0
NovaServers.boot_server_from_volume_and_delete:
-
args:

View File

@ -62,7 +62,10 @@ _nova_order = get_order(200)
@base.resource("nova", "servers", order=next(_nova_order))
class NovaServer(base.ResourceManager):
pass
def delete(self):
if getattr(self.raw_resource, "OS-EXT-STS:locked", False):
self.raw_resource.unlock()
super(NovaServer, self).delete()
@base.resource("nova", "keypairs", order=next(_nova_order))

View File

@ -173,6 +173,37 @@ class NovaServers(utils.NovaScenario,
action()
self._delete_server(server, force=force_delete)
@types.set(image=types.ImageResourceType,
flavor=types.FlavorResourceType)
@validation.image_valid_on_flavor("flavor", "image")
@validation.required_services(consts.Service.NOVA)
@validation.required_openstack(users=True)
@base.scenario(context={"cleanup": ["nova"]})
def boot_lock_unlock_and_delete(self, image, flavor,
min_sleep=0, max_sleep=0,
force_delete=False,
**kwargs):
"""Boot a server, lock it, then unlock and delete it.
Optional 'min_sleep' and 'max_sleep' parameters allow the
scenario to simulate a pause between locking and unlocking the
server (of random duration from min_sleep to max_sleep).
:param image: image to be used to boot an instance
:param flavor: flavor to be used to boot an instance
:param min_sleep: Minimum sleep time between locking and unlocking
in seconds
:param max_sleep: Maximum sleep time between locking and unlocking
in seconds
:param force_delete: True if force_delete should be used
:param kwargs: Optional additional arguments for server creation
"""
server = self._boot_server(image, flavor, **kwargs)
self._lock_server(server)
self.sleep_between(min_sleep, max_sleep)
self._unlock_server(server)
self._delete_server(server, force=force_delete)
@types.set(image=types.ImageResourceType,
flavor=types.FlavorResourceType)
@validation.image_valid_on_flavor("flavor", "image")

View File

@ -747,3 +747,19 @@ class NovaScenario(base.Scenario):
def _list_hypervisors(self, detailed=True):
"""List hypervisors."""
return self.admin_clients("nova").hypervisors.list(detailed)
@base.atomic_action_timer("nova.lock_server")
def _lock_server(self, server):
"""Lock the given server.
:param server: Server to lock
"""
server.lock()
@base.atomic_action_timer("nova.unlock_server")
def _unlock_server(self, server):
"""Unlock the given server.
:param server: Server to unlock
"""
server.unlock()

View File

@ -0,0 +1,25 @@
{
"NovaServers.boot_lock_unlock_and_delete": [
{
"args": {
"flavor": {
"name": "m1.tiny"
},
"image": {
"name": "cirros-0.3.2-x86_64-uec"
}
},
"runner": {
"type": "constant",
"times": 10,
"concurrency": 2
},
"context": {
"users": {
"tenants": 1,
"users_per_tenant": 1
}
}
}
]
}

View File

@ -0,0 +1,16 @@
---
NovaServers.boot_lock_unlock_and_delete:
-
args:
flavor:
name: "m1.tiny"
image:
name: "cirros-0.3.2-x86_64-uec"
runner:
type: "constant"
times: 10
concurrency: 2
context:
users:
tenants: 1
users_per_tenant: 1

View File

@ -82,6 +82,29 @@ class QuotaMixinTestCase(test.TestCase):
self.assertEqual([quota.tenant_uuid], quota.list())
class NovaServerTestCase(test.TestCase):
def test_delete(self):
server = resources.NovaServer()
server.raw_resource = mock.Mock()
server._manager = mock.Mock()
server.delete()
server._manager.return_value.delete.assert_called_once_with(
server.raw_resource.id)
def test_delete_locked(self):
server = resources.NovaServer()
server.raw_resource = mock.Mock()
setattr(server.raw_resource, "OS-EXT-STS:locked", True)
server._manager = mock.Mock()
server.delete()
server.raw_resource.unlock.assert_called_once_with()
server._manager.return_value.delete.assert_called_once_with(
server.raw_resource.id)
class NovaSecurityGroupTestCase(test.TestCase):
@mock.patch("%s.base.ResourceManager._manager" % BASE)

View File

@ -106,6 +106,27 @@ class NovaServersTestCase(test.TestCase):
scenario._delete_server.assert_called_once_with(fake_server,
force=False)
def test_boot_lock_unlock_and_delete(self):
server = fakes.FakeServer()
image = fakes.FakeImage()
flavor = fakes.FakeFlavor()
scenario = servers.NovaServers()
scenario._boot_server = mock.Mock(return_value=server)
scenario._lock_server = mock.Mock(side_effect=lambda s: s.lock())
scenario._unlock_server = mock.Mock(side_effect=lambda s: s.unlock())
scenario._delete_server = mock.Mock(
side_effect=lambda s, **kwargs:
self.assertFalse(getattr(s, "OS-EXT-STS:locked", False)))
scenario.boot_lock_unlock_and_delete(image, flavor, fakearg="fakearg")
scenario._boot_server.assert_called_once_with(image, flavor,
fakearg="fakearg")
scenario._lock_server.assert_called_once_with(server)
scenario._unlock_server.assert_called_once_with(server)
scenario._delete_server.assert_called_once_with(server, force=False)
def test_validate_actions(self):
actions = [{"hardd_reboot": 6}]
scenario = servers.NovaServers()

View File

@ -757,3 +757,19 @@ class NovaScenarioTestCase(test.TestCase):
mock_clients("nova").hypervisors.list.assert_called_once_with(False)
self._test_atomic_action_timer(nova_scenario.atomic_actions(),
"nova.list_hypervisors")
def test__lock_server(self):
server = mock.Mock()
nova_scenario = utils.NovaScenario()
nova_scenario._lock_server(server)
server.lock.assert_called_once_with()
self._test_atomic_action_timer(nova_scenario.atomic_actions(),
"nova.lock_server")
def test__unlock_server(self):
server = mock.Mock()
nova_scenario = utils.NovaScenario()
nova_scenario._unlock_server(server)
server.unlock.assert_called_once_with()
self._test_atomic_action_timer(nova_scenario.atomic_actions(),
"nova.unlock_server")

View File

@ -105,10 +105,15 @@ class FakeResource(object):
class FakeServer(FakeResource):
def suspend(self):
self.status = "SUSPENDED"
def lock(self):
setattr(self, "OS-EXT-STS:locked", True)
def unlock(self):
setattr(self, "OS-EXT-STS:locked", False)
class FakeFailedServer(FakeResource):