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

« back to all changes in this revision

Viewing changes to ironic/drivers/modules/seamicro.py

  • Committer: Package Import Robot
  • Author(s): James Page
  • Date: 2015-01-05 12:21:37 UTC
  • mfrom: (1.2.4)
  • Revision ID: package-import@ubuntu.com-20150105122137-171bqrdpcxqipunk
Tags: 2015.1~b1-0ubuntu1
* New upstream beta release:
  - d/control: Align version requirements with upstream release.
* d/watch: Update uversionmangle to deal with kilo beta versioning
  changes.
* d/control: Bumped Standards-Version to 3.9.6, no changes.

Show diffs side-by-side

added added

removed removed

Lines of Context:
18
18
 
19
19
Provides vendor passthru methods for SeaMicro specific functionality.
20
20
"""
 
21
import os
 
22
import re
21
23
 
22
24
from oslo.config import cfg
23
25
from oslo.utils import importutils
 
26
from six.moves.urllib import parse as urlparse
24
27
 
25
28
from ironic.common import boot_devices
26
29
from ironic.common import exception
30
33
from ironic.common import states
31
34
from ironic.conductor import task_manager
32
35
from ironic.drivers import base
 
36
from ironic.drivers.modules import console_utils
33
37
from ironic.openstack.common import log as logging
34
38
from ironic.openstack.common import loopingcall
35
39
 
55
59
 
56
60
LOG = logging.getLogger(__name__)
57
61
 
58
 
VENDOR_PASSTHRU_METHODS = ['attach_volume', 'set_node_vlan_id']
59
 
 
60
62
_BOOT_DEVICES_MAP = {
61
63
    boot_devices.DISK: 'hd0',
62
64
    boot_devices.PXE: 'pxe',
74
76
}
75
77
COMMON_PROPERTIES = REQUIRED_PROPERTIES.copy()
76
78
COMMON_PROPERTIES.update(OPTIONAL_PROPERTIES)
 
79
CONSOLE_PROPERTIES = {
 
80
    'seamicro_terminal_port': _("node's UDP port to connect to. "
 
81
                                "Only required for console access.")
 
82
}
 
83
PORT_BASE = 2000
77
84
 
78
85
 
79
86
def _get_client(*args, **kwargs):
101
108
    :param node: An Ironic node object.
102
109
    :returns: SeaMicro driver info.
103
110
    :raises: MissingParameterValue if any required parameters are missing.
 
111
    :raises: InvalidParameterValue if required parameter are invalid.
104
112
    """
105
113
 
106
114
    info = node.driver_info or {}
107
115
    missing_info = [key for key in REQUIRED_PROPERTIES if not info.get(key)]
108
116
    if missing_info:
109
117
        raise exception.MissingParameterValue(_(
110
 
            "SeaMicro driver requires the following to be set: %s.")
111
 
            % missing_info)
 
118
            "SeaMicro driver requires the following parameters to be set in"
 
119
            " node's driver_info: %s.") % missing_info)
112
120
 
113
121
    api_endpoint = info.get('seamicro_api_endpoint')
114
122
    username = info.get('seamicro_username')
115
123
    password = info.get('seamicro_password')
116
124
    server_id = info.get('seamicro_server_id')
117
125
    api_version = info.get('seamicro_api_version', "2")
 
126
    port = info.get('seamicro_terminal_port')
 
127
 
 
128
    if port:
 
129
        try:
 
130
            port = int(port)
 
131
        except ValueError:
 
132
            raise exception.InvalidParameterValue(_(
 
133
                "SeaMicro terminal port is not an integer."))
 
134
 
 
135
    r = re.compile(r"(^[0-9]+)/([0-9]+$)")
 
136
    if not r.match(server_id):
 
137
        raise exception.InvalidParameterValue(_(
 
138
            "Invalid 'seamicro_server_id' parameter in node's "
 
139
            "driver_info. Expected format of 'seamicro_server_id' "
 
140
            "is <int>/<int>"))
 
141
 
 
142
    url = urlparse.urlparse(api_endpoint)
 
143
    if (not (url.scheme == "http") or not url.netloc):
 
144
        raise exception.InvalidParameterValue(_(
 
145
            "Invalid 'seamicro_api_endpoint' parameter in node's "
 
146
            "driver_info."))
118
147
 
119
148
    res = {'username': username,
120
149
           'password': password,
121
150
           'api_endpoint': api_endpoint,
122
151
           'server_id': server_id,
123
152
           'api_version': api_version,
124
 
           'uuid': node.uuid}
 
153
           'uuid': node.uuid,
 
154
           'port': port}
125
155
 
126
156
    return res
127
157
 
250
280
 
251
281
 
252
282
def _reboot(node, timeout=None):
253
 
    """Reboot this node
 
283
    """Reboot this node.
 
284
 
254
285
    :param node: Ironic node one of :class:`ironic.db.models.Node`
255
286
    :param timeout: Time in seconds to wait till reboot is compelete
256
287
    :raises: InvalidParameterValue if a seamicro parameter is invalid.
330
361
                                                     least_used_pool)
331
362
 
332
363
 
 
364
def get_telnet_port(driver_info):
 
365
    """Get SeaMicro telnet port to listen."""
 
366
    server_id = int(driver_info['server_id'].split("/")[0])
 
367
    return PORT_BASE + (10 * server_id)
 
368
 
 
369
 
333
370
class Power(base.PowerInterface):
334
371
    """SeaMicro Power Interface.
335
372
 
415
452
        return COMMON_PROPERTIES
416
453
 
417
454
    def validate(self, task, **kwargs):
418
 
        method = kwargs['method']
419
 
        if method not in VENDOR_PASSTHRU_METHODS:
420
 
            raise exception.InvalidParameterValue(_(
421
 
                "Unsupported method (%s) passed to SeaMicro driver.")
422
 
                % method)
423
455
        _parse_driver_info(task.node)
424
456
 
425
 
    def vendor_passthru(self, task, **kwargs):
426
 
        """Dispatch vendor specific method calls."""
427
 
        method = kwargs['method']
428
 
        if method in VENDOR_PASSTHRU_METHODS:
429
 
            return getattr(self, "_" + method)(task, **kwargs)
430
 
 
431
 
    def _set_node_vlan_id(self, task, **kwargs):
 
457
    @base.passthru(['POST'])
 
458
    def set_node_vlan_id(self, task, **kwargs):
432
459
        """Sets a untagged vlan id for NIC 0 of node.
433
460
 
434
461
        @kwargs vlan_id: id of untagged vlan for NIC 0 of node
456
483
        node.properties = properties
457
484
        node.save()
458
485
 
459
 
    def _attach_volume(self, task, **kwargs):
460
 
        """Attach volume from SeaMicro storage pools for ironic to node.
461
 
            If kwargs['volume_id'] not given, Create volume in SeaMicro
462
 
            storage pool and attach to node.
 
486
    @base.passthru(['POST'])
 
487
    def attach_volume(self, task, **kwargs):
 
488
        """Attach a volume to a node.
 
489
 
 
490
        Attach volume from SeaMicro storage pools for ironic to node.
 
491
        If kwargs['volume_id'] not given, Create volume in SeaMicro
 
492
        storage pool and attach to node.
463
493
 
464
494
        @kwargs volume_id: id of pre-provisioned volume that is to be attached
465
495
                           as root volume of node
580
610
 
581
611
        """
582
612
        raise NotImplementedError()
 
613
 
 
614
 
 
615
class ShellinaboxConsole(base.ConsoleInterface):
 
616
    """A ConsoleInterface that uses telnet and shellinabox."""
 
617
 
 
618
    def get_properties(self):
 
619
        d = COMMON_PROPERTIES.copy()
 
620
        d.update(CONSOLE_PROPERTIES)
 
621
        return d
 
622
 
 
623
    def validate(self, task):
 
624
        """Validate the Node console info.
 
625
 
 
626
        :param task: a task from TaskManager.
 
627
        :raises: MissingParameterValue if required seamicro parameters are
 
628
                 missing
 
629
        :raises: InvalidParameterValue if required parameter are invalid.
 
630
        """
 
631
        driver_info = _parse_driver_info(task.node)
 
632
        if not driver_info['port']:
 
633
            raise exception.MissingParameterValue(_(
 
634
                "Missing 'seamicro_terminal_port' parameter in node's "
 
635
                "driver_info"))
 
636
 
 
637
    def start_console(self, task):
 
638
        """Start a remote console for the node.
 
639
 
 
640
        :param task: a task from TaskManager
 
641
        :raises: MissingParameterValue if required seamicro parameters are
 
642
                 missing
 
643
        :raises: ConsoleError if the directory for the PID file cannot be
 
644
                 created
 
645
        :raises: ConsoleSubprocessFailed when invoking the subprocess failed
 
646
        :raises: InvalidParameterValue if required parameter are invalid.
 
647
        """
 
648
 
 
649
        driver_info = _parse_driver_info(task.node)
 
650
        telnet_port = get_telnet_port(driver_info)
 
651
        chassis_ip = urlparse.urlparse(driver_info['api_endpoint']).netloc
 
652
 
 
653
        seamicro_cmd = ("/:%(uid)s:%(gid)s:HOME:telnet %(chassis)s %(port)s"
 
654
                       % {'uid': os.getuid(),
 
655
                          'gid': os.getgid(),
 
656
                          'chassis': chassis_ip,
 
657
                          'port': telnet_port})
 
658
 
 
659
        console_utils.start_shellinabox_console(driver_info['uuid'],
 
660
                                                driver_info['port'],
 
661
                                                seamicro_cmd)
 
662
 
 
663
    def stop_console(self, task):
 
664
        """Stop the remote console session for the node.
 
665
 
 
666
        :param task: a task from TaskManager
 
667
        :raises: MissingParameterValue if required seamicro parameters are
 
668
                 missing
 
669
        :raises: ConsoleError if unable to stop the console
 
670
        :raises: InvalidParameterValue if required parameter are invalid.
 
671
        """
 
672
 
 
673
        driver_info = _parse_driver_info(task.node)
 
674
        console_utils.stop_shellinabox_console(driver_info['uuid'])
 
675
 
 
676
    def get_console(self, task):
 
677
        """Get the type and connection information about the console.
 
678
 
 
679
        :raises: MissingParameterValue if required seamicro parameters are
 
680
                 missing
 
681
        :raises: InvalidParameterValue if required parameter are invalid.
 
682
        """
 
683
 
 
684
        driver_info = _parse_driver_info(task.node)
 
685
        url = console_utils.get_shellinabox_console_url(driver_info['port'])
 
686
        return {'type': 'shellinabox', 'url': url}