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
7 # http://www.apache.org/licenses/LICENSE-2.0
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.
18 from ironic.conductor import utils as manager_utils
19 from ironic.common import boot_devices
20 from ironic.common import exception
21 from ironic.drivers.modules import ipmitool
23 from .nokia_hw import NokiaIronicVirtMediaHW
25 class OR18(NokiaIronicVirtMediaHW):
26 def __init__(self, log):
27 super(OR18, self).__init__(log)
29 def get_disk_attachment_status(self, task):
30 # Check NFS Service Status
32 out, err = ipmitool.send_raw(task, '0x32 0xd8 0x06 0x01 0x01 0x00')
33 _image_name = str(bytearray.fromhex(out.replace('\n', '').strip()))
39 def _get_virtual_media_device_count(self, task, devicetype):
42 # Get num of enabled devices
43 if devicetype == 'CD':
45 self.log.debug('Get virtual CD count')
46 elif devicetype == 'FD':
48 self.log.debug('Get virtual FD count')
49 elif devicetype == 'HD':
51 self.log.debug('Get virtual HD count')
53 self.log.warning('Unknown device type "%s"' % devicetype)
56 cmd = '0x32 0xca %s' % _devparam
57 out, err = ipmitool.send_raw(task, cmd)
58 _num_inst = int(out.strip())
59 self.log.debug('Number of enabled %s devices is %d' % (devicetype, _num_inst))
61 except Exception as err:
62 # Drive might not be mounted to start with
63 self.log.debug('Exception when getting number of enabled %s devices. error: %s' % (devicetype, str(err)))
66 def _set_virtual_media_device_count(self, task, devicetype, devicecount):
67 # Chapter 46.2 page 181
68 if not 0 <= devicecount <= 4:
69 self.log.warning('Number of devices must be in range 0 to 4')
72 if devicetype == 'CD':
74 self.log.debug('Setting virtual CD count to %d' % devicecount)
75 elif devicetype == 'HD':
77 self.log.debug('Setting virtual HD count to %d' % devicecount)
79 self.log.warning('_set_virtual_media_device_count: Unknown device type "%s"' % devicetype)
83 cmd = '0x32 0xcb %s 0x%s' % (_devparam, str(devicecount))
84 ipmitool.send_raw(task, cmd)
86 _conf_device_num = self._get_virtual_media_device_count(task, devicetype)
88 while _conf_device_num != devicecount and _tries > 0:
89 self.log.debug('Virtual %s count is %d expecting %d' % (devicetype, _conf_device_num, devicecount))
91 _conf_device_num = self._get_virtual_media_device_count(task, devicetype)
94 except Exception as err:
95 self.log.warning('Exception when setting virtual media device count, error: %s' % str(err))
99 def _check_virtual_media_started(self, task):
100 service_status = None
101 # check virtmedia service status
103 cmd = '0x32 0xca 0x08'
104 out, err = ipmitool.send_raw(task, cmd)
105 service_status = out.strip()
106 self.log.warning('Virtual media service status: %s' % str(service_status))
107 except Exception as err:
108 self.log.warning('Exception when checking virtual media service: %s' % str(err))
109 if service_status == '01':
113 def _start_virtual_media(self, task):
114 # Enable "Remote Media Support" in GUI (p145)
116 cmd = '0x32 0xcb 0x08 0x01'
117 self.log.debug('Start virtual media service')
118 ipmitool.send_raw(task, cmd)
119 except Exception as err:
120 self.log.warning('Exception when starting virtual media service: %s' % str(err))
122 def _restart_virtual_media_service(self, task):
124 cmd = '0x32 0xcb 0x0a 0x01'
125 self.log.debug('Restart virtual media service')
126 ipmitool.send_raw(task, cmd)
127 except Exception as err:
128 self.log.warning('Exception when restarting virtual media service: %s' % str(err))
130 def _restart_ris(self, task):
132 self.log.debug('Restart RIS')
133 cmd = '0x32 0x9f 0x08 0x0b'
134 ipmitool.send_raw(task, cmd)
135 except Exception as err:
136 self.log.warning('Exception when restarting RIS: %s' % str(err))
140 def _restart_ris_cd(self, task):
142 self.log.debug('Restart RIS CD media')
143 cmd = '0x32 0x9f 0x01 0x0b 0x01'
144 ipmitool.send_raw(task, cmd)
145 except Exception as err:
146 self.log.warning('Exception when restarting RIS CD media: %s' % str(err))
150 def _enable_virtual_media(self, task):
151 # Speed up things if it service is already running
152 if self._check_virtual_media_started(task):
153 self.log.debug('Virtual media service already running.')
154 # Service is already started
159 self._start_virtual_media(task)
160 # Just enabling the service doe not seem to start it (in all HW)
161 # Resetting it after enabling helps
162 self._restart_virtual_media_service(task)
163 while (not self._check_virtual_media_started(task)):
164 if _try > _max_tries:
165 self.log.warning('Ensure virtual media service start failed, attempts exceeded.')
171 def _set_nfs_server_ip(self, driver_info, task):
173 cmd = '0x32 0x9f 0x01 0x02 0x00 %s' % (self.hex_convert(driver_info['provisioning_server'], True, 63))
174 self.log.debug('Virtual media server "%s"' % driver_info['provisioning_server'])
175 ipmitool.send_raw(task, cmd)
176 except Exception as err:
177 self.log.warning('Exception when setting virtual media server: %s' % str(err))
180 def _set_share_type(self, task):
182 cmd = '0x32 0x9f 0x01 0x05 0x00 0x6e 0x66 0x73 0x00 0x00 0x00'
183 self.log.debug('Virtual media share type to NFS.')
184 ipmitool.send_raw(task, cmd)
185 except Exception as err:
186 self.log.warning('Exception when setting virtual media service type NFS: %s' % str(err))
189 def _set_nfs_root_path(self, driver_info, task):
191 self.log.debug('Virtual media path to "%s"' % self.remote_share)
192 # set progress bit (hmm. seems to return error if it is already set.. So should check..)
193 # Welp there is no way checking this. As workaround clearing it first ( does not seem to
194 # return error even if alreay cleared).
196 cmd = '0x32 0x9f 0x01 0x01 0x00 0x00'
197 ipmitool.send_raw(task, cmd)
200 cmd = '0x32 0x9f 0x01 0x01 0x00 0x01'
201 ipmitool.send_raw(task, cmd)
203 cmd = '0x32 0x9f 0x01 0x01 0x01 %s' % (self.hex_convert(self.remote_share, True, 64))
204 ipmitool.send_raw(task, cmd)
207 cmd = '0x32 0x9f 0x01 0x01 0x00 0x00'
208 ipmitool.send_raw(task, cmd)
209 except Exception as err:
210 self.log.warning('Exception when setting virtual media path: %s' % str(err))
213 def _set_setup_nfs(self, driver_info, task):
216 self._set_share_type(task)
218 self._set_nfs_server_ip(driver_info, task)
219 # Set NFS Mount Root path
220 self._set_nfs_root_path(driver_info, task)
226 def _toggle_virtual_device(self, enabled, task):
227 # Enable "Mount CD/DVD" in GUI (p144) should cause vmedia restart withing 2 seconds.
228 # Seems "Mount CD/DVD" need to be enabled (or toggled) after config. refresh/vmedia restart
231 # cmd = '0x32 0xcb 0x00 0x0%s' %(str(int(enabled)))
237 cmd = '0x32 0xcb 0x00 0x%s' % _stat
238 self.log.debug('Set mount CD/DVD enable status %s' % str(enabled))
239 ipmitool.send_raw(task, cmd)
244 self.log.debug('Ensure CD/DVD enable status is %s' % str(enabled))
245 while (_status != _stat):
246 if _try > _max_tries:
247 self.log.warning('Ensure virtual media status failed, attempts exceeded. Ignoring.')
250 cmd = '0x32 0xca 0x00'
251 out, err = ipmitool.send_raw(task, cmd)
252 _status = out.strip()
253 self.log.debug('CD/DVD enable status is "%s"' % str(_status))
256 except Exception as err:
257 self.log.warning('Exception when CD/DVD virtual media new firmware? ignoring... Error: %s' % str(err))
260 def _mount_virtual_device(self, task):
261 return self._toggle_virtual_device(True, task)
263 def _demount_virtual_device(self, task):
264 return self._toggle_virtual_device(False, task)
266 def _get_mounted_image_count(self, task):
269 cmd = '0x32 0xd8 0x00 0x01'
270 out, err = ipmitool.send_raw(task, cmd)
273 count = int(data, 16)
274 self.log.debug('Available image count: %d' % count)
275 except Exception as err:
276 self.log.debug('Exception when trying to get the image count: %s' % str(err))
279 def _set_image_name(self, image_filename, task):
281 #cmd = '0x32 0xd7 0x01 0x01 0x01 0x01 %s' % (self.hex_convert(image_filename))
282 cmd = '0x32 0xd7 0x01 0x01 0x01 0x01 %s' % (self.hex_convert(image_filename, True, 64))
283 self.log.debug('Setting virtual media image: %s' % image_filename)
284 ipmitool.send_raw(task, cmd)
285 except Exception as err:
286 self.log.debug('Exception when setting virtual media image: %s' % str(err))
290 def _stop_remote_redirection(self, task):
292 # Get num of enabled devices
293 _num_inst = self._get_virtual_media_device_count(task, 'CD')
294 for driveindex in range(0, _num_inst):
295 cmd = '0x32 0xd7 0x00 0x01 0x01 0x00 %s' % hex(driveindex)
296 self.log.debug('Stop redirection CD/DVD drive index %d' % driveindex)
297 out, err = ipmitool.send_raw(task, cmd)
298 self.log.debug('ipmitool out = %s' % (out))
299 except Exception as err:
300 # Drive might not be mounted to start with
301 self.log.debug('_stop_remote_redirection: Ignoring exception when stopping redirection CD/DVD drive index %d error: %s' % (driveindex, str(err)))
304 def _clear_ris_configuration(self, task):
305 # Clear RIS configuration
307 cmd = '0x32 0x9f 0x01 0x0d'
308 self.log.debug('Clear RIS configuration.')
309 ipmitool.send_raw(task, cmd)
310 except Exception as err:
311 self.log.warning('Exception when clearing RIS NFS configuration: %s' % str(err))
315 def _wait_for_mount_count(self, task):
316 # Poll until we got some images from server
319 while self._get_mounted_image_count(task) == 0:
320 self.log.debug('Check available images count try %d/%d' % (_try, _max_tries))
321 if _try > _max_tries:
322 self.log.warning('Available images count 0, attempts exceeded.')
328 def attach_virtual_cd(self, image_filename, driver_info, task):
330 #Enable virtual media
331 if not self._enable_virtual_media(task):
332 self.log.error("Failed to enable virtual media")
335 #Enable CD/DVD device
336 if not self._toggle_virtual_device(True, task):
337 self.log.error("Failed to enable virtual device")
340 #Clear RIS configuration
341 if not self._clear_ris_configuration(task):
342 self.log.error("Failed to clear RIS configuration")
346 if not self._set_setup_nfs(driver_info, task):
347 self.log.error("Failed to setup nfs")
350 # Restart Remote Image CD
351 if not self._restart_ris_cd(task):
352 self.log.error("Failed to restart RIS CD")
355 #Wait for device to be mounted
356 if not self._wait_for_mount_count(task):
357 self.log.error("Failed when waiting for the device to appear")
361 if not self._set_image_name(image_filename, task):
362 self.log.error("Failed to set image name")
365 return self.check_and_wait_for_cd_mounting(image_filename, task, driver_info)
367 def detach_virtual_cd(self, driver_info, task):
368 """Detaches virtual cdrom on the node.
370 :param task: an ironic task object
372 #Enable virtual media
373 if not self._enable_virtual_media(task):
374 self.log.error("detach_virtual_cd: Failed to enable virtual media")
377 # Restart Remote Image Service
378 if not self._restart_ris(task):
379 self.log.error("Failed to restart RIS")
383 self._stop_remote_redirection(task)
385 #Clear RIS configuration
386 if not self._clear_ris_configuration(task):
387 self.log.error("detach_virtual_cd: Failed to clear RIS configuration")
390 #Demount virtual device
391 if not self._demount_virtual_device(task):
392 self.log.error('detach_virtual_cd: Exception when disabling CD/DVD virtual media')
395 # Reduce the number of virtual devices (both HD and CD default to 4 devices each)
396 if not self._set_virtual_media_device_count(task, 'HD', 0):
398 if not self._set_virtual_media_device_count(task, 'CD', 1):
403 def set_boot_device(self, task):
404 manager_utils.node_set_boot_device(task, boot_devices.CDROM, persistent=True)
406 # #Set boot device to virtual remote CD/DVD persistenly
409 # #P 422 of ipmi spec
410 # cmd = '0x00 0x08 0x05 0xC0 0x20 0x00 0x00 0x00'
411 # out, err = ipmitool.send_raw(task, cmd)
412 # #BMC boot flag valid bit clearing 1f -> all bit set
413 # #P 420 of ipmi spec
414 # cmd = '0x00 0x08 0x03 0x1f'
415 # out, err = ipmitool.send_raw(task, cmd)
416 # self.log.info('Set the boot device to remote cd')
417 # except Exception as err:
418 # self.log.warning('Error when setting boot device to remote cd')