-
Notifications
You must be signed in to change notification settings - Fork 6
/
arbstatus.py
executable file
·189 lines (170 loc) · 6.92 KB
/
arbstatus.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
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
#!/usr/bin/env python3
# SPDX-FileCopyrightText: Copyright (c) 2019-2020 Center for High Performance Computing <[email protected]>
#
# SPDX-License-Identifier: GPL-2.0-only
#
# Written by Dylan Gardner
# Usage: ./arbstatus.py
import argparse
import shlex
import getpass
import time
import os
import pwd
import sys
import toml
def parse_statusdb_url(args):
"""
Given args, return the correct statusdb url.
"""
# Local sqlite database
if args.database_loc:
return "sqlite:///{}".format(args.database_loc)
# Provided URL
elif args.statusdb_url:
return args.statusdb_url
# Resolve to what statusdb_url is when empty in the config
elif cfg.database.statusdb_url == "":
return "sqlite:///{}".format(cfg.database.log_location + "/statuses.db")
# Use statusdb_url from the config
else:
return cfg.database.statusdb_url
def main(args):
statusdb_url = parse_statusdb_url(args)
statusdb_obj = statusdb.lookup_statusdb(statusdb_url)
status = statusdb_obj.get_status(pwd.getpwnam(args.username).pw_uid)
timeout = float("inf")
if statuses.lookup_is_penalty(status.current):
timeout = statuses.lookup_status_prop(status.current).timeout
timeleft = timeout - (time.time() - status.timestamp)
# Cannot cast inf to int
timeleft = int(timeleft) if timeleft != float("inf") else timeleft
properties = {
"Status": status.current,
"Time Left": f"{timeleft}{'s' if timeleft != float('inf') else ''}",
"Penalty Occurrences": status.occurrences,
"Default Status": status.default,
"Authority": status.authority,
}
print("\n".join(
[f"{name + ':':<20}{val:>10}" for name, val in properties.items()]
))
def bootstrap(args):
"""
Configures the program so that it can function correctly. This is done by
changing into the arbiter directory and then importing arbiter functions.
"""
# Make the path to files absolute. This makes behavior consistent when
# changing directories. Otherwise, configuration files would be relative to
# the arbiter/ directory
args.configs = [os.path.abspath(path) for path in args.configs]
os.chdir(args.arbdir)
insert(args.arbdir)
import cfgparser
try:
if not cfgparser.load_config(*args.configs, pedantic=False):
print("There was an issue with the specified configuration (see "
"above). You can investigate this with the cfgparser.py "
"tool.")
sys.exit(2)
except (TypeError, toml.decoder.TomlDecodeError) as err:
print("Configuration error:", str(err), file=sys.stderr)
sys.exit(2)
def insert(context):
"""
Appends a path to into the python path.
"""
context_path = os.path.dirname(__file__)
sys.path.insert(0, os.path.abspath(os.path.join(context_path, context)))
def arbiter_environ():
"""
Returns a dictionary with the ARB environment variables. If a variable is
not found, it is not in the dictionary.
"""
env = {}
env_vars = {
"ARBETC": ("-e", "--etc"),
"ARBDIR": ("-a", "--arbdir"),
"ARBCONFIG": ("-g", "--config")
}
for env_name, ignored_prefixes in env_vars.items():
env_value = os.environ.get(env_name)
if not env_value:
continue
warn = lambda i, s: print("{} in {} {}".format(i, env_name, s))
expanded_path = lambda p: os.path.expandvars(os.path.expanduser(p))
for prefix in ignored_prefixes:
if env_value.startswith(prefix):
env_value = env_value.lstrip(prefix).lstrip()
break
if env_name == "ARBCONFIG":
config_paths = shlex.split(env_value, comments=False, posix=True)
valid_paths = []
for path in config_paths:
if not os.path.isfile(expanded_path(path)):
warn(path, "does not exist")
continue
valid_paths.append(path)
if valid_paths:
env[env_name] = valid_paths
continue
expanded_value = expanded_path(env_value)
if not os.path.exists(expanded_value):
warn(env_value, "does not exist")
continue
if not os.path.isdir(expanded_value):
warn(env_value, "is not a directory")
continue
if env_name == "ARBDIR" and not os.path.exists(expanded_value + "/arbiter.py"):
warn(env_value, "does not contain arbiter modules! (not arbiter/ ?)")
continue
if env_name == "ARBETC" and not os.path.exists(expanded_value + "/integrations.py"):
warn(env_value, "does not contain etc modules! (no integrations.py)")
continue
env[env_name] = expanded_value
return env
if __name__ == "__main__":
parser = argparse.ArgumentParser(description="Arbiter status reporter")
arb_environ = arbiter_environ()
parser.add_argument("username",
nargs="?",
help="Queries the status of the user by username.",
default=getpass.getuser(),
type=str)
parser.add_argument("-a", "--arbdir",
type=str,
help="Sets the directory in which arbiter modules "
"are loaded from. Defaults to $ARBDIR if "
"present or ../arbiter otherwise.",
default=arb_environ.get("ARBDIR", "../arbiter"),
dest="arbdir")
parser.add_argument("-g", "--config",
type=str,
nargs="+",
help="The configuration files to use. Configs will be "
"cascaded together starting at the leftmost (the "
"primary config) going right (the overwriting "
"configs). Defaults to $ARBCONFIG if present or "
"../etc/config.toml otherwise.",
default=arb_environ.get("ARBCONFIG", ["../etc/config.toml"]),
dest="configs")
env = parser.add_mutually_exclusive_group()
env.add_argument("-u", "--statusdb-url",
type=str,
help="Pulls from the specified statusdb url. Defaults "
"to database.statusdb_url specified in the "
"configuration.",
dest="statusdb_url")
env.add_argument("-d", "--database",
type=str,
help="Pulls from the specified sqlite statusdb, rather "
"than database.statusdb_url specified in the "
"configuration.",
dest="database_loc")
args = parser.parse_args()
bootstrap(args)
import statusdb
import statuses
import database
from cfgparser import cfg
main(args)