#!/usr/bin/python
# Copyright 2017 Northern.tech AS
#
#    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
#
#        https://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 subprocess
import tempfile
import time
import logging
import os

from platform import python_version
if python_version().startswith('2'):
    from fabric.api import *
else:
    # Dummy parallel decorator for Python3/Fabric 2
    # Feature has not been implemented: https://github.com/pyinvoke/invoke/issues/63
    def parallel(func):
        def func_wrapper():
            return None
        return func_wrapper

import conftest

COMPOSE_FILES_PATH = os.path.realpath(os.path.join(os.path.dirname(__file__), ".."))

COMPOSE_FILES = [
    COMPOSE_FILES_PATH + "/docker-compose.yml",
    COMPOSE_FILES_PATH + "/docker-compose.client.yml",
    COMPOSE_FILES_PATH + "/docker-compose.storage.minio.yml",
    COMPOSE_FILES_PATH + "/docker-compose.testing.yml",
]

log_files = []
logger = logging.getLogger("root")


def store_logs():
    inline_logs = conftest.inline_logs

    if inline_logs:
        docker_compose_cmd("logs -f &",
                           env={'COMPOSE_HTTP_TIMEOUT': '100000'})
    else:
        tfile = tempfile.mktemp("mender_testing")
        docker_compose_cmd("logs -f --no-color > %s 2>&1 &" % tfile,
                           env={'COMPOSE_HTTP_TIMEOUT': '100000'})
        logger.info("docker-compose log file stored here: %s" % tfile)
        log_files.append(tfile)


def docker_compose_cmd(arg_list, use_common_files=True, env=None):
    """
        start a specific docker-compose setup, and retry a few times due to:
        - https://github.com/opencontainers/runc/issues/1326
    """
    files_args = ""

    if use_common_files:
        for file in COMPOSE_FILES:
            files_args += " -f %s" % file

    with conftest.docker_lock:
        cmd = "docker-compose -p %s %s %s" % (conftest.docker_compose_instance,
                                              files_args,
                                              arg_list)

        logger.info("running with: %s" % cmd)

        penv = dict(os.environ)
        if env:
            penv.update(env)

        for count in range(5):
            try:
                output = subprocess.check_output(cmd, stderr=subprocess.STDOUT, shell=True, env=penv)

                if "up -d" in arg_list:
                    store_logs()

                # Return as string (Python 2/3 compatible)
                if isinstance(output, bytes):
                    return output.decode()
                return output

            except subprocess.CalledProcessError as e:
                logger.warning("failed to run docker-compose: error: %s, retrying..." % (e.output))
                time.sleep(count * 30)
                continue

        raise Exception("failed to start docker-compose (called: %s): exit code: %d, output: %s" % (e.cmd, e.returncode, e.output))


def stop_docker_compose():
    with conftest.docker_lock:
        # Take down all docker instances in this namespace.
        cmd = "docker ps -aq -f name=%s | xargs -r docker rm -fv" % conftest.docker_compose_instance
        logger.info("running %s" % cmd)
        subprocess.check_call(cmd, shell=True)
        cmd = "docker network list -q -f name=%s | xargs -r docker network rm" % conftest.docker_compose_instance
        logger.info("running %s" % cmd)
        subprocess.check_call(cmd, shell=True)