Migrate vpe-router layer to new directory structure
authorAdam Israel <adam.israel@canonical.com>
Tue, 27 Sep 2016 20:15:59 +0000 (16:15 -0400)
committerAdam Israel <adam.israel@canonical.com>
Tue, 27 Sep 2016 21:39:34 +0000 (17:39 -0400)
Change-Id: I107d48c2977531155072cd3f57bc76f732bb2c50
Signed-off-by: Adam Israel <adam.israel@canonical.com>
25 files changed:
layers/vpe-router/README.md [new file with mode: 0644]
layers/vpe-router/actions.yaml [new file with mode: 0644]
layers/vpe-router/actions/add-corporation [new file with mode: 0755]
layers/vpe-router/actions/configure-interface [new file with mode: 0755]
layers/vpe-router/actions/connect-domains [new file with mode: 0755]
layers/vpe-router/actions/delete-corporation [new file with mode: 0755]
layers/vpe-router/actions/delete-domain-connection [new file with mode: 0755]
layers/vpe-router/config.yaml [new file with mode: 0644]
layers/vpe-router/layer.yaml [new file with mode: 0644]
layers/vpe-router/lib/charms/router.py [new file with mode: 0644]
layers/vpe-router/metadata.yaml [new file with mode: 0644]
layers/vpe-router/reactive/vpe_router.py [new file with mode: 0644]
layers/vpe-router/wheelhouse.txt [new file with mode: 0644]
vpe-router/actions.yaml [deleted file]
vpe-router/actions/add-corporation [deleted file]
vpe-router/actions/configure-interface [deleted file]
vpe-router/actions/connect-domains [deleted file]
vpe-router/actions/delete-corporation [deleted file]
vpe-router/actions/delete-domain-connection [deleted file]
vpe-router/config.yaml [deleted file]
vpe-router/layer.yaml [deleted file]
vpe-router/lib/charms/router.py [deleted file]
vpe-router/metadata.yaml [deleted file]
vpe-router/reactive/vpe_router.py [deleted file]
vpe-router/wheelhouse.txt [deleted file]

diff --git a/layers/vpe-router/README.md b/layers/vpe-router/README.md
new file mode 100644 (file)
index 0000000..e69de29
diff --git a/layers/vpe-router/actions.yaml b/layers/vpe-router/actions.yaml
new file mode 100644 (file)
index 0000000..913cc64
--- /dev/null
@@ -0,0 +1,96 @@
+configure-interface:
+  description: Configure an ethernet interface.
+  params:
+    iface-name:
+      type: string
+      description: Device name, e.g. eth1
+    cidr:
+      type: string
+      description: Network range to assign to the interface
+  required: [iface-name]
+add-corporation:
+  description: Add a new corporation to the router
+  params:
+    domain-name:
+      type: string
+      description: Name of the vlan corporation
+    iface-name:
+      type: string
+      description: Device name. eg eth1
+    vlan-id:
+      type: integer
+      description: The name of the vlan?
+    cidr:
+      type: string
+      description: Network range to assign to the tagged vlan-id
+    area:
+      type: string
+      description: Link State Advertisements (LSA) type
+    subnet-cidr:
+      type: string
+      description: Network range
+    subnet-area:
+      type: string
+      description: Link State Advertisements (LSA) type
+  required: [domain-name, iface-name, vlan-id, cidr, area, subnet-cidr, subnet-area]
+delete-corporation:
+  description: Remove the corporation from the router completely
+  params:
+    domain-name:
+      type: string
+      description: The domain of the corporation to remove
+    cidr:
+      type: string
+      description: Network range to assign to the tagged vlan-id
+    area:
+      type: string
+      description: Link State Advertisements (LSA) type
+    subnet-cidr:
+      type: string
+      description: Network range
+    subnet-area:
+      type: string
+      description: Link State Advertisements (LSA) type
+  required: [domain-name, cidr, area, subnet-cidr, subnet-area]
+connect-domains:
+  description: Connect the router to another router, where the same domain is present
+  params:
+    domain-name:
+      type: string
+      description: The domain of the coproration to connect
+    iface-name:
+      type: string
+      description: Device name. eg eth1
+    tunnel-name:
+      type: string
+      description: Name of the tunnel ?
+    local-ip:
+      type: string
+      description: local ip ?
+    remote-ip:
+      type: string
+      description: remote ip ?
+    tunnel-key:
+      type: string
+      description: tunnel key?
+    internal-local-ip:
+      type: string
+      description: internal local ip?
+    internal-remote-ip:
+      type: string
+      description: internal remote ip?
+    tunnel-type:
+      type: string
+      default: gre
+      description: The type of tunnel to establish.
+  required: [domain-name, iface-name, tunnel-name, local-ip, remote-ip, tunnel-key, internal-local-ip, internal-remote-ip]
+delete-domain-connection:
+  description: Remove the tunnel to another router where the domain is present.
+  params:
+    domain-name:
+      type: string
+      description: The domain of the corporation to unlink
+    tunnel-name:
+      type: string
+      description: The name of the tunnel to unlink that the domain-name is attached to
+  required: [domain-name, tunnel-name]
diff --git a/layers/vpe-router/actions/add-corporation b/layers/vpe-router/actions/add-corporation
new file mode 100755 (executable)
index 0000000..c8ab2f8
--- /dev/null
@@ -0,0 +1,18 @@
+#!/usr/bin/env python3
+import sys
+sys.path.append('lib')
+
+from charms.reactive import main
+from charms.reactive import set_state
+from charmhelpers.core.hookenv import action_fail
+
+"""
+`set_state` only works here because it's flushed to disk inside the `main()`
+loop. remove_state will need to be called inside the action method.
+"""
+set_state('vpe.add-corporation')
+
+try:
+    main()
+except Exception as e:
+    action_fail(repr(e))
diff --git a/layers/vpe-router/actions/configure-interface b/layers/vpe-router/actions/configure-interface
new file mode 100755 (executable)
index 0000000..db9a099
--- /dev/null
@@ -0,0 +1,18 @@
+#!/usr/bin/env python3
+import sys
+sys.path.append('lib')
+
+from charms.reactive import main
+from charms.reactive import set_state
+from charmhelpers.core.hookenv import action_fail
+
+"""
+`set_state` only works here because it's flushed to disk inside the `main()`
+loop. remove_state will need to be called inside the action method.
+"""
+set_state('vpe.configure-interface')
+
+try:
+    main()
+except Exception as e:
+    action_fail(repr(e))
diff --git a/layers/vpe-router/actions/connect-domains b/layers/vpe-router/actions/connect-domains
new file mode 100755 (executable)
index 0000000..48adfc7
--- /dev/null
@@ -0,0 +1,20 @@
+#!/usr/bin/env python3
+
+# Load modules from $CHARM_DIR/lib
+import sys
+sys.path.append('lib')
+
+from charms.reactive import main
+from charms.reactive import set_state
+from charmhelpers.core.hookenv import action_fail
+
+"""
+`set_state` only works here because it's flushed to disk inside the `main()`
+loop. remove_state will need to be called inside the action method.
+"""
+set_state('vpe.connect-domains')
+
+try:
+    main()
+except Exception as e:
+    action_fail(repr(e))
diff --git a/layers/vpe-router/actions/delete-corporation b/layers/vpe-router/actions/delete-corporation
new file mode 100755 (executable)
index 0000000..0576c08
--- /dev/null
@@ -0,0 +1,19 @@
+#!/usr/bin/env python3
+import sys
+sys.path.append('lib')
+
+from charms.reactive import main
+from charms.reactive import set_state
+from charmhelpers.core.hookenv import action_fail
+
+
+"""
+`set_state` only works here because it's flushed to disk inside the `main()`
+loop. remove_state will need to be called inside the action method.
+"""
+set_state('vpe.delete-corporation')
+
+try:
+    main()
+except Exception as e:
+    action_fail(repr(e))
diff --git a/layers/vpe-router/actions/delete-domain-connection b/layers/vpe-router/actions/delete-domain-connection
new file mode 100755 (executable)
index 0000000..5ba05f6
--- /dev/null
@@ -0,0 +1,19 @@
+#!/usr/bin/env python3
+import sys
+sys.path.append('lib')
+
+from charms.reactive import main
+from charms.reactive import set_state
+from charmhelpers.core.hookenv import action_fail
+
+
+"""
+`set_state` only works here because it's flushed to disk inside the `main()`
+loop. remove_state will need to be called inside the action method.
+"""
+set_state('vpe.delete-domain-connection')
+
+try:
+    main()
+except Exception as e:
+    action_fail(repr(e))
diff --git a/layers/vpe-router/config.yaml b/layers/vpe-router/config.yaml
new file mode 100644 (file)
index 0000000..562515f
--- /dev/null
@@ -0,0 +1,17 @@
+options:
+  vpe-router:
+    default:
+    type: string
+    description: Hostname or IP of the vpe router to connect to
+  user:
+    type: string
+    default: root
+    description: Username for VPE Router
+  pass:
+    type: string
+    default:
+    description: Password for VPE Router
+  hostname:
+    type: string
+    default:
+    description: The hostname to set the vpe router to.
diff --git a/layers/vpe-router/layer.yaml b/layers/vpe-router/layer.yaml
new file mode 100644 (file)
index 0000000..524a4f4
--- /dev/null
@@ -0,0 +1 @@
+includes: ['layer:basic']
diff --git a/layers/vpe-router/lib/charms/router.py b/layers/vpe-router/lib/charms/router.py
new file mode 100644 (file)
index 0000000..54ff7fb
--- /dev/null
@@ -0,0 +1,80 @@
+
+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))
diff --git a/layers/vpe-router/metadata.yaml b/layers/vpe-router/metadata.yaml
new file mode 100644 (file)
index 0000000..65ae2da
--- /dev/null
@@ -0,0 +1,14 @@
+name: vpe-router
+maintainers:
+  - Marco Ceppi <marco.ceppi@canonical.com>
+  - Adam Israel <adam.israel@canonical.com>
+summary: setup a virtualized PE Router with GRE tunnels
+series:
+  - trusty
+  - xenial
+description: | 
+  this charm, when deployed and configured, will provide a secure virtualized
+  provider edge router.
+peers:
+  loadbalance:
+    interface: vpe-router
diff --git a/layers/vpe-router/reactive/vpe_router.py b/layers/vpe-router/reactive/vpe_router.py
new file mode 100644 (file)
index 0000000..e2be327
--- /dev/null
@@ -0,0 +1,644 @@
+
+from charmhelpers.core.hookenv import (
+    config,
+    status_set,
+    action_get,
+    action_fail,
+    log,
+)
+
+from charms.reactive import (
+    hook,
+    when,
+    when_not,
+    helpers,
+    set_state,
+    remove_state,
+)
+
+from charms import router
+import subprocess
+
+cfg = config()
+
+
+@hook('config-changed')
+def validate_config():
+    try:
+        """
+        If the ssh credentials are available, we'll act as a proxy charm.
+        Otherwise, we execute against the unit we're deployed on to.
+        """
+        if all(k in cfg for k in ['pass', 'vpe-router', 'user']):
+            routerip = cfg['vpe-router']
+            user = cfg['user']
+            passwd = cfg['pass']
+
+            if routerip and user and passwd:
+                # Assumption: this will be a root user
+                out, err = router.ssh(['whoami'], routerip,
+                                      user, passwd)
+                if out.strip() != user:
+                    remove_state('vpe.configured')
+                    status_set('blocked', 'vpe is not configured')
+                    raise Exception('invalid credentials')
+
+                # Set the router's hostname
+                try:
+                    if user == 'root' and 'hostname' in cfg:
+                        hostname = cfg['hostname']
+                        out, err = router.ssh(['hostname', hostname],
+                                              routerip,
+                                              user, passwd)
+                        out, err = router.ssh(['sed',
+                                              '-i',
+                                               '"s/hostname.*$/hostname %s/"'
+                                               % hostname,
+                                               '/usr/admin/global/hostname.sh'
+                                               ],
+                                              routerip,
+                                              user, passwd)
+                        set_state('vpe.configured')
+                        status_set('active', 'ready!')
+                    else:
+                        remove_state('vpe.configured')
+                        status_set('blocked', 'vpe is not configured')
+                except subprocess.CalledProcessError as e:
+                    remove_state('vpe.configured')
+                    status_set('blocked', 'validation failed: %s' % e)
+                    log('Command failed: %s (%s)' %
+                        (' '.join(e.cmd), str(e.output)))
+                    raise
+
+    except Exception as e:
+        log(repr(e))
+        remove_state('vpe.configured')
+        status_set('blocked', 'validation failed: %s' % e)
+
+
+@when_not('vpe.configured')
+def not_ready_add():
+    actions = [
+        'vpe.add-corporation',
+        'vpe.connect-domains',
+        'vpe.delete-domain-connections',
+        'vpe.remove-corporation',
+        'vpe.configure-interface',
+        'vpe.configure-ospf',
+    ]
+
+    if helpers.any_states(*actions):
+        action_fail('VPE is not configured')
+
+    status_set('blocked', 'vpe is not configured')
+
+
+def start_ospfd():
+    # We may want to make this configurable via config setting
+    ospfd = '/usr/local/bin/ospfd'
+
+    try:
+        (stdout, stderr) = router._run(['touch',
+                                        '/usr/admin/global/ospfd.conf'])
+        (stdout, stderr) = router._run([ospfd, '-d', '-f',
+                                        '/usr/admin/global/ospfd.conf'])
+    except subprocess.CalledProcessError as e:
+        log('Command failed: %s (%s)' %
+            (' '.join(e.cmd), str(e.output)))
+
+
+def configure_ospf(domain, cidr, area, subnet_cidr, subnet_area, enable=True):
+    """Configure the OSPF service"""
+
+    # Check to see if the OSPF daemon is running, and start it if not
+    try:
+        (stdout, stderr) = router._run(['pgrep', 'ospfd'])
+    except subprocess.CalledProcessError as e:
+        # If pgrep fails, the process wasn't found.
+        start_ospfd()
+        log('Command failed (ospfd not running): %s (%s)' %
+            (' '.join(e.cmd), str(e.output)))
+
+    upordown = ''
+    if not enable:
+        upordown = 'no'
+    try:
+        vrfctl = '/usr/local/bin/vrfctl'
+        vtysh = '/usr/local/bin/vtysh'
+
+        (stdout, stderr) = router._run([vrfctl, 'list'])
+
+        domain_id = 0
+        for line in stdout.split('\n'):
+            if domain in line:
+                domain_id = int(line[3:5])
+
+        if domain_id > 0:
+            router._run([vtysh,
+                         '-c',
+                         '"configure terminal"',
+                         '-c',
+                         '"router ospf %d vr %d"' % (domain_id, domain_id),
+                         '-c',
+                         '"%s network %s area %s"' % (upordown, cidr, area),
+                         '-c',
+                         '"%s network %s area %s"' % (upordown,
+                                                      subnet_cidr,
+                                                      subnet_area),
+                         ])
+
+        else:
+            log("Invalid domain id")
+    except subprocess.CalledProcessError as e:
+        action_fail('Command failed: %s (%s)' %
+                    (' '.join(e.cmd), str(e.output)))
+    finally:
+        remove_state('vpe.configure-interface')
+        status_set('active', 'ready!')
+
+
+@when('vpe.configured')
+@when('vpe.configure-interface')
+def configure_interface():
+    """
+    Configure an ethernet interface
+    """
+    iface_name = action_get('iface-name')
+    cidr = action_get('cidr')
+
+    # cidr is optional
+    if cidr:
+        try:
+            # Add may fail, but change seems to add or update
+            router.ip('address', 'change', cidr, 'dev', iface_name)
+        except subprocess.CalledProcessError as e:
+            action_fail('Command failed: %s (%s)' %
+                        (' '.join(e.cmd), str(e.output)))
+            return
+        finally:
+            remove_state('vpe.configure-interface')
+            status_set('active', 'ready!')
+
+    try:
+        router.ip('link', 'set', 'dev', iface_name, 'up')
+    except subprocess.CalledProcessError as e:
+        action_fail('Command failed: %s (%s)' %
+                    (' '.join(e.cmd), str(e.output)))
+    finally:
+        remove_state('vpe.configure-interface')
+        status_set('active', 'ready!')
+
+
+@when('vpe.configured')
+@when('vpe.add-corporation')
+def add_corporation():
+    '''
+    Create and Activate the network corporation
+    '''
+    domain_name = action_get('domain-name')
+    iface_name = action_get('iface-name')
+    # HACK: python's list, used deeper, throws an exception on ints in a tuple
+    vlan_id = str(action_get('vlan-id'))
+    cidr = action_get('cidr')
+    area = action_get('area')
+    subnet_cidr = action_get('subnet-cidr')
+    subnet_area = action_get('subnet-area')
+
+    iface_vlanid = '%s.%s' % (iface_name, vlan_id)
+
+    status_set('maintenance', 'adding corporation {}'.format(domain_name))
+
+    """
+    Attempt to run all commands to add the network corporation. If any step
+    fails, abort and call `delete_corporation()` to undo.
+    """
+    try:
+        """
+        $ ip link add link eth3 name eth3.103 type vlan id 103
+        """
+        router.ip('link',
+                  'add',
+                  'link',
+                  iface_name,
+                  'name',
+                  iface_vlanid,
+                  'type',
+                  'vlan',
+                  'id',
+                  vlan_id)
+
+        """
+        $ ip netns add domain
+        """
+        router.ip('netns',
+                  'add',
+                  domain_name)
+
+        """
+        $ ip link set dev eth3.103 netns corpB
+        """
+        router.ip('link',
+                  'set',
+                  'dev',
+                  iface_vlanid,
+                  'netns',
+                  domain_name)
+
+        """
+        $ ifconfig eth3 up
+        """
+        router._run(['ifconfig', iface_name, 'up'])
+
+        """
+        $ ip netns exec corpB ip link set dev eth3.103 up
+        """
+        router.ip('netns',
+                  'exec',
+                  domain_name,
+                  'ip',
+                  'link',
+                  'set',
+                  'dev',
+                  iface_vlanid,
+                  'up')
+
+        """
+        $ ip netns exec corpB ip address add 10.0.1.1/24 dev eth3.103
+        """
+        mask = cidr.split("/")[1]
+        ip = '%s/%s' % (area, mask)
+        router.ip('netns',
+                  'exec',
+                  domain_name,
+                  'ip',
+                  'address',
+                  'add',
+                  ip,
+                  'dev',
+                  iface_vlanid)
+
+        configure_ospf(domain_name, cidr, area, subnet_cidr, subnet_area, True)
+
+    except subprocess.CalledProcessError as e:
+        delete_corporation()
+        action_fail('Command failed: %s (%s)' %
+                    (' '.join(e.cmd), str(e.output)))
+    finally:
+        remove_state('vpe.add-corporation')
+        status_set('active', 'ready!')
+
+
+@when('vpe.configured')
+@when('vpe.delete-corporation')
+def delete_corporation():
+
+    domain_name = action_get('domain-name')
+    cidr = action_get('cidr')
+    area = action_get('area')
+    subnet_cidr = action_get('subnet-cidr')
+    subnet_area = action_get('subnet-area')
+
+    status_set('maintenance', 'deleting corporation {}'.format(domain_name))
+
+    try:
+        """
+        Remove all tunnels defined for this domain
+
+        $ ip netns exec domain_name ip tun show
+            | grep gre
+            | grep -v "remote any"
+            | cut -d":" -f1
+        """
+        p = router.ip(
+            'netns',
+            'exec',
+            domain_name,
+            'ip',
+            'tun',
+            'show',
+            '|',
+            'grep',
+            'gre',
+            '|',
+            'grep',
+            '-v',
+            '"remote any"',
+            '|',
+            'cut -d":" -f1'
+        )
+
+        # `p` should be a tuple of (stdout, stderr)
+        tunnels = p[0].split('\n')
+
+        for tunnel in tunnels:
+            try:
+                """
+                $ ip netns exec domain_name ip link set $tunnel_name down
+                """
+                router.ip(
+                    'netns',
+                    'exec',
+                    domain_name,
+                    'ip',
+                    'link',
+                    'set',
+                    tunnel,
+                    'down'
+                )
+            except subprocess.CalledProcessError as e:
+                log('Command failed: %s (%s)' %
+                    (' '.join(e.cmd), str(e.output)))
+                pass
+
+            try:
+                """
+                $ ip netns exec domain_name ip tunnel del $tunnel_name
+                """
+                router.ip(
+                    'netns',
+                    'exec',
+                    domain_name,
+                    'ip',
+                    'tunnel',
+                    'del',
+                    tunnel
+                )
+            except subprocess.CalledProcessError as e:
+                log('Command failed: %s (%s)' %
+                    (' '.join(e.cmd), str(e.output)))
+                pass
+
+        """
+        Remove all interfaces associated to the domain
+
+        $ ip netns exec domain_name ifconfig | grep mtu | cut -d":" -f1
+        """
+        p = router.ip(
+            'netns',
+            'exec',
+            domain_name,
+            'ifconfig',
+            '|',
+            'grep mtu',
+            '|',
+            'cut -d":" -f1'
+        )
+
+        ifaces = p[0].split('\n')
+        for iface in ifaces:
+
+            try:
+                """
+                $ ip netns exec domain_name ip link set $iface down
+                """
+                router.ip(
+                    'netns',
+                    'exec',
+                    domain_name,
+                    'ip',
+                    'link',
+                    'set',
+                    iface,
+                    'down'
+                )
+            except subprocess.CalledProcessError as e:
+                log('Command failed: %s (%s)' %
+                    (' '.join(e.cmd), str(e.output)))
+
+            try:
+                """
+                $ ifconfig eth3 down
+                """
+                router._run(['ifconfig', iface, 'down'])
+            except subprocess.CalledProcessError as e:
+                log('Command failed: %s (%s)' %
+                    (' '.join(e.cmd), str(e.output)))
+                pass
+
+            try:
+                """
+                $ ip link del dev $iface
+                """
+                router.ip(
+                    'link',
+                    'del',
+                    'dev',
+                    iface
+                )
+            except subprocess.CalledProcessError as e:
+                log('Command failed: %s (%s)' %
+                    (' '.join(e.cmd), str(e.output)))
+                pass
+
+        try:
+            """
+            Remove the domain
+
+            $ ip netns del domain_name
+            """
+            router.ip(
+                'netns',
+                'del',
+                domain_name
+            )
+        except subprocess.CalledProcessError as e:
+            log('Command failed: %s (%s)' % (' '.join(e.cmd), str(e.output)))
+            pass
+
+        try:
+            configure_ospf(domain_name,
+                           cidr,
+                           area,
+                           subnet_cidr,
+                           subnet_area,
+                           False)
+        except subprocess.CalledProcessError as e:
+            action_fail('Command failed: %s (%s)' %
+                        (' '.join(e.cmd), str(e.output)))
+
+    except:
+        # Do nothing
+        log('delete-corporation failed.')
+        pass
+
+    finally:
+        remove_state('vpe.delete-corporation')
+        status_set('active', 'ready!')
+
+
+@when('vpe.configured')
+@when('vpe.connect-domains')
+def connect_domains():
+
+    params = [
+        'domain-name',
+        'iface-name',
+        'tunnel-name',
+        'local-ip',
+        'remote-ip',
+        'tunnel-key',
+        'internal-local-ip',
+        'internal-remote-ip',
+        'tunnel-type',
+    ]
+
+    config = {}
+    for p in params:
+        config[p] = action_get(p)
+
+    status_set('maintenance', 'connecting domains')
+
+    try:
+        """
+        $ ip tunnel add tunnel_name mode gre local local_ip remote remote_ip
+            dev iface_name key tunnel_key csum
+        """
+        router.ip(
+            'tunnel',
+            'add',
+            config['tunnel-name'],
+            'mode',
+            config['tunnel-type'],
+            'local',
+            config['local-ip'],
+            'remote',
+            config['remote-ip'],
+            'dev',
+            config['iface-name'],
+            'key',
+            config['tunnel-key'],
+            'csum'
+        )
+
+    except subprocess.CalledProcessError as e:
+        log('Command failed (retrying with ip tunnel change): %s (%s)' %
+            (' '.join(e.cmd), str(e.output)))
+        try:
+            """
+            If the tunnel already exists (like gre0) and can't be deleted,
+            modify it instead of trying to add it.
+            """
+            router.ip(
+                'tunnel',
+                'change',
+                config['tunnel-name'],
+                'mode',
+                config['tunnel-type'],
+                'local',
+                config['local-ip'],
+                'remote',
+                config['remote-ip'],
+                'dev',
+                config['iface-name'],
+                'key',
+                config['tunnel-key'],
+                'csum'
+            )
+        except subprocess.CalledProcessError as e:
+            delete_domain_connection()
+            action_fail('Command failed: %s (%s)' %
+                        (' '.join(e.cmd), str(e.output)))
+        finally:
+            remove_state('vpe.connect-domains')
+            status_set('active', 'ready!')
+
+    try:
+        """
+        $ ip link set dev tunnel_name netns domain_name
+        """
+        router.ip(
+            'link',
+            'set',
+            'dev',
+            config['tunnel-name'],
+            'netns',
+            config['domain-name']
+        )
+
+        """
+        $ ip netns exec domain_name ip link set dev tunnel_name up
+        """
+        router.ip(
+            'netns',
+            'exec',
+            config['domain-name'],
+            'ip',
+            'link',
+            'set',
+            'dev',
+            config['tunnel-name'],
+            'up'
+        )
+
+        """
+        $ ip netns exec domain_name ip address add internal_local_ip peer
+            internal_remote_ip dev tunnel_name
+        """
+        router.ip(
+            'netns',
+            'exec',
+            config['domain-name'],
+            'ip',
+            'address',
+            'add',
+            config['internal-local-ip'],
+            'peer',
+            config['internal-remote-ip'],
+            'dev',
+            config['tunnel-name']
+        )
+    except subprocess.CalledProcessError as e:
+        delete_domain_connection()
+        action_fail('Command failed: %s (%s)' %
+                    (' '.join(e.cmd), str(e.output)))
+    finally:
+        remove_state('vpe.connect-domains')
+        status_set('active', 'ready!')
+
+
+@when('vpe.configured')
+@when('vpe.delete-domain-connection')
+def delete_domain_connection():
+    ''' Remove the tunnel to another router where the domain is present '''
+    domain = action_get('domain-name')
+    tunnel_name = action_get('tunnel-name')
+
+    status_set('maintenance', 'deleting domain connection: {}'.format(domain))
+
+    try:
+
+        try:
+            """
+            $ ip netns exec domain_name ip link set tunnel_name down
+            """
+            router.ip('netns',
+                      'exec',
+                      domain,
+                      'ip',
+                      'link',
+                      'set',
+                      tunnel_name,
+                      'down')
+        except subprocess.CalledProcessError as e:
+            action_fail('Command failed: %s (%s)' %
+                        (' '.join(e.cmd), str(e.output)))
+
+        try:
+            """
+            $ ip netns exec domain_name ip tunnel del tunnel_name
+            """
+            router.ip('netns',
+                      'exec',
+                      domain,
+                      'ip',
+                      'tunnel',
+                      'del',
+                      tunnel_name)
+        except subprocess.CalledProcessError as e:
+            action_fail('Command failed: %s (%s)' %
+                        (' '.join(e.cmd), str(e.output)))
+    except:
+        pass
+    finally:
+        remove_state('vpe.delete-domain-connection')
+        status_set('active', 'ready!')
diff --git a/layers/vpe-router/wheelhouse.txt b/layers/vpe-router/wheelhouse.txt
new file mode 100644 (file)
index 0000000..df2de69
--- /dev/null
@@ -0,0 +1 @@
+paramiko>=1.16.0,<1.17
diff --git a/vpe-router/actions.yaml b/vpe-router/actions.yaml
deleted file mode 100644 (file)
index 913cc64..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-configure-interface:
-  description: Configure an ethernet interface.
-  params:
-    iface-name:
-      type: string
-      description: Device name, e.g. eth1
-    cidr:
-      type: string
-      description: Network range to assign to the interface
-  required: [iface-name]
-add-corporation:
-  description: Add a new corporation to the router
-  params:
-    domain-name:
-      type: string
-      description: Name of the vlan corporation
-    iface-name:
-      type: string
-      description: Device name. eg eth1
-    vlan-id:
-      type: integer
-      description: The name of the vlan?
-    cidr:
-      type: string
-      description: Network range to assign to the tagged vlan-id
-    area:
-      type: string
-      description: Link State Advertisements (LSA) type
-    subnet-cidr:
-      type: string
-      description: Network range
-    subnet-area:
-      type: string
-      description: Link State Advertisements (LSA) type
-  required: [domain-name, iface-name, vlan-id, cidr, area, subnet-cidr, subnet-area]
-delete-corporation:
-  description: Remove the corporation from the router completely
-  params:
-    domain-name:
-      type: string
-      description: The domain of the corporation to remove
-    cidr:
-      type: string
-      description: Network range to assign to the tagged vlan-id
-    area:
-      type: string
-      description: Link State Advertisements (LSA) type
-    subnet-cidr:
-      type: string
-      description: Network range
-    subnet-area:
-      type: string
-      description: Link State Advertisements (LSA) type
-  required: [domain-name, cidr, area, subnet-cidr, subnet-area]
-connect-domains:
-  description: Connect the router to another router, where the same domain is present
-  params:
-    domain-name:
-      type: string
-      description: The domain of the coproration to connect
-    iface-name:
-      type: string
-      description: Device name. eg eth1
-    tunnel-name:
-      type: string
-      description: Name of the tunnel ?
-    local-ip:
-      type: string
-      description: local ip ?
-    remote-ip:
-      type: string
-      description: remote ip ?
-    tunnel-key:
-      type: string
-      description: tunnel key?
-    internal-local-ip:
-      type: string
-      description: internal local ip?
-    internal-remote-ip:
-      type: string
-      description: internal remote ip?
-    tunnel-type:
-      type: string
-      default: gre
-      description: The type of tunnel to establish.
-  required: [domain-name, iface-name, tunnel-name, local-ip, remote-ip, tunnel-key, internal-local-ip, internal-remote-ip]
-delete-domain-connection:
-  description: Remove the tunnel to another router where the domain is present.
-  params:
-    domain-name:
-      type: string
-      description: The domain of the corporation to unlink
-    tunnel-name:
-      type: string
-      description: The name of the tunnel to unlink that the domain-name is attached to
-  required: [domain-name, tunnel-name]
diff --git a/vpe-router/actions/add-corporation b/vpe-router/actions/add-corporation
deleted file mode 100755 (executable)
index c8ab2f8..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-#!/usr/bin/env python3
-import sys
-sys.path.append('lib')
-
-from charms.reactive import main
-from charms.reactive import set_state
-from charmhelpers.core.hookenv import action_fail
-
-"""
-`set_state` only works here because it's flushed to disk inside the `main()`
-loop. remove_state will need to be called inside the action method.
-"""
-set_state('vpe.add-corporation')
-
-try:
-    main()
-except Exception as e:
-    action_fail(repr(e))
diff --git a/vpe-router/actions/configure-interface b/vpe-router/actions/configure-interface
deleted file mode 100755 (executable)
index db9a099..0000000
+++ /dev/null
@@ -1,18 +0,0 @@
-#!/usr/bin/env python3
-import sys
-sys.path.append('lib')
-
-from charms.reactive import main
-from charms.reactive import set_state
-from charmhelpers.core.hookenv import action_fail
-
-"""
-`set_state` only works here because it's flushed to disk inside the `main()`
-loop. remove_state will need to be called inside the action method.
-"""
-set_state('vpe.configure-interface')
-
-try:
-    main()
-except Exception as e:
-    action_fail(repr(e))
diff --git a/vpe-router/actions/connect-domains b/vpe-router/actions/connect-domains
deleted file mode 100755 (executable)
index 48adfc7..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/usr/bin/env python3
-
-# Load modules from $CHARM_DIR/lib
-import sys
-sys.path.append('lib')
-
-from charms.reactive import main
-from charms.reactive import set_state
-from charmhelpers.core.hookenv import action_fail
-
-"""
-`set_state` only works here because it's flushed to disk inside the `main()`
-loop. remove_state will need to be called inside the action method.
-"""
-set_state('vpe.connect-domains')
-
-try:
-    main()
-except Exception as e:
-    action_fail(repr(e))
diff --git a/vpe-router/actions/delete-corporation b/vpe-router/actions/delete-corporation
deleted file mode 100755 (executable)
index 0576c08..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/usr/bin/env python3
-import sys
-sys.path.append('lib')
-
-from charms.reactive import main
-from charms.reactive import set_state
-from charmhelpers.core.hookenv import action_fail
-
-
-"""
-`set_state` only works here because it's flushed to disk inside the `main()`
-loop. remove_state will need to be called inside the action method.
-"""
-set_state('vpe.delete-corporation')
-
-try:
-    main()
-except Exception as e:
-    action_fail(repr(e))
diff --git a/vpe-router/actions/delete-domain-connection b/vpe-router/actions/delete-domain-connection
deleted file mode 100755 (executable)
index 5ba05f6..0000000
+++ /dev/null
@@ -1,19 +0,0 @@
-#!/usr/bin/env python3
-import sys
-sys.path.append('lib')
-
-from charms.reactive import main
-from charms.reactive import set_state
-from charmhelpers.core.hookenv import action_fail
-
-
-"""
-`set_state` only works here because it's flushed to disk inside the `main()`
-loop. remove_state will need to be called inside the action method.
-"""
-set_state('vpe.delete-domain-connection')
-
-try:
-    main()
-except Exception as e:
-    action_fail(repr(e))
diff --git a/vpe-router/config.yaml b/vpe-router/config.yaml
deleted file mode 100644 (file)
index 562515f..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-options:
-  vpe-router:
-    default:
-    type: string
-    description: Hostname or IP of the vpe router to connect to
-  user:
-    type: string
-    default: root
-    description: Username for VPE Router
-  pass:
-    type: string
-    default:
-    description: Password for VPE Router
-  hostname:
-    type: string
-    default:
-    description: The hostname to set the vpe router to.
diff --git a/vpe-router/layer.yaml b/vpe-router/layer.yaml
deleted file mode 100644 (file)
index 524a4f4..0000000
+++ /dev/null
@@ -1 +0,0 @@
-includes: ['layer:basic']
diff --git a/vpe-router/lib/charms/router.py b/vpe-router/lib/charms/router.py
deleted file mode 100644 (file)
index 54ff7fb..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-
-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))
diff --git a/vpe-router/metadata.yaml b/vpe-router/metadata.yaml
deleted file mode 100644 (file)
index 65ae2da..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-name: vpe-router
-maintainers:
-  - Marco Ceppi <marco.ceppi@canonical.com>
-  - Adam Israel <adam.israel@canonical.com>
-summary: setup a virtualized PE Router with GRE tunnels
-series:
-  - trusty
-  - xenial
-description: | 
-  this charm, when deployed and configured, will provide a secure virtualized
-  provider edge router.
-peers:
-  loadbalance:
-    interface: vpe-router
diff --git a/vpe-router/reactive/vpe_router.py b/vpe-router/reactive/vpe_router.py
deleted file mode 100644 (file)
index e2be327..0000000
+++ /dev/null
@@ -1,644 +0,0 @@
-
-from charmhelpers.core.hookenv import (
-    config,
-    status_set,
-    action_get,
-    action_fail,
-    log,
-)
-
-from charms.reactive import (
-    hook,
-    when,
-    when_not,
-    helpers,
-    set_state,
-    remove_state,
-)
-
-from charms import router
-import subprocess
-
-cfg = config()
-
-
-@hook('config-changed')
-def validate_config():
-    try:
-        """
-        If the ssh credentials are available, we'll act as a proxy charm.
-        Otherwise, we execute against the unit we're deployed on to.
-        """
-        if all(k in cfg for k in ['pass', 'vpe-router', 'user']):
-            routerip = cfg['vpe-router']
-            user = cfg['user']
-            passwd = cfg['pass']
-
-            if routerip and user and passwd:
-                # Assumption: this will be a root user
-                out, err = router.ssh(['whoami'], routerip,
-                                      user, passwd)
-                if out.strip() != user:
-                    remove_state('vpe.configured')
-                    status_set('blocked', 'vpe is not configured')
-                    raise Exception('invalid credentials')
-
-                # Set the router's hostname
-                try:
-                    if user == 'root' and 'hostname' in cfg:
-                        hostname = cfg['hostname']
-                        out, err = router.ssh(['hostname', hostname],
-                                              routerip,
-                                              user, passwd)
-                        out, err = router.ssh(['sed',
-                                              '-i',
-                                               '"s/hostname.*$/hostname %s/"'
-                                               % hostname,
-                                               '/usr/admin/global/hostname.sh'
-                                               ],
-                                              routerip,
-                                              user, passwd)
-                        set_state('vpe.configured')
-                        status_set('active', 'ready!')
-                    else:
-                        remove_state('vpe.configured')
-                        status_set('blocked', 'vpe is not configured')
-                except subprocess.CalledProcessError as e:
-                    remove_state('vpe.configured')
-                    status_set('blocked', 'validation failed: %s' % e)
-                    log('Command failed: %s (%s)' %
-                        (' '.join(e.cmd), str(e.output)))
-                    raise
-
-    except Exception as e:
-        log(repr(e))
-        remove_state('vpe.configured')
-        status_set('blocked', 'validation failed: %s' % e)
-
-
-@when_not('vpe.configured')
-def not_ready_add():
-    actions = [
-        'vpe.add-corporation',
-        'vpe.connect-domains',
-        'vpe.delete-domain-connections',
-        'vpe.remove-corporation',
-        'vpe.configure-interface',
-        'vpe.configure-ospf',
-    ]
-
-    if helpers.any_states(*actions):
-        action_fail('VPE is not configured')
-
-    status_set('blocked', 'vpe is not configured')
-
-
-def start_ospfd():
-    # We may want to make this configurable via config setting
-    ospfd = '/usr/local/bin/ospfd'
-
-    try:
-        (stdout, stderr) = router._run(['touch',
-                                        '/usr/admin/global/ospfd.conf'])
-        (stdout, stderr) = router._run([ospfd, '-d', '-f',
-                                        '/usr/admin/global/ospfd.conf'])
-    except subprocess.CalledProcessError as e:
-        log('Command failed: %s (%s)' %
-            (' '.join(e.cmd), str(e.output)))
-
-
-def configure_ospf(domain, cidr, area, subnet_cidr, subnet_area, enable=True):
-    """Configure the OSPF service"""
-
-    # Check to see if the OSPF daemon is running, and start it if not
-    try:
-        (stdout, stderr) = router._run(['pgrep', 'ospfd'])
-    except subprocess.CalledProcessError as e:
-        # If pgrep fails, the process wasn't found.
-        start_ospfd()
-        log('Command failed (ospfd not running): %s (%s)' %
-            (' '.join(e.cmd), str(e.output)))
-
-    upordown = ''
-    if not enable:
-        upordown = 'no'
-    try:
-        vrfctl = '/usr/local/bin/vrfctl'
-        vtysh = '/usr/local/bin/vtysh'
-
-        (stdout, stderr) = router._run([vrfctl, 'list'])
-
-        domain_id = 0
-        for line in stdout.split('\n'):
-            if domain in line:
-                domain_id = int(line[3:5])
-
-        if domain_id > 0:
-            router._run([vtysh,
-                         '-c',
-                         '"configure terminal"',
-                         '-c',
-                         '"router ospf %d vr %d"' % (domain_id, domain_id),
-                         '-c',
-                         '"%s network %s area %s"' % (upordown, cidr, area),
-                         '-c',
-                         '"%s network %s area %s"' % (upordown,
-                                                      subnet_cidr,
-                                                      subnet_area),
-                         ])
-
-        else:
-            log("Invalid domain id")
-    except subprocess.CalledProcessError as e:
-        action_fail('Command failed: %s (%s)' %
-                    (' '.join(e.cmd), str(e.output)))
-    finally:
-        remove_state('vpe.configure-interface')
-        status_set('active', 'ready!')
-
-
-@when('vpe.configured')
-@when('vpe.configure-interface')
-def configure_interface():
-    """
-    Configure an ethernet interface
-    """
-    iface_name = action_get('iface-name')
-    cidr = action_get('cidr')
-
-    # cidr is optional
-    if cidr:
-        try:
-            # Add may fail, but change seems to add or update
-            router.ip('address', 'change', cidr, 'dev', iface_name)
-        except subprocess.CalledProcessError as e:
-            action_fail('Command failed: %s (%s)' %
-                        (' '.join(e.cmd), str(e.output)))
-            return
-        finally:
-            remove_state('vpe.configure-interface')
-            status_set('active', 'ready!')
-
-    try:
-        router.ip('link', 'set', 'dev', iface_name, 'up')
-    except subprocess.CalledProcessError as e:
-        action_fail('Command failed: %s (%s)' %
-                    (' '.join(e.cmd), str(e.output)))
-    finally:
-        remove_state('vpe.configure-interface')
-        status_set('active', 'ready!')
-
-
-@when('vpe.configured')
-@when('vpe.add-corporation')
-def add_corporation():
-    '''
-    Create and Activate the network corporation
-    '''
-    domain_name = action_get('domain-name')
-    iface_name = action_get('iface-name')
-    # HACK: python's list, used deeper, throws an exception on ints in a tuple
-    vlan_id = str(action_get('vlan-id'))
-    cidr = action_get('cidr')
-    area = action_get('area')
-    subnet_cidr = action_get('subnet-cidr')
-    subnet_area = action_get('subnet-area')
-
-    iface_vlanid = '%s.%s' % (iface_name, vlan_id)
-
-    status_set('maintenance', 'adding corporation {}'.format(domain_name))
-
-    """
-    Attempt to run all commands to add the network corporation. If any step
-    fails, abort and call `delete_corporation()` to undo.
-    """
-    try:
-        """
-        $ ip link add link eth3 name eth3.103 type vlan id 103
-        """
-        router.ip('link',
-                  'add',
-                  'link',
-                  iface_name,
-                  'name',
-                  iface_vlanid,
-                  'type',
-                  'vlan',
-                  'id',
-                  vlan_id)
-
-        """
-        $ ip netns add domain
-        """
-        router.ip('netns',
-                  'add',
-                  domain_name)
-
-        """
-        $ ip link set dev eth3.103 netns corpB
-        """
-        router.ip('link',
-                  'set',
-                  'dev',
-                  iface_vlanid,
-                  'netns',
-                  domain_name)
-
-        """
-        $ ifconfig eth3 up
-        """
-        router._run(['ifconfig', iface_name, 'up'])
-
-        """
-        $ ip netns exec corpB ip link set dev eth3.103 up
-        """
-        router.ip('netns',
-                  'exec',
-                  domain_name,
-                  'ip',
-                  'link',
-                  'set',
-                  'dev',
-                  iface_vlanid,
-                  'up')
-
-        """
-        $ ip netns exec corpB ip address add 10.0.1.1/24 dev eth3.103
-        """
-        mask = cidr.split("/")[1]
-        ip = '%s/%s' % (area, mask)
-        router.ip('netns',
-                  'exec',
-                  domain_name,
-                  'ip',
-                  'address',
-                  'add',
-                  ip,
-                  'dev',
-                  iface_vlanid)
-
-        configure_ospf(domain_name, cidr, area, subnet_cidr, subnet_area, True)
-
-    except subprocess.CalledProcessError as e:
-        delete_corporation()
-        action_fail('Command failed: %s (%s)' %
-                    (' '.join(e.cmd), str(e.output)))
-    finally:
-        remove_state('vpe.add-corporation')
-        status_set('active', 'ready!')
-
-
-@when('vpe.configured')
-@when('vpe.delete-corporation')
-def delete_corporation():
-
-    domain_name = action_get('domain-name')
-    cidr = action_get('cidr')
-    area = action_get('area')
-    subnet_cidr = action_get('subnet-cidr')
-    subnet_area = action_get('subnet-area')
-
-    status_set('maintenance', 'deleting corporation {}'.format(domain_name))
-
-    try:
-        """
-        Remove all tunnels defined for this domain
-
-        $ ip netns exec domain_name ip tun show
-            | grep gre
-            | grep -v "remote any"
-            | cut -d":" -f1
-        """
-        p = router.ip(
-            'netns',
-            'exec',
-            domain_name,
-            'ip',
-            'tun',
-            'show',
-            '|',
-            'grep',
-            'gre',
-            '|',
-            'grep',
-            '-v',
-            '"remote any"',
-            '|',
-            'cut -d":" -f1'
-        )
-
-        # `p` should be a tuple of (stdout, stderr)
-        tunnels = p[0].split('\n')
-
-        for tunnel in tunnels:
-            try:
-                """
-                $ ip netns exec domain_name ip link set $tunnel_name down
-                """
-                router.ip(
-                    'netns',
-                    'exec',
-                    domain_name,
-                    'ip',
-                    'link',
-                    'set',
-                    tunnel,
-                    'down'
-                )
-            except subprocess.CalledProcessError as e:
-                log('Command failed: %s (%s)' %
-                    (' '.join(e.cmd), str(e.output)))
-                pass
-
-            try:
-                """
-                $ ip netns exec domain_name ip tunnel del $tunnel_name
-                """
-                router.ip(
-                    'netns',
-                    'exec',
-                    domain_name,
-                    'ip',
-                    'tunnel',
-                    'del',
-                    tunnel
-                )
-            except subprocess.CalledProcessError as e:
-                log('Command failed: %s (%s)' %
-                    (' '.join(e.cmd), str(e.output)))
-                pass
-
-        """
-        Remove all interfaces associated to the domain
-
-        $ ip netns exec domain_name ifconfig | grep mtu | cut -d":" -f1
-        """
-        p = router.ip(
-            'netns',
-            'exec',
-            domain_name,
-            'ifconfig',
-            '|',
-            'grep mtu',
-            '|',
-            'cut -d":" -f1'
-        )
-
-        ifaces = p[0].split('\n')
-        for iface in ifaces:
-
-            try:
-                """
-                $ ip netns exec domain_name ip link set $iface down
-                """
-                router.ip(
-                    'netns',
-                    'exec',
-                    domain_name,
-                    'ip',
-                    'link',
-                    'set',
-                    iface,
-                    'down'
-                )
-            except subprocess.CalledProcessError as e:
-                log('Command failed: %s (%s)' %
-                    (' '.join(e.cmd), str(e.output)))
-
-            try:
-                """
-                $ ifconfig eth3 down
-                """
-                router._run(['ifconfig', iface, 'down'])
-            except subprocess.CalledProcessError as e:
-                log('Command failed: %s (%s)' %
-                    (' '.join(e.cmd), str(e.output)))
-                pass
-
-            try:
-                """
-                $ ip link del dev $iface
-                """
-                router.ip(
-                    'link',
-                    'del',
-                    'dev',
-                    iface
-                )
-            except subprocess.CalledProcessError as e:
-                log('Command failed: %s (%s)' %
-                    (' '.join(e.cmd), str(e.output)))
-                pass
-
-        try:
-            """
-            Remove the domain
-
-            $ ip netns del domain_name
-            """
-            router.ip(
-                'netns',
-                'del',
-                domain_name
-            )
-        except subprocess.CalledProcessError as e:
-            log('Command failed: %s (%s)' % (' '.join(e.cmd), str(e.output)))
-            pass
-
-        try:
-            configure_ospf(domain_name,
-                           cidr,
-                           area,
-                           subnet_cidr,
-                           subnet_area,
-                           False)
-        except subprocess.CalledProcessError as e:
-            action_fail('Command failed: %s (%s)' %
-                        (' '.join(e.cmd), str(e.output)))
-
-    except:
-        # Do nothing
-        log('delete-corporation failed.')
-        pass
-
-    finally:
-        remove_state('vpe.delete-corporation')
-        status_set('active', 'ready!')
-
-
-@when('vpe.configured')
-@when('vpe.connect-domains')
-def connect_domains():
-
-    params = [
-        'domain-name',
-        'iface-name',
-        'tunnel-name',
-        'local-ip',
-        'remote-ip',
-        'tunnel-key',
-        'internal-local-ip',
-        'internal-remote-ip',
-        'tunnel-type',
-    ]
-
-    config = {}
-    for p in params:
-        config[p] = action_get(p)
-
-    status_set('maintenance', 'connecting domains')
-
-    try:
-        """
-        $ ip tunnel add tunnel_name mode gre local local_ip remote remote_ip
-            dev iface_name key tunnel_key csum
-        """
-        router.ip(
-            'tunnel',
-            'add',
-            config['tunnel-name'],
-            'mode',
-            config['tunnel-type'],
-            'local',
-            config['local-ip'],
-            'remote',
-            config['remote-ip'],
-            'dev',
-            config['iface-name'],
-            'key',
-            config['tunnel-key'],
-            'csum'
-        )
-
-    except subprocess.CalledProcessError as e:
-        log('Command failed (retrying with ip tunnel change): %s (%s)' %
-            (' '.join(e.cmd), str(e.output)))
-        try:
-            """
-            If the tunnel already exists (like gre0) and can't be deleted,
-            modify it instead of trying to add it.
-            """
-            router.ip(
-                'tunnel',
-                'change',
-                config['tunnel-name'],
-                'mode',
-                config['tunnel-type'],
-                'local',
-                config['local-ip'],
-                'remote',
-                config['remote-ip'],
-                'dev',
-                config['iface-name'],
-                'key',
-                config['tunnel-key'],
-                'csum'
-            )
-        except subprocess.CalledProcessError as e:
-            delete_domain_connection()
-            action_fail('Command failed: %s (%s)' %
-                        (' '.join(e.cmd), str(e.output)))
-        finally:
-            remove_state('vpe.connect-domains')
-            status_set('active', 'ready!')
-
-    try:
-        """
-        $ ip link set dev tunnel_name netns domain_name
-        """
-        router.ip(
-            'link',
-            'set',
-            'dev',
-            config['tunnel-name'],
-            'netns',
-            config['domain-name']
-        )
-
-        """
-        $ ip netns exec domain_name ip link set dev tunnel_name up
-        """
-        router.ip(
-            'netns',
-            'exec',
-            config['domain-name'],
-            'ip',
-            'link',
-            'set',
-            'dev',
-            config['tunnel-name'],
-            'up'
-        )
-
-        """
-        $ ip netns exec domain_name ip address add internal_local_ip peer
-            internal_remote_ip dev tunnel_name
-        """
-        router.ip(
-            'netns',
-            'exec',
-            config['domain-name'],
-            'ip',
-            'address',
-            'add',
-            config['internal-local-ip'],
-            'peer',
-            config['internal-remote-ip'],
-            'dev',
-            config['tunnel-name']
-        )
-    except subprocess.CalledProcessError as e:
-        delete_domain_connection()
-        action_fail('Command failed: %s (%s)' %
-                    (' '.join(e.cmd), str(e.output)))
-    finally:
-        remove_state('vpe.connect-domains')
-        status_set('active', 'ready!')
-
-
-@when('vpe.configured')
-@when('vpe.delete-domain-connection')
-def delete_domain_connection():
-    ''' Remove the tunnel to another router where the domain is present '''
-    domain = action_get('domain-name')
-    tunnel_name = action_get('tunnel-name')
-
-    status_set('maintenance', 'deleting domain connection: {}'.format(domain))
-
-    try:
-
-        try:
-            """
-            $ ip netns exec domain_name ip link set tunnel_name down
-            """
-            router.ip('netns',
-                      'exec',
-                      domain,
-                      'ip',
-                      'link',
-                      'set',
-                      tunnel_name,
-                      'down')
-        except subprocess.CalledProcessError as e:
-            action_fail('Command failed: %s (%s)' %
-                        (' '.join(e.cmd), str(e.output)))
-
-        try:
-            """
-            $ ip netns exec domain_name ip tunnel del tunnel_name
-            """
-            router.ip('netns',
-                      'exec',
-                      domain,
-                      'ip',
-                      'tunnel',
-                      'del',
-                      tunnel_name)
-        except subprocess.CalledProcessError as e:
-            action_fail('Command failed: %s (%s)' %
-                        (' '.join(e.cmd), str(e.output)))
-    except:
-        pass
-    finally:
-        remove_state('vpe.delete-domain-connection')
-        status_set('active', 'ready!')
diff --git a/vpe-router/wheelhouse.txt b/vpe-router/wheelhouse.txt
deleted file mode 100644 (file)
index df2de69..0000000
+++ /dev/null
@@ -1 +0,0 @@
-paramiko>=1.16.0,<1.17