def rebuild(self, context, server): """Rebuild/redeploy a server. :param context: The security context. :param server: The server object. """ 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 try: self.ironicclient.call("node.set_provision_state", node_uuid, ironic_states.REBUILD) except (ironic_exc.InternalServerError, ironic_exc.BadRequest) as e: msg = (_("Failed to request Ironic to rebuild server " "%(server)s: %(reason)s") % { 'server': server.uuid, 'reason': six.text_type(e) }) raise exception.ServerDeployFailure(msg) # Although the target provision state is REBUILD, it will actually go # to ACTIVE once the redeploy is finished. timer = loopingcall.FixedIntervalLoopingCall(self._wait_for_active, server) timer.start(interval=CONF.ironic.api_retry_interval).wait() LOG.info('Server was successfully rebuilt', server=server)
def _wait_for_active(self, server): """Wait for the node to be marked as ACTIVE in Ironic.""" server.refresh() if server.status in (states.DELETING, states.ERROR, states.DELETED): raise exception.ServerDeployAborted( _("Server %s provisioning was aborted") % server.uuid) node = self._validate_server_and_node(server) if node.provision_state == ironic_states.ACTIVE: # job is done LOG.debug("Ironic node %(node)s is now ACTIVE", dict(node=node.uuid), server=server) raise loopingcall.LoopingCallDone() if node.target_provision_state in (ironic_states.DELETED, ironic_states.AVAILABLE): # ironic is trying to delete it now raise exception.ServerNotFound(server=server.uuid) if node.provision_state in (ironic_states.NOSTATE, ironic_states.AVAILABLE): # ironic already deleted it raise exception.ServerNotFound(server=server.uuid) if node.provision_state == ironic_states.DEPLOYFAIL: # ironic failed to deploy msg = (_("Failed to provision server %(server)s: %(reason)s") % { 'server': server.uuid, 'reason': node.last_error }) raise exception.ServerDeployFailure(msg) _log_ironic_polling('become ACTIVE', node, server)
def _wait_for_servers_status(cls, server_id, wait_interval, wait_timeout, status=None, power_state=None, locked=None): """Waits for a Server to reach the given status, power_state, lock state. """ server_status = None server_power_state = None server_locked = None start = int(time.time()) def _condition(): compare_pairs = ((status, server_status), (power_state, server_power_state), (locked, server_locked)) return all([r == a for r, a in compare_pairs if r is not None]) while not _condition(): time.sleep(wait_interval) try: body = cls.baremetal_compute_client.show_server(server_id) server_status = body['status'] server_power_state = body['power_state'] server_locked = body['locked'] except lib_exc.NotFound: if status == 'deleted': break else: raise if server_status == 'error' and status != 'error': msg = ('Failed to provision server %s' % server_id) raise exception.ServerDeployFailure(msg) if int(time.time()) - start >= wait_timeout: message = ('Server %s failed to reach %s status ' '(current %s) within the required time (%s s).' % (server_id, status, server_status, wait_timeout)) raise lib_exc.TimeoutException(message)
def manage(self, server, node_uuid): """Manage an existing bare metal node. :param server: The bare metal server object. :param node_uuid: The manageable bare metal node uuid. """ # Associate the node with a server patch = [{'path': '/instance_uuid', 'op': 'add', 'value': server.uuid}] try: self.ironicclient.call('node.update', node_uuid, patch, retry_on_conflict=False) except ironic_exc.BadRequest: msg = (_("Failed to update parameters on node %(node)s " "when provisioning the server %(server)s") % { 'node': node_uuid, 'server': server.uuid }) LOG.error(msg) raise exception.ServerDeployFailure(msg)
def _add_server_info_to_node(self, node, server): patch = list() # Associate the node with a server patch.append({ 'path': '/instance_uuid', 'op': 'add', 'value': server.uuid }) # Add the required fields to deploy a node. patch.append({ 'path': '/instance_info/image_source', 'op': 'add', 'value': server.image_uuid }) # TODO(zhenguo) Add partition support patch.append({ 'path': '/instance_info/root_gb', 'op': 'add', 'value': str(node.properties.get('local_gb', 0)) }) try: # FIXME(lucasagomes): The "retry_on_conflict" parameter was added # to basically causes the deployment to fail faster in case the # node picked by the scheduler is already associated with another # server due bug #1341420. self.ironicclient.call('node.update', node.uuid, patch, retry_on_conflict=False) except ironic_exc.BadRequest: msg = (_("Failed to add deploy parameters on node %(node)s " "when provisioning the server %(server)s") % { 'node': node.uuid, 'server': server.uuid }) LOG.error(msg) raise exception.ServerDeployFailure(msg)
def _add_server_info_to_node(self, node, server, preserve_ephemeral=None, partitions=None): patch = list() # Associate the node with a server patch.append({ 'path': '/instance_uuid', 'op': 'add', 'value': server.uuid }) # Add the required fields to deploy a node. patch.append({ 'path': '/instance_info/image_source', 'op': 'add', 'value': server.image_uuid }) root_gb = node.properties.get('local_gb', 0) if preserve_ephemeral is not None: patch.append({ 'path': '/instance_info/preserve_ephemeral', 'op': 'add', 'value': str(preserve_ephemeral) }) if partitions: patch.append({ 'path': '/instance_info/ephemeral_gb', 'op': 'add', 'value': str(partitions.get('ephemeral_gb', 0)) }) patch.append({ 'path': '/instance_info/swap_mb', 'op': 'add', 'value': str(partitions.get('swap_mb', 0)) }) # Local boot support with partition images, **must** contain # ``grub2`` installed within it patch.append({ 'path': '/instance_info/capabilities', 'op': 'add', 'value': '{"boot_option": "local"}' }) # If partitions is not None, use the root_gb in partitions instead root_gb = partitions.get('root_gb', root_gb) # root_gb is required not optional patch.append({ 'path': '/instance_info/root_gb', 'op': 'add', 'value': str(root_gb) }) try: # FIXME(lucasagomes): The "retry_on_conflict" parameter was added # to basically causes the deployment to fail faster in case the # node picked by the scheduler is already associated with another # server due bug #1341420. self.ironicclient.call('node.update', node.uuid, patch, retry_on_conflict=False) except ironic_exc.BadRequest: msg = (_("Failed to add deploy parameters on node %(node)s " "when provisioning the server %(server)s") % { 'node': node.uuid, 'server': server.uuid }) LOG.error(msg) raise exception.ServerDeployFailure(msg)