ironic-lib is being retired; this change imports any used code from ironic-lib and updates references. This contains some changes to how we throw exceptions; aligning ironic-lib code with IPA practice to have all exceptions be a RESTError. This also allows us to remove code around serializing ironic-lib exceptions. Change-Id: I137340ce6820c68d8e0f1a32668151bba7b1ddd7
		
			
				
	
	
		
			103 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			103 lines
		
	
	
		
			4.1 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
# Copyright 2015 Rackspace, Inc.
 | 
						|
#
 | 
						|
# Licensed under the Apache License, Version 2.0 (the "License");
 | 
						|
# you may not use this file except in compliance with the License.
 | 
						|
# You may obtain a copy of the License at
 | 
						|
#
 | 
						|
# http://www.apache.org/licenses/LICENSE-2.0
 | 
						|
#
 | 
						|
# Unless required by applicable law or agreed to in writing, software
 | 
						|
# distributed under the License is distributed on an "AS IS" BASIS,
 | 
						|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | 
						|
# See the License for the specific language governing permissions and
 | 
						|
# limitations under the License.
 | 
						|
 | 
						|
from oslo_log import log
 | 
						|
 | 
						|
from ironic_python_agent import errors
 | 
						|
from ironic_python_agent.extensions import base
 | 
						|
from ironic_python_agent import hardware
 | 
						|
 | 
						|
LOG = log.getLogger()
 | 
						|
 | 
						|
 | 
						|
class ServiceExtension(base.BaseAgentExtension):
 | 
						|
    @base.sync_command('get_service_steps')
 | 
						|
    def get_service_steps(self, node, ports):
 | 
						|
        """Get the list of service steps supported for the node and ports
 | 
						|
 | 
						|
        :param node: A dict representation of a node
 | 
						|
        :param ports: A dict representation of ports attached to node
 | 
						|
 | 
						|
        :returns: A list of service steps with keys step, priority, and
 | 
						|
            reboot_requested
 | 
						|
        """
 | 
						|
        LOG.debug('Getting service steps, called with node: %(node)s, '
 | 
						|
                  'ports: %(ports)s', {'node': node, 'ports': ports})
 | 
						|
        hardware.cache_node(node)
 | 
						|
        # Results should be a dict, not a list
 | 
						|
        candidate_steps = hardware.dispatch_to_all_managers(
 | 
						|
            'get_service_steps', node, ports)
 | 
						|
 | 
						|
        LOG.debug('Service steps before deduplication: %s', candidate_steps)
 | 
						|
        service_steps = hardware.deduplicate_steps(candidate_steps)
 | 
						|
        LOG.debug('Returning service steps: %s', service_steps)
 | 
						|
 | 
						|
        return {
 | 
						|
            'service_steps': service_steps,
 | 
						|
            'hardware_manager_version': hardware.get_current_versions(),
 | 
						|
        }
 | 
						|
 | 
						|
    @base.async_command('execute_service_step')
 | 
						|
    def execute_service_step(self, step, node, ports, service_version=None,
 | 
						|
                             **kwargs):
 | 
						|
        """Execute a service step.
 | 
						|
 | 
						|
        :param step: A step with 'step', 'priority' and 'interface' keys
 | 
						|
        :param node: A dict representation of a node
 | 
						|
        :param ports: A dict representation of ports attached to node
 | 
						|
        :param service_version: The service version as returned by
 | 
						|
                              hardware.get_current_versions() at the beginning
 | 
						|
                              of the service operation.
 | 
						|
        :returns: a CommandResult object with command_result set to whatever
 | 
						|
            the step returns.
 | 
						|
        """
 | 
						|
        # Ensure the agent is still the same version, or raise an exception
 | 
						|
        LOG.debug('Executing service step %s', step)
 | 
						|
        hardware.cache_node(node)
 | 
						|
        hardware.check_versions(service_version)
 | 
						|
 | 
						|
        if 'step' not in step:
 | 
						|
            msg = 'Malformed service_step, no "step" key: %s' % step
 | 
						|
            LOG.error(msg)
 | 
						|
            raise ValueError(msg)
 | 
						|
        kwargs.update(step.get('args') or {})
 | 
						|
        try:
 | 
						|
            result = hardware.dispatch_to_managers(step['step'], node, ports,
 | 
						|
                                                   **kwargs)
 | 
						|
        except errors.RESTError:
 | 
						|
            LOG.exception('Error performing service step %s', step['step'])
 | 
						|
            raise
 | 
						|
        except Exception as e:
 | 
						|
            msg = ('Unexpected exception performing service step %(step)s. '
 | 
						|
                   '%(cls)s: %(err)s' % {'step': step['step'],
 | 
						|
                                         'cls': e.__class__.__name__,
 | 
						|
                                         'err': e})
 | 
						|
            LOG.exception(msg)
 | 
						|
            raise errors.ServicingError(msg)
 | 
						|
 | 
						|
        LOG.info('Service step completed: %(step)s, result: %(result)s',
 | 
						|
                 {'step': step, 'result': result})
 | 
						|
 | 
						|
        # Cast result tuples (like output of utils.execute) as lists, or
 | 
						|
        # API throws errors
 | 
						|
        if isinstance(result, tuple):
 | 
						|
            result = list(result)
 | 
						|
 | 
						|
        # Return the step that was executed so we can dispatch
 | 
						|
        # to the appropriate Ironic interface
 | 
						|
        return {
 | 
						|
            'service_result': result,
 | 
						|
            'service_step': step
 | 
						|
        }
 |