Merge "Allow suspend and resume again if failed last time"

This commit is contained in:
Jenkins 2015-07-08 10:05:40 +00:00 committed by Gerrit Code Review
commit 3a47b49dd4
6 changed files with 120 additions and 55 deletions

View File

@ -942,7 +942,10 @@ class Resource(object):
action = self.SUSPEND
# Don't try to suspend the resource unless it's in a stable state
if (self.action == self.DELETE or self.status != self.COMPLETE):
# or if the previous suspend failed
if (self.action == self.DELETE or
(self.action != self.SUSPEND and
self.status != self.COMPLETE)):
exc = exception.Error(_('State %s invalid for suspend')
% six.text_type(self.state))
raise exception.ResourceFailure(exc, self, action)
@ -957,12 +960,15 @@ class Resource(object):
'''
action = self.RESUME
# Can't resume a resource unless it's SUSPEND_COMPLETE
if self.state != (self.SUSPEND, self.COMPLETE):
# Allow resume a resource if it's SUSPEND_COMPLETE
# or RESUME_FAILED or RESUME_COMPLETE. Recommend to check
# the real state of physical resource in handle_resume()
if self.state not in ((self.SUSPEND, self.COMPLETE),
(self.RESUME, self.FAILED),
(self.RESUME, self.COMPLETE)):
exc = exception.Error(_('State %s invalid for resume')
% six.text_type(self.state))
raise exception.ResourceFailure(exc, self, action)
LOG.info(_LI('resuming %s'), six.text_type(self))
return self._do_action(action)

View File

@ -795,8 +795,11 @@ class Instance(resource.Resource):
else:
raise
else:
LOG.debug("suspending instance %s" % self.resource_id)
server.suspend()
# if the instance has been suspended successful,
# no need to suspend again
if self.client_plugin().get_status(server) != 'SUSPENDED':
LOG.debug("suspending instance %s" % self.resource_id)
server.suspend()
return server.id
def check_suspend_complete(self, server_id):
@ -834,8 +837,11 @@ class Instance(resource.Resource):
else:
raise
else:
LOG.debug("resuming instance %s" % self.resource_id)
server.resume()
# if the instance has been resumed successful,
# no need to resume again
if self.client_plugin().get_status(server) != 'ACTIVE':
LOG.debug("resuming instance %s" % self.resource_id)
server.resume()
return server.id
def check_resume_complete(self, server_id):

View File

@ -1405,8 +1405,11 @@ class Server(stack_user.StackUser):
else:
raise
else:
LOG.debug('suspending server %s' % self.resource_id)
server.suspend()
# if the server has been suspended successful,
# no need to suspend again
if self.client_plugin().get_status(server) != 'SUSPENDED':
LOG.debug('suspending server %s' % self.resource_id)
server.suspend()
return server.id
def check_suspend_complete(self, server_id):
@ -1444,8 +1447,11 @@ class Server(stack_user.StackUser):
else:
raise
else:
LOG.debug('resuming server %s' % self.resource_id)
server.resume()
# if the server has been resumed successful,
# no need to resume again
if self.client_plugin().get_status(server) != 'ACTIVE':
LOG.debug('resuming server %s' % self.resource_id)
server.resume()
return server.id
def check_resume_complete(self, server_id):

View File

@ -1013,16 +1013,14 @@ class InstancesTest(common.HeatTestCase):
scheduler.TaskRunner(instance.create)()
self.assertEqual((instance.CREATE, instance.COMPLETE), instance.state)
def test_instance_status_suspend(self):
def _test_instance_status_suspend(self, name,
state=('CREATE', 'COMPLETE')):
return_server = self.fc.servers.list()[1]
instance = self._create_test_instance(return_server,
'in_suspend_wait')
instance = self._create_test_instance(return_server, name)
instance.resource_id = '1234'
self.m.ReplayAll()
instance.state_set(state[0], state[1])
# Override the get_servers_1234 handler status to SUSPENDED, but
# return the ACTIVE state first (twice, so we sleep)
d1 = {'server': self.fc.client.get_servers_detail()[1]['servers'][0]}
d2 = copy.deepcopy(d1)
d1['server']['status'] = 'ACTIVE'
@ -1039,16 +1037,28 @@ class InstancesTest(common.HeatTestCase):
self.m.VerifyAll()
def test_instance_status_resume(self):
def test_instance_suspend_in_create_complete(self):
self._test_instance_status_suspend(
name='test_suspend_in_create_complete')
def test_instance_suspend_in_suspend_failed(self):
self._test_instance_status_suspend(
name='test_suspend_in_suspend_failed',
state=('SUSPEND', 'FAILED'))
def test_server_suspend_in_suspend_complete(self):
self._test_instance_status_suspend(
name='test_suspend_in_suspend_complete',
state=('SUSPEND', 'COMPLETE'))
def _test_instance_status_resume(self, name,
state=('SUSPEND', 'COMPLETE')):
return_server = self.fc.servers.list()[1]
instance = self._create_test_instance(return_server,
'in_resume_wait')
instance = self._create_test_instance(return_server, name)
instance.resource_id = '1234'
self.m.ReplayAll()
instance.state_set(state[0], state[1])
# 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'
@ -1067,6 +1077,20 @@ class InstancesTest(common.HeatTestCase):
self.m.VerifyAll()
def test_instance_resume_in_suspend_complete(self):
self._test_instance_status_resume(
name='test_resume_in_suspend_complete')
def test_instance_resume_in_resume_failed(self):
self._test_instance_status_resume(
name='test_resume_in_resume_failed',
state=('RESUME', 'FAILED'))
def test_instance_resume_in_resume_complete(self):
self._test_instance_status_resume(
name='test_resume_in_resume_complete',
state=('RESUME', 'COMPLETE'))
def test_server_resume_other_exception(self):
return_server = self.fc.servers.list()[1]
instance = self._create_test_instance(return_server,

View File

@ -1905,16 +1905,13 @@ class ServersTest(common.HeatTestCase):
self.m.VerifyAll()
def test_server_status_suspend(self):
def _test_server_status_suspend(self, name, state=('CREATE', 'COMPLETE')):
return_server = self.fc.servers.list()[1]
server = self._create_test_server(return_server,
'srv_susp_w')
server = self._create_test_server(return_server, name)
server.resource_id = '1234'
self.m.ReplayAll()
server.state_set(state[0], state[1])
# Override the get_servers_1234 handler status to SUSPENDED, but
# return the ACTIVE state first (twice, so we sleep)
d1 = {'server': self.fc.client.get_servers_detail()[1]['servers'][0]}
d2 = copy.deepcopy(d1)
d1['server']['status'] = 'ACTIVE'
@ -1931,6 +1928,19 @@ class ServersTest(common.HeatTestCase):
self.m.VerifyAll()
def test_server_suspend_in_create_complete(self):
self._test_server_status_suspend('test_suspend_in_create_complete')
def test_server_suspend_in_suspend_failed(self):
self._test_server_status_suspend(
name='test_suspend_in_suspend_failed',
state=('SUSPEND', 'FAILED'))
def test_server_suspend_in_suspend_complete(self):
self._test_server_status_suspend(
name='test_suspend_in_suspend_complete',
state=('SUSPEND', 'COMPLETE'))
def test_server_status_suspend_unknown_status(self):
return_server = self.fc.servers.list()[1]
server = self._create_test_server(return_server,
@ -1962,16 +1972,13 @@ class ServersTest(common.HeatTestCase):
self.m.VerifyAll()
def test_server_status_resume(self):
def _test_server_status_resume(self, name, state=('SUSPEND', 'COMPLETE')):
return_server = self.fc.servers.list()[1]
server = self._create_test_server(return_server,
'srv_res_w')
server = self._create_test_server(return_server, name)
server.resource_id = '1234'
self.m.ReplayAll()
server.state_set(state[0], state[1])
# 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'
@ -1983,13 +1990,25 @@ class ServersTest(common.HeatTestCase):
get().AndReturn((200, d2))
self.m.ReplayAll()
server.state_set(server.SUSPEND, server.COMPLETE)
scheduler.TaskRunner(server.resume)()
self.assertEqual((server.RESUME, server.COMPLETE), server.state)
self.m.VerifyAll()
def test_server_resume_in_suspend_complete(self):
self._test_server_status_resume(
name='test_resume_in_suspend_complete')
def test_server_resume_in_resume_failed(self):
self._test_server_status_resume(
name='test_resume_in_resume_failed',
state=('RESUME', 'FAILED'))
def test_server_resume_in_resume_complete(self):
self._test_server_status_resume(
name='test_resume_in_resume_complete',
state=('RESUME', 'COMPLETE'))
def test_server_status_resume_no_resource_id(self):
return_server = self.fc.servers.list()[1]
server = self._create_test_server(return_server,

View File

@ -980,7 +980,7 @@ class ResourceTest(common.HeatTestCase):
scheduler.TaskRunner(res.resume)()
self.assertEqual((res.RESUME, res.COMPLETE), res.state)
def test_suspend_fail_inprogress(self):
def test_suspend_fail_invalid_states(self):
tmpl = rsrc_defn.ResourceDefinition('test_resource',
'GenericResourceType',
{'Foo': 'abc'})
@ -988,19 +988,19 @@ class ResourceTest(common.HeatTestCase):
scheduler.TaskRunner(res.create)()
self.assertEqual((res.CREATE, res.COMPLETE), res.state)
res.state_set(res.CREATE, res.IN_PROGRESS)
suspend = scheduler.TaskRunner(res.suspend)
self.assertRaises(exception.ResourceFailure, suspend)
invalid_actions = (a for a in res.ACTIONS if a != res.SUSPEND)
invalid_status = (s for s in res.STATUSES if s != res.COMPLETE)
invalid_states = [s for s in
itertools.product(invalid_actions, invalid_status)]
res.state_set(res.UPDATE, res.IN_PROGRESS)
suspend = scheduler.TaskRunner(res.suspend)
self.assertRaises(exception.ResourceFailure, suspend)
for state in invalid_states:
res.state_set(*state)
suspend = scheduler.TaskRunner(res.suspend)
expected = 'State %s invalid for suspend' % six.text_type(state)
exc = self.assertRaises(exception.ResourceFailure, suspend)
self.assertIn(expected, six.text_type(exc))
res.state_set(res.DELETE, res.IN_PROGRESS)
suspend = scheduler.TaskRunner(res.suspend)
self.assertRaises(exception.ResourceFailure, suspend)
def test_resume_fail_not_suspend_complete(self):
def test_resume_fail_invalid_states(self):
tmpl = rsrc_defn.ResourceDefinition('test_resource',
'GenericResourceType',
{'Foo': 'abc'})
@ -1008,13 +1008,17 @@ class ResourceTest(common.HeatTestCase):
scheduler.TaskRunner(res.create)()
self.assertEqual((res.CREATE, res.COMPLETE), res.state)
non_suspended_states = [s for s in
itertools.product(res.ACTIONS, res.STATUSES)
if s != (res.SUSPEND, res.COMPLETE)]
for state in non_suspended_states:
invalid_states = [s for s in
itertools.product(res.ACTIONS, res.STATUSES)
if s not in ((res.SUSPEND, res.COMPLETE),
(res.RESUME, res.FAILED),
(res.RESUME, res.COMPLETE))]
for state in invalid_states:
res.state_set(*state)
resume = scheduler.TaskRunner(res.resume)
self.assertRaises(exception.ResourceFailure, resume)
expected = 'State %s invalid for resume' % six.text_type(state)
exc = self.assertRaises(exception.ResourceFailure, resume)
self.assertIn(expected, six.text_type(exc))
def test_suspend_fail_exception(self):
tmpl = rsrc_defn.ResourceDefinition('test_resource',