Seed code for ironic_virtmedia_driver
[ta/ironic-virtmedia-driver.git] / src / ironic_virtmedia_driver / vendors / nokia / nokia_hw.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 time
17
18 from ironic.drivers.modules import ipmitool
19 from ironic.common.i18n import  _translators
20 from oslo_concurrency import processutils
21 from ironic.common import exception
22
23 from ..ironic_virtmedia_hw import IronicVirtMediaHW
24
25 class NokiaIronicVirtMediaHW(IronicVirtMediaHW):
26     def __init__(self, log):
27         super(NokiaIronicVirtMediaHW, self).__init__(log)
28         self.remote_share = '/remote_image_share_root/'
29
30     def attach_virtual_cd(self, image_filename, driver_info, task):
31         """ see ironic_virtmedia_hw.py"""
32         raise NotImplementedError
33
34     def detach_virtual_cd(self, driver_info, task):
35         """ see ironic_virtmedia_hw.py"""
36         raise NotImplementedError
37
38     def set_boot_device(self, task):
39         """ see ironic_virtmedia_hw.py"""
40         raise NotImplementedError
41
42     def get_disk_attachment_status(self, task):
43         """ Get the disk attachment status.
44         :param task: a TaskManager instance.
45         :returns: <str>: 'mounting' if operation is ongoing
46                          'nfserror' if failed
47                          'mounted' if the disk is successfully mounted
48         """
49         raise NotImplementedError
50
51     @staticmethod
52     def hex_convert(string_value, padding=False, length=0):
53         hex_value = '0x'
54         hex_value += ' 0x'.join(x.encode('hex') for x in string_value)
55         if padding and (len(string_value)<length):
56             hex_value += ' 0x'
57             hex_value += ' 0x'.join('00' for _ in range(len(string_value), length)) 
58         return hex_value
59
60     def _issue_bmc_reset(self, driver_info, task):
61         """ Issues a bmc reset and waits till the bcm is ready for servicing
62         """
63         cmd = 'bmc reset cold'
64         node_uuid = task.node.uuid
65         self.log.debug("Issuing bmc cold reset to node %s" %(task.node.name))
66         try:
67             out, err = ipmitool._exec_ipmitool(driver_info, cmd)
68             self.log.debug('bmc reset returned stdout: %(stdout)s, stderr:'
69                            ' %(stderr)s', {'stdout': out, 'stderr': err})
70         except processutils.ProcessExecutionError as err:
71             self.log.exception(_translators.log_error('IPMI "bmc reset" failed for node %(node_id)s '
72                                                       'with error: %(error)s.'),
73                                {'node_id': node_uuid, 'error': err})
74             raise exception.IPMIFailure(cmd=cmd)
75
76         sleep_count = 10
77         cmd = 'bmc info'
78         while sleep_count:
79             try:
80                 out, err = ipmitool._exec_ipmitool(driver_info, cmd)
81                 self.log.debug('bmc reset returned stdout: %(stdout)s, stderr:'
82                                ' %(stderr)s', {'stdout': out, 'stderr': err})
83                 break
84             except processutils.ProcessExecutionError as err:
85                 self.log.debug(_translators.log_error('IPMI "bmc info" failed for node %(node_id)s '
86                                                       'with error: %(error)s. Sleeping and retrying later.'
87                                                       'sleep_count: %(sleep_count)s'),
88                                {'node_id': node_uuid, 'error': err, 'sleep_count': sleep_count})
89                 time.sleep(10)
90                 sleep_count -= 1
91
92         if not sleep_count:
93             self.log.exception('After bmc reset, connection to bmc is lost!')
94             raise exception.IPMIFailure(cmd='bmc reset')
95
96
97     def _wait_for_cd_mounting(self, driver_info, task):
98         sleep_count = 10
99         while self.get_disk_attachment_status(task) == 'mounting' and sleep_count:
100             self.log.debug("Waiting for the CD to be Mounted")
101             sleep_count -= 1
102             time.sleep(1)
103
104         if sleep_count:
105             return True
106
107         self.log.warning("NFS mount timed out!. Trying BMC reset!")
108         self._issue_bmc_reset(driver_info, task)
109
110     def check_and_wait_for_cd_mounting(self, image_filename, task, driver_info):
111         mount_status = self.get_disk_attachment_status(task)
112         if mount_status == 'mounting':
113             if self._wait_for_cd_mounting(driver_info, task):
114                 self.log.debug("Attached CD: %s" %(image_filename))
115                 return True
116             else:
117                 return False
118         elif mount_status == 'nfserror':
119             self.log.exception("NFS mount failed!. Issue could be with NFS server status or connectivity to target.")
120             raise exception.InstanceDeployFailure(reason='NFS mount failed!')
121         elif mount_status == 'mounted':
122             self.log.debug("Attached CD: %s" %(image_filename))
123             return True
124         else:
125             self.log.exception("NFS mount failed!. Unknown error!")
126             raise exception.InstanceDeployFailure(reason='NFS mount failed!')