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:
parent
5269c74306
commit
321c872e9f
|
@ -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.
|
||||
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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):
|
||||
|
|
Loading…
Reference in New Issue