Seed code for ironic_virtmedia_driver
[ta/ironic-virtmedia-driver.git] / src / ironic_virtmedia_driver / vendors / hp / hp.py
1 # Copyright 2019 Nokia
2 #
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
6 #
7 #     http://www.apache.org/licenses/LICENSE-2.0
8 #
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.
14 #
15
16 import json
17
18 from ironic.common.i18n import _
19
20 from ironic_virtmedia_driver.vendors.ironic_virtmedia_hw import IronicVirtMediaHW
21 from ironic_virtmedia_driver import virtmedia_exception
22
23 import redfish.ris.tpdefs
24 from redfish import AuthMethod, redfish_client
25 from redfish.rest.v1 import ServerDownOrUnreachableError
26
27 class HP(IronicVirtMediaHW):
28     def __init__(self, log):
29         super(HP, self).__init__(log)
30         self.remote_share = '/bootimages/'
31         self.typepath = None
32
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']
38         redfishclient = None
39         try:
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)
53         return redfishclient
54
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
60
61     def _search_for_type(self, typename, resources):
62         instances = []
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)
68         return instances
69
70     def _get_instances(self, connection):
71         resources = {}
72
73         response = connection.get("/redfish/v1/resourcedirectory/")
74         if response.status == 200:
75             resources["resources"] = response.dict["Instances"]
76         else:
77             return []
78
79         return self._search_for_type("Manager.", resources)
80
81     def _get_error(self, response):
82         message = json.loads(response.text)
83         error = message["error"]["@Message.ExtendedInfo"][0]["MessageId"].split(".")
84         return error
85
86
87     def _umount_virtual_cd(self, connection, cd_location):
88         unmount_path = cd_location
89         unmount_body = {"Action": "EjectVirtualMedia", "Target": self.typepath.defs.oempath}
90         resp = connection.post(path=unmount_path, body=unmount_body)
91         if resp.status != 200:
92             self.log.error("Unmounting cd failed: %r, cd location: %r", resp, unmount_path)
93             operation = _("Failed to unmount image")
94             error = self._get_error(resp)
95             raise virtmedia_exception.VirtmediaOperationError(
96                 operation=operation, error=error)
97
98
99     def _get_virtual_media_devices(self, connection, instance):
100         rsp = connection.get(instance["@odata.id"])
101         rsp = connection.get(rsp.dict["VirtualMedia"]["@odata.id"])
102         return rsp.dict['Members']
103
104     def _mount_virtual_cd(self, connection, image_location):
105         instances = self._get_instances(connection)
106         for instance in instances:
107             for vmlink in self._get_virtual_media_devices(connection, instance):
108                 response = connection.get(vmlink["@odata.id"])
109
110                 if response.status == 200 and "DVD" in response.dict["MediaTypes"]:
111                     if response.dict['Inserted']:
112                         self._umount_virtual_cd(connection, vmlink["@odata.id"])
113
114                     body = {"Image": image_location}
115
116                     if image_location:
117                         body["Oem"] = {self.typepath.defs.oemhp: {"BootOnNextServerReset": \
118                                                         True}}
119
120                         response = connection.patch(path=vmlink["@odata.id"], body=body)
121                 elif response.status != 200:
122                     self.log.error("Failed to mount image")
123                     error = self._get_error(response)
124                     operation = _("Failed to mount image")
125                     raise virtmedia_exception.VirtmediaOperationError(
126                         operation=operation, error=error)
127
128     def attach_virtual_cd(self, image_filename, driver_info, task):
129         connection = self._init_connection(driver_info)
130         image_location = 'http://' + driver_info['provisioning_server'] + ':' + driver_info['provisioning_server_http_port'] + self.remote_share + image_filename
131         self._mount_virtual_cd(connection, image_location)
132         connection.logout()
133         return True
134
135     def detach_virtual_cd(self, driver_info, task):
136         connection = self._init_connection(driver_info)
137         instances = self._get_instances(connection)
138         for instance in instances:
139             for vmlink in self._get_virtual_media_devices(connection, instance):
140                 response = connection.get(vmlink["@odata.id"])
141                 if response.status == 200 and "DVD" in response.dict["MediaTypes"]:
142                     if response.dict['Inserted']:
143                         self._umount_virtual_cd(connection, vmlink["@odata.id"])
144         connection.logout()
145         return True
146
147     def set_boot_device(self, task):
148         """ This is done during the mounting"""
149         pass