diff options
author | Christopher Kenna <cjk@cs.unc.edu> | 2012-09-11 15:20:55 -0400 |
---|---|---|
committer | Christopher Kenna <cjk@cs.unc.edu> | 2012-09-11 15:20:55 -0400 |
commit | e65475c098f1291fad5392b57518e17c92131b0b (patch) | |
tree | 4b102632ed4d314f39594693c39fba50722bdedf | |
parent | 2240a1abbb239f1c280f40cd5e1f9a20517fddd9 (diff) |
Add power management script for the IP 9258.
-rwxr-xr-x | powermanager.py | 133 |
1 files changed, 133 insertions, 0 deletions
diff --git a/powermanager.py b/powermanager.py new file mode 100755 index 0000000..89aad80 --- /dev/null +++ b/powermanager.py | |||
@@ -0,0 +1,133 @@ | |||
1 | #!/usr/bin/env python | ||
2 | |||
3 | from __future__ import print_function | ||
4 | |||
5 | import sys | ||
6 | import argparse | ||
7 | import os.path | ||
8 | import urllib2 | ||
9 | |||
10 | from operator import methodcaller | ||
11 | from time import sleep | ||
12 | |||
13 | |||
14 | """Manages the power for the IP Power 9258. | ||
15 | |||
16 | You are meant to create symlinks to this file for each port. | ||
17 | |||
18 | """ | ||
19 | |||
20 | class PowerManagerException(RuntimeError): | ||
21 | def __init__(self, reason): | ||
22 | super(PowerManagerException, self).__init__() | ||
23 | self.reason = reason | ||
24 | |||
25 | class PowerManager(object): | ||
26 | """Manages the power for a single port of the IP Power 9258.""" | ||
27 | |||
28 | def __init__(self, host, username, password, port): | ||
29 | self.host = host | ||
30 | self.username = username | ||
31 | self.password = password | ||
32 | self.port = port | ||
33 | |||
34 | def __call_url(self, port_value): | ||
35 | port_state = '{}={}'.format(self.port, port_value) | ||
36 | full_url = 'http://{}/Set.cmd?CMD=SetPower+{}'.format(self.host, | ||
37 | port_state) | ||
38 | basic_handler = urllib2.HTTPBasicAuthHandler() | ||
39 | basic_handler.add_password(realm='IP9258', | ||
40 | uri='http://{}/'.format(self.host), | ||
41 | user=self.username, | ||
42 | passwd=self.password) | ||
43 | opener = urllib2.build_opener(basic_handler) | ||
44 | urllib2.install_opener(opener) | ||
45 | try: | ||
46 | url_res = urllib2.urlopen(full_url) | ||
47 | txt = url_res.read() | ||
48 | if -1 == txt.find(port_state): | ||
49 | """Response should be the port_state we wanted, plus HTML.""" | ||
50 | raise PowerManagerException('Bad response: {}'.format(txt)) | ||
51 | except urllib2.URLError as e: | ||
52 | raise PowerManagerException('Error opening URL: {}'.format( | ||
53 | e.reason)) | ||
54 | |||
55 | def power_on(self): | ||
56 | print("Power on.") | ||
57 | self.__call_url('1') | ||
58 | |||
59 | def power_off(self): | ||
60 | print("Power off.") | ||
61 | self.__call_url('0') | ||
62 | |||
63 | def power_cycle(self): | ||
64 | self.power_off() | ||
65 | sleep(1) | ||
66 | self.power_on() | ||
67 | |||
68 | @classmethod | ||
69 | def dispatch_action(cls, power_manager, action): | ||
70 | ACTION_CALLBACKS = {'on': methodcaller('power_on'), | ||
71 | 'off': methodcaller('power_off'), | ||
72 | 'cycle': methodcaller('power_cycle')} | ||
73 | actions = ACTION_CALLBACKS.keys() | ||
74 | try: | ||
75 | action_method = ACTION_CALLBACKS[action] | ||
76 | except KeyError: | ||
77 | raise ValueError('Invalid action: {}'.format(action)) | ||
78 | action_method(power_manager) | ||
79 | |||
80 | |||
81 | def parse_args(): | ||
82 | p = argparse.ArgumentParser(description='Control power.') | ||
83 | p.add_argument('action', help='on|off|cycle') | ||
84 | return p.parse_args(sys.argv[1:]) | ||
85 | |||
86 | def find_port(): | ||
87 | """Finds port to use based on script name. | ||
88 | |||
89 | Assumes the script is named <SOMETHING>-power.py, where the part before the | ||
90 | dash is a dict key. | ||
91 | |||
92 | """ | ||
93 | POWER_PORTS = { 'pound': 'P60', 'pandaboard': 'P61' } | ||
94 | |||
95 | script_name = os.path.basename(sys.argv[0]) | ||
96 | dash_pos = script_name.find('-') | ||
97 | if -1 == dash_pos: | ||
98 | raise ValueError('No dash found in script name: {}'.format(script_name)) | ||
99 | port_key = script_name[:dash_pos] | ||
100 | try: | ||
101 | return POWER_PORTS[port_key] | ||
102 | except KeyError: | ||
103 | raise KeyError('Port key not found in dict: {}'.format(port_key)) | ||
104 | |||
105 | def read_password(): | ||
106 | fname = os.path.expanduser('~/.poundpower') | ||
107 | with open(fname) as f: | ||
108 | password = f.read().strip() | ||
109 | return password | ||
110 | |||
111 | def main(): | ||
112 | HOST = 'pound-pwr.cs.unc.edu' | ||
113 | USERNAME = 'admin' | ||
114 | |||
115 | try: | ||
116 | password = read_password() | ||
117 | except IOError as e: | ||
118 | print('Error reading password file: {}'.format(e), file=sys.stderr) | ||
119 | sys.exit(1) | ||
120 | |||
121 | args = parse_args() | ||
122 | |||
123 | port = find_port() | ||
124 | mgr = PowerManager(HOST, USERNAME, password, port) | ||
125 | try: | ||
126 | PowerManager.dispatch_action(mgr, args.action) | ||
127 | except PowerManagerException as e: | ||
128 | print('Exception: {}'.format(e.reason), file=sys.stderr) | ||
129 | sys.exit(1) | ||
130 | sys.exit(0) | ||
131 | |||
132 | if __name__ == '__main__': | ||
133 | main() | ||