Skip to content
Snippets Groups Projects
router.py 2.43 KiB
Newer Older

import paramiko
import subprocess

from charmhelpers.core.hookenv import config


class NetNS(object):
    def __init__(self, name):
        pass

    @classmethod
    def create(cls, name):
        # @TODO: Need to check if namespace exists already
        try:
            ip('netns', 'add', name)
        except Exception as e:
            raise Exception('could not create net namespace: %s' % e)

        return cls(name)

    def up(self, iface, cidr):
        self.do('ip', 'link', 'set', 'dev', iface, 'up')
        self.do('ip', 'address', 'add', cidr, 'dev', iface)

    def add_iface(self, iface):
        ip('link', 'set', 'dev', iface, 'netns', self.name)

    def do(self, *cmd):
        ip(*['netns', 'exec', self.name] + cmd)


def ip(*args):
    return _run(['ip'] + list(args))


def _run(cmd, env=None):
    if isinstance(cmd, str):
        cmd = cmd.split() if ' ' in cmd else [cmd]

    cfg = config()
    if all(k in cfg for k in ['pass', 'vpe-router', 'user']):
        router = cfg['vpe-router']
        user = cfg['user']
        passwd = cfg['pass']

        if router and user and passwd:
            return ssh(cmd, router, user, passwd)

    p = subprocess.Popen(cmd,
                         env=env,
                         stdout=subprocess.PIPE,
                         stderr=subprocess.PIPE)
    stdout, stderr = p.communicate()
    retcode = p.poll()
    if retcode > 0:
        raise subprocess.CalledProcessError(returncode=retcode,
                                            cmd=cmd,
                                            output=stderr.decode("utf-8").strip())
    return (''.join(stdout), ''.join(stderr))


def ssh(cmd, host, user, password=None):
    ''' 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 '''

    cmds = ' '.join(cmd)
    client = paramiko.SSHClient()
    client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    client.connect(host, port=22, username=user, password=password)

    stdin, stdout, stderr = client.exec_command(cmds)
    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))