#!/usr/bin/python
# coding: utf8
#######################################################################
#
#   Copyright (c) 2015 Orange
#   valentin.boucher@orange.com
#
# All rights reserved. This program and the accompanying materials
# are made available under the terms of the Apache License, Version 2.0
# which accompanies this distribution, and is available at
# http://www.apache.org/licenses/LICENSE-2.0
########################################################################

import os
import shutil
import subprocess32 as subprocess
import yaml

from git import Repo

import functest.utils.functest_logger as ft_logger


class orchestrator:

    def __init__(self, testcase_dir, inputs={}):
        self.testcase_dir = testcase_dir
        self.blueprint_dir = testcase_dir + 'cloudify-manager-blueprint/'
        self.input_file = 'inputs.yaml'
        self.manager_blueprint = False
        self.config = inputs
        self.logger = ft_logger.Logger("Orchestrator").getLogger()
        self.manager_up = False

    def set_credentials(self, username, password, tenant_name, auth_url):
        self.config['keystone_username'] = username
        self.config['keystone_password'] = password
        self.config['keystone_url'] = auth_url
        self.config['keystone_tenant_name'] = tenant_name

    def set_flavor_id(self, flavor_id):
        self.config['flavor_id'] = flavor_id

    def set_image_id(self, image_id):
        self.config['image_id'] = image_id

    def set_external_network_name(self, external_network_name):
        self.config['external_network_name'] = external_network_name

    def set_ssh_user(self, ssh_user):
        self.config['ssh_user'] = ssh_user

    def set_nova_url(self, nova_url):
        self.config['nova_url'] = nova_url

    def set_neutron_url(self, neutron_url):
        self.config['neutron_url'] = neutron_url

    def set_nameservers(self, nameservers):
        if 0 < len(nameservers):
            self.config['dns_subnet_1'] = nameservers[0]

    def download_manager_blueprint(self, manager_blueprint_url,
                                   manager_blueprint_branch):
        if self.manager_blueprint:
            self.logger.info(
                "cloudify manager server blueprint is "
                "already downloaded !")
        else:
            self.logger.info(
                "Downloading the cloudify manager server blueprint")
            download_result = self._download_blueprints(
                manager_blueprint_url,
                manager_blueprint_branch,
                self.blueprint_dir)

            if not download_result:
                self.logger.error("Failed to download manager blueprint")
                exit(-1)
            else:
                self.manager_blueprint = True

    def manager_up(self):
        return self.manager_up

    def deploy_manager(self):
        if self.manager_blueprint:
            self.logger.info("Writing the inputs file")
            with open(self.blueprint_dir + "inputs.yaml", "w") as f:
                f.write(yaml.dump(self.config, default_style='"'))
            f.close()

            # Ensure no ssh key file already exists
            key_files = ["/.ssh/cloudify-manager-kp.pem",
                         "/.ssh/cloudify-agent-kp.pem"]
            home = os.path.expanduser("~")

            for key_file in key_files:
                if os.path.isfile(home + key_file):
                    os.remove(home + key_file)

            self.logger.info("Launching the cloudify-manager deployment")
            script = "set -e; "
            script += ("source " + self.testcase_dir +
                       "venv_cloudify/bin/activate; ")
            script += "cd " + self.testcase_dir + "; "
            script += "cfy init -r; "
            script += "cd cloudify-manager-blueprint; "
            script += ("cfy local create-requirements -o requirements.txt " +
                       "-p openstack-manager-blueprint.yaml; ")
            script += "pip install -r requirements.txt; "
            script += ("cfy bootstrap --install-plugins " +
                       "-p openstack-manager-blueprint.yaml -i inputs.yaml; ")
            cmd = "/bin/bash -c '" + script + "'"
            error = execute_command(cmd, self.logger)
            if error:
                return error

            self.logger.info("Cloudify-manager server is UP !")

            self.manager_up = True

    def undeploy_manager(self):
        self.logger.info("Launching the cloudify-manager undeployment")

        self.manager_up = False

        script = "source " + self.testcase_dir + "venv_cloudify/bin/activate; "
        script += "cd " + self.testcase_dir + "; "
        script += "cfy teardown -f --ignore-deployments; "
        cmd = "/bin/bash -c '" + script + "'"
        execute_command(cmd, self.logger)

        self.logger.info(
            "Cloudify-manager server has been successfully removed!")

    def download_upload_and_deploy_blueprint(self, blueprint, config,
                                             bp_name, dep_name):
        self.logger.info("Downloading the {0} blueprint".format(
            blueprint['file_name']))
        destination_folder = self.testcase_dir + \
            blueprint['destination_folder']
        download_result = self._download_blueprints(blueprint['url'],
                                                    blueprint['branch'],
                                                    destination_folder)

        if not download_result:
            self.logger.error(
                "Failed to download blueprint {0}".
                format(blueprint['file_name']))
            exit(-1)

        self.logger.info("Writing the inputs file")

        with open(self.testcase_dir + blueprint['destination_folder'] +
                  "/inputs.yaml", "w") as f:
            f.write(yaml.dump(config, default_style='"'))
        f.close()

        self.logger.info("Launching the {0} deployment".format(bp_name))
        script = "source " + self.testcase_dir + "venv_cloudify/bin/activate; "
        script += ("cd " + self.testcase_dir +
                   blueprint['destination_folder'] + "; ")
        script += ("cfy blueprints upload -b " +
                   bp_name + " -p openstack-blueprint.yaml; ")
        script += ("cfy deployments create -b " + bp_name +
                   " -d " + dep_name + " --inputs inputs.yaml; ")
        script += ("cfy executions start -w install -d " +
                   dep_name + " --timeout 1800; ")

        cmd = "/bin/bash -c '" + script + "'"
        error = execute_command(cmd, self.logger, 2000)
        if error:
            return error
        self.logger.info("The deployment of {0} is ended".format(dep_name))

    def undeploy_deployment(self, dep_name):
        self.logger.info("Launching the {0} undeployment".format(dep_name))
        script = "source " + self.testcase_dir + "venv_cloudify/bin/activate; "
        script += "cd " + self.testcase_dir + "; "
        script += ("cfy executions start -w uninstall -d " + dep_name +
                   " --timeout 1800 ; ")
        script += "cfy deployments delete -d " + dep_name + "; "

        cmd = "/bin/bash -c '" + script + "'"
        try:
            execute_command(cmd, self.logger)
        except:
            self.logger.error("Clearwater undeployment failed")

    def _download_blueprints(self, blueprint_url, branch, dest_path):
        if os.path.exists(dest_path):
            shutil.rmtree(dest_path)
        try:
            Repo.clone_from(blueprint_url, dest_path, branch=branch)
            return True
        except:
            return False


def execute_command(cmd, logger, timeout=1800):
    """
    Execute Linux command
    """
    if logger:
        logger.debug('Executing command : {}'.format(cmd))
    timeout_exception = False
    output_file = "output.txt"
    f = open(output_file, 'w+')
    try:
        p = subprocess.call(cmd, shell=True, stdout=f,
                            stderr=subprocess.STDOUT, timeout=timeout)
    except subprocess.TimeoutExpired:
        timeout_exception = True
        if logger:
            logger.error("TIMEOUT when executing command %s" % cmd)
        pass

    f.close()
    f = open(output_file, 'r')
    result = f.read()
    if result != "" and logger:
        logger.debug(result)
    if p == 0:
        return False
    else:
        if logger and not timeout_exception:
            logger.error("Error when executing command %s" % cmd)
        f = open(output_file, 'r')
        lines = f.readlines()
        result = lines[len(lines) - 3]
        result += lines[len(lines) - 2]
        result += lines[len(lines) - 1]
        return result