#!/usr/bin/python2.7
import json
import os
import sys
import logging
import argparse
import fcntl
import errno
from contextlib import contextmanager
from dockerup import conf, DockerUp

"""
Service for synchronizing locally running Docker containers with an external
configuration file. If available, EC2 user-data is used as the configuration file,
otherwise dockerup looks in /etc/dockerup/dockerup.json by default (override with --config).

This script can be run on-demand or via a cron job.

Sample config file is shown below:

{
    "containers": [
        {
            "type": "docker",
            "name": "historical-app",
            "image": "barchart/historical-app-alpha",
            "portMappings": [ 
                {
                    "containerPort": "8080",
                    "hostPort": "8080"
                }
            ]
        },
        {
            "type": "docker",
            "name": "logstash-forwarder",
            "image": "barchart/logstash-forwarder",
            "volumes": [
                {
                    "containerPath": "/var/log/containers",
                    "hostPath": "/var/log/ext",
                    "mode": "ro"
                }
            ]
        }
    ]
}
"""

DEFAULT_CONFIG = '/etc/dockerup/dockerup.conf'
DEFAULT_CACHE = '/var/cache/dockerup'
LOG_FORMAT='%(asctime)s %(levelname)s %(name)s:%(lineno)d %(message)s'

@contextmanager
def flock(filename):

    try:
        with open(filename, 'a') as fd:
            fcntl.lockf(fd, fcntl.LOCK_EX | fcntl.LOCK_NB)
            yield
    except IOError, e:
        if e.errno == errno.EAGAIN:
            print 'Lock could not be acquired: %s' % filename
            sys.exit(-1)
        raise


if __name__ == '__main__':

    # Command line args
    parser = argparse.ArgumentParser()
    parser.add_argument('--config', default=DEFAULT_CONFIG, help='Configuration file')
    parser.add_argument('--cache', default=DEFAULT_CACHE, help='Configuration cache')
    parser.add_argument('--confdir', help='Scan directory for configuration files')
    parser.add_argument('--aws', dest='aws', action='store_const', const=True, help='Fetch EC2 user-data for configuration')
    parser.add_argument('--no-aws', dest='aws', action='store_const', const=False, help='Ignore EC2 user-data for configuration')
    parser.add_argument('--server', dest='server', action='store_const', const=True, help='Start in server mode, polling for changes periodically')
    parser.add_argument('--pull', dest='pull', action='store_const', const=True, help='Force pulling images from registry')
    parser.add_argument('--no-pull', dest='pull', action='store_const', const=False, help='Skip pulling images from registry')
    parser.add_argument('-v', '--verbose', action='store_true', help='Verbose logging for debugging')
    args = parser.parse_args()

    # Logging configuration
    if args.verbose:
        logging.basicConfig(level=logging.DEBUG, format=LOG_FORMAT)
    else:
        logging.basicConfig(level=logging.INFO, format=LOG_FORMAT, filename='/var/log/ext/dockerup.log')
    log = logging.getLogger(__name__)

    # Chatty
    urllib = logging.getLogger('urllib3.connectionpool')
    urllib.setLevel(logging.INFO)

    # Initialize cache
    if not os.path.exists(args.cache):
        try:
            os.makedirs(args.cache)
            log.debug('Created cache directory: %s' % args.cache)
        except Exception as e:
            log.error('Could not create cache directory: %s' % e)
            sys.exit(1)

    with flock('%s/run.lock' % args.cache):
        DockerUp(conf.settings(args), args.cache).start()
