Brad Bishop | a34c030 | 2019-09-23 22:34:48 -0400 | [diff] [blame] | 1 | #! /usr/bin/env python3 |
| 2 | # |
| 3 | # Copyright (C) 2019 Garmin Ltd. |
| 4 | # |
| 5 | # SPDX-License-Identifier: GPL-2.0-only |
| 6 | # |
| 7 | |
| 8 | import argparse |
| 9 | import hashlib |
| 10 | import logging |
| 11 | import os |
| 12 | import pprint |
| 13 | import sys |
| 14 | import threading |
| 15 | import time |
Andrew Geissler | 5199d83 | 2021-09-24 16:47:35 -0500 | [diff] [blame] | 16 | import warnings |
Patrick Williams | ac13d5f | 2023-11-24 18:59:46 -0600 | [diff] [blame] | 17 | import netrc |
| 18 | import json |
Andrew Geissler | edff492 | 2024-06-19 14:12:16 -0400 | [diff] [blame] | 19 | import statistics |
Andrew Geissler | 5199d83 | 2021-09-24 16:47:35 -0500 | [diff] [blame] | 20 | warnings.simplefilter("default") |
Brad Bishop | a34c030 | 2019-09-23 22:34:48 -0400 | [diff] [blame] | 21 | |
| 22 | try: |
| 23 | import tqdm |
| 24 | ProgressBar = tqdm.tqdm |
| 25 | except ImportError: |
| 26 | class ProgressBar(object): |
| 27 | def __init__(self, *args, **kwargs): |
| 28 | pass |
| 29 | |
| 30 | def __enter__(self): |
| 31 | return self |
| 32 | |
| 33 | def __exit__(self, *args, **kwargs): |
| 34 | pass |
| 35 | |
| 36 | def update(self): |
| 37 | pass |
| 38 | |
| 39 | sys.path.insert(0, os.path.join(os.path.dirname(os.path.dirname(__file__)), 'lib')) |
| 40 | |
| 41 | import hashserv |
Patrick Williams | ac13d5f | 2023-11-24 18:59:46 -0600 | [diff] [blame] | 42 | import bb.asyncrpc |
Brad Bishop | a34c030 | 2019-09-23 22:34:48 -0400 | [diff] [blame] | 43 | |
| 44 | DEFAULT_ADDRESS = 'unix://./hashserve.sock' |
| 45 | METHOD = 'stress.test.method' |
| 46 | |
Patrick Williams | ac13d5f | 2023-11-24 18:59:46 -0600 | [diff] [blame] | 47 | def print_user(u): |
| 48 | print(f"Username: {u['username']}") |
| 49 | if "permissions" in u: |
| 50 | print("Permissions: " + " ".join(u["permissions"])) |
| 51 | if "token" in u: |
| 52 | print(f"Token: {u['token']}") |
| 53 | |
Brad Bishop | a34c030 | 2019-09-23 22:34:48 -0400 | [diff] [blame] | 54 | |
| 55 | def main(): |
Patrick Williams | da29531 | 2023-12-05 16:48:56 -0600 | [diff] [blame] | 56 | def handle_get(args, client): |
| 57 | result = client.get_taskhash(args.method, args.taskhash, all_properties=True) |
| 58 | if not result: |
| 59 | return 0 |
| 60 | |
| 61 | print(json.dumps(result, sort_keys=True, indent=4)) |
| 62 | return 0 |
| 63 | |
| 64 | def handle_get_outhash(args, client): |
| 65 | result = client.get_outhash(args.method, args.outhash, args.taskhash) |
| 66 | if not result: |
| 67 | return 0 |
| 68 | |
| 69 | print(json.dumps(result, sort_keys=True, indent=4)) |
| 70 | return 0 |
| 71 | |
Brad Bishop | a34c030 | 2019-09-23 22:34:48 -0400 | [diff] [blame] | 72 | def handle_stats(args, client): |
| 73 | if args.reset: |
| 74 | s = client.reset_stats() |
| 75 | else: |
| 76 | s = client.get_stats() |
Patrick Williams | ac13d5f | 2023-11-24 18:59:46 -0600 | [diff] [blame] | 77 | print(json.dumps(s, sort_keys=True, indent=4)) |
Brad Bishop | a34c030 | 2019-09-23 22:34:48 -0400 | [diff] [blame] | 78 | return 0 |
| 79 | |
| 80 | def handle_stress(args, client): |
| 81 | def thread_main(pbar, lock): |
| 82 | nonlocal found_hashes |
| 83 | nonlocal missed_hashes |
| 84 | nonlocal max_time |
Andrew Geissler | edff492 | 2024-06-19 14:12:16 -0400 | [diff] [blame] | 85 | nonlocal times |
Brad Bishop | a34c030 | 2019-09-23 22:34:48 -0400 | [diff] [blame] | 86 | |
Patrick Williams | ac13d5f | 2023-11-24 18:59:46 -0600 | [diff] [blame] | 87 | with hashserv.create_client(args.address) as client: |
| 88 | for i in range(args.requests): |
| 89 | taskhash = hashlib.sha256() |
| 90 | taskhash.update(args.taskhash_seed.encode('utf-8')) |
| 91 | taskhash.update(str(i).encode('utf-8')) |
Brad Bishop | a34c030 | 2019-09-23 22:34:48 -0400 | [diff] [blame] | 92 | |
Patrick Williams | ac13d5f | 2023-11-24 18:59:46 -0600 | [diff] [blame] | 93 | start_time = time.perf_counter() |
| 94 | l = client.get_unihash(METHOD, taskhash.hexdigest()) |
| 95 | elapsed = time.perf_counter() - start_time |
Brad Bishop | a34c030 | 2019-09-23 22:34:48 -0400 | [diff] [blame] | 96 | |
Patrick Williams | ac13d5f | 2023-11-24 18:59:46 -0600 | [diff] [blame] | 97 | with lock: |
| 98 | if l: |
| 99 | found_hashes += 1 |
| 100 | else: |
| 101 | missed_hashes += 1 |
Brad Bishop | a34c030 | 2019-09-23 22:34:48 -0400 | [diff] [blame] | 102 | |
Andrew Geissler | edff492 | 2024-06-19 14:12:16 -0400 | [diff] [blame] | 103 | times.append(elapsed) |
Patrick Williams | ac13d5f | 2023-11-24 18:59:46 -0600 | [diff] [blame] | 104 | pbar.update() |
Brad Bishop | a34c030 | 2019-09-23 22:34:48 -0400 | [diff] [blame] | 105 | |
| 106 | max_time = 0 |
| 107 | found_hashes = 0 |
| 108 | missed_hashes = 0 |
| 109 | lock = threading.Lock() |
Andrew Geissler | edff492 | 2024-06-19 14:12:16 -0400 | [diff] [blame] | 110 | times = [] |
Brad Bishop | a34c030 | 2019-09-23 22:34:48 -0400 | [diff] [blame] | 111 | start_time = time.perf_counter() |
Andrew Geissler | edff492 | 2024-06-19 14:12:16 -0400 | [diff] [blame] | 112 | with ProgressBar(total=args.clients * args.requests) as pbar: |
Brad Bishop | a34c030 | 2019-09-23 22:34:48 -0400 | [diff] [blame] | 113 | threads = [threading.Thread(target=thread_main, args=(pbar, lock), daemon=False) for _ in range(args.clients)] |
| 114 | for t in threads: |
| 115 | t.start() |
| 116 | |
| 117 | for t in threads: |
| 118 | t.join() |
Andrew Geissler | edff492 | 2024-06-19 14:12:16 -0400 | [diff] [blame] | 119 | total_elapsed = time.perf_counter() - start_time |
Brad Bishop | a34c030 | 2019-09-23 22:34:48 -0400 | [diff] [blame] | 120 | |
Brad Bishop | a34c030 | 2019-09-23 22:34:48 -0400 | [diff] [blame] | 121 | with lock: |
Andrew Geissler | edff492 | 2024-06-19 14:12:16 -0400 | [diff] [blame] | 122 | mean = statistics.mean(times) |
| 123 | median = statistics.median(times) |
| 124 | stddev = statistics.pstdev(times) |
| 125 | |
| 126 | print(f"Number of clients: {args.clients}") |
| 127 | print(f"Requests per client: {args.requests}") |
| 128 | print(f"Number of requests: {len(times)}") |
| 129 | print(f"Total elapsed time: {total_elapsed:.3f}s") |
| 130 | print(f"Total request rate: {len(times)/total_elapsed:.3f} req/s") |
| 131 | print(f"Average request time: {mean:.3f}s") |
| 132 | print(f"Median request time: {median:.3f}s") |
| 133 | print(f"Request time std dev: {stddev:.3f}s") |
| 134 | print(f"Maximum request time: {max(times):.3f}s") |
| 135 | print(f"Minimum request time: {min(times):.3f}s") |
| 136 | print(f"Hashes found: {found_hashes}") |
| 137 | print(f"Hashes missed: {missed_hashes}") |
Brad Bishop | a34c030 | 2019-09-23 22:34:48 -0400 | [diff] [blame] | 138 | |
| 139 | if args.report: |
| 140 | with ProgressBar(total=args.requests) as pbar: |
| 141 | for i in range(args.requests): |
| 142 | taskhash = hashlib.sha256() |
| 143 | taskhash.update(args.taskhash_seed.encode('utf-8')) |
| 144 | taskhash.update(str(i).encode('utf-8')) |
| 145 | |
| 146 | outhash = hashlib.sha256() |
| 147 | outhash.update(args.outhash_seed.encode('utf-8')) |
| 148 | outhash.update(str(i).encode('utf-8')) |
| 149 | |
| 150 | client.report_unihash(taskhash.hexdigest(), METHOD, outhash.hexdigest(), taskhash.hexdigest()) |
| 151 | |
| 152 | with lock: |
| 153 | pbar.update() |
| 154 | |
Andrew Geissler | 2013739 | 2023-10-12 04:59:14 -0600 | [diff] [blame] | 155 | def handle_remove(args, client): |
| 156 | where = {k: v for k, v in args.where} |
| 157 | if where: |
| 158 | result = client.remove(where) |
| 159 | print("Removed %d row(s)" % (result["count"])) |
| 160 | else: |
| 161 | print("No query specified") |
| 162 | |
| 163 | def handle_clean_unused(args, client): |
| 164 | result = client.clean_unused(args.max_age) |
| 165 | print("Removed %d rows" % (result["count"])) |
| 166 | return 0 |
| 167 | |
Patrick Williams | ac13d5f | 2023-11-24 18:59:46 -0600 | [diff] [blame] | 168 | def handle_refresh_token(args, client): |
| 169 | r = client.refresh_token(args.username) |
| 170 | print_user(r) |
| 171 | |
| 172 | def handle_set_user_permissions(args, client): |
| 173 | r = client.set_user_perms(args.username, args.permissions) |
| 174 | print_user(r) |
| 175 | |
| 176 | def handle_get_user(args, client): |
| 177 | r = client.get_user(args.username) |
| 178 | print_user(r) |
| 179 | |
| 180 | def handle_get_all_users(args, client): |
| 181 | users = client.get_all_users() |
| 182 | print("{username:20}| {permissions}".format(username="Username", permissions="Permissions")) |
| 183 | print(("-" * 20) + "+" + ("-" * 20)) |
| 184 | for u in users: |
| 185 | print("{username:20}| {permissions}".format(username=u["username"], permissions=" ".join(u["permissions"]))) |
| 186 | |
| 187 | def handle_new_user(args, client): |
| 188 | r = client.new_user(args.username, args.permissions) |
| 189 | print_user(r) |
| 190 | |
| 191 | def handle_delete_user(args, client): |
| 192 | r = client.delete_user(args.username) |
| 193 | print_user(r) |
| 194 | |
| 195 | def handle_get_db_usage(args, client): |
| 196 | usage = client.get_db_usage() |
| 197 | print(usage) |
| 198 | tables = sorted(usage.keys()) |
| 199 | print("{name:20}| {rows:20}".format(name="Table name", rows="Rows")) |
| 200 | print(("-" * 20) + "+" + ("-" * 20)) |
| 201 | for t in tables: |
| 202 | print("{name:20}| {rows:<20}".format(name=t, rows=usage[t]["rows"])) |
| 203 | print() |
| 204 | |
| 205 | total_rows = sum(t["rows"] for t in usage.values()) |
| 206 | print(f"Total rows: {total_rows}") |
| 207 | |
| 208 | def handle_get_db_query_columns(args, client): |
| 209 | columns = client.get_db_query_columns() |
| 210 | print("\n".join(sorted(columns))) |
| 211 | |
Patrick Williams | 73bd93f | 2024-02-20 08:07:48 -0600 | [diff] [blame] | 212 | def handle_gc_status(args, client): |
| 213 | result = client.gc_status() |
| 214 | if not result["mark"]: |
| 215 | print("No Garbage collection in progress") |
| 216 | return 0 |
| 217 | |
| 218 | print("Current Mark: %s" % result["mark"]) |
| 219 | print("Total hashes to keep: %d" % result["keep"]) |
| 220 | print("Total hashes to remove: %s" % result["remove"]) |
| 221 | return 0 |
| 222 | |
| 223 | def handle_gc_mark(args, client): |
| 224 | where = {k: v for k, v in args.where} |
| 225 | result = client.gc_mark(args.mark, where) |
| 226 | print("New hashes marked: %d" % result["count"]) |
| 227 | return 0 |
| 228 | |
| 229 | def handle_gc_sweep(args, client): |
| 230 | result = client.gc_sweep(args.mark) |
| 231 | print("Removed %d rows" % result["count"]) |
| 232 | return 0 |
| 233 | |
| 234 | def handle_unihash_exists(args, client): |
| 235 | result = client.unihash_exists(args.unihash) |
| 236 | if args.quiet: |
| 237 | return 0 if result else 1 |
| 238 | |
| 239 | print("true" if result else "false") |
| 240 | return 0 |
| 241 | |
Andrew Geissler | edff492 | 2024-06-19 14:12:16 -0400 | [diff] [blame] | 242 | def handle_ping(args, client): |
| 243 | times = [] |
| 244 | for i in range(1, args.count + 1): |
| 245 | if not args.quiet: |
| 246 | print(f"Ping {i} of {args.count}... ", end="") |
| 247 | start_time = time.perf_counter() |
| 248 | client.ping() |
| 249 | elapsed = time.perf_counter() - start_time |
| 250 | times.append(elapsed) |
| 251 | if not args.quiet: |
| 252 | print(f"{elapsed:.3f}s") |
| 253 | |
| 254 | mean = statistics.mean(times) |
| 255 | median = statistics.median(times) |
| 256 | std_dev = statistics.pstdev(times) |
| 257 | |
| 258 | if not args.quiet: |
| 259 | print("------------------------") |
| 260 | print(f"Number of pings: {len(times)}") |
| 261 | print(f"Average round trip time: {mean:.3f}s") |
| 262 | print(f"Median round trip time: {median:.3f}s") |
| 263 | print(f"Round trip time std dev: {std_dev:.3f}s") |
| 264 | print(f"Min time is: {min(times):.3f}s") |
| 265 | print(f"Max time is: {max(times):.3f}s") |
| 266 | return 0 |
| 267 | |
Brad Bishop | a34c030 | 2019-09-23 22:34:48 -0400 | [diff] [blame] | 268 | parser = argparse.ArgumentParser(description='Hash Equivalence Client') |
| 269 | parser.add_argument('--address', default=DEFAULT_ADDRESS, help='Server address (default "%(default)s")') |
| 270 | parser.add_argument('--log', default='WARNING', help='Set logging level') |
Patrick Williams | ac13d5f | 2023-11-24 18:59:46 -0600 | [diff] [blame] | 271 | parser.add_argument('--login', '-l', metavar="USERNAME", help="Authenticate as USERNAME") |
| 272 | parser.add_argument('--password', '-p', metavar="TOKEN", help="Authenticate using token TOKEN") |
| 273 | parser.add_argument('--become', '-b', metavar="USERNAME", help="Impersonate user USERNAME (if allowed) when performing actions") |
| 274 | parser.add_argument('--no-netrc', '-n', action="store_false", dest="netrc", help="Do not use .netrc") |
Brad Bishop | a34c030 | 2019-09-23 22:34:48 -0400 | [diff] [blame] | 275 | |
| 276 | subparsers = parser.add_subparsers() |
| 277 | |
Patrick Williams | da29531 | 2023-12-05 16:48:56 -0600 | [diff] [blame] | 278 | get_parser = subparsers.add_parser('get', help="Get the unihash for a taskhash") |
| 279 | get_parser.add_argument("method", help="Method to query") |
| 280 | get_parser.add_argument("taskhash", help="Task hash to query") |
| 281 | get_parser.set_defaults(func=handle_get) |
| 282 | |
| 283 | get_outhash_parser = subparsers.add_parser('get-outhash', help="Get output hash information") |
| 284 | get_outhash_parser.add_argument("method", help="Method to query") |
| 285 | get_outhash_parser.add_argument("outhash", help="Output hash to query") |
| 286 | get_outhash_parser.add_argument("taskhash", help="Task hash to query") |
| 287 | get_outhash_parser.set_defaults(func=handle_get_outhash) |
| 288 | |
Brad Bishop | a34c030 | 2019-09-23 22:34:48 -0400 | [diff] [blame] | 289 | stats_parser = subparsers.add_parser('stats', help='Show server stats') |
| 290 | stats_parser.add_argument('--reset', action='store_true', |
| 291 | help='Reset server stats') |
| 292 | stats_parser.set_defaults(func=handle_stats) |
| 293 | |
| 294 | stress_parser = subparsers.add_parser('stress', help='Run stress test') |
| 295 | stress_parser.add_argument('--clients', type=int, default=10, |
| 296 | help='Number of simultaneous clients') |
| 297 | stress_parser.add_argument('--requests', type=int, default=1000, |
| 298 | help='Number of requests each client will perform') |
| 299 | stress_parser.add_argument('--report', action='store_true', |
| 300 | help='Report new hashes') |
| 301 | stress_parser.add_argument('--taskhash-seed', default='', |
| 302 | help='Include string in taskhash') |
| 303 | stress_parser.add_argument('--outhash-seed', default='', |
| 304 | help='Include string in outhash') |
| 305 | stress_parser.set_defaults(func=handle_stress) |
| 306 | |
Andrew Geissler | 2013739 | 2023-10-12 04:59:14 -0600 | [diff] [blame] | 307 | remove_parser = subparsers.add_parser('remove', help="Remove hash entries") |
| 308 | remove_parser.add_argument("--where", "-w", metavar="KEY VALUE", nargs=2, action="append", default=[], |
| 309 | help="Remove entries from table where KEY == VALUE") |
| 310 | remove_parser.set_defaults(func=handle_remove) |
| 311 | |
| 312 | clean_unused_parser = subparsers.add_parser('clean-unused', help="Remove unused database entries") |
| 313 | clean_unused_parser.add_argument("max_age", metavar="SECONDS", type=int, help="Remove unused entries older than SECONDS old") |
| 314 | clean_unused_parser.set_defaults(func=handle_clean_unused) |
| 315 | |
Patrick Williams | ac13d5f | 2023-11-24 18:59:46 -0600 | [diff] [blame] | 316 | refresh_token_parser = subparsers.add_parser('refresh-token', help="Refresh auth token") |
| 317 | refresh_token_parser.add_argument("--username", "-u", help="Refresh the token for another user (if authorized)") |
| 318 | refresh_token_parser.set_defaults(func=handle_refresh_token) |
| 319 | |
| 320 | set_user_perms_parser = subparsers.add_parser('set-user-perms', help="Set new permissions for user") |
| 321 | set_user_perms_parser.add_argument("--username", "-u", help="Username", required=True) |
| 322 | set_user_perms_parser.add_argument("permissions", metavar="PERM", nargs="*", default=[], help="New permissions") |
| 323 | set_user_perms_parser.set_defaults(func=handle_set_user_permissions) |
| 324 | |
| 325 | get_user_parser = subparsers.add_parser('get-user', help="Get user") |
| 326 | get_user_parser.add_argument("--username", "-u", help="Username") |
| 327 | get_user_parser.set_defaults(func=handle_get_user) |
| 328 | |
| 329 | get_all_users_parser = subparsers.add_parser('get-all-users', help="List all users") |
| 330 | get_all_users_parser.set_defaults(func=handle_get_all_users) |
| 331 | |
| 332 | new_user_parser = subparsers.add_parser('new-user', help="Create new user") |
| 333 | new_user_parser.add_argument("--username", "-u", help="Username", required=True) |
| 334 | new_user_parser.add_argument("permissions", metavar="PERM", nargs="*", default=[], help="New permissions") |
| 335 | new_user_parser.set_defaults(func=handle_new_user) |
| 336 | |
| 337 | delete_user_parser = subparsers.add_parser('delete-user', help="Delete user") |
| 338 | delete_user_parser.add_argument("--username", "-u", help="Username", required=True) |
| 339 | delete_user_parser.set_defaults(func=handle_delete_user) |
| 340 | |
| 341 | db_usage_parser = subparsers.add_parser('get-db-usage', help="Database Usage") |
| 342 | db_usage_parser.set_defaults(func=handle_get_db_usage) |
| 343 | |
| 344 | db_query_columns_parser = subparsers.add_parser('get-db-query-columns', help="Show columns that can be used in database queries") |
| 345 | db_query_columns_parser.set_defaults(func=handle_get_db_query_columns) |
| 346 | |
Patrick Williams | 73bd93f | 2024-02-20 08:07:48 -0600 | [diff] [blame] | 347 | gc_status_parser = subparsers.add_parser("gc-status", help="Show garbage collection status") |
| 348 | gc_status_parser.set_defaults(func=handle_gc_status) |
| 349 | |
| 350 | gc_mark_parser = subparsers.add_parser('gc-mark', help="Mark hashes to be kept for garbage collection") |
| 351 | gc_mark_parser.add_argument("mark", help="Mark for this garbage collection operation") |
| 352 | gc_mark_parser.add_argument("--where", "-w", metavar="KEY VALUE", nargs=2, action="append", default=[], |
| 353 | help="Keep entries in table where KEY == VALUE") |
| 354 | gc_mark_parser.set_defaults(func=handle_gc_mark) |
| 355 | |
| 356 | gc_sweep_parser = subparsers.add_parser('gc-sweep', help="Perform garbage collection and delete any entries that are not marked") |
| 357 | gc_sweep_parser.add_argument("mark", help="Mark for this garbage collection operation") |
| 358 | gc_sweep_parser.set_defaults(func=handle_gc_sweep) |
| 359 | |
| 360 | unihash_exists_parser = subparsers.add_parser('unihash-exists', help="Check if a unihash is known to the server") |
| 361 | unihash_exists_parser.add_argument("--quiet", action="store_true", help="Don't print status. Instead, exit with 0 if unihash exists and 1 if it does not") |
| 362 | unihash_exists_parser.add_argument("unihash", help="Unihash to check") |
| 363 | unihash_exists_parser.set_defaults(func=handle_unihash_exists) |
| 364 | |
Andrew Geissler | edff492 | 2024-06-19 14:12:16 -0400 | [diff] [blame] | 365 | ping_parser = subparsers.add_parser('ping', help="Ping server") |
| 366 | ping_parser.add_argument("-n", "--count", type=int, help="Number of pings. Default is %(default)s", default=10) |
| 367 | ping_parser.add_argument("-q", "--quiet", action="store_true", help="Don't print each ping; only print results") |
| 368 | ping_parser.set_defaults(func=handle_ping) |
| 369 | |
Brad Bishop | a34c030 | 2019-09-23 22:34:48 -0400 | [diff] [blame] | 370 | args = parser.parse_args() |
| 371 | |
| 372 | logger = logging.getLogger('hashserv') |
| 373 | |
| 374 | level = getattr(logging, args.log.upper(), None) |
| 375 | if not isinstance(level, int): |
| 376 | raise ValueError('Invalid log level: %s' % args.log) |
| 377 | |
| 378 | logger.setLevel(level) |
| 379 | console = logging.StreamHandler() |
| 380 | console.setLevel(level) |
| 381 | logger.addHandler(console) |
| 382 | |
Patrick Williams | ac13d5f | 2023-11-24 18:59:46 -0600 | [diff] [blame] | 383 | login = args.login |
| 384 | password = args.password |
| 385 | |
| 386 | if login is None and args.netrc: |
| 387 | try: |
| 388 | n = netrc.netrc() |
| 389 | auth = n.authenticators(args.address) |
| 390 | if auth is not None: |
| 391 | login, _, password = auth |
| 392 | except FileNotFoundError: |
| 393 | pass |
Patrick Williams | 03514f1 | 2024-04-05 07:04:11 -0500 | [diff] [blame] | 394 | except netrc.NetrcParseError as e: |
| 395 | sys.stderr.write(f"Error parsing {e.filename}:{e.lineno}: {e.msg}\n") |
Patrick Williams | ac13d5f | 2023-11-24 18:59:46 -0600 | [diff] [blame] | 396 | |
Brad Bishop | a34c030 | 2019-09-23 22:34:48 -0400 | [diff] [blame] | 397 | func = getattr(args, 'func', None) |
| 398 | if func: |
Patrick Williams | ac13d5f | 2023-11-24 18:59:46 -0600 | [diff] [blame] | 399 | try: |
| 400 | with hashserv.create_client(args.address, login, password) as client: |
| 401 | if args.become: |
| 402 | client.become_user(args.become) |
| 403 | return func(args, client) |
| 404 | except bb.asyncrpc.InvokeError as e: |
| 405 | print(f"ERROR: {e}") |
| 406 | return 1 |
Brad Bishop | a34c030 | 2019-09-23 22:34:48 -0400 | [diff] [blame] | 407 | |
| 408 | return 0 |
| 409 | |
| 410 | |
| 411 | if __name__ == '__main__': |
| 412 | try: |
| 413 | ret = main() |
| 414 | except Exception: |
| 415 | ret = 1 |
| 416 | import traceback |
| 417 | traceback.print_exc() |
| 418 | sys.exit(ret) |