Seed code for ironic_virtmedia_driver
[ta/ironic-virtmedia-driver.git] / src / ironic_virtmedia_driver / vendors / hp / hp.py
diff --git a/src/ironic_virtmedia_driver/vendors/hp/hp.py b/src/ironic_virtmedia_driver/vendors/hp/hp.py
new file mode 100644 (file)
index 0000000..a1ff242
--- /dev/null
@@ -0,0 +1,149 @@
+# 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.
+#
+
+import json
+
+from ironic.common.i18n import _
+
+from ironic_virtmedia_driver.vendors.ironic_virtmedia_hw import IronicVirtMediaHW
+from ironic_virtmedia_driver import virtmedia_exception
+
+import redfish.ris.tpdefs
+from redfish import AuthMethod, redfish_client
+from redfish.rest.v1 import ServerDownOrUnreachableError
+
+class HP(IronicVirtMediaHW):
+    def __init__(self, log):
+        super(HP, self).__init__(log)
+        self.remote_share = '/bootimages/'
+        self.typepath = None
+
+    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
+        try:
+            redfishclient = redfish_client(base_url=host, \
+                  username=user, password=password, \
+                  default_prefix="/redfish/v1")
+            redfishclient.login(auth=AuthMethod.SESSION)
+            self._init_typepath(redfishclient)
+        except ServerDownOrUnreachableError as error:
+            operation = _("iLO not responding")
+            raise virtmedia_exception.VirtmediaOperationError(
+                operation=operation, error=error)
+        except Exception as error:
+            operation = _("Failed to login to iLO")
+            raise virtmedia_exception.VirtmediaOperationError(
+                operation=operation, error=error)
+        return redfishclient
+
+    def _init_typepath(self, connection):
+        typepath = redfish.ris.tpdefs.Typesandpathdefines()
+        typepath.getgen(url=connection.get_base_url())
+        typepath.defs.redfishchange()
+        self.typepath = typepath
+
+    def _search_for_type(self, typename, resources):
+        instances = []
+        nosettings = [item for item in resources["resources"] if "/settings/" not in item["@odata.id"]]
+        for item in nosettings:
+            if "@odata.type" in item and \
+               typename.lower() in item["@odata.type"].lower():
+                instances.append(item)
+        return instances
+
+    def _get_instances(self, connection):
+        resources = {}
+
+        response = connection.get("/redfish/v1/resourcedirectory/")
+        if response.status == 200:
+            resources["resources"] = response.dict["Instances"]
+        else:
+            return []
+
+        return self._search_for_type("Manager.", resources)
+
+    def _get_error(self, response):
+        message = json.loads(response.text)
+        error = message["error"]["@Message.ExtendedInfo"][0]["MessageId"].split(".")
+        return error
+
+
+    def _umount_virtual_cd(self, connection, cd_location):
+        unmount_path = cd_location
+        unmount_body = {"Action": "EjectVirtualMedia", "Target": self.typepath.defs.oempath}
+        resp = connection.post(path=unmount_path, body=unmount_body)
+        if resp.status != 200:
+            self.log.error("Unmounting cd failed: %r, cd location: %r", resp, unmount_path)
+            operation = _("Failed to unmount image")
+            error = self._get_error(resp)
+            raise virtmedia_exception.VirtmediaOperationError(
+                operation=operation, error=error)
+
+
+    def _get_virtual_media_devices(self, connection, instance):
+        rsp = connection.get(instance["@odata.id"])
+        rsp = connection.get(rsp.dict["VirtualMedia"]["@odata.id"])
+        return rsp.dict['Members']
+
+    def _mount_virtual_cd(self, connection, image_location):
+        instances = self._get_instances(connection)
+        for instance in instances:
+            for vmlink in self._get_virtual_media_devices(connection, instance):
+                response = connection.get(vmlink["@odata.id"])
+
+                if response.status == 200 and "DVD" in response.dict["MediaTypes"]:
+                    if response.dict['Inserted']:
+                        self._umount_virtual_cd(connection, vmlink["@odata.id"])
+
+                    body = {"Image": image_location}
+
+                    if image_location:
+                        body["Oem"] = {self.typepath.defs.oemhp: {"BootOnNextServerReset": \
+                                                        True}}
+
+                        response = connection.patch(path=vmlink["@odata.id"], body=body)
+                elif response.status != 200:
+                    self.log.error("Failed to mount image")
+                    error = self._get_error(response)
+                    operation = _("Failed to mount image")
+                    raise virtmedia_exception.VirtmediaOperationError(
+                        operation=operation, error=error)
+
+    def attach_virtual_cd(self, image_filename, driver_info, task):
+        connection = self._init_connection(driver_info)
+        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
+
+    def detach_virtual_cd(self, driver_info, task):
+        connection = self._init_connection(driver_info)
+        instances = self._get_instances(connection)
+        for instance in instances:
+            for vmlink in self._get_virtual_media_devices(connection, instance):
+                response = connection.get(vmlink["@odata.id"])
+                if response.status == 200 and "DVD" in response.dict["MediaTypes"]:
+                    if response.dict['Inserted']:
+                        self._umount_virtual_cd(connection, vmlink["@odata.id"])
+        connection.logout()
+        return True
+
+    def set_boot_device(self, task):
+        """ This is done during the mounting"""
+        pass