"Fossies" - the Fresh Open Source Software Archive

Member "ironic-16.0.3/ironic/conductor/cleaning.py" (18 Jan 2021, 11499 Bytes) of package /linux/misc/openstack/ironic-16.0.3.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) Python source code syntax highlighting (style: standard) with prefixed line numbers. Alternatively you can here view or download the uninterpreted source code file. For more information about "cleaning.py" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 16.0.2_vs_16.0.3.

    1 #    Licensed under the Apache License, Version 2.0 (the "License"); you may
    2 #    not use this file except in compliance with the License. You may obtain
    3 #    a copy of the License at
    4 #
    5 #         http://www.apache.org/licenses/LICENSE-2.0
    6 #
    7 #    Unless required by applicable law or agreed to in writing, software
    8 #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
    9 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
   10 #    License for the specific language governing permissions and limitations
   11 #    under the License.
   12 
   13 """Functionality related to cleaning."""
   14 
   15 from oslo_log import log
   16 
   17 from ironic.common import exception
   18 from ironic.common.i18n import _
   19 from ironic.common import states
   20 from ironic.conductor import steps as conductor_steps
   21 from ironic.conductor import task_manager
   22 from ironic.conductor import utils
   23 from ironic.conf import CONF
   24 from ironic.drivers import utils as driver_utils
   25 
   26 LOG = log.getLogger(__name__)
   27 
   28 
   29 @task_manager.require_exclusive_lock
   30 def do_node_clean(task, clean_steps=None):
   31     """Internal RPC method to perform cleaning of a node.
   32 
   33     :param task: a TaskManager instance with an exclusive lock on its node
   34     :param clean_steps: For a manual clean, the list of clean steps to
   35                         perform. Is None For automated cleaning (default).
   36                         For more information, see the clean_steps parameter
   37                         of :func:`ConductorManager.do_node_clean`.
   38     """
   39     node = task.node
   40     manual_clean = clean_steps is not None
   41     clean_type = 'manual' if manual_clean else 'automated'
   42     LOG.debug('Starting %(type)s cleaning for node %(node)s',
   43               {'type': clean_type, 'node': node.uuid})
   44 
   45     if not manual_clean and utils.skip_automated_cleaning(node):
   46         # Skip cleaning, move to AVAILABLE.
   47         node.clean_step = None
   48         node.save()
   49 
   50         task.process_event('done')
   51         LOG.info('Automated cleaning is disabled, node %s has been '
   52                  'successfully moved to AVAILABLE state.', node.uuid)
   53         return
   54 
   55     # NOTE(dtantsur): this is only reachable during automated cleaning,
   56     # for manual cleaning we verify maintenance mode earlier on.
   57     if (not CONF.conductor.allow_provisioning_in_maintenance
   58             and node.maintenance):
   59         msg = _('Cleaning a node in maintenance mode is not allowed')
   60         return utils.cleaning_error_handler(task, msg,
   61                                             tear_down_cleaning=False)
   62 
   63     try:
   64         # NOTE(ghe): Valid power and network values are needed to perform
   65         # a cleaning.
   66         task.driver.power.validate(task)
   67         task.driver.network.validate(task)
   68     except exception.InvalidParameterValue as e:
   69         msg = (_('Validation failed. Cannot clean node %(node)s. '
   70                  'Error: %(msg)s') %
   71                {'node': node.uuid, 'msg': e})
   72         return utils.cleaning_error_handler(task, msg)
   73 
   74     if manual_clean:
   75         info = node.driver_internal_info
   76         info['clean_steps'] = clean_steps
   77         node.driver_internal_info = info
   78         node.save()
   79 
   80     # Do caching of bios settings if supported by driver,
   81     # this will be called for both manual and automated cleaning.
   82     try:
   83         task.driver.bios.cache_bios_settings(task)
   84     except exception.UnsupportedDriverExtension:
   85         LOG.warning('BIOS settings are not supported for node %s, '
   86                     'skipping', task.node.uuid)
   87     # TODO(zshi) remove this check when classic drivers are removed
   88     except Exception:
   89         msg = (_('Caching of bios settings failed on node %(node)s. '
   90                  'Continuing with node cleaning.')
   91                % {'node': node.uuid})
   92         LOG.exception(msg)
   93 
   94     # Allow the deploy driver to set up the ramdisk again (necessary for
   95     # IPA cleaning)
   96     try:
   97         prepare_result = task.driver.deploy.prepare_cleaning(task)
   98     except Exception as e:
   99         msg = (_('Failed to prepare node %(node)s for cleaning: %(e)s')
  100                % {'node': node.uuid, 'e': e})
  101         return utils.cleaning_error_handler(task, msg, traceback=True)
  102 
  103     if prepare_result == states.CLEANWAIT:
  104         # Prepare is asynchronous, the deploy driver will need to
  105         # set node.driver_internal_info['clean_steps'] and
  106         # node.clean_step and then make an RPC call to
  107         # continue_node_clean to start cleaning.
  108 
  109         # For manual cleaning, the target provision state is MANAGEABLE,
  110         # whereas for automated cleaning, it is AVAILABLE (the default).
  111         target_state = states.MANAGEABLE if manual_clean else None
  112         task.process_event('wait', target_state=target_state)
  113         return
  114 
  115     try:
  116         conductor_steps.set_node_cleaning_steps(task)
  117     except (exception.InvalidParameterValue,
  118             exception.NodeCleaningFailure) as e:
  119         msg = (_('Cannot clean node %(node)s. Error: %(msg)s')
  120                % {'node': node.uuid, 'msg': e})
  121         return utils.cleaning_error_handler(task, msg)
  122 
  123     steps = node.driver_internal_info.get('clean_steps', [])
  124     step_index = 0 if steps else None
  125     do_next_clean_step(task, step_index)
  126 
  127 
  128 @utils.fail_on_error(utils.cleaning_error_handler,
  129                      _("Unexpected error when processing next clean step"))
  130 @task_manager.require_exclusive_lock
  131 def do_next_clean_step(task, step_index):
  132     """Do cleaning, starting from the specified clean step.
  133 
  134     :param task: a TaskManager instance with an exclusive lock
  135     :param step_index: The first clean step in the list to execute. This
  136         is the index (from 0) into the list of clean steps in the node's
  137         driver_internal_info['clean_steps']. Is None if there are no steps
  138         to execute.
  139     """
  140     node = task.node
  141     # For manual cleaning, the target provision state is MANAGEABLE,
  142     # whereas for automated cleaning, it is AVAILABLE.
  143     manual_clean = node.target_provision_state == states.MANAGEABLE
  144     if step_index is None:
  145         steps = []
  146     else:
  147         steps = node.driver_internal_info['clean_steps'][step_index:]
  148 
  149     LOG.info('Executing %(state)s on node %(node)s, remaining steps: '
  150              '%(steps)s', {'node': node.uuid, 'steps': steps,
  151                            'state': node.provision_state})
  152 
  153     # Execute each step until we hit an async step or run out of steps
  154     for ind, step in enumerate(steps):
  155         # Save which step we're about to start so we can restart
  156         # if necessary
  157         node.clean_step = step
  158         driver_internal_info = node.driver_internal_info
  159         driver_internal_info['clean_step_index'] = step_index + ind
  160         node.driver_internal_info = driver_internal_info
  161         node.save()
  162         interface = getattr(task.driver, step.get('interface'))
  163         LOG.info('Executing %(step)s on node %(node)s',
  164                  {'step': step, 'node': node.uuid})
  165         try:
  166             result = interface.execute_clean_step(task, step)
  167         except Exception as e:
  168             if isinstance(e, exception.AgentConnectionFailed):
  169                 if task.node.driver_internal_info.get('cleaning_reboot'):
  170                     LOG.info('Agent is not yet running on node %(node)s '
  171                              'after cleaning reboot, waiting for agent to '
  172                              'come up to run next clean step %(step)s.',
  173                              {'node': node.uuid, 'step': step})
  174                     driver_internal_info['skip_current_clean_step'] = False
  175                     node.driver_internal_info = driver_internal_info
  176                     target_state = (states.MANAGEABLE if manual_clean
  177                                     else None)
  178                     task.process_event('wait', target_state=target_state)
  179                     return
  180 
  181             msg = (_('Node %(node)s failed step %(step)s: '
  182                      '%(exc)s') %
  183                    {'node': node.uuid, 'exc': e,
  184                     'step': node.clean_step})
  185             driver_utils.collect_ramdisk_logs(task.node, label='cleaning')
  186             utils.cleaning_error_handler(task, msg, traceback=True)
  187             return
  188 
  189         # Check if the step is done or not. The step should return
  190         # states.CLEANWAIT if the step is still being executed, or
  191         # None if the step is done.
  192         if result == states.CLEANWAIT:
  193             # Kill this worker, the async step will make an RPC call to
  194             # continue_node_clean to continue cleaning
  195             LOG.info('Clean step %(step)s on node %(node)s being '
  196                      'executed asynchronously, waiting for driver.',
  197                      {'node': node.uuid, 'step': step})
  198             target_state = states.MANAGEABLE if manual_clean else None
  199             task.process_event('wait', target_state=target_state)
  200             return
  201         elif result is not None:
  202             msg = (_('While executing step %(step)s on node '
  203                      '%(node)s, step returned invalid value: %(val)s')
  204                    % {'step': step, 'node': node.uuid, 'val': result})
  205             return utils.cleaning_error_handler(task, msg)
  206         LOG.info('Node %(node)s finished clean step %(step)s',
  207                  {'node': node.uuid, 'step': step})
  208 
  209     if CONF.agent.deploy_logs_collect == 'always':
  210         driver_utils.collect_ramdisk_logs(task.node, label='cleaning')
  211 
  212     # Clear clean_step
  213     node.clean_step = None
  214     utils.wipe_cleaning_internal_info(task)
  215     node.save()
  216     try:
  217         task.driver.deploy.tear_down_cleaning(task)
  218     except Exception as e:
  219         msg = (_('Failed to tear down from cleaning for node %(node)s, '
  220                  'reason: %(err)s')
  221                % {'node': node.uuid, 'err': e})
  222         return utils.cleaning_error_handler(task, msg,
  223                                             traceback=True,
  224                                             tear_down_cleaning=False)
  225 
  226     LOG.info('Node %s cleaning complete', node.uuid)
  227     event = 'manage' if manual_clean or node.retired else 'done'
  228     # NOTE(rloo): No need to specify target prov. state; we're done
  229     task.process_event(event)
  230 
  231 
  232 @task_manager.require_exclusive_lock
  233 def do_node_clean_abort(task, step_name=None):
  234     """Internal method to abort an ongoing operation.
  235 
  236     :param task: a TaskManager instance with an exclusive lock
  237     :param step_name: The name of the clean step.
  238     """
  239     node = task.node
  240     try:
  241         task.driver.deploy.tear_down_cleaning(task)
  242     except Exception as e:
  243         log_msg = (_('Failed to tear down cleaning for node %(node)s '
  244                      'after aborting the operation. Error: %(err)s') %
  245                    {'node': node.uuid, 'err': e})
  246         error_msg = _('Failed to tear down cleaning after aborting '
  247                       'the operation')
  248         utils.cleaning_error_handler(task, log_msg,
  249                                      errmsg=error_msg,
  250                                      traceback=True,
  251                                      tear_down_cleaning=False,
  252                                      set_fail_state=False)
  253         return
  254 
  255     info_message = _('Clean operation aborted for node %s') % node.uuid
  256     last_error = _('By request, the clean operation was aborted')
  257     if step_name:
  258         msg = _(' after the completion of step "%s"') % step_name
  259         last_error += msg
  260         info_message += msg
  261 
  262     node.last_error = last_error
  263     node.clean_step = None
  264     utils.wipe_cleaning_internal_info(task)
  265     node.save()
  266     LOG.info(info_message)