#!/usr/bin/python

import sys
import json
import shlex
import subprocess

# TODO: Required programs: etcd
# TODO: Comments and webdocs
# TODO: Copy to example/library

DOCUMENTATION = '''
module: blue_green
short_description: Retrieves color and port used for blue-green deployment.
description:
  - Retrieves and stores current and future colors and ports from/to etcd.
  - Data retrieved can be used for blue-green deployment with, for example, Docker.
  - etcd must be installed on the destination.
version_added: 0.1
author: Viktor Farcic <viktor@farcic.com>
options:
  state:
    default: retrieved
    choices: ['retrieved', 'changed']
    description:
      - Retrieved returns both current and new colors and ports.
      - Changed will change current color and port to new ones.
  name:
    required: true
  blue_port:
    required: true
  green_port:
    required: true
'''

EXAMPLES = '''
# Retrieve currently running color and ports
- blue_green: name=bdd blue_port=9001 green_port=9002
  register: colors
# Deploy the new version of the application container with a different IP
- docker:
    image="vfarcic/bdd"
    name="bdd-{{ colors.new_color }}"
    state="running"
    ports="{{ colors.new_port }}:9000"
# Change color and port
- blue_green: name=bdd blue_port=9001 green_port=9002 state=changed
  register: colors
# Remove the old container
- docker: image="vfarcic/bdd" name="bdd-{{ colors.old_color }}" state="absent"
'''

def etcd_get(module, key):
    (rc, out, err) = module.run_command("etcdctl get /%s/%s" % (module.params['name'], key))
    if not rc in (0, 4):
        module.fail_json(msg="failed getting /%s/%s from etcdctl" % (module.params['name'], key))
    else:
        return out.strip()

def etcd_change(module, key, value):
    (rc, out, err) = module.run_command("etcdctl set /%s/%s %s" % (module.params['name'], key, value))
    if rc != 0:
        module.fail_json(msg="failed setting /%s/%s to %s in etcdctl" % (module.params['name'], key, value))

def get_new_color(current_color):
    if current_color == 'blue':
        return 'green'
    else:
        return 'blue'

def get_new_port(current_color, green_port, blue_port):
    if current_color == 'blue':
        return green_port
    else:
        return blue_port

def retrieve(module):
    current_color = etcd_get(module, 'color')
    current_port = etcd_get(module, 'port')
    new_color = get_new_color(current_color)
    new_port = get_new_port(current_color, module.params['green_port'], module.params['blue_port'])
    module.exit_json(changed=True,
                     current_color=current_color,
                     current_port=current_port,
                     new_color=new_color,
                     new_port=new_port
    )

def change(module):
    current_color = etcd_get(module, 'color')
    new_color = get_new_color(current_color)
    etcd_change(module, 'color', new_color)
    current_port = etcd_get(module, 'port')
    new_port = get_new_port(current_color, module.params['green_port'], module.params['blue_port'])
    etcd_change(module, 'port', new_port)
    module.exit_json(changed=True,
                     old_color=current_color,
                     old_port=current_port,
                     current_color=new_color,
                     current_port=new_port
    )

def main():
    module = AnsibleModule(
        argument_spec = dict(
            state = dict(default='retrieved', choices=['retrieved', 'changed']),
            name = dict(required=True),
            blue_port = dict(required=True),
            green_port = dict(required=True)
        )
    )
    if module.params['state'] == 'retrieved':
        retrieve(module)
    else:
        change(module)

from ansible.module_utils.basic import *
main()