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.common.i18n import _
20 from ironic_virtmedia_driver.vendors.ironic_virtmedia_hw import IronicVirtMediaHW
21 from ironic_virtmedia_driver import virtmedia_exception
23 import redfish.ris.tpdefs
24 from redfish import AuthMethod, redfish_client
25 from redfish.rest.v1 import ServerDownOrUnreachableError
27 class HP(IronicVirtMediaHW):
28 def __init__(self, log):
29 super(HP, self).__init__(log)
30 self.remote_share = '/bootimages/'
33 def _init_connection(self, driver_info):
34 """Get connection info and init rest_object"""
35 host = 'https://' + driver_info['address']
36 user = driver_info['username']
37 password = driver_info['password']
40 redfishclient = redfish_client(base_url=host, \
41 username=user, password=password, \
42 default_prefix="/redfish/v1")
43 redfishclient.login(auth=AuthMethod.SESSION)
44 self._init_typepath(redfishclient)
45 except ServerDownOrUnreachableError as error:
46 operation = _("iLO not responding")
47 raise virtmedia_exception.VirtmediaOperationError(
48 operation=operation, error=error)
49 except Exception as error:
50 operation = _("Failed to login to iLO")
51 raise virtmedia_exception.VirtmediaOperationError(
52 operation=operation, error=error)
55 def _init_typepath(self, connection):
56 typepath = redfish.ris.tpdefs.Typesandpathdefines()
57 typepath.getgen(url=connection.get_base_url())
58 typepath.defs.redfishchange()
59 self.typepath = typepath
61 def _search_for_type(self, typename, resources):
63 nosettings = [item for item in resources["resources"] if "/settings/" not in item["@odata.id"]]
64 for item in nosettings:
65 if "@odata.type" in item and \
66 typename.lower() in item["@odata.type"].lower():
67 instances.append(item)
70 def _get_instances(self, connection):
73 response = connection.get("/redfish/v1/resourcedirectory/")
74 if response.status == 200:
75 resources["resources"] = response.dict["Instances"]
79 return self._search_for_type("Manager.", resources)
81 def _get_error(self, response):
82 message = json.loads(response.text)
83 error = message["error"]["@Message.ExtendedInfo"][0]["MessageId"].split(".")
86 def _get_eject_media(self, response):
88 r_dict = response.dict
89 ops = r_dict.get("Oem", {}).get(self.typepath.defs.oemhp, {}).get("Actions")
91 for key in ops.keys():
92 if "EjectVirtualMedia" in key:
93 return ops[key]['target']
94 except Exception as err:
95 self.log.error("Failure in finding eject action from response")
98 def _umount_virtual_cd(self, connection, response):
101 if self.typepath.defs.isgen10 or \
102 self.typepath.defs.isgen9:
103 unmount_path = self._get_eject_media(response)
106 operation = _("Failed to unmount image")
107 error = _("Failed to find unmount path")
108 raise virtmedia_exception.VirtmediaOperationError(
109 operation=operation, error=error)
111 unmount_path = response.dict.get("@odata.id", "")
112 unmount_body = {"Action": "EjectVirtualMedia",
113 "Target": self.typepath.defs.oempath}
115 resp = connection.post(path=unmount_path, body=unmount_body)
116 if resp.status != 200:
117 self.log.error("Unmounting cd failed: %r, cd location: %r", resp, unmount_path)
118 operation = _("Failed to unmount image")
119 error = self._get_error(resp)
120 raise virtmedia_exception.VirtmediaOperationError(
121 operation=operation, error=error)
124 def _get_virtual_media_devices(self, connection, instance):
125 rsp = connection.get(instance["@odata.id"])
126 rsp = connection.get(rsp.dict["VirtualMedia"]["@odata.id"])
127 return rsp.dict['Members']
129 def _mount_virtual_cd(self, connection, image_location):
130 instances = self._get_instances(connection)
131 for instance in instances:
132 for vmlink in self._get_virtual_media_devices(connection, instance):
133 response = connection.get(vmlink["@odata.id"])
135 if response.status == 200 and "DVD" in response.dict["MediaTypes"]:
136 if response.dict['Inserted']:
137 self._umount_virtual_cd(connection, response)
139 body = {"Image": image_location}
142 body["Oem"] = {self.typepath.defs.oemhp: {"BootOnNextServerReset": \
145 response = connection.patch(path=vmlink["@odata.id"], body=body)
146 elif response.status != 200:
147 self.log.error("Failed to mount image")
148 error = self._get_error(response)
149 operation = _("Failed to mount image")
150 raise virtmedia_exception.VirtmediaOperationError(
151 operation=operation, error=error)
153 def attach_virtual_cd(self, image_filename, driver_info, task):
154 connection = self._init_connection(driver_info)
155 image_location = 'http://' + driver_info['provisioning_server'] + ':' + driver_info['provisioning_server_http_port'] + self.remote_share + image_filename
156 self._mount_virtual_cd(connection, image_location)
160 def detach_virtual_cd(self, driver_info, task):
161 connection = self._init_connection(driver_info)
162 instances = self._get_instances(connection)
163 for instance in instances:
164 for vmlink in self._get_virtual_media_devices(connection, instance):
165 response = connection.get(vmlink["@odata.id"])
166 if response.status == 200 and "DVD" in response.dict["MediaTypes"]:
167 if response.dict['Inserted']:
168 self._umount_virtual_cd(connection, response)
172 def set_boot_device(self, task):
173 """ This is done during the mounting"""