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 AR |
19 | |
20 | import sys | |
61110684 | 21 | import json |
d8ddde1a | 22 | import functools |
b2b1b982 | 23 | import subprocess |
93f19e92 | 24 | |
b266c229 | 25 | USAGE = """ |
93f19e92 AR |
26 | Usage: |
27 | ||
28 | $ libremanage [server name] [command] | |
29 | ||
30 | Example: | |
31 | ||
32 | $ libremanage web2 reboot | |
33 | ||
34 | Server names are defined in the accompanying config.py. | |
35 | ||
36 | Valid commands are as follows: | |
37 | ||
38 | - shutdown, reboot, poweron: Power management | |
9ed4bf16 | 39 | - tty: Open TTY in GNU Screen |
93f19e92 AR |
40 | """ |
41 | ||
61110684 AR |
42 | with open("config.json") as f: |
43 | CONFIG = json.load(f) | |
e14c36b3 | 44 | |
28c204f9 AR |
45 | def open_ssh(server, command): |
46 | config = server["ssh"] | |
da2eb513 | 47 | subprocess.run(["ssh", config["username"] + "@" + config["host"], "-p", str(config["port"]), command]) |
e14c36b3 | 48 | |
40a688c0 AR |
49 | def die_with_usage(message): |
50 | print(message) | |
b266c229 AR |
51 | print(USAGE) |
52 | sys.exit(1) | |
53 | ||
40a688c0 AR |
54 | if len(sys.argv) != 3: |
55 | die_with_usage("Incorrect number of arguments") | |
56 | ||
d8ddde1a | 57 | def get_server_handle(name): |
82ee0c31 AR |
58 | server = CONFIG["servers"][name] |
59 | server["ssh"] = CONFIG["managers"][server["manager"]] | |
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 AR |
71 | |
72 | # Export pin, write value, unexport | |
73 | open_ssh(server, "echo " + str(conf["pin"]) + " > /sys/class/gpio/export") | |
74 | open_ssh(server, "cat /sys/class/gpio/gpio" + str(conf["pin"]) + "/value") | |
75 | open_ssh(server, "echo " + str(conf["pin"]) + " > /sys/class/gpio/unexport") | |
d8ddde1a AR |
76 | |
77 | COMMANDS = { | |
e14d7650 AR |
78 | # Power managemment |
79 | ||
da2eb513 AR |
80 | "shutdown": functools.partial(set_server_power, 0), |
81 | "poweron": functools.partial(set_server_power, 1), | |
82 | "reboot": lambda s: (set_server_power(0, s), set_server_power(1, s)), | |
e14d7650 AR |
83 | |
84 | # TTY access (or keyboard if wired as such) | |
85 | ||
f0ccad0a | 86 | "tty": lambda s: open_ssh(s, "screen " + s["tty"]["file"] + str(s["tty"]["baud"])), |
e14c36b3 | 87 | |
da2eb513 | 88 | # SSH sanity tests |
82ee0c31 | 89 | |
28c204f9 AR |
90 | "sanity": lambda s: open_ssh(s, "whoami"), |
91 | "console": lambda s: open_ssh(s, ""), | |
d8ddde1a AR |
92 | } |
93 | ||
d24528e4 | 94 | def issue_command(server_name, command): |
d8ddde1a | 95 | server = get_server_handle(server_name) |
d24528e4 | 96 | print(server_name, command) |
40a688c0 AR |
97 | |
98 | try: | |
da2eb513 | 99 | callback = COMMANDS[command] |
40a688c0 AR |
100 | except KeyError: |
101 | die_with_usage("Invalid command supplied") | |
d24528e4 | 102 | |
82ee0c31 | 103 | callback(server) |
e14d7650 | 104 | |
d24528e4 | 105 | issue_command(sys.argv[1], sys.argv[2]) |