#!/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('--aws', action='store_true', help='Fetch EC2 user-data for configuration')
	parser.add_argument('--confdir', help='Scan directory for configuration files')
	parser.add_argument('-v', '--verbose', action='store_true', help='Verbose logging for debugging')
	args = parser.parse_args()

	# Logging configuration
	level = logging.DEBUG if args.verbose else logging.INFO
	logging.basicConfig(level=level, format=LOG_FORMAT)
	log = logging.getLogger(__name__)

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

	with flock('%s/run.lock' % args.cache):

		settings = conf.settings(args)
		config = conf.Config()

		if 'confdir' in settings:
			config.merge(conf.FilesConfig(settings['confdir']))

		if 'aws' in settings and settings['aws']:
			config.merge(conf.AWSConfig())

		if not len(config.config):
			print 'No configuration provided'
			sys.exit(1)

		DockerUp(config.config, args.cache).start()
