
import subprocess
import paramiko

from charmhelpers.core.hookenv import (
    config,
    status_set,
    action_get,
    action_set,
    action_fail,
)

from charms.reactive import (
    when,
    when_not,
    set_state as set_flag,
    remove_state as remove_flag,
)


@when('config.changed')
def test_connection():
    status_set('maintenance', 'configuring ssh connection')
    remove_flag('vyos-proxy.ready')
    try:
        who, _ = run('whoami')
    except MgmtNotConfigured as e:
        remove_flag('vyos-proxy.configured')
        status_set('blocked', str(e))
    except subprocess.CalledProcessError as e:
        remove_flag('vyos-proxy.configured')
        status_set('blocked', e.output)
    else:
        set_flag('vyos-proxy.configured')


@when('vyos-proxy.configured')
@when_not('vyos-proxy.ready')
def vyos_proxy_ready():
    status_set('active', 'ready')
    set_flag('vyos-proxy.ready')


@when('actions.ping')
@when_not('vyos-proxy.configured')
def pingme():
    action_fail('proxy is not ready')


@when('actions.ping')
@when('vyos-proxy.configured')
def pingme_forreal():
    try:
        result, err = run('ping -qc {} {}'.format(action_get('count'), action_get('destination')))
    except:
        action_fail('ping command failed')
    finally:
        remove_flag('actions.ping')

    # Here you can send results back from ping, if you had time to parse it
    action_set({'output': result})



class MgmtNotConfigured(Exception):
    pass


def run(cmd):
    ''' Suddenly this project needs to SSH to something. So we replicate what
        _run was doing with subprocess using the Paramiko library. This is
        temporary until this charm /is/ the VPE Router '''

    cfg = config()

    hostname = cfg.get('hostname')
    password = cfg.get('pass')
    username = cfg.get('user')

    if not (username and password and hostname):
        raise MgmtNotConfigured('incomplete remote credentials')

    client = paramiko.SSHClient()
    client.set_missing_host_key_policy(paramiko.AutoAddPolicy())

    try:
        client.connect(cfg.get('hostname'), port=22,
                       username=cfg.get('user'), password=cfg.get('pass'))
    except paramiko.ssh_exception.AuthenticationException:
        raise MgmtNotConfigured('invalid credentials')

    stdin, stdout, stderr = client.exec_command(cmd)
    retcode = stdout.channel.recv_exit_status()
    client.close()  # @TODO re-use connections
    if retcode > 0:
        output = stderr.read().strip()
        raise subprocess.CalledProcessError(returncode=retcode, cmd=cmd,
                                            output=output)
    return (''.join(stdout), ''.join(stderr))
