#!/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()
