3 from netaddr import EUI, mac_unix
6 from run_oa_command import RunOACommand
9 LOG = logging.getLogger(__name__)
10 out_hdlr = logging.FileHandler(__file__.split('.')[0] + '.log', mode='w')
11 out_hdlr.setFormatter(logging.Formatter('%(levelname)s: %(message)s'))
12 LOG.addHandler(out_hdlr)
13 LOG.setLevel(logging.DEBUG)
15 class HpAdapter(object):
17 # Exception thrown at any kind of failure to get the requested
19 class NoInfoFoundError(Exception):
22 # Totally failed to connect so a re-try with other HW should
23 # be done. This exception should never escape this class.
24 class InternalConnectError(Exception):
27 # Format MAC so leading zeroes are displayed
28 class mac_dhcp(mac_unix):
31 def __init__(self, mgmt_ip, username, password):
32 self.mgmt_ip = mgmt_ip
33 self.username = username
34 self.password = password
35 self.oa_error_message = ''
37 def get_blade_mac_addresses(self, shelf, blade):
39 LOG.debug("Entering: get_mac_addr_hp(%d,%d)" % (shelf, blade))
40 self.oa_error_message = ''
41 oa = RunOACommand(self.mgmt_ip, self.username, self.password)
43 LOG.debug("Connect to active OA for shelf %d" % shelf)
45 res = oa.connect_to_active()
47 raise self.InternalConnectError(oa.error_message)
49 raise self.InternalConnectError(oa.error_message)
50 if not oa.connected():
51 raise self.NoInfoFoundError(oa.error_message)
53 cmd = ("show server info " + str(blade))
55 LOG.debug("Send command to OA: %s" % cmd)
57 serverinfo = oa.send_command(cmd)
59 raise self.NoInfoFoundError(oa.error_message)
63 (left, right) = self.find_mac(serverinfo, shelf, blade)
65 left = EUI(left, dialect=self.mac_dhcp)
66 right = EUI(right, dialect=self.mac_dhcp)
67 return [str(left), str(right)]
69 def get_blade_hardware_info(self, shelf, blade=None):
72 LOG.debug("Entering: get_hp_info(%d,%d)" % (shelf, blade))
74 LOG.debug("Entering: get_hp_info(%d)" % shelf)
76 self.oa_error_message = ''
77 oa = RunOACommand(self.mgmt_ip, self.username, self.password)
79 LOG.debug("Connect to active OA for shelf %d" % shelf)
82 res = oa.connect_to_active()
84 self.oa_error_message = oa.error_message
87 self.oa_error_message = oa.error_message
89 if not oa.connected():
90 self.oa_error_message = oa.error_message
93 # If no blade specified we're done we know this is an HP at this point
98 check = "show server info %d" % blade
99 LOG.debug("Send command to OA: %s" % check)
100 output = oa.send_command("%s" % check)
103 match = r"Product Name:\s+(.+)\Z"
104 if re.search(match, str(output[:])) is None:
105 self.oa_error_message = ("Blade %d in shelf %d does not exist\n"
110 seobj = re.search(match, line)
112 return "HP %s" % seobj.group(1)
115 def power_off_blades(self, shelf, blade_list):
116 return self.set_state(shelf, 'locked', blade_list=blade_list)
118 def power_on_blades(self, shelf, blade_list):
119 return self.set_state(shelf, 'unlocked', blade_list=blade_list)
121 def power_off_blade(self, shelf, blade):
122 return self.set_state(shelf, 'locked', one_blade=blade)
124 def power_on_blade(self, shelf, blade):
125 return self.set_state(shelf, 'unlocked', one_blade=blade)
127 def set_boot_order_blade(self, shelf, blade):
128 return self.set_boot_order(shelf, one_blade=blade)
130 def set_boot_order_blades(self, shelf, blade_list):
131 return self.set_boot_order(shelf, blade_list=blade_list)
135 # Search HP's OA server info for MAC for left and right control
136 def find_mac(self, serverinfo, shelf, blade):
139 for line in serverinfo:
140 if ("No Server Blade Installed" in line or
141 "Invalid Arguments" in line):
142 raise self.NoInfoFoundError("Blade %d in shelf %d "
143 "does not exist." % (blade, shelf))
144 seobj = re.search(r"LOM1:1-a\s+([0-9A-F:]+)", line, re.I)
146 left = seobj.group(1)
148 seobj = re.search(r"LOM1:2-a\s+([0-9A-F:]+)", line, re.I)
150 right = seobj.group(1)
153 raise self.NoInfoFoundError("Could not find MAC for blade %d "
154 "in shelf %d." % (blade, shelf))
156 # Do power on or off on all configured blades in shelf
157 # Return None to indicate that no connection do OA succeeded,
158 # Return False to indicate some connection to OA succeeded,
160 # Return True to indicate that power state succesfully updated
161 # state: locked, unlocked
162 def set_state(self, shelf, state, one_blade=None, blade_list=None):
164 if state not in ['locked', 'unlocked']:
168 LOG.debug("Entering: set_state_hp(%d,%s,%d)" %
169 (shelf, state, one_blade))
171 LOG.debug("Entering: set_state_hp(%d,%s)" % (shelf, state))
173 self.oa_error_message = ''
175 oa = RunOACommand(self.mgmt_ip, self.username, self.password)
177 LOG.debug("Connect to active OA for shelf %d" % shelf)
180 res = oa.connect_to_active()
182 self.oa_error_message = oa.error_message
185 self.oa_error_message = oa.error_message
187 if not oa.connected():
188 self.oa_error_message = oa.error_message
194 blades = sorted(blade_list)
196 LOG.debug("Check if blades are present")
198 check = "show server list"
200 LOG.debug("Send command to OA: %s" % check)
201 output = oa.send_command(check)
205 prog = re.compile(r"\s+" + str(blade) + r"\s+\[Absent\]",
207 if prog.search(str(output[:])) is not None:
209 self.oa_error_message = ("Blade %d in shelf %d "
212 self.oa_error_message += ("does not exist.\n"
213 "Set state %s not performed.\n"
216 self.oa_error_message += (
217 "specified but does not exist.\nSet "
218 "state %s not performed on shelf %d\n"
225 bladelist += str(blade)
228 LOG.debug("All blades present")
230 # Use leading upper case on On/Off so it can be reused in match
232 if state == "locked":
238 cmd = "power%s server %s" % (powerstate, bladelist)
243 LOG.debug("Send command to OA: %s" % cmd)
248 self.oa_error_message = oa.error_message
252 # Check that all blades reach the state which can take some time,
253 # so re-try a couple of times
254 LOG.debug("Check if state %s successfully set" % state)
257 LOG.debug("Send command to OA: %s" % check)
259 output = oa.send_command(check)
261 self.oa_error_message = oa.error_message
265 match = (r"\s+" + str(blade) +
266 r"\s+\w+\s+\w+.\w+.\w+.\w+\s+\w+\s+%s" %
268 prog = re.compile(match, re.MULTILINE)
269 if prog.search(str(output[:])) is None:
276 self.oa_error_message = (
277 "Could not set state %s on blade %d in shelf %d\n"
278 % (state, one_blade, shelf))
280 self.oa_error_message += line
283 # state reached for all blades, exit the infinite loop
287 LOG.debug("State %s successfully set on blade %d in shelf %d"
288 % (state, one_blade, shelf))
290 LOG.debug("State %s successfully set on blades %s in shelf %d"
291 % (state, blade_list, shelf))
295 # Change boot order on all blades in shelf
296 # Return None to indicate that no connection do OA succeeded,
297 # Return False to indicate some connection to OA succeeded,
299 # Return True to indicate that boot order succesfully changed
300 def set_boot_order(self, shelf, one_blade=None, blade_list=None):
303 LOG.debug("Entering: set_bootorder_hp(%d,%d)" % (shelf, one_blade))
305 LOG.debug("Entering: set_bootorder_hp(%d)" % shelf)
307 self.oa_error_message = ''
309 oa = RunOACommand(self.mgmt_ip, self.username, self.password)
311 LOG.debug("Connect to active OA for shelf %d" % shelf)
314 res = oa.connect_to_active()
316 self.oa_error_message = oa.error_message
319 self.oa_error_message = oa.error_message
321 if not oa.connected():
322 self.oa_error_message = oa.error_message
328 blades = sorted(blade_list)
330 LOG.debug("Check if blades are present")
332 check = "show server list"
334 LOG.debug("Send command to OA: %s" % check)
336 output = oa.send_command(check)
340 prog = re.compile(r"\s+" + str(blade) + r"\s+\[Absent\]",
342 if prog.search(str(output[:])) is not None:
344 self.oa_error_message = ("Blade %d in shelf %d "
347 self.oa_error_message += (
348 "does not exist.\nChange boot order not performed.\n")
350 self.oa_error_message += (
351 "specified but does not exist.\n"
352 "Change boot order not performed on shelf %d\n"
359 bladelist += str(blade)
362 LOG.debug("All blades present")
364 # Boot origins are pushed so first set boot from hard disk, then PXE
365 # NB! If we want to support boot from SD we must add USB to the "stack"
366 cmd1 = "set server boot first hdd %s" % bladelist
367 cmd2 = "set server boot first pxe %s" % bladelist
368 for cmd in [cmd1, cmd2]:
370 LOG.debug("Send command to OA: %s" % cmd)
372 output = oa.send_command(cmd)
374 self.oa_error_message = oa.error_message
376 self.oa_error_message += line
380 # Check that all blades got the correct boot order
381 # Needs updating if USB is added
382 LOG.debug("Check if boot order successfully set")
383 match = (r"^.*Boot Order\):\',\s*\'(\\t)+PXE NIC 1\',\s*\'(\\t)"
385 prog = re.compile(match)
388 check = "show server boot %d" % blade
390 LOG.debug("Send command to OA: %s" % check)
392 output = oa.send_command(check)
394 self.oa_error_message = oa.error_message
397 if prog.search(str(output[:])) is None:
399 self.oa_error_message = ("Failed to set boot order on blade "
400 "%d in shelf %d\n" % (blade, shelf))
402 self.oa_error_message += line
404 LOG.debug("Boot order successfully set on blade %d in shelf %d"
408 LOG.debug("Boot order successfully set on all configured blades "
409 "in shelf %d" % (shelf))