~ubuntu-branches/ubuntu/vivid/ironic/vivid-updates

« back to all changes in this revision

Viewing changes to ironic/drivers/base.py

  • Committer: Package Import Robot
  • Author(s): Chuck Short
  • Date: 2015-03-30 11:14:57 UTC
  • mfrom: (1.2.6)
  • Revision ID: package-import@ubuntu.com-20150330111457-kr4ju3guf22m4vbz
Tags: 2015.1~b3-0ubuntu1
* New upstream release.
  + d/control: 
    - Align with upstream dependencies.
    - Add dh-python to build-dependencies.
    - Add psmisc as a dependency. (LP: #1358820)
  + d/p/fix-requirements.patch: Rediffed.
  + d/ironic-conductor.init.in: Fixed typos in LSB headers,
    thanks to JJ Asghar. (LP: #1429962)

Show diffs side-by-side

added added

removed removed

Lines of Context:
19
19
 
20
20
import abc
21
21
import collections
 
22
import copy
22
23
import functools
23
24
import inspect
24
25
 
25
26
import eventlet
26
 
from oslo.utils import excutils
 
27
from oslo_utils import excutils
27
28
import six
28
29
 
29
30
from ironic.common import exception
94
95
    May be None, if the driver does not implement any vendor extensions.
95
96
    """
96
97
 
 
98
    inspect = None
 
99
    """`Standard` attribute for inspection related features.
 
100
 
 
101
    A reference to an instance of :class:InspectInterface.
 
102
    May be None, if unsupported by a driver.
 
103
    """
 
104
    standard_interfaces.append('inspect')
 
105
 
97
106
    @abc.abstractmethod
98
107
    def __init__(self):
99
108
        pass
114
123
        return properties
115
124
 
116
125
 
 
126
class BaseInterface(object):
 
127
    """A base interface implementing common functions for Driver Interfaces."""
 
128
    interface_type = 'base'
 
129
 
 
130
    def __new__(cls, *args, **kwargs):
 
131
        # Get the list of clean steps when the interface is initialized by
 
132
        # the conductor. We use __new__ instead of __init___
 
133
        # to avoid breaking backwards compatibility with all the drivers.
 
134
        # We want to return all steps, regardless of priority.
 
135
        instance = super(BaseInterface, cls).__new__(cls, *args, **kwargs)
 
136
        instance.clean_steps = []
 
137
        for n, method in inspect.getmembers(instance, inspect.ismethod):
 
138
            if getattr(method, '_is_clean_step', False):
 
139
                # Create a CleanStep to represent this method
 
140
                step = {'step': method.__name__,
 
141
                        'priority': method._clean_step_priority,
 
142
                        'interface': instance.interface_type}
 
143
                instance.clean_steps.append(step)
 
144
        LOG.debug('Found clean steps %(steps)s for interface %(interface)s',
 
145
                  {'steps': instance.clean_steps,
 
146
                   'interface': instance.interface_type})
 
147
        return instance
 
148
 
 
149
    def get_clean_steps(self, task):
 
150
        """Get a list of (enabled and disabled) clean steps for the interface.
 
151
 
 
152
        This function will return all clean steps (both enabled and disabled)
 
153
        for the interface, in an unordered list.
 
154
 
 
155
        :param task: A TaskManager object, useful for interfaces overriding
 
156
            this function
 
157
        :returns: A list of clean step dictionaries
 
158
        """
 
159
        return self.clean_steps
 
160
 
 
161
    def execute_clean_step(self, task, step):
 
162
        """Execute the clean step on task.node.
 
163
 
 
164
        A clean step should take a single argument: a TaskManager object.
 
165
        A step can be executed synchronously or asynchronously. A step should
 
166
        return None if the method has completed synchronously or
 
167
        states.CLEANING if the step will continue to execute asynchronously.
 
168
        If the step executes asynchronously, it should issue a call to the
 
169
        'continue_node_clean' RPC, so the conductor can begin the next
 
170
        clean step.
 
171
 
 
172
        :param task: A TaskManager object
 
173
        :param step: The clean step dictionary representing the step to execute
 
174
        :returns: None if this method has completed synchronously, or
 
175
            states.CLEANING if the step will continue to execute
 
176
            asynchronously.
 
177
        """
 
178
        return getattr(self, step['step'])(task)
 
179
 
 
180
 
117
181
@six.add_metaclass(abc.ABCMeta)
118
 
class DeployInterface(object):
 
182
class DeployInterface(BaseInterface):
119
183
    """Interface for deploy-related actions."""
 
184
    interface_type = 'deploy'
120
185
 
121
186
    @abc.abstractmethod
122
187
    def get_properties(self):
217
282
        :param task: a TaskManager instance containing the node to act on.
218
283
        """
219
284
 
 
285
    def prepare_cleaning(self, task):
 
286
        """Prepare the node for cleaning or zapping tasks.
 
287
 
 
288
        For example, nodes that use the Ironic Python Agent will need to
 
289
        boot the ramdisk in order to do in-band cleaning and zapping tasks.
 
290
 
 
291
        If the function is asynchronous, the driver will need to handle
 
292
        settings node.driver_internal_info['clean_steps'] and node.clean_step,
 
293
        as they would be set in ironic.conductor.manager._do_node_clean,
 
294
        but cannot be set when this is asynchronous. After, the interface
 
295
        should make an RPC call to continue_node_cleaning to start cleaning.
 
296
 
 
297
        NOTE(JoshNang) this should be moved to BootInterface when it gets
 
298
        implemented.
 
299
 
 
300
        :param task: a TaskManager instance containing the node to act on.
 
301
        :returns: If this function is going to be asynchronous, should return
 
302
            `states.CLEANING`. Otherwise, should return `None`. The interface
 
303
            will need to call _get_cleaning_steps and then RPC to
 
304
            continue_node_cleaning
 
305
        """
 
306
        pass
 
307
 
 
308
    def tear_down_cleaning(self, task):
 
309
        """Tear down after cleaning or zapping is completed.
 
310
 
 
311
        Given that cleaning or zapping is complete, do all cleanup and tear
 
312
        down necessary to allow the node to be deployed to again.
 
313
 
 
314
        NOTE(JoshNang) this should be moved to BootInterface when it gets
 
315
        implemented.
 
316
 
 
317
        :param task: a TaskManager instance containing the node to act on.
 
318
        """
 
319
        pass
 
320
 
220
321
 
221
322
@six.add_metaclass(abc.ABCMeta)
222
 
class PowerInterface(object):
 
323
class PowerInterface(BaseInterface):
223
324
    """Interface for power-related actions."""
 
325
    interface_type = 'power'
224
326
 
225
327
    @abc.abstractmethod
226
328
    def get_properties(self):
453
555
            dmeta = getattr(ref, '_driver_metadata', None)
454
556
 
455
557
            if vmeta is not None:
456
 
                vmeta.metadata['func'] = ref
457
 
                inst.vendor_routes.update({vmeta.method: vmeta.metadata})
 
558
                metadata = copy.deepcopy(vmeta.metadata)
 
559
                metadata['func'] = ref
 
560
                inst.vendor_routes.update({vmeta.method: metadata})
458
561
 
459
562
            if dmeta is not None:
460
 
                dmeta.metadata['func'] = ref
461
 
                inst.driver_routes.update({dmeta.method: dmeta.metadata})
 
563
                metadata = copy.deepcopy(dmeta.metadata)
 
564
                metadata['func'] = ref
 
565
                inst.driver_routes.update({dmeta.method: metadata})
462
566
 
463
567
        return inst
464
568
 
499
603
 
500
604
 
501
605
@six.add_metaclass(abc.ABCMeta)
502
 
class ManagementInterface(object):
 
606
class ManagementInterface(BaseInterface):
503
607
    """Interface for management related actions."""
 
608
    interface_type = 'management'
504
609
 
505
610
    @abc.abstractmethod
506
611
    def get_properties(self):
607
712
        """
608
713
 
609
714
 
 
715
@six.add_metaclass(abc.ABCMeta)
 
716
class InspectInterface(object):
 
717
    """Interface for inspection-related actions."""
 
718
 
 
719
    @abc.abstractmethod
 
720
    def get_properties(self):
 
721
        """Return the properties of the interface.
 
722
 
 
723
        :returns: dictionary of <property name>:<property description> entries.
 
724
        """
 
725
 
 
726
    @abc.abstractmethod
 
727
    def validate(self, task):
 
728
        """Validate the driver-specific inspection information.
 
729
 
 
730
        If invalid, raises an exception; otherwise returns None.
 
731
 
 
732
        :param task: a task from TaskManager.
 
733
        :raises: InvalidParameterValue
 
734
        :raises: MissingParameterValue
 
735
        """
 
736
 
 
737
    @abc.abstractmethod
 
738
    def inspect_hardware(self, task):
 
739
        """Inspect hardware.
 
740
 
 
741
        Inspect hardware to obtain the essential & additional hardware
 
742
        properties.
 
743
 
 
744
        :param task: a task from TaskManager.
 
745
        :raises: HardwareInspectionFailure, if unable to get essential
 
746
                 hardware properties.
 
747
        :returns: resulting state of the inspection i.e. states.MANAGEABLE
 
748
                  or None.
 
749
        """
 
750
 
 
751
 
 
752
def clean_step(priority):
 
753
    """Decorator for cleaning and zapping steps.
 
754
 
 
755
    If priority is greater than 0, the function will be executed as part of the
 
756
    CLEANING state for any node using the interface with the decorated clean
 
757
    step. During CLEANING, a list of steps will be ordered by priority for all
 
758
    interfaces associated with the node, and then execute_clean_step() will be
 
759
    called on each step. Steps will be executed based on priority, with the
 
760
    highest priority step being called first, the next highest priority
 
761
    being call next, and so on.
 
762
 
 
763
    Decorated clean steps should take a single argument, a TaskManager object.
 
764
 
 
765
    Any step with this decorator will be available for ZAPPING, even if
 
766
    priority is set to 0. Zapping steps will be executed in a similar fashion
 
767
    to cleaning and with the same TaskManager object, but the priority ordering
 
768
    is determined by the user when calling the zapping API.
 
769
 
 
770
    Clean steps can be either synchronous or asynchronous. If the step is
 
771
    synchronous, it should return `None` when finished, and the conductor will
 
772
    continue on to the next step. If the step is asynchronous, the step should
 
773
    return `states.CLEANING` to signal to the conductor. When the step is
 
774
    complete, the step should make an RPC call to `continue_node_clean` to move
 
775
    to the next step in cleaning.
 
776
 
 
777
    Example::
 
778
 
 
779
        class MyInterface(base.BaseInterface):
 
780
            # CONF.example_cleaning_priority should be an int CONF option
 
781
            @base.clean_step(priority=CONF.example_cleaning_priority)
 
782
            def example_cleaning(self, task):
 
783
                # do some cleaning
 
784
 
 
785
    :param priority: an integer priority, should be a CONF option
 
786
    """
 
787
    def decorator(func):
 
788
        func._is_clean_step = True
 
789
        func._clean_step_priority = priority
 
790
        return func
 
791
    return decorator
 
792
 
 
793
 
610
794
def driver_periodic_task(parallel=True, **other):
611
795
    """Decorator for a driver-specific periodic task.
612
796