Add support for Ampere Falcon server
[ta/ironic-virtmedia-driver.git] / src / ironic_virtmedia_driver / vendors / openbmc_hw.py
1 # Copyright 2019 Nokia
2 # Copyright 2019 Cachengo
3 # Copyright 2019 ENEA
4 #
5 # Licensed under the Apache License, Version 2.0 (the "License");
6 # you may not use this file except in compliance with the License.
7 # You may obtain a copy of the License at
8 #
9 #     http://www.apache.org/licenses/LICENSE-2.0
10 #
11 # Unless required by applicable law or agreed to in writing, software
12 # distributed under the License is distributed on an "AS IS" BASIS,
13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 # See the License for the specific language governing permissions and
15 # limitations under the License.
16 #
17
18 import time
19
20 from ironic.drivers.modules import ipmitool
21 from ironic.common.i18n import  _translators
22 from oslo_concurrency import processutils
23 from ironic.common import exception
24
25 from .ironic_virtmedia_hw import IronicVirtMediaHW
26
27 class OpenBMCIronicVirtMediaHW(IronicVirtMediaHW):
28     def __init__(self, log):
29         super(OpenBMCIronicVirtMediaHW, self).__init__(log)
30         self.remote_share = '/remote_image_share_root/'
31
32     def get_disk_attachment_status(self, task):
33         """ Get the disk attachment status.
34         :param task: a TaskManager instance.
35         :returns: <str>: 'mounting' if operation is ongoing
36                          'nfserror' if failed
37                          'mounted' if the disk is successfully mounted
38         """
39         raise NotImplementedError
40
41     @staticmethod
42     def hex_convert(string_value, padding=False, length=0):
43         if padding:
44            string_value = string_value.ljust(length, '\0')
45         return ' '.join('0x%s' % x.encode('hex') for x in string_value)
46
47     def _issue_bmc_reset(self, driver_info, task):
48         """ Issues a bmc reset and waits till the BMC is ready for servicing
49         """
50         cmd = 'bmc reset cold'
51         node_uuid = task.node.uuid
52         self.log.debug("Issuing bmc cold reset to node %s" %(task.node.name))
53         try:
54             out, err = ipmitool._exec_ipmitool(driver_info, cmd)
55             self.log.debug('bmc reset returned stdout: %(stdout)s, stderr:'
56                            ' %(stderr)s', {'stdout': out, 'stderr': err})
57         except processutils.ProcessExecutionError as err:
58             self.log.exception(_translators.log_error('IPMI "bmc reset" failed for node %(node_id)s '
59                                                       'with error: %(error)s.'),
60                                {'node_id': node_uuid, 'error': err})
61             raise exception.IPMIFailure(cmd=cmd)
62
63         sleep_count = 10
64         cmd = 'bmc info'
65         while sleep_count:
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                 break
71             except processutils.ProcessExecutionError as err:
72                 self.log.debug(_translators.log_error('IPMI "bmc info" failed for node %(node_id)s '
73                                                       'with error: %(error)s. Sleeping and retrying later.'
74                                                       'sleep_count: %(sleep_count)s'),
75                                {'node_id': node_uuid, 'error': err, 'sleep_count': sleep_count})
76                 time.sleep(10)
77                 sleep_count -= 1
78
79         if not sleep_count:
80             self.log.exception('After bmc reset, connection to bmc is lost!')
81             raise exception.IPMIFailure(cmd='bmc reset')
82
83
84     def _wait_for_cd_mounting(self, driver_info, task):
85         sleep_count = 10
86         while self.get_disk_attachment_status(task) == 'mounting' and sleep_count:
87             self.log.debug("Waiting for the CD to be Mounted")
88             sleep_count -= 1
89             time.sleep(1)
90
91         if sleep_count:
92             return True
93
94         self.log.warning("NFS mount timed out!. Trying BMC reset!")
95         self._issue_bmc_reset(driver_info, task)
96
97     def check_and_wait_for_cd_mounting(self, image_filename, task, driver_info):
98         mount_status = self.get_disk_attachment_status(task)
99         if mount_status == 'mounting':
100             if self._wait_for_cd_mounting(driver_info, task):
101                 self.log.debug("Attached CD: %s" %(image_filename))
102                 return True
103             else:
104                 return False
105         elif mount_status == 'nfserror':
106             self.log.exception("NFS mount failed!. Issue could be with NFS server status or connectivity to target.")
107             raise exception.InstanceDeployFailure(reason='NFS mount failed!')
108         elif mount_status == 'mounted':
109             self.log.debug("Attached CD: %s" %(image_filename))
110             return True
111         else:
112             self.log.exception("NFS mount failed!. Unknown error!")
113             raise exception.InstanceDeployFailure(reason='NFS mount failed!')