#!/usr/bin/env python


"""autodock-hipache

Automatically reconfigure hipache virtualhosts upon on container events.
When a container is started and has an environment variable called VIRTUALHOST
it is used to reconfigure hipache to route web requests to the new container.
"""


from __future__ import print_function

import sys
import logging
from os import environ


from autodock.plugin import Plugin
from hipachectl.api import Hipache as HipacheAPI


logging.basicConfig(
    format="%(asctime)s - %(name)s - %(levelname)s - %(message)s",
    level=logging.INFO,
    stream=sys.stderr
)


logger = logging.getLogger(__name__)


def parse_args(parser):
    parser.add_argument(
        "-r", "--redis-url", action="store", dest="redis_url", metavar="URL", type=str,
        default=environ.get("REDIS_PORT_6379", environ.get("REDIS_URL", "tcp://redis:6379")),
        help="Redis URL for Hipache"
    )

    return parser


class Hipache(Plugin):

    def init(self, *args):
        super(Hipache, self).init(*args)

        self.hipache = HipacheAPI(self.args.redis_url)

        map(self._add_container, self.rpc.docker("containers", True))

    def _add_container(self, id):
        ip, port, ports, virtualhost = self._get_container_info(id)

        if not virtualhost:
            return

        if port not in ports:
            logging.warning(
                "Container {} requesting routing for {} to unexposed {}:{}".format(
                    id, virtualhost, ip, port
                )
            )
            return

        logging.info(
            "Container {} requested routing for {} to {}:{}".format(
                id, virtualhost, ip, port
            )
        )

        self.hipache.add(virtualhost, virtualhost, ip, port)

    def _get_container_info(self, id):
        info = self.rpc.docker("inspect_container", id)

        exposed = [k.split("/") for k in (info["Config"]["ExposedPorts"] or {}).keys()]
        ports = [int(port) for port, protocol in exposed if protocol == "tcp"]

        ip = info["NetworkSettings"]["IPAddress"]

        env = dict([e.split("=") for e in info["Config"]["Env"]])

        port = int(env.get("PORT", "80"))
        virtualhost = env.get("VIRTUALHOST", None)

        return ip, port, ports, virtualhost

    def _remove_container(self, id):
        ip, port, ports, virtualhost = self._get_container_info(id)

        logging.info(
            "Container {} routing removed for {} to {}:{}".format(
                id, virtualhost, ip, port
            )
        )

        self.hipache.delete(virtualhost, virtualhost, ip, port)

    def container_started(self, event, **data):
        logging.info("Container {} started".format(data["id"][:10]))

        self._add_container(data["id"])

    def container_stopped(self, event, **data):
        logging.info("Container {} stopped".format(data["id"][:10]))

        self._remove_container(data["id"])

    def container_killed(self, event, **data):
        logging.info("Container {} killed".format(data["id"][:10]))

        self._remove_container(data["id"])

    def container_died(self, event, **data):
        logging.info("Container {} died".format(data["id"][:10]))

        self._remove_container(data["id"])

    def container_paused(self, event, **data):
        logging.info("Container {} paused".format(data["id"][:10]))

        self._remove_container(data["id"])

    def container_restarted(self, event, **data):
        logging.info("Container {} restarted".format(data["id"][:10]))

    def container_unpaused(self, event, **data):
        logging.info("Container {} unpaused".format(data["id"][:10]))

        self._add_container(data["id"])


def main():
    Hipache(parse_args).run()


if __name__ == "__main__":
    main()
