Commit | Line | Data |
---|---|---|
3f7ab73a AR |
1 | """ |
2 | libremanage - Lightweight, free software for remote side-chanel server management | |
3 | ||
4 | Copyright (C) 2018 Alyssa Rosenzweig | |
5 | ||
6 | This program is free software: you can redistribute it and/or modify | |
7 | it under the terms of the GNU Affero General Public License as published by | |
8 | the Free Software Foundation, either version 3 of the License, or | |
9 | (at your option) any later version. | |
10 | ||
11 | This program is distributed in the hope that it will be useful, | |
12 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
13 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
14 | GNU Affero General Public License for more details. | |
15 | ||
16 | You should have received a copy of the GNU Affero General Public License | |
17 | along with this program. If not, see <https://www.gnu.org/licenses/>. | |
18 | """ | |
93f19e92 | 19 | |
b266c229 | 20 | USAGE = """ |
93f19e92 AR |
21 | Usage: |
22 | ||
23 | $ libremanage [server name] [command] | |
24 | ||
25 | Example: | |
26 | ||
27 | $ libremanage web2 reboot | |
28 | ||
29 | Server names are defined in the accompanying config.py. | |
30 | ||
31 | Valid commands are as follows: | |
32 | ||
33 | - shutdown, reboot, poweron: Power management | |
9ed4bf16 | 34 | - tty: Open TTY in GNU Screen |
93f19e92 AR |
35 | """ |
36 | ||
22f864bb AR |
37 | import sys |
38 | import json | |
39 | import functools | |
40 | import subprocess | |
e14c36b3 | 41 | |
28c204f9 AR |
42 | def open_ssh(server, command): |
43 | config = server["ssh"] | |
e51c7dbc | 44 | subprocess.run(["ssh", "-t", config["username"] + "@" + config["host"], "-p", str(config["port"]), command]) |
e14c36b3 | 45 | |
40a688c0 AR |
46 | def die_with_usage(message): |
47 | print(message) | |
b266c229 AR |
48 | print(USAGE) |
49 | sys.exit(1) | |
50 | ||
d8ddde1a | 51 | def get_server_handle(name): |
38e0ee81 AR |
52 | try: |
53 | server = CONFIG["servers"][name] | |
54 | except KeyError: | |
55 | die_with_usage("Unknown server, please configure") | |
56 | ||
57 | # Associate manager configuration | |
82ee0c31 | 58 | server["ssh"] = CONFIG["managers"][server["manager"]] |
38e0ee81 | 59 | |
82ee0c31 | 60 | return server |
d8ddde1a AR |
61 | |
62 | def set_server_power(state, server): | |
20249149 | 63 | print("Setting to power state " + str(state)) |
e799dcd1 AR |
64 | conf = server["power"] |
65 | ||
66 | # Set invert to write LOW for power on and HIGH for off | |
67 | if conf["invert"]: | |
68 | state = 1 - state | |
69 | ||
70 | print(conf["pin"]) | |
282c96f8 | 71 | |
c10fa78c | 72 | # Export pin, configure, write value, unexport |
282c96f8 | 73 | open_ssh(server, "echo " + str(conf["pin"]) + " > /sys/class/gpio/export") |
c2e97249 | 74 | open_ssh(server, "echo out > /sys/class/gpio/gpio" + str(conf["pin"]) + "/direction") |
c10fa78c | 75 | open_ssh(server, "echo " + str(state) + " > /sys/class/gpio/gpio" + str(conf["pin"]) + "/value") |
282c96f8 | 76 | open_ssh(server, "echo " + str(conf["pin"]) + " > /sys/class/gpio/unexport") |
d8ddde1a AR |
77 | |
78 | COMMANDS = { | |
e14d7650 AR |
79 | # Power managemment |
80 | ||
da2eb513 AR |
81 | "shutdown": functools.partial(set_server_power, 0), |
82 | "poweron": functools.partial(set_server_power, 1), | |
83 | "reboot": lambda s: (set_server_power(0, s), set_server_power(1, s)), | |
e14d7650 AR |
84 | |
85 | # TTY access (or keyboard if wired as such) | |
86 | ||
e51c7dbc | 87 | "tty": lambda s: open_ssh(s, "screen " + s["tty"]["file"] + " " + str(s["tty"]["baud"])), |
e14c36b3 | 88 | |
da2eb513 | 89 | # SSH sanity tests |
82ee0c31 | 90 | |
28c204f9 AR |
91 | "sanity": lambda s: open_ssh(s, "whoami"), |
92 | "console": lambda s: open_ssh(s, ""), | |
d8ddde1a AR |
93 | } |
94 | ||
d24528e4 | 95 | def issue_command(server_name, command): |
d8ddde1a | 96 | server = get_server_handle(server_name) |
d24528e4 | 97 | print(server_name, command) |
40a688c0 AR |
98 | |
99 | try: | |
da2eb513 | 100 | callback = COMMANDS[command] |
40a688c0 AR |
101 | except KeyError: |
102 | die_with_usage("Invalid command supplied") | |
d24528e4 | 103 | |
82ee0c31 | 104 | callback(server) |
e14d7650 | 105 | |
22f864bb AR |
106 | # Load configuration, get command, and go! |
107 | ||
108 | with open("config.json") as f: | |
109 | CONFIG = json.load(f) | |
110 | ||
111 | if len(sys.argv) != 3: | |
112 | die_with_usage("Incorrect number of arguments") | |
113 | ||
d24528e4 | 114 | issue_command(sys.argv[1], sys.argv[2]) |