forked from ManageIQ/integration_tests
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathipmi.py
143 lines (116 loc) · 4.7 KB
/
ipmi.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
import subprocess
from utils.wait import wait_for
class IPMI():
""" Utility to access IPMI via CLI.
The IPMI utility uses the ``ipmitool`` package to access the remote management
card of a server.
.. note: ``ipmitool`` is not a standard tool and will need to be installed separately.
.. warning These commands do not gracefully shutdown a machine. The immediately remove
power to a machine. Use with caution.
Args:
hostname: The hostname of the remote management console.
username: The username for the remote management console.
password: The password tied to the username.
interface_type: A string giving the ``interface_type`` to pass to the CLI.
timeout: The number of seconds to wait before giving up on a command.
Returns: A :py:class:`IPMI` instnace.
"""
def __init__(self, hostname, username, password, interface_type="lan", timeout=30):
self.hostname = hostname
self.username = username
self.password = password
self.interface_type = interface_type
cmd_args = ['ipmitool']
cmd_args.extend(['-H', self.hostname])
cmd_args.extend(['-U', self.username])
cmd_args.extend(['-P', self.password])
cmd_args.extend(['-I', self.interface_type])
self.cmd_args = cmd_args
self.timeout = timeout
def is_power_on(self):
""" Checks if the power is on.
Returns: ``True`` if power is on, ``False`` if not.
"""
command = "chassis power status"
output = self._run_command(command)
if "Chassis Power is on" in output:
return True
elif "Chassis Power is off" in output:
return False
else:
raise IPMIException("Unexpected command output: {}".format(output))
def power_off(self):
""" Turns the power off.
Returns: ``True`` if power is off, ``False`` if not.
"""
if not self.is_power_on():
return True
else:
return self._change_power_state(power_on=False)
def power_on(self):
""" Turns the power on.
Returns: ``True`` if power is on, ``False`` if not.
"""
if self.is_power_on():
return True
else:
return self._change_power_state(power_on=True)
def power_reset(self):
""" Turns the power off.
Returns: ``True`` if power reset initiated, ``False`` if not.
"""
if not self.is_power_on():
return self.power_on()
else:
command = "chassis power reset"
output = self._run_command(command)
if "Reset" in output:
return True
else:
raise Exception("Unexpected command output: {}".format(output))
def _change_power_state(self, power_on=True):
""" Changes the power state of a machine.
Args:
power_on: A boolean. ``True`` to request the power be turned on,
``False`` to turn it off.
Returns: ``True`` if operation was successful, ``False`` if not.
"""
if power_on:
command = "chassis power on"
else:
command = "chassis power off"
output = self._run_command(command)
if "Chassis Power Control: Up/On" in output and power_on:
return True
elif "Chassis Power Control: Down/Off" in output and not power_on:
return True
else:
raise Exception("Unexpected command output: {}".format(output))
def _run_command(self, command):
""" Builds the command arguments from the command string.
Args:
command: An IPMI command to be passed to the CLI as a string.
As an example, "chassis power on".
Returns: The string output from the command's stdout.
"""
command_args = self.cmd_args + command.split(" ")
return self._run_ipmi(command_args)
def _run_ipmi(self, command_args):
""" Runs the actual IPMI command
Args:
command_args: A list of command arguments to be send to ``ipmitool``.
Returns: The string output from the command's stdout.
Raises:
IPMIException: If the return code is non zero.
"""
proc = subprocess.Popen(command_args, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
wait_for(proc.poll, fail_condition=None, num_sec=self.timeout)
if proc.returncode == 0:
return proc.stdout.read()
else:
raise IPMIException("Unexpected failure: {}".format(proc.stderr.read()))
class IPMIException(Exception):
"""
Raised during :py:meth:`_run_ipmi` if the error code is non zero.
"""
pass