#!/usr/bin/env python3 # Copyright 2016 Red Hat, Inc. # # Licensed under the Apache License, Version 2.0 (the "License"); you may # not use this file except in compliance with the License. You may obtain # a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the # License for the specific language governing permissions and limitations # under the License. import socket import sys import os import json from openstackclient import shell as osc_shell from io import StringIO server_address = "/tmp/openstack.sock" try: os.unlink(server_address) except OSError: if os.path.exists(server_address): raise sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) print('starting up on %s' % server_address, file=sys.stderr) sock.bind(server_address) # Listen for incoming connections sock.listen(1) def send(sock, doc): jdoc = json.dumps(doc) sock.send(b'%d\n' % len(jdoc)) sock.sendall(jdoc.encode('utf-8')) def recv(sock): length_str = b'' char = sock.recv(1) while char != b'\n': length_str += char char = sock.recv(1) total = int(length_str) # use a memoryview to receive the data chunk by chunk efficiently jdoc = memoryview(bytearray(total)) next_offset = 0 while total - next_offset > 0: recv_size = sock.recv_into(jdoc[next_offset:], total - next_offset) next_offset += recv_size try: doc = json.loads(jdoc.tobytes()) except (TypeError, ValueError) as e: raise Exception('Data received was not in JSON format') return doc while True: csock, client_address = sock.accept() try: doc = recv(csock) print("%s %s" % (doc["app"], doc["argv"]), file=sys.stderr) oldenv = {} for name in doc["env"].keys(): oldenv[name] = os.environ.get(name, None) os.environ[name] = doc["env"][name] try: old_stdout = sys.stdout old_stderr = sys.stderr my_stdout = sys.stdout = StringIO() my_stderr = sys.stderr = StringIO() class Exit(BaseException): def __init__(self, status): self.status = status def noexit(stat): raise Exit(stat) sys.exit = noexit if doc["app"] == "openstack": sh = osc_shell.OpenStackShell() ret = sh.run(doc["argv"]) else: print("Unknown application %s" % doc["app"], file=sys.stderr) ret = 1 except Exit as e: ret = e.status finally: sys.stdout = old_stdout sys.stderr = old_stderr for name in oldenv.keys(): if oldenv[name] is None: del os.environ[name] else: os.environ[name] = oldenv[name] send(csock, { "stdout": my_stdout.getvalue(), "stderr": my_stderr.getvalue(), "status": ret, }) except BaseException as e: print(e, file=sys.stderr) finally: csock.close()