#!/usr/bin/python
# coding: utf-8
import collections
import subprocess
import sys
import yaml

# hack yaml into using OrderedDict
# https://stackoverflow.com/a/21048064/5959984
def dict_representer(dumper, data):
    return dumper.represent_dict(data.iteritems())

def dict_constructor(loader, node):
    return collections.OrderedDict(loader.construct_pairs(node))

yaml.add_representer(collections.OrderedDict, dict_representer)
yaml.add_constructor(yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG, dict_constructor)


def run():
    requested_app = None
    requested_env = None
    if len(sys.argv) > 3:
        sys.exit('Usage: {} [app] [env]'.format(sys.argv[0]))
    if len(sys.argv) > 2:
        requested_env = sys.argv[2]
    if len(sys.argv) > 1:
        requested_app = sys.argv[1]
    with open('/etc/yandex-direct/direct-apps.conf.yaml', 'r') as f:
        apps_config = yaml.load(f)
    apps = []
    if requested_app:
        if requested_app not in apps_config['apps']:
            sys.exit('error: no app "{}" in apps-config'.format(requested_app))
        deploy_type = apps_config['apps'][requested_app]['deploy_type']
        if deploy_type == 'yadeploy':
            apps = [requested_app]
        else:
            sys.exit('error: deploy type for app "{}" is not "yadeploy"')
    else:
        apps = [item for item in apps_config['apps'] if apps_config['apps'][item].get('deploy_type', '') == 'yadeploy']
    errors = 0
    for app in apps:
        conf = apps_config['apps'][app]
        if 'yadeploy-stages' not in conf:
            sys.stderr.write('yadeploy stages not defined for app "{}"\n'.format(app))
            errors += 1
            continue
        if 'yadeploy-resource-type' not in conf:
            sys.stderr.write('yadeploy resource type not defined for app "{}"\n'.format(app))
            errors += 1
            continue
        for env in conf['yadeploy-stages']:
            if requested_env and env != requested_env:
                continue
            stage = conf['yadeploy-stages'][env]
            cmd = ['dctl', 'status', 'stage', '-c', 'xdc', stage]
            try:
                dctl_status_output_lines = subprocess.check_output(cmd).rstrip().split('\n')
            except subprocess.CalledProcessError:
                sys.stderr.write('error: command {} exited with non-zero status\n'.format(cmd))
                errors += 1
                continue
            status = '<unknown>'
            for line in dctl_status_output_lines:
                parts = line.split('|')
                if len(parts) > 1 and parts[1].strip() == stage:
                    status = parts[4].strip()
            cmd = ['dctl', 'get', 'stage', stage]
            try:
                dctl_get_stage_output = subprocess.check_output(['dctl', 'get', 'stage', stage])
            except subprocess.CalledProcessError:
                sys.stderr.write('error: command {} exited with non-zero status\n'.format(cmd))
                errors += 1
                continue
            stage_spec = yaml.load(dctl_get_stage_output)['spec']
            deploy_unit = stage_spec['deploy_units'].keys()[0]  # считаем, что у стейджа только один деплой-юнит
            deploy_unit_spec = stage_spec['deploy_units'][deploy_unit]
            version = '<unknown>'
            if 'multi_cluster_replica_set' in deploy_unit_spec:
                layers = deploy_unit_spec['multi_cluster_replica_set']['replica_set']['pod_template_spec']['spec']['pod_agent_payload']['spec']['resources']['layers']
            else:
                layers = deploy_unit_spec['replica_set']['replica_set_template']['pod_template_spec']['spec']['pod_agent_payload']['spec']['resources']['layers']
            app_layer = [layer for layer in layers if layer.get('meta', {}).get('sandbox_resource', {}).get('resource_type', '') == conf['yadeploy-resource-type']][0]
            try:
                version = app_layer['meta']['sandbox_resource']['attributes']['resource_version']
            except KeyError:
                version = '<unknown>'
            print '{:13s} {:13s} {:30s} {:10s} {:10s}'.format(app, env, stage, status, version)

if __name__ == '__main__':
    run()
