#!/usr/bin/env python2
# -*- coding: utf-8 -*-
#
# This file is part of Kargo.
#
#    Foobar is free software: you can redistribute it and/or modify
#    it under the terms of the GNU General Public License as published by
#    the Free Software Foundation, either version 3 of the License, or
#    (at your option) any later version.
#
#    Foobar is distributed in the hope that it will be useful,
#    but WITHOUT ANY WARRANTY; without even the implied warranty of
#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
#    GNU General Public License for more details.
#
#    You should have received a copy of the GNU General Public License
#    along with Foobar.  If not, see <http://www.gnu.org/licenses/>.

__version__ = '0.3.2'

import os
import argparse
import getpass
try:
    from ansible.utils.display import Display
except ImportError:
    raise ImportError('Cannot find Ansible: Please check your installation (required version 2)')
from kargo.common import clone_kargo_git_repo, read_password
from kargo.configure import Config
from kargo.inventory import CfgInventory
from kargo.deploy import RunPlaybook
from kargo.cloud import AWS, GCE
display = Display()


def prepare(options):
    clone_kargo_git_repo(options)
    Cfg = CfgInventory(options, 'metal')
    Cfg.write_inventory(options['k8s_nodes'])


def aws(options):
    clone_kargo_git_repo(options)
    A = AWS(options)
    A.gen_ec2_playbook()
    A.create_instances()
    A.write_inventory()


def gce(options):
    clone_kargo_git_repo(options)
    G = GCE(options)
    G.gen_gce_playbook()
    G.create_instances()
    G.write_inventory()


def deploy(options):
    Run = RunPlaybook(options)
    Run.ssh_prepare()
    Run.deploy_kubernetes()

if __name__ == '__main__':
    # Main parser
    parser = argparse.ArgumentParser(
        prog='kargo',
        description='%(prog)s Kubernetes cluster deployment tool',
        add_help=False
    )
    subparsers = parser.add_subparsers(help='commands')

    parser.add_argument(
        '-v', '--version', action='version',
        version='%(prog)s'+' %s' % __version__
    )
    # Options shared by the first step subparsers (prepare, gce, aws)
    firststep_parser = argparse.ArgumentParser(add_help=False)
    firststep_parser.add_argument(
        '--noclone', default=False, action='store_true', dest='noclone',
        help='Do not clone the git repo. Useful when the repo is already downloaded'
    )

    # Options shared by all subparsers
    parent_parser = argparse.ArgumentParser(add_help=False)
    parent_parser.add_argument(
        '-p', '--path', dest='kargo_path',
        help='Where the Ansible playbooks are installed'
    )
    parent_parser.add_argument('--config', dest='configfile', help="Config file")
    parent_parser.add_argument(
        '-y', '--assumeyes', default=False, dest='assume_yes', action='store_true',
        help='When a yes/no prompt would be presented, assume that the user entered "yes"'
    )
    parent_parser.add_argument(
        '-i', '--inventory', dest='inventory_path', help='Inventory file path'
    )

    # prepare
    prepare_parser = subparsers.add_parser(
        'prepare', parents=[parent_parser, firststep_parser],
        help='generate inventory and create vms on cloud providers'
    )
    prepare_parser.add_argument('--add', dest='add_node', action='store_true',
        help="Add node to an existing cluster")
    prepare_parser.add_argument(
        '--nodes', dest='k8s_nodes', metavar='N', nargs='+',
        required=True, help='List of nodes'
    )
    prepare_parser.set_defaults(func=prepare)

    # aws
    aws_parser = subparsers.add_parser(
        'aws', parents=[parent_parser, firststep_parser], help='Create AWS instances and generate inventory'
    )
    aws_parser.add_argument(
        '--access-key', dest='aws_access_key', help='AWS access key'
    )
    aws_parser.add_argument(
        '--secret-key', dest='aws_secret_key', help='AWS secret key'
    )
    aws_parser.add_argument(
        '--type', dest='instance_type', help='AWS instance type'
    )
    aws_parser.add_argument(
        '--keypair', dest='key_name', help='AWS key pair name'
    )
    aws_parser.add_argument('--region', dest='region', help='AWS region')
    aws_parser.add_argument(
        '--security-group', dest='group', help='AWS security group'
    )
    aws_parser.add_argument('--vpc-id', dest='aws_vpc_id', help='EC2 VPC id')
    aws_parser.add_argument(
        '--vpc-subnet', dest='vpc_subnet_id', help='EC2 VPC regional subnet'
    )
    aws_parser.add_argument('--ami', dest='ami', help='AWS AMI')
    aws_parser.add_argument(
        '--cluster-name', dest='cluster_name', help='Name of the cluster'
    )
    aws_parser.add_argument('--add', dest='add_node', action='store_true',
        help="Add node to an existing cluster")
    aws_parser.add_argument(
        '--instances', dest='count', type=int,
        help='Number of nodes', required=True
    )
    aws_parser.set_defaults(func=aws)

    # gce
    gce_parser = subparsers.add_parser(
        'gce', parents=[parent_parser, firststep_parser],
         help='Create GCE machines and generate inventory'
    )
    gce_parser.add_argument(
        '--pem_file', dest='pem_file', help='GCE ssh pem file path'
    )
    gce_parser.add_argument(
        '--zone', dest='zone', help='GCE zone'
    )
    gce_parser.add_argument(
        '--type', dest='machine_type', help='GCE machine type'
    )
    gce_parser.add_argument('--image', dest='image', help='GCE image')
    gce_parser.add_argument(
        '--project', dest='project_id', help='GCE project ID'
    )
    gce_parser.add_argument(
        '--email', dest='service_account_email', help='GCE project ID'
    )
    gce_parser.add_argument(
        '--cluster-name', dest='cluster_name', help='Name of the cluster'
    )
    gce_parser.add_argument('--add', dest='add_node', action='store_true',
        help="Add node to an existing cluster")
    gce_parser.add_argument(
        '--instances', dest='count', type=int,
        help='Number of nodes', required=True
    )
    gce_parser.set_defaults(func=gce)

    # deploy
    deploy_parser = subparsers.add_parser(
        'deploy', parents=[parent_parser],
        help='Create GCE machines and generate inventory'
    )
    deploy_parser.add_argument(
        '-k', '--sshkey', dest='ssh_key',
        help='ssh key for authentication on remote servers'
    )
    deploy_parser.add_argument(
        '-u', '--user', dest='ansible_user', default=getpass.getuser(),
        help='Ansible SSH user (remote user)'
    )
    deploy_parser.add_argument(
        '--passwd', dest='k8s_passwd',
        help="Set the 'kube' passwd to authenticate to the API (default changeme')"
    )
    deploy_parser.add_argument(
        '-P', '--prompt-passwd', default=False, action='store_true', dest='prompt_pwd',
        help="Set the 'kube' passwd to authenticate to the API (Interactive mode)"
    )
    deploy_parser.add_argument(
        '-N', '--kube-network', dest='kube_network', default='10.233.0.0/16',
        help="""Network to be used inside the cluster (/16),
             (must not overlap with any of your infrastructure networks).
             default: 10.233.0.0/16"""
    )
    deploy_parser.add_argument(
        '-n', '--network-plugin', default='flannel',
        choices=['flannel', 'weave', 'calico']
    )
    deploy_parser.add_argument(
        '--aws', default=False, action='store_true',
        help='Kubernetes deployment on AWS'
    )
    deploy_parser.add_argument(
        '--gce', default=False, action='store_true',
        help='Kubernetes deployment on GCE'
    )
    deploy_parser.add_argument(
        '--coreos', default=False, action='store_true',
        help='bootstrap python on CoreOS'
    )
    deploy_parser.add_argument(
        '--ansible-opts', dest='ansible_opts',
        help='Ansible options'
    )
    deploy_parser.set_defaults(func=deploy)

    # Parse arguments
    args = parser.parse_args()
    if args.configfile is None:
        args.configfile = '/etc/kargo/kargo.yml'
    # Read configfile and update options dict
    C = Config(args.configfile)
    config = C.parse_configfile
    # Set kargo_path
    if 'kargo_path' not in config.keys() and args.kargo_path is None:
        config['kargo_path'] = os.path.join(os.path.expanduser("~"), 'kargo')
    arguments = dict(args._get_kwargs())
    for key, value in arguments.items():
        if value is not None:
            config[key] = value
    # Set inventory_path
    if 'inventory_path' not in config.keys() and args.inventory_path is None:
        config['inventory_path'] = os.path.join(
            config['kargo_path'], 'inventory/inventory.cfg'
        )
    # Set logfile
    if 'logfile' not in config.keys():
        config['logfile'] = os.path.join(config['kargo_path'], 'kargo.log')
    # Set kubernetes 'kube' password
    if 'prompt_pwd' in config.keys() and config['prompt_pwd'] is True:
        pwd = read_password()
        config['k8s_passwd'] = pwd
    # Run functions with all the options
    os.environ['ANSIBLE_FORCE_COLOR'] = 'true'
    args.func(config)
