| 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() |