Support time-delays in server.resize

Resize operation in nova(that we are for flavor update) is
asynchronous. So the server may be ACTIVE when we are checking
server-resize operations(not RESIZE as was excepted).
We need to wait for a while till the server becomes RESIZE.

The patch add support of this case to Server resource in heat.
Closes-bug: #1471135

Change-Id: I19914081996104c5f2144a6de795173f26774c21
This commit is contained in:
kairat_kushaev 2015-07-06 11:32:16 +03:00
parent 7dcb065b55
commit f46af8a8e2
3 changed files with 59 additions and 9 deletions

View File

@ -432,7 +432,10 @@ echo -e '%s\tALL=(ALL)\tNOPASSWD: ALL' >> /etc/sudoers
If that's the case, confirm the resize, if not raise an error. If that's the case, confirm the resize, if not raise an error.
""" """
self.refresh_server(server) self.refresh_server(server)
while server.status == 'RESIZE': # resize operation is asynchronous so the server resize may not start
# when checking server status (the server may stay ACTIVE instead
# of RESIZE).
while server.status in ('RESIZE', 'ACTIVE'):
yield yield
self.refresh_server(server) self.refresh_server(server)
if server.status == 'VERIFY_RESIZE': if server.status == 'VERIFY_RESIZE':

View File

@ -701,9 +701,9 @@ class InstancesTest(common.HeatTestCase):
self.m.StubOutWithMock(self.fc.servers, 'get') self.m.StubOutWithMock(self.fc.servers, 'get')
self.fc.servers.get('1234').AndReturn(return_server) self.fc.servers.get('1234').AndReturn(return_server)
def activate_status(server): def fail_status(server):
server.status = 'ACTIVE' server.status = 'ERROR'
return_server.get = activate_status.__get__(return_server) return_server.get = fail_status.__get__(return_server)
self.m.StubOutWithMock(self.fc.client, 'post_servers_1234_action') self.m.StubOutWithMock(self.fc.client, 'post_servers_1234_action')
self.fc.client.post_servers_1234_action( self.fc.client.post_servers_1234_action(
@ -714,7 +714,7 @@ class InstancesTest(common.HeatTestCase):
error = self.assertRaises(exception.ResourceFailure, updater) error = self.assertRaises(exception.ResourceFailure, updater)
self.assertEqual( self.assertEqual(
"Error: resources.ud_type_f: " "Error: resources.ud_type_f: "
"Resizing to 'm1.small' failed, status 'ACTIVE'", "Resizing to 'm1.small' failed, status 'ERROR'",
six.text_type(error)) six.text_type(error))
self.assertEqual((instance.UPDATE, instance.FAILED), instance.state) self.assertEqual((instance.UPDATE, instance.FAILED), instance.state)
self.m.VerifyAll() self.m.VerifyAll()

View File

@ -1605,9 +1605,9 @@ class ServersTest(common.HeatTestCase):
self.m.StubOutWithMock(self.fc.servers, 'get') self.m.StubOutWithMock(self.fc.servers, 'get')
self.fc.servers.get('1234').AndReturn(return_server) self.fc.servers.get('1234').AndReturn(return_server)
def activate_status(server): def fail_status(server):
server.status = 'ACTIVE' server.status = 'ERROR'
return_server.get = activate_status.__get__(return_server) return_server.get = fail_status.__get__(return_server)
self.m.StubOutWithMock(self.fc.client, 'post_servers_1234_action') self.m.StubOutWithMock(self.fc.client, 'post_servers_1234_action')
self.fc.client.post_servers_1234_action( self.fc.client.post_servers_1234_action(
@ -1618,10 +1618,57 @@ class ServersTest(common.HeatTestCase):
error = self.assertRaises(exception.ResourceFailure, updater) error = self.assertRaises(exception.ResourceFailure, updater)
self.assertEqual( self.assertEqual(
"Error: resources.srv_update2: Resizing to 'm1.small' failed, " "Error: resources.srv_update2: Resizing to 'm1.small' failed, "
"status 'ACTIVE'", six.text_type(error)) "status 'ERROR'", six.text_type(error))
self.assertEqual((server.UPDATE, server.FAILED), server.state) self.assertEqual((server.UPDATE, server.FAILED), server.state)
self.m.VerifyAll() self.m.VerifyAll()
def test_server_update_flavor_resize_has_not_started(self):
"""Test update of server flavour if server resize has not started.
Server resize is asynchronous operation in nova. So when heat is
requesting resize and polling the server then the server may still be
in ACTIVE state. So we need to wait some amount of time till the server
status becomes RESIZE.
"""
# create the server for resizing
server = self.fc.servers.list()[1]
server.id = '1234'
server_resource = self._create_test_server(server,
'resize_server')
# prepare template with resized server
update_template = copy.deepcopy(server_resource.t)
update_template['Properties']['flavor'] = 'm1.small'
self.m.StubOutWithMock(self.fc.servers, 'get')
self.fc.servers.get('1234').AndReturn(server)
# define status transition when server resize
# ACTIVE(initial) -> ACTIVE -> RESIZE -> VERIFY_RESIZE
def active_status(srv):
srv.status = 'ACTIVE'
server.get = active_status.__get__(server)
def resize_status(srv):
srv.status = 'RESIZE'
server.get = resize_status.__get__(server)
def verify_resize_status(srv):
srv.status = 'VERIFY_RESIZE'
server.get = verify_resize_status.__get__(server)
self.m.StubOutWithMock(self.fc.client, 'post_servers_1234_action')
self.fc.client.post_servers_1234_action(
body={'resize': {'flavorRef': 2}}).AndReturn((202, None))
self.fc.client.post_servers_1234_action(
body={'confirmResize': None}).AndReturn((202, None))
self.m.ReplayAll()
# check that server resize has finished correctly
scheduler.TaskRunner(server_resource.update, update_template)()
self.assertEqual((server_resource.UPDATE, server_resource.COMPLETE),
server_resource.state)
self.m.VerifyAll()
def test_server_update_server_flavor_replace(self): def test_server_update_server_flavor_replace(self):
stack_name = 'update_flvrep' stack_name = 'update_flvrep'
(tmpl, stack) = self._setup_test_stack(stack_name) (tmpl, stack) = self._setup_test_stack(stack_name)