Specify image when do rebuilding

Implements: bp specify-image-during-rebuilding
APIImpact

Change-Id: I83104f4209eb4f67699ea9a721509f704d232af9
This commit is contained in:
Xinran 2017-08-03 10:57:40 +08:00
parent dd5f08210b
commit 108348ad41
9 changed files with 50 additions and 14 deletions

View File

@ -309,6 +309,12 @@ flavors:
in: body in: body
required: true required: true
type: array type: array
image_ident:
description: |
The UUID of the image to apply to rebuild your server.
in: body
required: false
type: string
imageRef: imageRef:
description: | description: |
The UUID of the image to use for your server. The UUID of the image to use for your server.

View File

@ -1,3 +1,4 @@
{ {
"target": "rebuild" "target": "rebuild",
"image_uuid":"9145be5b-38d0-4a05-8dd6-837a8ec15281"
} }

View File

@ -129,6 +129,7 @@ Request
- server_uuid: server_ident - server_uuid: server_ident
- target: provision_state - target: provision_state
- image_uuid: image_ident
**Example request to rebuild a Server:** **Example request to rebuild a Server:**

View File

@ -158,9 +158,9 @@ class ServerStatesController(ServerControllerBase):
pecan.request.engine_api.unlock(context, db_server) pecan.request.engine_api.unlock(context, db_server)
@policy.authorize_wsgi("mogan:server", "set_provision_state") @policy.authorize_wsgi("mogan:server", "set_provision_state")
@expose.expose(None, types.uuid, wtypes.text, @expose.expose(None, types.uuid, wtypes.text, types.uuid,
status_code=http_client.ACCEPTED) status_code=http_client.ACCEPTED)
def provision(self, server_uuid, target): def provision(self, server_uuid, target, image_uuid=None):
"""Asynchronous trigger the provisioning of the server. """Asynchronous trigger the provisioning of the server.
This will set the target provision state of the server, and This will set the target provision state of the server, and
@ -179,10 +179,10 @@ class ServerStatesController(ServerControllerBase):
raise exception.InvalidActionParameterValue( raise exception.InvalidActionParameterValue(
value=target, action="provision", value=target, action="provision",
server=server_uuid) server=server_uuid)
db_server = self._resource or self._get_resource(server_uuid) db_server = self._resource or self._get_resource(server_uuid)
if target == states.REBUILD: if target == states.REBUILD:
pecan.request.engine_api.rebuild(pecan.request.context, db_server) pecan.request.engine_api.rebuild(pecan.request.context, db_server,
image_uuid)
# Set the HTTP Location Header # Set the HTTP Location Header
url_args = '/'.join([server_uuid, 'states']) url_args = '/'.join([server_uuid, 'states'])
@ -675,7 +675,6 @@ class ServerController(ServerControllerBase):
:param server: a server within the request body. :param server: a server within the request body.
""" """
validation.check_schema(server, server_schemas.create_server) validation.check_schema(server, server_schemas.create_server)
min_count = server.get('min_count', 1) min_count = server.get('min_count', 1)
max_count = server.get('max_count', min_count) max_count = server.get('max_count', min_count)

View File

@ -100,7 +100,7 @@ class BaseEngineDriver(object):
""" """
raise NotImplementedError() raise NotImplementedError()
def rebuild(self, context, server): def rebuild(self, context, server, image_uuid):
"""Trigger node deploy process. """Trigger node deploy process.
:param server: server to rebuild. :param server: server to rebuild.

View File

@ -100,7 +100,6 @@ class IronicDriver(base_driver.BaseEngineDriver):
raise exception.ServerNotFound(server=server.uuid) raise exception.ServerNotFound(server=server.uuid)
def _add_server_info_to_node(self, node, server): def _add_server_info_to_node(self, node, server):
patch = list() patch = list()
# Associate the node with a server # Associate the node with a server
patch.append({'path': '/instance_uuid', 'op': 'add', patch.append({'path': '/instance_uuid', 'op': 'add',
@ -437,10 +436,14 @@ class IronicDriver(base_driver.BaseEngineDriver):
""" """
LOG.debug('Rebuild called for server', server=server) LOG.debug('Rebuild called for server', server=server)
node_uuid = server.node_uuid
node = self._get_node(node_uuid)
self._add_server_info_to_node(node, server)
# trigger the node rebuild # trigger the node rebuild
try: try:
self.ironicclient.call("node.set_provision_state", self.ironicclient.call("node.set_provision_state",
server.node_uuid, node_uuid,
ironic_states.REBUILD) ironic_states.REBUILD)
except (ironic_exc.InternalServerError, except (ironic_exc.InternalServerError,
ironic_exc.BadRequest) as e: ironic_exc.BadRequest) as e:

View File

@ -386,8 +386,17 @@ class API(object):
@check_server_lock @check_server_lock
@check_server_maintenance @check_server_maintenance
def rebuild(self, context, server): def rebuild(self, context, server, image_uuid=None):
"""Rebuild a server.""" """Rebuild a server."""
if not image_uuid:
image_uuid = server.image_uuid
# check if the image exists
self._get_image(context, image_uuid)
if image_uuid != server.image_uuid:
# replace original image with the new one
server.image_uuid = image_uuid
server.save()
fsm = utils.get_state_machine(start_state=server.status) fsm = utils.get_state_machine(start_state=server.status)
try: try:
utils.process_event(fsm, server, event='rebuild') utils.process_event(fsm, server, event='rebuild')

View File

@ -503,7 +503,6 @@ class EngineManager(base_manager.BaseEngineManager):
:param context: mogan request context :param context: mogan request context
:param server: server object :param server: server object
""" """
LOG.debug('Rebuilding server', server=server) LOG.debug('Rebuilding server', server=server)
fsm = utils.get_state_machine(start_state=server.status) fsm = utils.get_state_machine(start_state=server.status)
@ -517,7 +516,6 @@ class EngineManager(base_manager.BaseEngineManager):
"Exception: %(exception)s", "Exception: %(exception)s",
{"uuid": server.uuid, {"uuid": server.uuid,
"exception": e}) "exception": e})
utils.process_event(fsm, server, event='done') utils.process_event(fsm, server, event='done')
LOG.info('Server was successfully rebuilt', server=server) LOG.info('Server was successfully rebuilt', server=server)

View File

@ -340,21 +340,40 @@ class ComputeAPIUnitTest(base.DbTestCase):
mock_rebuild.assert_not_called() mock_rebuild.assert_not_called()
@mock.patch.object(engine_rpcapi.EngineAPI, 'rebuild_server') @mock.patch.object(engine_rpcapi.EngineAPI, 'rebuild_server')
def test_rebuild_locked_server_with_admin(self, mock_rebuild): @mock.patch('mogan.engine.api.API._get_image')
def test_rebuild_locked_server_with_admin(self, mock_rebuild,
mock_get_image):
fake_server = db_utils.get_test_server( fake_server = db_utils.get_test_server(
user_id=self.user_id, project_id=self.project_id, user_id=self.user_id, project_id=self.project_id,
locked=True, locked_by='owner') locked=True, locked_by='owner')
fake_server_obj = self._create_fake_server_obj(fake_server) fake_server_obj = self._create_fake_server_obj(fake_server)
admin_context = context.get_admin_context() admin_context = context.get_admin_context()
mock_get_image.side_effect = None
self.engine_api.rebuild(admin_context, fake_server_obj) self.engine_api.rebuild(admin_context, fake_server_obj)
self.assertTrue(mock_rebuild.called) self.assertTrue(mock_rebuild.called)
@mock.patch.object(engine_rpcapi.EngineAPI, 'rebuild_server') @mock.patch.object(engine_rpcapi.EngineAPI, 'rebuild_server')
def test_rebuild_server(self, mock_rebuild): @mock.patch('mogan.engine.api.API._get_image')
def test_rebuild_server(self, mock_rebuild, mock_get_image):
fake_server = db_utils.get_test_server( fake_server = db_utils.get_test_server(
user_id=self.user_id, project_id=self.project_id) user_id=self.user_id, project_id=self.project_id)
fake_server_obj = self._create_fake_server_obj(fake_server) fake_server_obj = self._create_fake_server_obj(fake_server)
mock_get_image.side_effect = None
self.engine_api.rebuild(self.context, fake_server_obj) self.engine_api.rebuild(self.context, fake_server_obj)
self.assertTrue(mock_get_image.called)
self.assertTrue(mock_rebuild.called)
@mock.patch.object(engine_rpcapi.EngineAPI, 'rebuild_server')
@mock.patch('mogan.engine.api.API._get_image')
def test_rebuild_server_with_new_image(self, mock_rebuild, mock_get_image):
fake_server = db_utils.get_test_server(
user_id=self.user_id, project_id=self.project_id)
fake_server_obj = self._create_fake_server_obj(fake_server)
mock_get_image.side_effect = None
image_uuid = 'fake-uuid'
self.engine_api.rebuild(self.context, fake_server_obj, image_uuid)
self.assertTrue(mock_get_image.called)
self.assertTrue(mock_rebuild.called) self.assertTrue(mock_rebuild.called)
@mock.patch.object(engine_rpcapi.EngineAPI, 'detach_interface') @mock.patch.object(engine_rpcapi.EngineAPI, 'detach_interface')