#!/usr/bin/env python
# -*- coding: utf-8 -*-
"""This is an ansible wrapper to help you to exec the different playbooks with your
inventories.

By default don't exec nothing only show the commands. With --nodryrun you can exec
the real commands.

Usage:
   ansiblew --alainstall=<dir_of_ala_install_repo> [options] [ ( <%= LA_services_in_use.map(m => m.map.name).join(' | ') %> )... | all ]
   ansiblew -h | --help
   ansiblew -v | --version

Options:
  -n --nodryrun              Exec the ansible-playbook commands
  -p --properties            Only update properties
  -l --limit=<hosts>         Limit to some inventories hosts
  -s --skip=<tags>           Skip tags
  -t --tags=<tags>           Limit to tags
  -i --inventory=<vars>      Extra inventory
  -e --extra=<vars>          Extra variables to pass to ansible-playbook
  -h --help                  Show help options.
  -u --user=<user>           Ansible become user [default: ubuntu]
  -w --newserver             Prepare the server for the first time (install ansible deps like python)
  -C --check                 Run ansible-playbook in check mode (dry run)
  -c --continue              Continue even if some ansible cmd fails
  -d --debug                 Show debug info.
  -v --version               Show ansiblew version.
     --ladocker=<dir>        Path to la-docker-compose repo; use its playbooks for container hosts
     --docker-local          Use *-dev-docker-inventory.ini (all hosts on 127.0.0.1) instead of *-inventory.ini
----
ansiblew 0.1.0
Copyright (C) 2019 living-atlases.gbif.org
Apache 2.0 License
"""
from docopt import docopt
import sys
import subprocess
import os.path

def execCmd(cmd, fail_on_error, nodryrun):
    import os, sys, pty

    # Run under a real PTY; 'exec' replaces the shell so SIGINT hits ansible directly
    try:
        status = pty.spawn(['/bin/sh', '-c', 'exec ' + cmd])
    except KeyboardInterrupt:
        sys.exit(130)

    # Map wait status to exit code (Py3.9+), fallback otherwise
    try:
        rc = os.waitstatus_to_exitcode(status)
    except AttributeError:
        rc = status >> 8

    if rc != 0 and fail_on_error:
        sys.exit(rc)

if __name__ == '__main__':
    args = docopt(__doc__)

    nodryrun = args['--nodryrun']
    debug = args['--debug']
    properties = args['--properties']
    skip = args['--skip']
    user = args['--user']
    tags = args['--tags']
    limit = args['--limit']
    check = args['--check']
    doall = args['all']
    newserver = args['--newserver']
    alainstall = args['--alainstall']
    cmdPrefix = "echo "
    extras = ""
    extraInvs = ""
    pkg = "<%= LA_pkg_name %>"
    isHub = <% if (typeof LA_is_hub != 'undefined' && LA_is_hub) { %>True<% } else { %>False<% } %>
    hub_pkg = <% if (typeof LA_hub_pkg_name != 'undefined') { %>"<%= LA_hub_pkg_name %>"<% } else { %>""<% } %>
    inv_path = <% if (typeof LA_hub_pkg_name != 'undefined') { %>"../<%= LA_pkg_name %>-inventories/<%= LA_pkg_name %>"<% } else { %>"<%= LA_pkg_name %>"<% } %>
    extra_vars = args['--extra']
    extra_inv = args['--inventory']
    fail_on_error = not args['--continue']
    ladocker = args['--ladocker']
    docker_local = args['--docker-local']

    # Add here some additional param for ansible like your ssh key, like:
    # additionalParams = "--private-key ~/.ssh/MyKey.pem"
    additionalParams = ""

    if debug:
        print(args)

    if properties:
        extras = "%s --tags common,properties,setfacts" % (extras)
    if skip:
        extras = "%s --skip-tags %s" % (extras, skip)
    if tags:
        extras = "%s --tags %s" % (extras, tags)
    if debug:
        extras = "%s -vvvv" % (extras)
    if limit:
        hubLimit=<% if (typeof LA_hub_pkg_name != 'undefined') { %>",hub-<%= LA_hub_pkg_name %>"<% } else { %>""<% } %>
        extras = "%s --limit %s%s" % (extras, limit, hubLimit)
    else:
        if isHub:
            hubLimit=<% if (typeof LA_hub_pkg_name != 'undefined') { %>"hub-<%= LA_hub_pkg_name %>"<% } else { %>""<% } %>
            extras = "%s --limit %s" % (extras, hubLimit)
    if extra_vars:
        extras = "%s --extra-vars '%s'" % (extras, extra_vars)
    if check:
        extras = "%s --check" % (extras)
    if nodryrun:
        cmdPrefix = ""

    if debug:
        print("Extras: %s" % (extras))

    <%_ if (typeof LA_is_hub != 'undefined' && LA_is_hub) { _%>
    if os.path.isfile("../%s-inventories/%s-toolkit.ini" % (pkg, pkg)):
        extraInvs = "-i ../%s-inventories/%s-toolkit.ini" % (pkg, pkg)
    if os.path.isfile("%s-toolkit.ini" % (hub_pkg)):
        extraInvs = "%s -i %s-toolkit.ini" % (extraInvs, hub_pkg)
    <%_ } else { _%>
    if os.path.isfile("%s-toolkit.ini" % pkg):
        extraInvs = "-i %s-toolkit.ini" % pkg
    <%_ } _%>

    # Add the --inventory extraInv if present
    if extra_inv:
        extraInvs = "%s -i %s" % (extraInvs, extra_inv)

    <%_ if (typeof LA_is_hub != 'undefined' && LA_is_hub) { _%>
    baseInventories = "-i %s-inventory.ini -i ./%s-inventory.ini -i %s-local-extras.ini " % (inv_path, hub_pkg, inv_path)
    # for now disabled that extraVars
    # extraVars = ',ala_install_repo=%s' % alainstall
    extraVars = ' biocache_hub=%s-hub bie_hub=%s-bie-hub regions=%s-regions' % (hub_pkg, hub_pkg, hub_pkg)
    <%_ } else { _%>
    if docker_local:
        baseInventories = "-i %s-dev-docker-inventory.ini -i %s-local-extras.ini" % (pkg, pkg)
    else:
        baseInventories = "-i %s-inventory.ini -i %s-local-extras.ini" % (pkg, pkg)
    extraVars = ''
    <%_ } _%>

    plays = []

    if newserver:
        plays.append("%s/ansible/newserver.yml" % alainstall)

    if ladocker:
        if doall:
            plays.append("%s/playbooks/site.yml" % ladocker)
    else:
        <% for(var j=0; j < LA_services_in_use.length; j++) {
            %>if args['<%= LA_services_in_use[j].map.name %>'] or doall:
            plays.append("%s/ansible/<%= LA_services_in_use[j].map.playbook %>.yml" % alainstall)
        <% } %>

    inventories = " "
    inventories = inventories.join(plays)

    playCmd = "%s ansible-playbook %s -u %s %s %s -i %s-local-passwords.ini %s %s --extra-vars 'target=all%s'" % (cmdPrefix, additionalParams, user, baseInventories, extraInvs, inv_path, inventories, extras, extraVars)
    execCmd(playCmd, fail_on_error, nodryrun)
