Deployment corrections for Fuel
[genesis.git] / fuel / deploy / cloud_deploy / hardware_adapters / hp / hp_adapter.py
1 import re
2 import time
3 from netaddr import EUI, mac_unix
4 from cloud import common
5 from ssh_client import SSHClient
6
7 LOG = common.LOG
8 err = common.err
9
10 S = {'bay': 0, 'ilo_name': 1, 'ilo_ip': 2, 'status': 3, 'power': 4,
11      'uid_partner': 5}
12
13 class HpAdapter(object):
14
15     def __init__(self, mgmt_ip, username, password):
16         self.mgmt_ip = mgmt_ip
17         self.username = username
18         self.password = password
19
20     class mac_dhcp(mac_unix):
21         word_fmt = '%.2x'
22
23     def next_ip(self):
24         digit_list = self.mgmt_ip.split('.')
25         digit_list[3] = str(int(digit_list[3]) + 1)
26         self.mgmt_ip = '.'.join(digit_list)
27
28     def connect(self):
29         verified_ips = [self.mgmt_ip]
30         ssh = SSHClient(self.mgmt_ip, self.username, self.password)
31         try:
32             ssh.open()
33         except Exception:
34             self.next_ip()
35             verified_ips.append(self.mgmt_ip)
36             ssh = SSHClient(self.mgmt_ip, self.username, self.password)
37             try:
38                 ssh.open()
39             except Exception as e:
40                 err('Could not connect to HP Onboard Administrator through '
41                     'these IPs: %s, reason: %s' % (verified_ips, e))
42
43         lines = self.clean_lines(ssh.execute('show oa status'))
44         for line in lines:
45             if 'Role:   Standby' in line:
46                 ssh.close()
47                 if self.mgmt_ip != verified_ips[0]:
48                     err('Can only talk to OA %s which is the standby OA\n'
49                         % self.mgmt_ip)
50                 else:
51                     LOG.debug('%s is the standby OA, trying next OA\n'
52                               % self.mgmt_ip)
53                     self.next_ip()
54                     verified_ips.append(self.mgmt_ip)
55                     ssh = SSHClient(self.mgmt_ip, self.username, self.password)
56                     try:
57                         ssh.open()
58                     except Exception as e:
59                         err('Could not connect to HP Onboard Administrator'
60                             ' through these IPs: %s, reason: %s'
61                             % (verified_ips, e))
62
63             elif 'Role:   Active' in line:
64                 return ssh
65         err('Could not reach Active OA through these IPs %s' % verified_ips)
66
67     def get_blades_mac_addresses(self, shelf, blade_list):
68         macs_per_blade_dict = {}
69         LOG.debug('Getting MAC addresses for shelf %s, blades %s'
70                   % (shelf, blade_list))
71         ssh = self.connect()
72         for blade in blade_list:
73             lines = self.clean_lines(
74                 ssh.execute('show server info %s' % blade))
75             left, right = self.find_mac(lines, shelf, blade)
76
77             left = EUI(left, dialect=self.mac_dhcp)
78             right = EUI(right, dialect=self.mac_dhcp)
79             macs_per_blade_dict[blade] = [str(left), str(right)]
80         ssh.close()
81         return macs_per_blade_dict
82
83     def find_mac(self, printout, shelf, blade):
84         left = False
85         right = False
86         for line in printout:
87             if ('No Server Blade Installed' in line or
88                 'Invalid Arguments' in line):
89                 err('Blade %d in shelf %d does not exist' % (blade, shelf))
90
91             seobj = re.search(r'LOM1:1-a\s+([0-9A-F:]+)', line, re.I)
92             if seobj:
93                 left = seobj.group(1)
94             else:
95                 seobj = re.search(r'LOM1:2-a\s+([0-9A-F:]+)', line, re.I)
96                 if seobj:
97                     right = seobj.group(1)
98             if left and right:
99                 return left, right
100
101     def get_hardware_info(self, shelf, blade=None):
102         ssh = self.connect()
103         if ssh and not blade:
104             ssh.close()
105             return 'HP'
106
107         lines = self.clean_lines(ssh.execute('show server info %s' % blade))
108         ssh.close()
109
110         match = r'Product Name:\s+(.+)\Z'
111         if not re.search(match, str(lines[:])):
112             LOG.debug('Blade %s in shelf %s does not exist\n' % (blade, shelf))
113             return False
114
115         for line in lines:
116             seobj = re.search(match, line)
117             if seobj:
118                 return 'HP %s' % seobj.group(1)
119         return False
120
121     def power_off_blades(self, shelf, blade_list):
122         return self.set_state(shelf, 'locked', blade_list)
123
124     def power_on_blades(self, shelf, blade_list):
125         return self.set_state(shelf, 'unlocked', blade_list)
126
127     def set_boot_order_blades(self, shelf, blade_list):
128         return self.set_boot_order(shelf, blade_list=blade_list)
129
130     def parse(self, lines):
131         parsed_list = []
132         for l in lines[5:-2]:
133              parsed = []
134              cluttered = [e.strip() for e in l.split(' ')]
135              for p in cluttered:
136                  if p:
137                      parsed.append(p)
138              parsed_list.append(parsed)
139         return parsed_list
140
141     def set_state(self, shelf, state, blade_list):
142         if state not in ['locked', 'unlocked']:
143             LOG.debug('Incorrect state: %s' % state)
144             return None
145
146         LOG.debug('Setting state %s for blades %s in shelf %s'
147                   % (state, blade_list, shelf))
148
149         blade_list = sorted(blade_list)
150         ssh = self.connect()
151
152         LOG.debug('Check if blades are present')
153         server_list = self.parse(
154             self.clean_lines(ssh.execute('show server list')))
155
156         for blade in blade_list:
157             if server_list[S['status']] == 'Absent':
158                 LOG.debug('Blade %s in shelf %s is missing. '
159                           'Set state %s not performed\n'
160                           % (blade, shelf, state))
161                 blade_list.remove(blade)
162
163         bladelist = ','.join(blade_list)
164
165         # Use leading upper case on On/Off so it can be reused in match
166         force = ''
167         if state == 'locked':
168             powerstate = 'Off'
169             force = 'force'
170         else:
171             powerstate = 'On'
172         cmd = 'power%s server %s' % (powerstate, bladelist)
173         if force:
174             cmd += ' %s' % force
175
176         LOG.debug(cmd)
177         ssh.execute(cmd)
178
179         # Check that all blades reach the state which can take some time,
180         # so re-try a couple of times
181         LOG.debug('Check if state %s successfully set' % state)
182
183         WAIT_LOOP = 2
184         SLEEP_TIME = 3
185
186         set_blades = []
187
188         for i in range(WAIT_LOOP):
189             server_list = self.parse(
190                 self.clean_lines(ssh.execute('show server list')))
191
192             for blade in blade_list:
193                 for server in server_list:
194                     if (server[S['bay']] == blade and
195                         server[S['power']] == powerstate):
196                         set_blades.append(blade)
197                         break
198
199             all_set = set(blade_list) == set(set_blades)
200             if all_set:
201                 break
202             else:
203                 time.sleep(SLEEP_TIME)
204
205         ssh.close()
206
207         if all_set:
208             LOG.debug('State %s successfully set on blades %s in shelf %d'
209                       % (state, set_blades, shelf))
210             return True
211         else:
212             LOG.debug('Could not set state %s on blades %s in shelf %s\n'
213                       % (state, set(blade_list) - set(set_blades), shelf))
214         return False
215
216
217     def clean_lines(self, printout):
218         lines = []
219         for p in [l.strip() for l in printout.splitlines()]:
220             if p:
221                 lines.append(p)
222         return lines
223
224
225     def set_boot_order_blades(self, shelf, blade_list, boot_dev_list=None):
226
227         boot_dict = {'Hard Drive': 'hdd',
228                      'PXE NIC': 'pxe',
229                      'CD-ROM': 'cd',
230                      'USB': 'usb',
231                      'Diskette Driver': 'disk'}
232
233         boot_options = [b for b in boot_dict.itervalues()]
234         diff = list(set(boot_dev_list) - set(boot_options))
235         if diff:
236             err('The following boot options %s are not valid' % diff)
237
238         blade_list = sorted(blade_list)
239         LOG.debug('Setting boot order %s for blades %s in shelf %s'
240                   % (boot_dev_list, blade_list, shelf))
241
242         ssh = self.connect()
243
244         LOG.debug('Check if blades are present')
245         server_list = self.parse(
246             self.clean_lines(ssh.execute('show server list')))
247
248         for blade in blade_list:
249             if server_list[S['status']] == 'Absent':
250                 LOG.debug('Blade %s in shelf %s is missing. '
251                           'Change boot order %s not performed.\n'
252                           % (blade, shelf, boot_dev_list))
253                 blade_list.remove(blade)
254
255         bladelist = ','.join(blade_list)
256
257         for boot_dev in reversed(boot_dev_list):
258             ssh.execute('set server boot first %s %s' % (boot_dev, bladelist))
259
260         LOG.debug('Check if boot order is successfully set')
261
262         success_list = []
263         boot_keys = [b for b in boot_dict.iterkeys()]
264         for blade in blade_list:
265             lines = self.clean_lines(ssh.execute('show server boot %s'
266                                                  % blade))
267             boot_order = lines[lines.index('IPL Devices (Boot Order):')+1:]
268             boot_list = []
269             success = False
270             for b in boot_order:
271                 for k in boot_keys:
272                     if k in b:
273                         boot_list.append(boot_dict[k])
274                         break
275                 if boot_list == boot_dev_list:
276                     success = True
277                     break
278
279             success_list.append(success)
280             if success:
281                 LOG.debug('Boot order %s successfully set on blade %s in '
282                           'shelf %s\n' % (boot_dev_list, blade, shelf))
283             else:
284                 LOG.debug('Failed to set boot order %s on blade %s in '
285                           'shelf %s\n' % (boot_dev_list, blade, shelf))
286
287         ssh.close()
288         return all(success_list)