Add resume support to Instance
Change-Id: Id02c74243ff5fcd67ec8f6200ee7969b34f2faa1 blueprint: stack-suspend-resume
This commit is contained in:
parent
84d71d6342
commit
762605f572
@ -348,16 +348,20 @@ class Instance(resource.Resource):
|
||||
if server is not None:
|
||||
self.resource_id_set(server.id)
|
||||
|
||||
return server, scheduler.TaskRunner(self._attach_volumes_task())
|
||||
|
||||
def _attach_volumes_task(self):
|
||||
attach_tasks = (volume.VolumeAttachTask(self.stack,
|
||||
self.resource_id,
|
||||
volume_id,
|
||||
device)
|
||||
for volume_id, device in self.volumes())
|
||||
attach_volumes_task = scheduler.PollingTaskGroup(attach_tasks)
|
||||
|
||||
return server, scheduler.TaskRunner(attach_volumes_task)
|
||||
return scheduler.PollingTaskGroup(attach_tasks)
|
||||
|
||||
def check_create_complete(self, cookie):
|
||||
return self._check_active(cookie)
|
||||
|
||||
def _check_active(self, cookie):
|
||||
server, volume_attach = cookie
|
||||
|
||||
if not volume_attach.started():
|
||||
@ -563,6 +567,29 @@ class Instance(resource.Resource):
|
||||
else:
|
||||
return volumes_runner.step()
|
||||
|
||||
def handle_resume(self):
|
||||
'''
|
||||
Resume an instance - note we do not wait for the ACTIVE state,
|
||||
this is polled for by check_resume_complete in a similar way to the
|
||||
create logic so we can take advantage of coroutines
|
||||
'''
|
||||
if self.resource_id is None:
|
||||
raise exception.Error(_('Cannot resume %s, resource_id not set') %
|
||||
self.name)
|
||||
|
||||
try:
|
||||
server = self.nova().servers.get(self.resource_id)
|
||||
except clients.novaclient.exceptions.NotFound:
|
||||
raise exception.NotFound(_('Failed to find instance %s') %
|
||||
self.resource_id)
|
||||
else:
|
||||
logger.debug("resuming instance %s" % self.resource_id)
|
||||
server.resume()
|
||||
return server, scheduler.TaskRunner(self._attach_volumes_task())
|
||||
|
||||
def check_resume_complete(self, cookie):
|
||||
return self._check_active(cookie)
|
||||
|
||||
|
||||
def resource_mapping():
|
||||
return {
|
||||
|
@ -308,6 +308,28 @@ class instancesTest(HeatTestCase):
|
||||
|
||||
self.m.VerifyAll()
|
||||
|
||||
def test_instance_status_resume_immediate(self):
|
||||
return_server = self.fc.servers.list()[1]
|
||||
instance = self._create_test_instance(return_server,
|
||||
'test_instance_resume')
|
||||
|
||||
instance.resource_id = 1234
|
||||
self.m.ReplayAll()
|
||||
|
||||
# Override the get_servers_1234 handler status to SUSPENDED
|
||||
d = {'server': self.fc.client.get_servers_detail()[1]['servers'][0]}
|
||||
d['server']['status'] = 'ACTIVE'
|
||||
self.m.StubOutWithMock(self.fc.client, 'get_servers_1234')
|
||||
get = self.fc.client.get_servers_1234
|
||||
get().AndReturn((200, d))
|
||||
mox.Replay(get)
|
||||
instance.state_set(instance.SUSPEND, instance.COMPLETE)
|
||||
|
||||
scheduler.TaskRunner(instance.resume)()
|
||||
self.assertEqual(instance.state, (instance.RESUME, instance.COMPLETE))
|
||||
|
||||
self.m.VerifyAll()
|
||||
|
||||
def test_instance_status_suspend_wait(self):
|
||||
return_server = self.fc.servers.list()[1]
|
||||
instance = self._create_test_instance(return_server,
|
||||
@ -336,6 +358,36 @@ class instancesTest(HeatTestCase):
|
||||
|
||||
self.m.VerifyAll()
|
||||
|
||||
def test_instance_status_resume_wait(self):
|
||||
return_server = self.fc.servers.list()[1]
|
||||
instance = self._create_test_instance(return_server,
|
||||
'test_instance_resume')
|
||||
|
||||
instance.resource_id = 1234
|
||||
self.m.ReplayAll()
|
||||
|
||||
# Override the get_servers_1234 handler status to ACTIVE, but
|
||||
# return the SUSPENDED state first (twice, so we sleep)
|
||||
d1 = {'server': self.fc.client.get_servers_detail()[1]['servers'][0]}
|
||||
d2 = copy.deepcopy(d1)
|
||||
d1['server']['status'] = 'SUSPENDED'
|
||||
d2['server']['status'] = 'ACTIVE'
|
||||
self.m.StubOutWithMock(self.fc.client, 'get_servers_1234')
|
||||
get = self.fc.client.get_servers_1234
|
||||
get().AndReturn((200, d1))
|
||||
get().AndReturn((200, d1))
|
||||
self.m.StubOutWithMock(scheduler.TaskRunner, '_sleep')
|
||||
scheduler.TaskRunner._sleep(mox.IsA(int)).AndReturn(None)
|
||||
get().AndReturn((200, d2))
|
||||
self.m.ReplayAll()
|
||||
|
||||
instance.state_set(instance.SUSPEND, instance.COMPLETE)
|
||||
|
||||
scheduler.TaskRunner(instance.resume)()
|
||||
self.assertEqual(instance.state, (instance.RESUME, instance.COMPLETE))
|
||||
|
||||
self.m.VerifyAll()
|
||||
|
||||
def test_instance_suspend_volumes_step(self):
|
||||
return_server = self.fc.servers.list()[1]
|
||||
instance = self._create_test_instance(return_server,
|
||||
@ -365,6 +417,40 @@ class instancesTest(HeatTestCase):
|
||||
|
||||
self.m.VerifyAll()
|
||||
|
||||
def test_instance_resume_volumes_step(self):
|
||||
return_server = self.fc.servers.list()[1]
|
||||
instance = self._create_test_instance(return_server,
|
||||
'test_instance_resume')
|
||||
|
||||
instance.resource_id = 1234
|
||||
self.m.ReplayAll()
|
||||
|
||||
# Override the get_servers_1234 handler status to ACTIVE
|
||||
d = {'server': self.fc.client.get_servers_detail()[1]['servers'][0]}
|
||||
d['server']['status'] = 'ACTIVE'
|
||||
|
||||
# Return a dummy PollingTaskGroup to make check_resume_complete step
|
||||
def dummy_attach():
|
||||
yield
|
||||
dummy_tg = scheduler.PollingTaskGroup([dummy_attach, dummy_attach])
|
||||
self.m.StubOutWithMock(instance, '_attach_volumes_task')
|
||||
instance._attach_volumes_task().AndReturn(dummy_tg)
|
||||
|
||||
self.m.StubOutWithMock(self.fc.client, 'get_servers_1234')
|
||||
get = self.fc.client.get_servers_1234
|
||||
get().AndReturn((200, d))
|
||||
|
||||
self.m.StubOutWithMock(scheduler.TaskRunner, '_sleep')
|
||||
scheduler.TaskRunner._sleep(mox.IsA(int)).AndReturn(None)
|
||||
self.m.ReplayAll()
|
||||
|
||||
instance.state_set(instance.SUSPEND, instance.COMPLETE)
|
||||
|
||||
scheduler.TaskRunner(instance.resume)()
|
||||
self.assertEqual(instance.state, (instance.RESUME, instance.COMPLETE))
|
||||
|
||||
self.m.VerifyAll()
|
||||
|
||||
def test_instance_status_build_spawning(self):
|
||||
self._test_instance_status_not_build_active('BUILD(SPAWNING)')
|
||||
|
||||
|
@ -360,6 +360,8 @@ class FakeHTTPClient(base_client.HTTPClient):
|
||||
assert body[action] is None
|
||||
elif action == 'suspend':
|
||||
assert body[action] is None
|
||||
elif action == 'resume':
|
||||
assert body[action] is None
|
||||
elif action == 'addFixedIp':
|
||||
assert body[action].keys() == ['networkId']
|
||||
elif action == 'removeFixedIp':
|
||||
|
Loading…
Reference in New Issue
Block a user