| Ben Nemec | 9a97326 | 2019-08-12 20:10:49 +0000 | [diff] [blame] | 1 | #!/usr/bin/env python3 | 
|  | 2 | # Copyright 2016 Red Hat, Inc. | 
|  | 3 | # | 
|  | 4 | # Licensed under the Apache License, Version 2.0 (the "License"); you may | 
|  | 5 | # not use this file except in compliance with the License. You may obtain | 
|  | 6 | # a copy of the License at | 
|  | 7 | # | 
|  | 8 | #      http://www.apache.org/licenses/LICENSE-2.0 | 
|  | 9 | # | 
|  | 10 | # Unless required by applicable law or agreed to in writing, software | 
|  | 11 | # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT | 
|  | 12 | # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the | 
|  | 13 | # License for the specific language governing permissions and limitations | 
|  | 14 | # under the License. | 
|  | 15 |  | 
|  | 16 | import socket | 
|  | 17 | import sys | 
|  | 18 | import os | 
|  | 19 | import os.path | 
|  | 20 | import json | 
|  | 21 |  | 
|  | 22 | server_address = "/tmp/openstack.sock" | 
|  | 23 |  | 
|  | 24 | sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM) | 
|  | 25 |  | 
|  | 26 | try: | 
|  | 27 | sock.connect(server_address) | 
|  | 28 | except socket.error as msg: | 
|  | 29 | print(msg, file=sys.stderr) | 
|  | 30 | sys.exit(1) | 
|  | 31 |  | 
|  | 32 |  | 
|  | 33 | def send(sock, doc): | 
|  | 34 | jdoc = json.dumps(doc) | 
|  | 35 | sock.send(b'%d\n' % len(jdoc)) | 
|  | 36 | sock.sendall(jdoc.encode('utf-8')) | 
|  | 37 |  | 
|  | 38 | def recv(sock): | 
|  | 39 | length_str = b'' | 
|  | 40 |  | 
|  | 41 | char = sock.recv(1) | 
|  | 42 | if len(char) == 0: | 
|  | 43 | print("Unexpected end of file", file=sys.stderr) | 
|  | 44 | sys.exit(1) | 
|  | 45 |  | 
|  | 46 | while char != b'\n': | 
|  | 47 | length_str += char | 
|  | 48 | char = sock.recv(1) | 
|  | 49 | if len(char) == 0: | 
|  | 50 | print("Unexpected end of file", file=sys.stderr) | 
|  | 51 | sys.exit(1) | 
|  | 52 |  | 
|  | 53 | total = int(length_str) | 
|  | 54 |  | 
|  | 55 | # use a memoryview to receive the data chunk by chunk efficiently | 
|  | 56 | jdoc = memoryview(bytearray(total)) | 
|  | 57 | next_offset = 0 | 
|  | 58 | while total - next_offset > 0: | 
|  | 59 | recv_size = sock.recv_into(jdoc[next_offset:], total - next_offset) | 
|  | 60 | next_offset += recv_size | 
|  | 61 | try: | 
|  | 62 | doc = json.loads(jdoc.tobytes()) | 
|  | 63 | except (TypeError, ValueError) as e: | 
|  | 64 | raise Exception('Data received was not in JSON format') | 
|  | 65 | return doc | 
|  | 66 |  | 
|  | 67 | try: | 
|  | 68 | env = {} | 
|  | 69 | passenv = ["CINDER_VERSION", | 
|  | 70 | "OS_AUTH_URL", | 
| Ben Nemec | 9a97326 | 2019-08-12 20:10:49 +0000 | [diff] [blame] | 71 | "OS_NO_CACHE", | 
|  | 72 | "OS_PASSWORD", | 
|  | 73 | "OS_PROJECT_NAME", | 
|  | 74 | "OS_REGION_NAME", | 
|  | 75 | "OS_TENANT_NAME", | 
|  | 76 | "OS_USERNAME", | 
|  | 77 | "OS_VOLUME_API_VERSION", | 
|  | 78 | "OS_CLOUD"] | 
|  | 79 | for name in passenv: | 
|  | 80 | if name in os.environ: | 
|  | 81 | env[name] = os.environ[name] | 
|  | 82 |  | 
|  | 83 | cmd = { | 
|  | 84 | "app": os.path.basename(sys.argv[0]), | 
|  | 85 | "env": env, | 
|  | 86 | "argv": sys.argv[1:] | 
|  | 87 | } | 
|  | 88 | try: | 
|  | 89 | image_idx = sys.argv.index('image') | 
|  | 90 | create_idx = sys.argv.index('create') | 
|  | 91 | missing_file = image_idx < create_idx and \ | 
|  | 92 | not any(x.startswith('--file') for x in sys.argv) | 
|  | 93 | except ValueError: | 
|  | 94 | missing_file = False | 
|  | 95 |  | 
|  | 96 | if missing_file: | 
|  | 97 | # This means we were called with an image create command, but were | 
|  | 98 | # not provided a --file option. That likely means we're being passed | 
|  | 99 | # the image data to stdin, which won't work because we do not proxy | 
|  | 100 | # stdin to the server. So, we just reject the operation and ask the | 
|  | 101 | # caller to provide the file with --file instead. | 
|  | 102 | # We've already connected to the server, we need to send it some dummy | 
|  | 103 | # data so it doesn't wait forever. | 
|  | 104 | send(sock, {}) | 
|  | 105 | print('Image create without --file is not allowed in server mode', | 
|  | 106 | file=sys.stderr) | 
|  | 107 | sys.exit(1) | 
|  | 108 | else: | 
|  | 109 | send(sock, cmd) | 
|  | 110 |  | 
|  | 111 | doc = recv(sock) | 
|  | 112 | if doc["stdout"] != b'': | 
|  | 113 | print(doc["stdout"], end='') | 
|  | 114 | if doc["stderr"] != b'': | 
|  | 115 | print(doc["stderr"], file=sys.stderr) | 
|  | 116 | sys.exit(doc["status"]) | 
|  | 117 | finally: | 
|  | 118 | sock.close() |