#!/usr/bin/env python

# (c) 2012, Stephen Fromm <sfromm@gmail.com>
#
# Ansible 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.
#
# Ansible 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 Ansible.  If not, see <http://www.gnu.org/licenses/>.

import os
import sys
import socket
import logging

import ansible.playbook
import ansible.runner
import ansible.constants as C
from ansible import errors
from ansible import callbacks
from ansible import utils
from ansible import inventory

DEFAULT_PLAYBOOK = 'local.yml'

def main(args):
    """ Set up and run a local playbook """
    usage = "%prog [options]"
    parser = utils.base_parser(constants=C, usage=usage,
                               connect_opts=False, runas_opts=False)
    parser.set_defaults(module_name='git', transport='local',
                        one_line=False, tree=None)
    parser.add_option('-d', '--directory', dest='dest', default=None,
                      help='Directory to checkout git repository')
    parser.add_option('-U', '--url', dest='url', default=None,
                      help='URL of git repository')
    parser.add_option('-C', '--checkout', dest='checkout', default="HEAD",
                      help='Branch/Tag/Commit to checkout.  Defaults to HEAD.')
    parser.remove_option('-k') # Remove ssh password option
    parser.remove_option('-K') # Remove sudo password option
    parser.remove_option('-T') # Remove ssh timeout option
    options, args = parser.parse_args(args)

    clirunner_cb = callbacks.CliRunnerCallbacks()
    clirunner_cb.options = options        

    # ----------------------------------------------
    # First git clone/pull

    git_opts = "repo=%s dest=%s version=%s" % (options.url, options.dest, options.checkout)
    pattern = "localhost"
    inventory_manager = inventory.Inventory([pattern])
    
    """
    Ideally, changes should be reported via logging and not to STDOUT
    """

    runner = ansible.runner.Runner(
            module_name=options.module_name,
            module_args=git_opts,
            module_path=options.module_path,
            inventory=inventory_manager,
            forks=options.forks, 
            pattern=pattern,
            callbacks=clirunner_cb,
            transport=options.transport,
            debug=options.debug
    )
    try:
        runner.run()
    except errors.AnsibleError, e:
        print >>sys.stderr, "ERROR: %s" % e
        return 1

    # ----------------------------------------------
    # Second, run the playbook
    """
    Change to the directory where the git checkout is located.
    Insert 'local.yml' as the first playbook to be run.  This
    supports multiple playbooks being supplied on the CLI, similar
    to ansible-playbook.  This then loops on all the playbooks, 
    instantiates and runs a playbook.  A couple things of note:
      * The transport uses the default set above, local
      * The host_list argument to Playbook is set to a list of
        names.  These are localhost, the fqdn, and hostname.
    This last point is problematic because it will run a playbook
    3 times if the playbook is for 'all' hosts.  We do not necessarily
    want to override 'hosts' in the playbook because they may be generic
    across the entire infrastructure -- not host specific.

    Finally, this should use the logging module in some manner and
    not print data to STDOUT.
    """

    if os.path.exists("%s/%s" % (options.dest, DEFAULT_PLAYBOOK)):
        args.insert(0, DEFAULT_PLAYBOOK)
    os.chdir(options.dest)
    hostname = socket.getfqdn()
    stats = callbacks.AggregateStats()
    playbook_cb = callbacks.PlaybookCallbacks()
    pbrunner_cb = callbacks.PlaybookRunnerCallbacks(stats)
    local_host = [pattern, hostname, hostname.split('.')[0]]

    for playbook in args:
        pb = ansible.playbook.PlayBook(
                playbook=playbook,
                host_list=local_host,
                module_path=options.module_path,
                debug=options.debug,
                runner_callbacks=pbrunner_cb,
                callbacks=playbook_cb,
                transport=options.transport,
                stats=stats
        )
        """
        This just takes the reporting from ansible-playbook. 
        Ideally, this should use logging to report success/failure/changes.
        """
        try:
            pb.run()
            hosts = sorted(pb.stats.processed.keys())
            print "RECAP\n\n"
            for h in hosts:
                t = pb.stats.summarize(h)
                print "%-30s : ok=%4s changed=%4s unreachable=%4s failed=%4s " % (h, 
                   t['ok'], t['changed'], t['unreachable'], t['failures']
                )
            print "\n"
        except errors.AnsibleError, e:
            print >>sys.stderr, "ERROR: %s" % e
            return 1

    return 0

if __name__ == '__main__':
    try:
        sys.exit(main(sys.argv[1:]))
    except errors.AnsibleError, e:
        print >>sys.stderr, "ERROR: %s" % e
        sys.exit(1)
