DUNE-DAQ
DUNE Trigger and Data Acquisition software
Loading...
Searching...
No Matches
send-recv-restcmd.py
Go to the documentation of this file.
1#!/usr/bin/env python3
2
3import argparse
4import requests
5import json
6import time
7import sys
8from colorama import Fore, Back, Style
9
10from flask import Flask, request, cli
11from multiprocessing import Process, SimpleQueue
12import logging
13
14from rich.logging import RichHandler
15
16logging.basicConfig(
17 level="INFO",
18 format="%(message)s",
19 datefmt="[%X]",
20 handlers=[RichHandler(rich_tracebacks=True)]
21)
22
23
24log = logging.getLogger('werkzeug')
25log.setLevel(logging.ERROR)
26
27OKGREEN = '\033[92m'
28FAIL = '\033[91m'
29ENDC = '\033[0m'
30
31cli.show_server_banner = lambda *_: None
32
33parser = argparse.ArgumentParser(description='POST command object from file to commanded endpoint.')
34parser.add_argument('--host', type=str, default='localhost', help='target host/endpoint')
35parser.add_argument('-p', '--port', type=int, default=12345, help='target port')
36parser.add_argument('-a', '--answer-port', type=int, default=12333, help='answer to service listening on this port')
37parser.add_argument('-o', '--answer-host', type=str, default=None, help='answer to service listening on this host')
38parser.add_argument('-x', '--proxy', type=str, default=None, help='Use proxy for posting requests')
39
40parser.add_argument('-r', '--route', type=str, default='command', help='target route on endpoint')
41parser.add_argument('-f', '--file', type=str, required=True, help='file that contains command to be posted') # This should be an argument
42group = parser.add_mutually_exclusive_group()
43group.add_argument('-c', '--command', type=str, default=None, help='Only send command COMMAND, not all commands in file')
44parser.add_argument('-w', '--wait', type=int, default=2, help='seconds to wait between sending commands')
45group.add_argument('-i', '--interactive', dest='interactive', action='store_true', help='interactive mode')
46parser.add_argument('--non-interactive', dest='interactive', action='store_false')
47parser.set_defaults(interactive=False)
48
49args = parser.parse_args()
50
51reply_queue = SimpleQueue() # command reply queue
52
53
54app = Flask(__name__)
55@app.route('/response', methods = ['POST'])
56def index():
57 json = request.get_json(force=True)
58 # enqueue command reply
59 reply_queue.put(json)
60 return 'Response received'
61
62if __name__ == "__main__":
63 flask_server = Process(target=app.run, kwargs={'port': args.answer_port})
64 flask_server.start()
65
66url = 'http://'+args.host+':'+str(args.port)+'/'+args.route
67# print(f'Target url: {Fore.YELLOW+url+Style.RESET_ALL}')
68logging.info(f'Target url: {url}')
69headers = {'content-type': 'application/json', 'X-Answer-Port': str(args.answer_port)}
70if not args.answer_host is None:
71 headers['X-Answer-Host'] = args.answer_host
72
73cmdstr = None
74try:
75 with open(args.file) as f:
76 cmdstr = json.load(f)
77except:
78 # print(f"\nERROR: failed to open file '{str(args.file)}'.")
79 logging.error(f"ERROR: failed to open file '{str(args.file)}'.")
80 raise SystemExit(0)
81
82if isinstance(cmdstr, dict):
83 logging.info(f'Found single command in {args.file}.')
84 try:
85 response = requests.post(
86 url,
87 data=json.dumps(cmdstr),
88 headers=headers,
89 proxies=({
90 'http': f'socks5h://{args.proxy}',
91 'https': f'socks5h://{args.proxy}'}
92 if args.proxy else None
93 )
94 )
95 logging.info(f'Response code: {str(response)} with content: {response.content.decode("utf-8")}')
96 except Exception as e:
97 logging.error(f'Failed to send due to: {e}')
98elif isinstance(cmdstr, list):
99 print(f'Found a list of commands in {args.file}')
100 avacmds = [cdict['id'] for cdict in cmdstr if cdict["id"]]
101 if args.command and not args.command in avacmds:
102 raise SystemExit(f"\nERROR: No command '{args.command}' found in file '{str(args.file)}'.")
103 if not args.interactive:
104 for cmd in cmdstr:
105 try:
106 if args.command and cmd['id']!=args.command:
107 continue
108 response = requests.post(
109 url,
110 data=json.dumps(cmd),
111 headers=headers,
112 proxies=({
113 'http': f'socks5h://{args.proxy}',
114 'https': f'socks5h://{args.proxy}'}
115 if args.proxy else None
116 )
117 )
118 print(f'Response code: {str(response)} with content: {response.content.decode("utf-8")}')
119 # get command reply from queue
120 r = reply_queue.get()
121 print("Reply:")
122 print(f" Application : {Fore.CYAN}{r['appname']}{Style.RESET_ALL}")
123 print(f" Command : {Fore.CYAN}{r['data']['cmdid']}{Style.RESET_ALL}")
124 print(f" Result : {Fore.GREEN if r['success'] else Fore.RED}{r['result']}{Style.RESET_ALL}")
125 time.sleep(args.wait)
126 except:
127 print('Failed to send due to: %s' % sys.exc_info()[0])
128 else:
129 print('\nInteractive mode. Type the ID of the next command to send, or type \'end\' to finish.')
130 while True:
131 try:
132 print(f'\nAvailable commands: {", ".join([Fore.CYAN+c+Style.RESET_ALL for c in avacmds])}')
133 nextcmd = input('command >> ')
134 if nextcmd == "end":
135 break
136 cmdobj = [cdict for cdict in cmdstr if cdict["id"] == nextcmd]
137 if not cmdobj:
138 print('Unrecognized command %s. (Not present in the command list?)' % nextcmd)
139 else:
140 print(f'\nSending {Fore.CYAN+nextcmd+Style.RESET_ALL} command.')
141 try:
142 response = requests.post(
143 url,
144 data=json.dumps(cmdobj[0]),
145 headers=headers,
146 proxies=({
147 'http': f'socks5h://{args.proxy}',
148 'https': f'socks5h://{args.proxy}'}
149 if args.proxy else None
150 )
151 )
152 print(f'Response code: {str(response)} with content: {response.content.decode("utf-8")}')
153 # get command reply from queue
154 r = reply_queue.get()
155 print("Reply:")
156 print(f" Command : {Fore.CYAN}{r['data']['cmdid']}{Style.RESET_ALL}")
157 print(f" Result : {Fore.GREEN if r['success'] else Fore.RED}{r['result']}{Style.RESET_ALL}")
158 except:
159 print('Failed to send due to: %s' % sys.exc_info()[0])
160 except KeyboardInterrupt as ki:
161 break
162 except EOFError as e:
163 break
164
165print('Exiting...')
166flask_server.terminate()
167flask_server.join()