X-Git-Url: https://gerrit.akraino.org/r/gitweb?p=ta%2Fironic-virtmedia-driver.git;a=blobdiff_plain;f=src%2Fironic_virtmedia_driver%2Fvendors%2Fdell%2Fdell.py;fp=src%2Fironic_virtmedia_driver%2Fvendors%2Fdell%2Fdell.py;h=e4fb2555d22ae105757670cb42c1e49b2a3ee379;hp=0000000000000000000000000000000000000000;hb=be2fb9459b65bb8b07b23adebadc16530d26e231;hpb=aaec6775b13b0c694235c80e6dfbca8696307af9 diff --git a/src/ironic_virtmedia_driver/vendors/dell/dell.py b/src/ironic_virtmedia_driver/vendors/dell/dell.py new file mode 100644 index 0000000..e4fb255 --- /dev/null +++ b/src/ironic_virtmedia_driver/vendors/dell/dell.py @@ -0,0 +1,161 @@ +# Copyright 2019 Nokia +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +from ironic.common import boot_devices +from ironic.common.i18n import _ +from ironic.conductor import utils as manager_utils +from ironic.drivers.modules import ipmitool +from ironic_virtmedia_driver.vendors.ironic_virtmedia_hw import IronicVirtMediaHW +from ironic_virtmedia_driver import virtmedia_exception + +from redfish import redfish_client, AuthMethod +from redfish.rest.v1 import ServerDownOrUnreachableError + +class DELL(IronicVirtMediaHW): + def __init__(self, log): + super(DELL, self).__init__(log) + self.remote_share = '/bootimages/' + self.idrac_location = '/redfish/v1/Managers/iDRAC.Embedded.1/' + + def _init_connection(self, driver_info): + """Get connection info and init rest_object""" + host = 'https://' + driver_info['address'] + user = driver_info['username'] + password = driver_info['password'] + redfishclient = None + self.log.debug("Init connection: user: %s, passwd: %s, host: %s", user, password, host) + try: + redfishclient = redfish_client(base_url=host, \ + username=user, password=password) + redfishclient.login(auth=AuthMethod.SESSION) + except ServerDownOrUnreachableError as error: + operation = _("iDRAC not responding") + raise virtmedia_exception.VirtmediaOperationError( + operation=operation, error=error) + except Exception as error: + operation = _("Failed to login to iDRAC") + raise virtmedia_exception.VirtmediaOperationError( + operation=operation, error=error) + return redfishclient + + @staticmethod + def _check_success(response): + if response.status >= 200 and response.status < 300: + return True + else: + try: + _ = response.dict + raise virtmedia_exception.VirtmediaOperationError("Response status is %d, %s"% (response.status, response.dict["error"]["@Message.ExtendedInfo"][0]["MessageId"].split("."))) + except Exception: + raise virtmedia_exception.VirtmediaOperationError("Response status is not 200, %s"% response) + + def _check_supported_idrac_version(self, connection): + response = connection.get('%s/VirtualMedia/CD'%self.idrac_location) + self._check_success(response) + data = response.dict + for i in data.get('Actions', []): + if i == "#VirtualMedia.InsertMedia" or i == "#VirtualMedia.EjectMedia": + return True + raise virtmedia_exception.VirtmediaOperationError("Unsupported version of iDRAC, please update before continuing") + + def _get_virtual_media_devices(self, connection): + idr = connection.get("%s" % self.idrac_location) + self._check_success(idr) + try: + virtual_media = connection.get(idr.dict["VirtualMedia"]["@odata.id"]) + self._check_success(virtual_media) + except KeyError: + self.log.error("Cannot find a single virtual media device") + raise virtmedia_exception.VirtmediaOperationError("Cannot find any virtual media device on the server") + return virtual_media.dict["Members"] + + def _umount_virtual_device(self, connection, media_uri): + self.log.debug("Unmount") + unmount_location = media_uri + "/Actions/VirtualMedia.EjectMedia" + resp = connection.post(unmount_location, body={}) + self._check_success(resp) + + def _mount_virtual_device(self, connection, media_uri, image_location): + self.log.debug("Mount") + mount_location = media_uri + "/Actions/VirtualMedia.InsertMedia" + payload = {'Image': image_location, 'Inserted':True, 'WriteProtected':True} + resp = connection.post(mount_location, body=payload) + self._check_success(resp) + + def _unmount_all(self, connection): + medias = self._get_virtual_media_devices(connection) + for media in medias: + uri = media.get("@odata.id", None) + if not uri or connection.get(uri).dict["ConnectedVia"] == "NotConnected": + continue + self._umount_virtual_device(connection, uri) + + def _find_first_media(self, connection, typeinfo): + medias = self._get_virtual_media_devices(connection) + for media in medias: + response = connection.get(media["@odata.id"]) + if typeinfo in response.dict["MediaTypes"]: + return media["@odata.id"] + return None + + def _mount_virtual_cd(self, connection, image_location): + self._unmount_all(connection) + self.log.debug("Mount") + media_uri = self._find_first_media(connection, "DVD") + self._mount_virtual_device(connection, media_uri, image_location) + + def attach_virtual_cd(self, image_filename, driver_info, task): + connection = None + try: + self.log.debug("attach_virtual_cd") + connection = self._init_connection(driver_info) + self._check_supported_idrac_version(connection) + image_location = 'http://' + driver_info['provisioning_server'] + ':' + driver_info['provisioning_server_http_port'] + self.remote_share + image_filename + self._mount_virtual_cd(connection, image_location) + + connection.logout() + return True + except Exception: + if connection: + connection.logout() + raise + + def detach_virtual_cd(self, driver_info, task): + connection = None + try: + self.log.debug("detach_virtual_cd") + connection = self._init_connection(driver_info) + self._check_supported_idrac_version(connection) + self._unmount_all(connection) + connection.logout() + return True + except Exception: + if connection: + connection.logout() + raise + + def set_boot_device(self, task): + try: + #BMC boot flag valid bit clearing 1f -> all bit set + #P 420 of ipmi spec + # https://www.intel.com/content/www/us/en/servers/ipmi/ipmi-second-gen-interface-spec-v2-rev1-1.html + cmd = '0x00 0x08 0x03 0x1f' + ipmitool.send_raw(task, cmd) + self.log.info('Disable timeout for booting') + except Exception as err: + self.log.warning('Failed to disable booting options: %s', str(err)) + #For time being lets do the boot order with ipmitool since, well dell doesn't provide open support + #for this. + manager_utils.node_set_boot_device(task, boot_devices.CDROM, persistent=False)