summaryrefslogtreecommitdiffstats
path: root/src/spdk/scripts/rpc_http_proxy.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/spdk/scripts/rpc_http_proxy.py')
-rwxr-xr-xsrc/spdk/scripts/rpc_http_proxy.py124
1 files changed, 124 insertions, 0 deletions
diff --git a/src/spdk/scripts/rpc_http_proxy.py b/src/spdk/scripts/rpc_http_proxy.py
new file mode 100755
index 000000000..ea9d17b16
--- /dev/null
+++ b/src/spdk/scripts/rpc_http_proxy.py
@@ -0,0 +1,124 @@
+#!/usr/bin/env python3
+
+import argparse
+import base64
+import errno
+import json
+import socket
+import ssl
+import sys
+try:
+ from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler
+except ImportError:
+ from http.server import HTTPServer
+ from http.server import BaseHTTPRequestHandler
+
+rpc_sock = None
+
+parser = argparse.ArgumentParser(description='http(s) proxy for SPDK RPC calls')
+parser.add_argument('host', help='Host name / IP representing proxy server')
+parser.add_argument('port', help='Port number', type=int)
+parser.add_argument('user', help='User name used for authentication')
+parser.add_argument('password', help='Password used for authentication')
+parser.add_argument('-s', dest='sock', help='RPC domain socket path', default='/var/tmp/spdk.sock')
+parser.add_argument('-c', dest='cert', help='SSL certificate')
+
+
+def print_usage_and_exit(status):
+ print('Usage: rpc_http_proxy.py <server IP> <server port> <user name>' +
+ ' <password> <SPDK RPC socket (optional, default: /var/tmp/spdk.sock)>')
+ sys.exit(status)
+
+
+def rpc_call(req):
+ global rpc_sock
+
+ sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
+ sock.connect(rpc_sock)
+ sock.sendall(req)
+
+ if 'id' not in json.loads(req.decode('ascii')):
+ sock.close()
+ return None
+
+ buf = ''
+ closed = False
+ response = None
+
+ while not closed:
+ newdata = sock.recv(1024)
+ if (newdata == b''):
+ closed = True
+ buf += newdata.decode('ascii')
+ try:
+ response = json.loads(buf)
+ except ValueError:
+ continue # incomplete response; keep buffering
+ break
+
+ sock.close()
+
+ if not response and len(buf) > 0:
+ raise
+
+ return buf
+
+
+class ServerHandler(BaseHTTPRequestHandler):
+
+ key = ""
+
+ def do_HEAD(self):
+ self.send_response(200)
+ self.send_header('Content-type', 'text/html')
+ self.end_headers()
+
+ def do_AUTHHEAD(self):
+ self.send_response(401)
+ self.send_header('WWW-Authenticate', 'text/html')
+ self.send_header('Content-type', 'text/html')
+ self.end_headers()
+
+ def do_INTERNALERROR(self):
+ self.send_response(500)
+ self.send_header('Content-type', 'text/html')
+ self.end_headers()
+
+ def do_POST(self):
+ if self.headers['Authorization'] != 'Basic ' + self.key:
+ self.do_AUTHHEAD()
+ else:
+ data_string = self.rfile.read(int(self.headers['Content-Length']))
+
+ try:
+ response = rpc_call(data_string)
+ if response is not None:
+ self.do_HEAD()
+ self.wfile.write(bytes(response.encode(encoding='ascii')))
+ except ValueError:
+ self.do_INTERNALERROR()
+
+
+def main():
+ global rpc_sock
+
+ args = parser.parse_args()
+ rpc_sock = args.sock
+
+ # encoding user name and password
+ key = base64.b64encode((args.user+':'+args.password).encode(encoding='ascii')).decode('ascii')
+
+ try:
+ ServerHandler.key = key
+ httpd = HTTPServer((args.host, args.port), ServerHandler)
+ if args.cert is not None:
+ httpd.socket = ssl.wrap_socket(httpd.socket, certfile=args.cert, server_side=True)
+ print('Started RPC http proxy server')
+ httpd.serve_forever()
+ except KeyboardInterrupt:
+ print('Shutting down server')
+ httpd.socket.close()
+
+
+if __name__ == '__main__':
+ main()