3 from netaddr import EUI, mac_unix
4 from cloud import common
6 from run_oa_command import RunOACommand
10 class HpAdapter(object):
12 # Exception thrown at any kind of failure to get the requested
14 class NoInfoFoundError(Exception):
17 # Totally failed to connect so a re-try with other HW should
18 # be done. This exception should never escape this class.
19 class InternalConnectError(Exception):
22 # Format MAC so leading zeroes are displayed
23 class mac_dhcp(mac_unix):
26 def __init__(self, mgmt_ip, username, password):
27 self.mgmt_ip = mgmt_ip
28 self.username = username
29 self.password = password
30 self.oa_error_message = ''
32 def get_blade_mac_addresses(self, shelf, blade):
34 LOG.debug("Entering: get_mac_addr_hp(%d,%d)" % (shelf, blade))
35 self.oa_error_message = ''
36 oa = RunOACommand(self.mgmt_ip, self.username, self.password)
38 LOG.debug("Connect to active OA for shelf %d" % shelf)
40 res = oa.connect_to_active()
42 raise self.InternalConnectError(oa.error_message)
44 raise self.InternalConnectError(oa.error_message)
45 if not oa.connected():
46 raise self.NoInfoFoundError(oa.error_message)
48 cmd = ("show server info " + str(blade))
50 LOG.debug("Send command to OA: %s" % cmd)
52 serverinfo = oa.send_command(cmd)
54 raise self.NoInfoFoundError(oa.error_message)
58 (left, right) = self.find_mac(serverinfo, shelf, blade)
60 left = EUI(left, dialect=self.mac_dhcp)
61 right = EUI(right, dialect=self.mac_dhcp)
62 return [str(left), str(right)]
64 def get_blades_mac_addresses(self, shelf, blade_list):
65 macs_per_blade_dict = {}
66 LOG.debug("Getting MAC addresses for shelf %s, blades %s"
67 % (shelf, blade_list))
68 self.oa_error_message = ''
69 oa = RunOACommand(self.mgmt_ip, self.username, self.password)
71 LOG.debug("Connect to active OA for shelf %d" % shelf)
73 res = oa.connect_to_active()
75 raise self.InternalConnectError(oa.error_message)
77 raise self.InternalConnectError(oa.error_message)
78 if not oa.connected():
79 raise self.NoInfoFoundError(oa.error_message)
81 for blade in blade_list:
82 LOG.debug("Send command to OA: %s" % cmd)
83 cmd = ("show server info %s" % blade)
84 printout = oa.send_command(cmd)
85 left, right = self.find_mac(printout, shelf, blade)
86 left = EUI(left, dialect=self.mac_dhcp)
87 right = EUI(right, dialect=self.mac_dhcp)
88 macs_per_blade_dict[blade] = [str(left), str(right)]
90 raise self.NoInfoFoundError(oa.error_message)
93 return macs_per_blade_dict
95 def get_blade_hardware_info(self, shelf, blade=None):
97 LOG.debug("Entering: get_hp_info(%d,%d)" % (shelf, blade))
99 LOG.debug("Entering: get_hp_info(%d)" % shelf)
101 self.oa_error_message = ''
102 oa = RunOACommand(self.mgmt_ip, self.username, self.password)
104 LOG.debug("Connect to active OA for shelf %d" % shelf)
107 res = oa.connect_to_active()
109 self.oa_error_message = oa.error_message
112 self.oa_error_message = oa.error_message
114 if not oa.connected():
115 self.oa_error_message = oa.error_message
118 # If no blade specified we're done we know this is an HP at this point
123 check = "show server info %d" % blade
124 LOG.debug("Send command to OA: %s" % check)
125 output = oa.send_command("%s" % check)
128 match = r"Product Name:\s+(.+)\Z"
129 if re.search(match, str(output[:])) is None:
130 self.oa_error_message = ("Blade %d in shelf %d does not exist\n"
135 seobj = re.search(match, line)
137 return "HP %s" % seobj.group(1)
140 def power_off_blades(self, shelf, blade_list):
141 return self.set_state(shelf, 'locked', blade_list=blade_list)
143 def power_on_blades(self, shelf, blade_list):
144 return self.set_state(shelf, 'unlocked', blade_list=blade_list)
146 def set_boot_order_blades(self, shelf, blade_list):
147 return self.set_boot_order(shelf, blade_list=blade_list)
149 def power_off_blade(self, shelf, blade):
150 return self.set_state(shelf, 'locked', one_blade=blade)
152 def power_on_blade(self, shelf, blade):
153 return self.set_state(shelf, 'unlocked', one_blade=blade)
155 def set_boot_order_blade(self, shelf, blade):
156 return self.set_boot_order(shelf, one_blade=blade)
158 # Search HP's OA server info for MAC for left and right control
159 def find_mac(self, printout, shelf, blade):
162 for line in printout:
163 if ("No Server Blade Installed" in line or
164 "Invalid Arguments" in line):
165 raise self.NoInfoFoundError("Blade %d in shelf %d "
166 "does not exist." % (blade, shelf))
167 seobj = re.search(r"LOM1:1-a\s+([0-9A-F:]+)", line, re.I)
169 left = seobj.group(1)
171 seobj = re.search(r"LOM1:2-a\s+([0-9A-F:]+)", line, re.I)
173 right = seobj.group(1)
176 raise self.NoInfoFoundError("Could not find MAC for blade %d "
177 "in shelf %d." % (blade, shelf))
179 # Do power on or off on all configured blades in shelf
180 # Return None to indicate that no connection do OA succeeded,
181 # Return False to indicate some connection to OA succeeded,
183 # Return True to indicate that power state succesfully updated
184 # state: locked, unlocked
185 def set_state(self, shelf, state, one_blade=None, blade_list=None):
186 if state not in ['locked', 'unlocked']:
190 LOG.debug("Entering: set_state_hp(%d,%s,%d)" %
191 (shelf, state, one_blade))
193 LOG.debug("Entering: set_state_hp(%d,%s)" % (shelf, state))
195 self.oa_error_message = ''
197 oa = RunOACommand(self.mgmt_ip, self.username, self.password)
199 LOG.debug("Connect to active OA for shelf %d" % shelf)
202 res = oa.connect_to_active()
204 self.oa_error_message = oa.error_message
207 self.oa_error_message = oa.error_message
209 if not oa.connected():
210 self.oa_error_message = oa.error_message
216 blades = sorted(blade_list)
218 LOG.debug("Check if blades are present")
220 check = "show server list"
222 LOG.debug("Send command to OA: %s" % check)
223 output = oa.send_command(check)
227 prog = re.compile(r"\s+" + str(blade) + r"\s+\[Absent\]",
229 if prog.search(str(output[:])) is not None:
231 self.oa_error_message = ("Blade %d in shelf %d "
234 self.oa_error_message += ("does not exist.\n"
235 "Set state %s not performed.\n"
238 self.oa_error_message += (
239 "specified but does not exist.\nSet "
240 "state %s not performed on shelf %d\n"
247 bladelist += str(blade)
250 LOG.debug("All blades present")
252 # Use leading upper case on On/Off so it can be reused in match
254 if state == "locked":
260 cmd = "power%s server %s" % (powerstate, bladelist)
265 LOG.debug("Send command to OA: %s" % cmd)
270 self.oa_error_message = oa.error_message
274 # Check that all blades reach the state which can take some time,
275 # so re-try a couple of times
276 LOG.debug("Check if state %s successfully set" % state)
279 LOG.debug("Send command to OA: %s" % check)
281 output = oa.send_command(check)
283 self.oa_error_message = oa.error_message
287 match = (r"\s+" + str(blade) +
288 r"\s+\w+\s+\w+.\w+.\w+.\w+\s+\w+\s+%s" %
290 prog = re.compile(match, re.MULTILINE)
291 if prog.search(str(output[:])) is None:
298 self.oa_error_message = (
299 "Could not set state %s on blade %d in shelf %d\n"
300 % (state, one_blade, shelf))
302 self.oa_error_message += line
305 # state reached for all blades, exit the infinite loop
309 LOG.debug("State %s successfully set on blade %d in shelf %d"
310 % (state, one_blade, shelf))
312 LOG.debug("State %s successfully set on blades %s in shelf %d"
313 % (state, blade_list, shelf))
317 # Change boot order on all blades in shelf
318 # Return None to indicate that no connection do OA succeeded,
319 # Return False to indicate some connection to OA succeeded,
321 # Return True to indicate that boot order succesfully changed
322 def set_boot_order(self, shelf, one_blade=None, blade_list=None):
325 LOG.debug("Entering: set_bootorder_hp(%d,%d)" % (shelf, one_blade))
327 LOG.debug("Entering: set_bootorder_hp(%d)" % shelf)
329 self.oa_error_message = ''
331 oa = RunOACommand(self.mgmt_ip, self.username, self.password)
333 LOG.debug("Connect to active OA for shelf %d" % shelf)
336 res = oa.connect_to_active()
338 self.oa_error_message = oa.error_message
341 self.oa_error_message = oa.error_message
343 if not oa.connected():
344 self.oa_error_message = oa.error_message
350 blades = sorted(blade_list)
352 LOG.debug("Check if blades are present")
354 check = "show server list"
356 LOG.debug("Send command to OA: %s" % check)
358 output = oa.send_command(check)
362 prog = re.compile(r"\s+" + str(blade) + r"\s+\[Absent\]",
364 if prog.search(str(output[:])) is not None:
366 self.oa_error_message = ("Blade %d in shelf %d "
369 self.oa_error_message += (
370 "does not exist.\nChange boot order not performed.\n")
372 self.oa_error_message += (
373 "specified but does not exist.\n"
374 "Change boot order not performed on shelf %d\n"
381 bladelist += str(blade)
384 LOG.debug("All blades present")
386 # Boot origins are pushed so first set boot from hard disk, then PXE
387 # NB! If we want to support boot from SD we must add USB to the "stack"
388 cmd1 = "set server boot first hdd %s" % bladelist
389 cmd2 = "set server boot first pxe %s" % bladelist
390 for cmd in [cmd1, cmd2]:
392 LOG.debug("Send command to OA: %s" % cmd)
394 output = oa.send_command(cmd)
396 self.oa_error_message = oa.error_message
398 self.oa_error_message += line
402 # Check that all blades got the correct boot order
403 # Needs updating if USB is added
404 LOG.debug("Check if boot order successfully set")
405 match = (r"^.*Boot Order\):\',\s*\'(\\t)+PXE NIC 1\',\s*\'(\\t)"
407 prog = re.compile(match)
410 check = "show server boot %d" % blade
412 LOG.debug("Send command to OA: %s" % check)
414 output = oa.send_command(check)
416 self.oa_error_message = oa.error_message
419 if prog.search(str(output[:])) is None:
421 self.oa_error_message = ("Failed to set boot order on blade "
422 "%d in shelf %d\n" % (blade, shelf))
424 self.oa_error_message += line
426 LOG.debug("Boot order successfully set on blade %d in shelf %d"
430 LOG.debug("Boot order successfully set on all configured blades "
431 "in shelf %d" % (shelf))