Make rebuild an operation for nova server

In current implementation, the 'rebuild' operation is implemented in a
profile method 'do_rebuild', this is rendering the nova server profile
so special and leaving no room for other actions to be handled.

This patch changes the 'do_rebuild' into 'handle_rebuild', which is an
operation supported by nova server profile.

Change-Id: I294cc254fda9fc6a0d92cacf8f07c5389655e399
This commit is contained in:
tengqm 2017-01-28 23:07:14 -05:00
parent 5269c74306
commit 321c872e9f
4 changed files with 146 additions and 151 deletions

View File

@ -405,11 +405,6 @@ class Profile(object):
LOG.warning(_LW("Leave operation not specialized."))
return True
def do_rebuild(self, obj):
"""For subclass to override."""
LOG.warning(_LW("Rebuild operation not specialized."))
return True
def do_recover(self, obj, **options):
"""Default recover operation.

View File

@ -217,9 +217,9 @@ class ServerProfile(base.Profile):
}
OP_NAMES = (
OP_REBOOT, OP_CHANGE_PASSWORD,
OP_REBOOT, OP_REBUILD, OP_CHANGE_PASSWORD,
) = (
'reboot', 'change_password',
'reboot', 'rebuild', 'change_password',
)
REBOOT_TYPE = 'type'
@ -239,6 +239,9 @@ class ServerProfile(base.Profile):
)
}
),
OP_REBUILD: schema.Operation(
_("Rebuild the server using current image and admin password."),
),
OP_CHANGE_PASSWORD: schema.Operation(
_("Change the administrator password."),
schema={
@ -979,35 +982,6 @@ class ServerProfile(base.Profile):
self.compute(obj).server_metadata_delete(obj.physical_id, keys)
return super(ServerProfile, self).do_leave(obj)
def do_rebuild(self, obj):
if not obj.physical_id:
return False
self.server_id = obj.physical_id
driver = self.compute(obj)
try:
server = driver.server_get(self.server_id)
except exc.InternalError as ex:
raise exc.EResourceOperation(op='rebuilding', type='server',
id=self.server_id,
message=six.text_type(ex))
if server is None or server.image is None:
return False
image_id = server.image['id']
admin_pass = self.properties.get(self.ADMIN_PASS)
try:
driver.server_rebuild(self.server_id, image_id,
self.properties.get(self.NAME),
admin_pass)
driver.wait_for_server(self.server_id, 'ACTIVE')
except exc.InternalError as ex:
raise exc.EResourceOperation(op='rebuilding', type='server',
id=self.server_id,
message=six.text_type(ex))
return True
def do_check(self, obj):
if not obj.physical_id:
return False
@ -1031,11 +1005,9 @@ class ServerProfile(base.Profile):
if operation and not isinstance(operation, six.string_types):
operation = operation[0]
# TODO(Qiming): Handle the case that the operation contains other
# alternative recover operation
# Depends-On: https://review.openstack.org/#/c/359676/
if operation == 'REBUILD':
return self.do_rebuild(obj)
return self.handle_rebuild(obj)
return super(ServerProfile, self).do_recover(obj, **options)
@ -1053,6 +1025,35 @@ class ServerProfile(base.Profile):
self.compute(obj).wait_for_server(obj.physical_id, 'ACTIVE')
return True
def handle_rebuild(self, obj, **options):
if not obj.physical_id:
return False
server_id = obj.physical_id
driver = self.compute(obj)
try:
server = driver.server_get(server_id)
except exc.InternalError as ex:
raise exc.EResourceOperation(op='rebuilding', type='server',
id=server_id,
message=six.text_type(ex))
if server is None or server.image is None:
return False
image_id = server.image['id']
admin_pass = self.properties.get(self.ADMIN_PASS)
try:
driver.server_rebuild(server_id, image_id,
self.properties.get(self.NAME),
admin_pass)
driver.wait_for_server(server_id, 'ACTIVE')
except exc.InternalError as ex:
raise exc.EResourceOperation(op='rebuilding', type='server',
id=server_id,
message=six.text_type(ex))
return True
def handle_change_password(self, obj, **options):
"""Handler for the change_password operation."""
if not obj.physical_id:

View File

@ -844,114 +844,6 @@ class TestNovaServerBasic(base.SenlinTestCase):
self.assertFalse(res)
def test_do_rebuild(self):
profile = server.ServerProfile('t', self.spec)
x_image = {'id': '123'}
x_server = mock.Mock(image=x_image)
cc = mock.Mock()
cc.server_get.return_value = x_server
cc.server_rebuild.return_value = True
profile._computeclient = cc
node_obj = mock.Mock(physical_id='FAKE_ID')
res = profile.do_rebuild(node_obj)
self.assertTrue(res)
cc.server_get.assert_called_with('FAKE_ID')
cc.server_rebuild.assert_called_once_with('FAKE_ID', '123',
'FAKE_SERVER_NAME',
'adminpass')
cc.wait_for_server.assert_called_once_with('FAKE_ID', 'ACTIVE')
def test_do_rebuild_server_not_found(self):
profile = server.ServerProfile('t', self.spec)
cc = mock.Mock()
err = exc.InternalError(code=404, message='FAKE_ID not found')
cc.server_get.side_effect = err
profile._computeclient = cc
node_obj = mock.Mock(physical_id='FAKE_ID')
ex = self.assertRaises(exc.EResourceOperation,
profile.do_rebuild,
node_obj)
self.assertEqual("Failed in rebuilding server 'FAKE_ID': "
"FAKE_ID not found.",
six.text_type(ex))
cc.server_get.assert_called_once_with('FAKE_ID')
def test_do_rebuild_failed_rebuild(self):
profile = server.ServerProfile('t', self.spec)
x_image = {'id': '123'}
x_server = mock.Mock(image=x_image)
cc = mock.Mock()
cc.server_get.return_value = x_server
ex = exc.InternalError(code=500, message='cannot rebuild')
cc.server_rebuild.side_effect = ex
profile._computeclient = cc
node_obj = mock.Mock(physical_id='FAKE_ID')
ex = self.assertRaises(exc.EResourceOperation,
profile.do_rebuild,
node_obj)
self.assertEqual("Failed in rebuilding server 'FAKE_ID': "
"cannot rebuild.",
six.text_type(ex))
cc.server_get.assert_called_once_with('FAKE_ID')
cc.server_rebuild.assert_called_once_with('FAKE_ID', '123',
'FAKE_SERVER_NAME',
'adminpass')
self.assertEqual(0, cc.wait_for_server.call_count)
def test_do_rebuild_failed_waiting(self):
profile = server.ServerProfile('t', self.spec)
x_image = {'id': '123'}
x_server = mock.Mock(image=x_image)
cc = mock.Mock()
cc.server_get.return_value = x_server
ex = exc.InternalError(code=500, message='timeout')
cc.wait_for_server.side_effect = ex
profile._computeclient = cc
node_obj = mock.Mock(physical_id='FAKE_ID')
ex = self.assertRaises(exc.EResourceOperation,
profile.do_rebuild,
node_obj)
self.assertEqual("Failed in rebuilding server 'FAKE_ID': "
"timeout.", six.text_type(ex))
cc.server_get.assert_called_once_with('FAKE_ID')
cc.server_rebuild.assert_called_once_with('FAKE_ID', '123',
'FAKE_SERVER_NAME',
'adminpass')
cc.wait_for_server.assert_called_once_with('FAKE_ID', 'ACTIVE')
def test_do_rebuild_failed_retrieving_server(self):
profile = server.ServerProfile('t', self.spec)
cc = mock.Mock()
cc.server_get.return_value = None
profile._computeclient = cc
node_obj = mock.Mock(physical_id='FAKE_ID')
res = profile.do_rebuild(node_obj)
self.assertFalse(res)
cc.server_get.assert_called_once_with('FAKE_ID')
self.assertEqual(0, cc.server_rebuild.call_count)
self.assertEqual(0, cc.wait_for_server.call_count)
def test_do_rebuild_no_physical_id(self):
profile = server.ServerProfile('t', self.spec)
profile._computeclient = mock.Mock()
test_server = mock.Mock()
test_server.physical_id = None
# Test path where server doesn't already exist
res = profile.do_rebuild(test_server)
self.assertFalse(res)
def test_do_check(self):
profile = server.ServerProfile('t', self.spec)
@ -972,7 +864,7 @@ class TestNovaServerBasic(base.SenlinTestCase):
cc.server_get.assert_called_with('FAKE_ID')
self.assertTrue(res)
@mock.patch.object(server.ServerProfile, 'do_rebuild')
@mock.patch.object(server.ServerProfile, 'handle_rebuild')
def test_do_recover_rebuild(self, mock_rebuild):
profile = server.ServerProfile('t', self.spec)
node_obj = mock.Mock(physical_id='FAKE_ID')
@ -982,7 +874,7 @@ class TestNovaServerBasic(base.SenlinTestCase):
self.assertEqual(mock_rebuild.return_value, res)
mock_rebuild.assert_called_once_with(node_obj)
@mock.patch.object(server.ServerProfile, 'do_rebuild')
@mock.patch.object(server.ServerProfile, 'handle_rebuild')
def test_do_recover_with_list(self, mock_rebuild):
profile = server.ServerProfile('t', self.spec)
node_obj = mock.Mock(physical_id='FAKE_ID')
@ -1054,6 +946,114 @@ class TestNovaServerBasic(base.SenlinTestCase):
res = profile.handle_reboot(obj, type='foo')
self.assertFalse(res)
def test_handle_rebuild(self):
profile = server.ServerProfile('t', self.spec)
x_image = {'id': '123'}
x_server = mock.Mock(image=x_image)
cc = mock.Mock()
cc.server_get.return_value = x_server
cc.server_rebuild.return_value = True
profile._computeclient = cc
node_obj = mock.Mock(physical_id='FAKE_ID')
res = profile.handle_rebuild(node_obj)
self.assertTrue(res)
cc.server_get.assert_called_with('FAKE_ID')
cc.server_rebuild.assert_called_once_with('FAKE_ID', '123',
'FAKE_SERVER_NAME',
'adminpass')
cc.wait_for_server.assert_called_once_with('FAKE_ID', 'ACTIVE')
def test_handle_rebuild_server_not_found(self):
profile = server.ServerProfile('t', self.spec)
cc = mock.Mock()
err = exc.InternalError(code=404, message='FAKE_ID not found')
cc.server_get.side_effect = err
profile._computeclient = cc
node_obj = mock.Mock(physical_id='FAKE_ID')
ex = self.assertRaises(exc.EResourceOperation,
profile.handle_rebuild,
node_obj)
self.assertEqual("Failed in rebuilding server 'FAKE_ID': "
"FAKE_ID not found.",
six.text_type(ex))
cc.server_get.assert_called_once_with('FAKE_ID')
def test_handle_rebuild_failed_rebuild(self):
profile = server.ServerProfile('t', self.spec)
x_image = {'id': '123'}
x_server = mock.Mock(image=x_image)
cc = mock.Mock()
cc.server_get.return_value = x_server
ex = exc.InternalError(code=500, message='cannot rebuild')
cc.server_rebuild.side_effect = ex
profile._computeclient = cc
node_obj = mock.Mock(physical_id='FAKE_ID')
ex = self.assertRaises(exc.EResourceOperation,
profile.handle_rebuild,
node_obj)
self.assertEqual("Failed in rebuilding server 'FAKE_ID': "
"cannot rebuild.",
six.text_type(ex))
cc.server_get.assert_called_once_with('FAKE_ID')
cc.server_rebuild.assert_called_once_with('FAKE_ID', '123',
'FAKE_SERVER_NAME',
'adminpass')
self.assertEqual(0, cc.wait_for_server.call_count)
def test_handle_rebuild_failed_waiting(self):
profile = server.ServerProfile('t', self.spec)
x_image = {'id': '123'}
x_server = mock.Mock(image=x_image)
cc = mock.Mock()
cc.server_get.return_value = x_server
ex = exc.InternalError(code=500, message='timeout')
cc.wait_for_server.side_effect = ex
profile._computeclient = cc
node_obj = mock.Mock(physical_id='FAKE_ID')
ex = self.assertRaises(exc.EResourceOperation,
profile.handle_rebuild,
node_obj)
self.assertEqual("Failed in rebuilding server 'FAKE_ID': "
"timeout.", six.text_type(ex))
cc.server_get.assert_called_once_with('FAKE_ID')
cc.server_rebuild.assert_called_once_with('FAKE_ID', '123',
'FAKE_SERVER_NAME',
'adminpass')
cc.wait_for_server.assert_called_once_with('FAKE_ID', 'ACTIVE')
def test_handle_rebuild_failed_retrieving_server(self):
profile = server.ServerProfile('t', self.spec)
cc = mock.Mock()
cc.server_get.return_value = None
profile._computeclient = cc
node_obj = mock.Mock(physical_id='FAKE_ID')
res = profile.handle_rebuild(node_obj)
self.assertFalse(res)
cc.server_get.assert_called_once_with('FAKE_ID')
self.assertEqual(0, cc.server_rebuild.call_count)
self.assertEqual(0, cc.wait_for_server.call_count)
def test_handle_rebuild_no_physical_id(self):
profile = server.ServerProfile('t', self.spec)
profile._computeclient = mock.Mock()
test_server = mock.Mock()
test_server.physical_id = None
res = profile.handle_rebuild(test_server)
self.assertFalse(res)
def test_handle_change_password(self):
obj = mock.Mock(physical_id='FAKE_ID')
profile = server.ServerProfile('t', self.spec)

View File

@ -736,7 +736,6 @@ class TestProfileBase(base.SenlinTestCase):
self.assertEqual({}, profile.do_get_details(mock.Mock()))
self.assertTrue(profile.do_join(mock.Mock(), mock.Mock()))
self.assertTrue(profile.do_leave(mock.Mock()))
self.assertTrue(profile.do_rebuild(mock.Mock()))
self.assertTrue(profile.do_validate(mock.Mock()))
def test_do_recover_default(self):