Seed code for ironic_virtmedia_driver
[ta/ironic-virtmedia-driver.git] / src / ironic_virtmedia_driver / virtmedia_ipmi_boot.py
1 # Copyright 2019 Nokia
2 #
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
6 #
7 #     http://www.apache.org/licenses/LICENSE-2.0
8 #
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
14 #
15
16 import sys
17 import time
18
19 from oslo_log import log as logging
20
21 from ironic.common.i18n import _
22 from ironic.drivers.modules import ipmitool
23 from ironic.common import exception
24 from ironic.conductor import utils as manager_utils
25 from ironic_virtmedia_driver import virtmedia
26
27 LOG = logging.getLogger(__name__)
28
29 REQUIRED_PROPERTIES = {
30     'provisioning_server': 'Provisioning server IP hosting deployment ISO and metadata Floppy images. Required.',
31     'provisioning_server_http_port': 'Provisioning server port where the images can be obtained with http requests. Required.',
32     'vendor': 'Vendor for the installed hardware. Required.',
33     'product_family': 'Product family for the hardware. Required.'
34 }
35
36 COMMON_PROPERTIES = REQUIRED_PROPERTIES.copy()
37
38 def _parse_driver_info(node):
39     """Gets the information needed for accessing the node.
40
41     :param node: the Node of interest.
42     :returns: dictionary of information.
43     :raises: InvalidParameterValue if any required parameters are incorrect.
44     :raises: MissingParameterValue if any required parameters are missing.
45
46     """
47     info = node.driver_info or {}
48     missing_info = [key for key in REQUIRED_PROPERTIES if not info.get(key)]
49     if missing_info:
50         raise exception.MissingParameterValue(_(
51             "virtmedia_ipmi driver requires the following parameters to be set in "
52             "node's driver_info: %s.") % missing_info)
53
54     provisioning_server = info.get('provisioning_server')
55     provisioning_server_http_port = info.get('provisioning_server_http_port')
56     vendor = info.get('vendor')
57     product_family = info.get('product_family')
58     ipmi_params = ipmitool._parse_driver_info(node)
59     res = {
60         'provisioning_server': provisioning_server,
61         'provisioning_server_http_port': provisioning_server_http_port,
62         'vendor': vendor,
63         'product_family': product_family,
64     }
65     return dict(ipmi_params.items() + res.items())
66
67 def _get_hw_library(driver_info):
68     try:
69         vendor = driver_info.get('vendor').lower()
70         product_family = driver_info.get('product_family').lower()
71         obj = driver_info.get('product_family')
72
73         modulename = 'ironic_virtmedia_driver.vendors.%s.%s'%(vendor, product_family)
74         if modulename not in sys.modules:
75             modulej = __import__(modulename, fromlist=[''])
76             globals()[modulename] = modulej
77
78         module = sys.modules[modulename]
79
80         modj = None
81         if obj in dir(module):
82             modj = getattr(module, obj)
83             globals()[obj] = modj
84         else:
85             msg = "Cannot find driver for your hardware from the module Vendor: %s Product family: %s" % (vendor, product_family)
86             LOG.exception(msg)
87             raise exception.NotFound(msg)
88
89         return modj(LOG)
90
91     except ImportError as err:
92         msg = "Cannot import driver for your hardware Vendor: %s Product family: %s :: %s"% (vendor, product_family, str(err))
93         LOG.exception(msg)
94         raise exception.NotFound(msg)
95     except KeyError as err:
96         LOG.exception("virtmedia has a problem with hw type")
97         raise exception.IronicException("Internal virtmedia error")
98     return None
99
100 class VirtualMediaAndIpmiBoot(virtmedia.VirtmediaBoot):
101     def __init__(self):
102         """Constructor of VirtualMediaAndIpmiBoot.
103
104         :raises: InvalidParameterValue, if config option has invalid value.
105         """
106         super(VirtualMediaAndIpmiBoot, self).__init__()
107
108     def _attach_virtual_cd(self, task, image_filename):
109         """Attaches the given url as virtual media on the node.
110
111         :param node: an ironic node object.
112         :param bootable_iso_filename: a bootable ISO image to attach to.
113             The iso file should be present in NFS/CIFS server.
114         :raises: VirtmediaOperationError if attaching virtual media failed.
115         """
116         retry_count = 2
117         driver_info = _parse_driver_info(task.node)
118
119         hw = _get_hw_library(driver_info)
120
121         while not hw.attach_virtual_cd(image_filename, driver_info, task) and retry_count:
122             retry_count -= 1
123             time.sleep(1)
124             LOG.debug("Virtual media attachment failed. Retrying again")
125
126         if not retry_count:
127             LOG.exception("Failed to attach Virtual media. Max retries exceeded")
128             raise exception.InstanceDeployFailure(reason='NFS mount failed!')
129
130     def _detach_virtual_cd(self, task):
131         """Detaches virtual cdrom on the node.
132
133         :param node: an ironic node object.
134         :raises: VirtmediaOperationError if eject virtual cdrom failed.
135         """
136         driver_info = _parse_driver_info(task.node)
137         hw = _get_hw_library(driver_info)
138         hw.detach_virtual_cd(driver_info, task)
139
140     def _set_deploy_boot_device(self, task):
141         """Set the boot device for deployment"""
142         driver_info = _parse_driver_info(task.node)
143         hw = _get_hw_library(driver_info)
144         hw.set_boot_device(task)