| #!/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 os.path |
| import json |
| |
| server_address = "/tmp/openstack.sock" |
| |
| sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) |
| |
| try: |
| sock.connect(server_address) |
| except socket.error as msg: |
| print(msg, file=sys.stderr) |
| sys.exit(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) |
| if len(char) == 0: |
| print("Unexpected end of file", file=sys.stderr) |
| sys.exit(1) |
| |
| while char != b'\n': |
| length_str += char |
| char = sock.recv(1) |
| if len(char) == 0: |
| print("Unexpected end of file", file=sys.stderr) |
| sys.exit(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 |
| |
| try: |
| env = {} |
| passenv = ["CINDER_VERSION", |
| "OS_AUTH_URL", |
| "OS_NO_CACHE", |
| "OS_PASSWORD", |
| "OS_PROJECT_NAME", |
| "OS_REGION_NAME", |
| "OS_TENANT_NAME", |
| "OS_USERNAME", |
| "OS_VOLUME_API_VERSION", |
| "OS_CLOUD"] |
| for name in passenv: |
| if name in os.environ: |
| env[name] = os.environ[name] |
| |
| cmd = { |
| "app": os.path.basename(sys.argv[0]), |
| "env": env, |
| "argv": sys.argv[1:] |
| } |
| try: |
| image_idx = sys.argv.index('image') |
| create_idx = sys.argv.index('create') |
| missing_file = image_idx < create_idx and \ |
| not any(x.startswith('--file') for x in sys.argv) |
| except ValueError: |
| missing_file = False |
| |
| if missing_file: |
| # This means we were called with an image create command, but were |
| # not provided a --file option. That likely means we're being passed |
| # the image data to stdin, which won't work because we do not proxy |
| # stdin to the server. So, we just reject the operation and ask the |
| # caller to provide the file with --file instead. |
| # We've already connected to the server, we need to send it some dummy |
| # data so it doesn't wait forever. |
| send(sock, {}) |
| print('Image create without --file is not allowed in server mode', |
| file=sys.stderr) |
| sys.exit(1) |
| else: |
| send(sock, cmd) |
| |
| doc = recv(sock) |
| if doc["stdout"] != b'': |
| print(doc["stdout"], end='') |
| if doc["stderr"] != b'': |
| print(doc["stderr"], file=sys.stderr) |
| sys.exit(doc["status"]) |
| finally: |
| sock.close() |