scripts: Remote RPC access with authentication

This patch introduces script that may be used for
sending RPC commands from remote machine. This script
requires remote user to authenticate with user name
and password set at launch time.

Signed-off-by: Maciej Szwed <maciej.szwed@intel.com>
Change-Id: I4ef7c870f3ea760c44da63ba4c16954aa54d4473

Reviewed-on: https://review.gerrithub.io/426531
Tested-by: SPDK CI Jenkins <sys_sgci@intel.com>
Chandler-Test-Pool: SPDK Automated Test System <sys_sgsw@intel.com>
Reviewed-by: Ben Walker <benjamin.walker@intel.com>
Reviewed-by: Pawel Wodkowski <pawelx.wodkowski@intel.com>
Reviewed-by: Jim Harris <james.r.harris@intel.com>
Reviewed-by: Shuhei Matsumoto <shuhei.matsumoto.xt@hitachi.com>
This commit is contained in:
Maciej Szwed 2018-09-24 13:52:34 +02:00 committed by Ben Walker
parent 338b038f5b
commit 5a7f29dd6d

123
scripts/rpc_http_proxy.py Executable file
View File

@ -0,0 +1,123 @@
#!/usr/bin/env python3
import base64
import errno
import json
import socket
import sys
try:
from BaseHTTPServer import HTTPServer, BaseHTTPRequestHandler
except ImportError:
from http.server import HTTPServer
from http.server import BaseHTTPRequestHandler
rpc_sock = None
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
if len(sys.argv) == 1 or sys.argv[1] == '-h':
print_usage_and_exit(0)
elif len(sys.argv) < 5:
print('Not enough arguments')
print_usage_and_exit(errno.EINVAL)
elif len(sys.argv) > 6:
print('Too many arguments')
print_usage_and_exit(errno.E2BIG)
if len(sys.argv) == 6:
rpc_sock = sys.argv[5]
else:
rpc_sock = '/var/tmp/spdk.sock'
# encoding user name and password
key = base64.b64encode((sys.argv[3]+':'+sys.argv[4]).encode(encoding='ascii')).decode('ascii')
try:
ServerHandler.key = key
httpd = HTTPServer((sys.argv[1], int(sys.argv[2])), ServerHandler)
print('Started RPC http proxy server')
httpd.serve_forever()
except KeyboardInterrupt:
print('Shutting down server')
httpd.socket.close()
if __name__ == '__main__':
main()