aboutsummaryrefslogtreecommitdiffstats
path: root/vicn/resource/linux
diff options
context:
space:
mode:
Diffstat (limited to 'vicn/resource/linux')
-rw-r--r--vicn/resource/linux/bridge.py28
-rw-r--r--vicn/resource/linux/certificate.py30
-rw-r--r--vicn/resource/linux/certificate_store.py54
-rw-r--r--vicn/resource/linux/dnsmasq.py14
-rw-r--r--vicn/resource/linux/file.py12
-rw-r--r--vicn/resource/linux/folder.py88
-rw-r--r--vicn/resource/linux/gre_tunnel.py63
-rw-r--r--vicn/resource/linux/iperf.py4
-rw-r--r--vicn/resource/linux/keypair.py8
-rw-r--r--vicn/resource/linux/link.py26
-rw-r--r--vicn/resource/linux/macvlan.py8
-rw-r--r--vicn/resource/linux/macvtap.py8
-rw-r--r--vicn/resource/linux/net_device.py106
-rw-r--r--vicn/resource/linux/netmon.py2
-rw-r--r--vicn/resource/linux/ovs.py6
-rw-r--r--vicn/resource/linux/package_manager.py17
-rw-r--r--vicn/resource/linux/phy_interface.py20
-rw-r--r--vicn/resource/linux/phy_link.py51
-rw-r--r--vicn/resource/linux/physical.py6
-rw-r--r--vicn/resource/linux/qtplayer.py5
-rw-r--r--vicn/resource/linux/repository.py6
-rw-r--r--vicn/resource/linux/service.py29
-rw-r--r--vicn/resource/linux/sym_veth_pair.py52
-rw-r--r--vicn/resource/linux/tap_device.py25
-rw-r--r--vicn/resource/linux/veth_pair.py94
-rw-r--r--vicn/resource/linux/veth_pair_lxc.py74
26 files changed, 597 insertions, 239 deletions
diff --git a/vicn/resource/linux/bridge.py b/vicn/resource/linux/bridge.py
index 7b5ceed7..edc8acdc 100644
--- a/vicn/resource/linux/bridge.py
+++ b/vicn/resource/linux/bridge.py
@@ -22,18 +22,15 @@ from vicn.core.address_mgr import AddressManager
from vicn.core.attribute import Attribute, Multiplicity
from vicn.core.exception import ResourceNotFound
from vicn.core.requirement import Requirement
-from vicn.core.task import inline_task
+from vicn.core.task import inline_task, inherit
from vicn.resource.channel import Channel
+from vicn.resource.interface import Interface
from vicn.resource.linux.bridge_mgr import BridgeManager
-from vicn.resource.linux.net_device import BaseNetDevice
+from vicn.resource.linux.net_device import NetDevice
log = logging.getLogger(__name__)
-# FIXME This should use the AddressManager to get allocated a name that does
-# not exist
-DEFAULT_BRIDGE_NAME = 'br0'
-
-class Bridge(Channel, BaseNetDevice):
+class Bridge(Channel, NetDevice):
"""
Resource: Bridge
"""
@@ -62,21 +59,10 @@ class Bridge(Channel, BaseNetDevice):
# Resource lifecycle
#--------------------------------------------------------------------------
- @inline_task
- def __get__(self):
- # FIXME we currently force the recreation of the bridge, delegating the
- # check to the creation function
- raise ResourceNotFound
-
+ @inherit(Channel, Interface)
def __create__(self):
- # FIXME : reserves .1 IP address for the bridge, provided no other
- # class uses this trick
- AddressManager().get_ip(self)
return self.node.bridge_manager.add_bridge(self.device_name)
- # Everything should be handled by BaseNetDevice
- __delete__ = None
-
#--------------------------------------------------------------------------
# Resource lifecycle
#--------------------------------------------------------------------------
@@ -86,7 +72,7 @@ class Bridge(Channel, BaseNetDevice):
Returns:
Task
"""
- return self.node.bridge_manager.add_interface(self.device_name,
+ return self.node.bridge_manager.add_interface(self.device_name,
interface.device_name, vlan)
def __method_add_interface__(self, interface, vlan=None):
@@ -99,6 +85,6 @@ class Bridge(Channel, BaseNetDevice):
"""
log.info('Removing interface {} from bridge {}'.format(
interface.device_name, self.name))
- return self.node.bridge_manager.del_interface(self.device_name,
+ return self.node.bridge_manager.del_interface(self.device_name,
interface.device_name)
diff --git a/vicn/resource/linux/certificate.py b/vicn/resource/linux/certificate.py
index dd451770..2cc6c9b0 100644
--- a/vicn/resource/linux/certificate.py
+++ b/vicn/resource/linux/certificate.py
@@ -23,6 +23,7 @@ from vicn.core.attribute import Attribute, Multiplicity, Reference
from vicn.core.exception import ResourceNotFound
from vicn.core.resource import Resource
from vicn.core.task import task, inline_task, BashTask
+from vicn.core.task import inherit_parent
from vicn.resource.linux.file import File
from vicn.resource.node import Node
@@ -49,29 +50,40 @@ class Certificate(Resource):
multiplicity = Multiplicity.ManyToOne)
cert = Attribute(String, description = 'Certificate path',
mandatory = True)
- key = Attribute(String, description = 'Key path',
- mandatory = True)
+ key = Attribute(String, description = 'Key path')
#--------------------------------------------------------------------------
# Resource lifecycle
#--------------------------------------------------------------------------
- @inline_task
- def __initialize__(self):
+ def __init__(self, *args, **kwargs):
+ super().__init__(*args, **kwargs)
self._cert_file = File(node = Reference(self, 'node'),
filename = Reference(self, 'cert'),
managed = False)
- self._key_file = File(node = Reference(self, 'node'),
- filename = Reference(self, 'key'),
- managed = False)
+ if self.key:
+ self._key_file = File(node = Reference(self, 'node'),
+ filename = Reference(self, 'key'),
+ managed = False)
+ else:
+ self._key_file = None
+ @inherit_parent
def __get__(self):
- return self._cert_file.__get__() | self._key_file.__get__()
+ if self.key:
+ return self._cert_file.__get__() | self._key_file.__get__()
+ else:
+ return self._cert_file.__get__()
+ @inherit_parent
def __create__(self):
return BashTask(self.node, CMD_CREATE, {'self': self})
+ @inherit_parent
def __delete__(self):
- return self._cert_file.__delete__() | self._key_file.__delete__()
+ if self.key:
+ return self._cert_file.__delete__() | self._key_file.__delete__()
+ else:
+ return self._cert_file.__delete__()
diff --git a/vicn/resource/linux/certificate_store.py b/vicn/resource/linux/certificate_store.py
new file mode 100644
index 00000000..59d9a239
--- /dev/null
+++ b/vicn/resource/linux/certificate_store.py
@@ -0,0 +1,54 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2017 Cisco and/or its affiliates.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+from vicn.core.attribute import Attribute, Multiplicity
+from vicn.core.resource import Resource
+from vicn.resource.linux.certificate import Certificate
+from vicn.resource.node import Node
+
+PACKAGE = 'ca-certificates'
+
+CMD_ADD_CERTIFICATE = '''
+cp {certificate.cert} {store.PATH}
+dpkg-reconfigure ca-certificates
+'''
+
+class CertificateStore(Resource):
+ """
+ Resource: System-wide Certificate Store
+
+ This resource allows manipulation of the trusted certificates on the system.
+ Use with care.
+
+ TODO:
+ - Ensure ca-certificates package is installed.
+ - Issue a warning to the user when it is used.
+ """
+
+ PATH = '/usr/share/ca-certificates'
+
+ certificates = Attribute(Certificate, multiplicity = Multiplicity.OneToMany)
+ node = Attribute(Node, mandatory = True, requirements = [
+ #Requirement(PACKAGE, 'in', 'packages')
+ ])
+
+ def _add_certificate(self):
+ # Return a task that takes a certificate as parameter
+ PARAM = None
+ return BashTask(self.node, CMD_ADD_CERTIFICATE, {'store': self, 'certificate': PARAM},
+ root = True)
diff --git a/vicn/resource/linux/dnsmasq.py b/vicn/resource/linux/dnsmasq.py
index b5aa8053..70358ecb 100644
--- a/vicn/resource/linux/dnsmasq.py
+++ b/vicn/resource/linux/dnsmasq.py
@@ -24,6 +24,7 @@ from string import Template
from netmodel.model.type import String, Bool
from vicn.core.attribute import Attribute
from vicn.core.resource import EmptyResource
+from vicn.core.task import inherit_parent, override_parent
from vicn.resource.dns_server import DnsServer
from vicn.resource.interface import Interface
from vicn.resource.linux.file import TextFile
@@ -72,15 +73,16 @@ class DnsMasq(Service, DnsServer):
log_dhcp = Attribute(Bool, description = 'Flag: log DHCP queries',
default = True)
- #--------------------------------------------------------------------------
- # Resource lifecycle
- #--------------------------------------------------------------------------
-
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
if not self.interface:
raise Exception("Cannot initialize bridge without interface")
+ #--------------------------------------------------------------------------
+ # Resource lifecycle
+ #--------------------------------------------------------------------------
+
+ @inherit_parent
def __subresources__(self):
# Overwrite configuration file
flags = list()
@@ -112,3 +114,7 @@ class DnsMasq(Service, DnsServer):
return TextFile(node = self.node, owner = self, filename = FN_CONF,
content = conf, overwrite = True)
+
+ @override_parent
+ def __create__(self):
+ return self.__method_stop_start()
diff --git a/vicn/resource/linux/file.py b/vicn/resource/linux/file.py
index 44b4b5be..2a62f60e 100644
--- a/vicn/resource/linux/file.py
+++ b/vicn/resource/linux/file.py
@@ -16,11 +16,12 @@
# limitations under the License.
#
+from netmodel.model.key import Key
from netmodel.model.type import String, Bool
from vicn.core.attribute import Attribute, Multiplicity
from vicn.core.exception import ResourceNotFound
from vicn.core.resource import Resource
-from vicn.core.task import BashTask, inline_task
+from vicn.core.task import BashTask, inline_task, inherit_parent
from vicn.resource.node import Node
CREATE_DIR_CMD = "mkdir -p {dir}"
@@ -38,22 +39,23 @@ class File(Resource):
Resource: File
"""
filename = Attribute(String, description = 'Path to the file',
- key = True,
mandatory = True)
node = Attribute(Node, description = 'Node on which the file is created',
mandatory = True,
multiplicity = Multiplicity.ManyToOne,
reverse_name = 'files',
- key = True,
reverse_description = 'Files created on the node')
overwrite = Attribute(Bool,
description = 'Determines whether an existing file is overwritten',
default = False)
+ __key__ = Key(node, filename)
+
#--------------------------------------------------------------------------
# Resource lifecycle
#--------------------------------------------------------------------------
+ @inherit_parent
def __get__(self):
# UGLY
@inline_task
@@ -72,12 +74,14 @@ class File(Resource):
test = BashTask(self.node, GET_FILE_CMD, {"file": self}, parse=is_path)
return test
+ @inherit_parent
def __create__(self):
ctask = BashTask(self.node, CREATE_FILE_CMD, {"file": self})
if self.overwrite:
ctask = BashTask(self.node, DELETE_FILE_CMD, {'file': self}) > ctask
return ctask
+ @inherit_parent
def __delete__(self):
return BashTask(self.node, DELETE_FILE_CMD, { "file" : self})
@@ -96,6 +100,8 @@ class TextFile(File):
# Resource lifecycle
#--------------------------------------------------------------------------
+ # XXX REDUNDANT !!!
+ @inherit_parent
def __create__(self):
return BashTask(self.node, CMD_PRINT_TO_FILE, {'file': self})
diff --git a/vicn/resource/linux/folder.py b/vicn/resource/linux/folder.py
new file mode 100644
index 00000000..636ecbcd
--- /dev/null
+++ b/vicn/resource/linux/folder.py
@@ -0,0 +1,88 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2017 Cisco and/or its affiliates.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+from netmodel.model.key import Key
+from netmodel.model.type import String, Bool, Integer
+from vicn.core.attribute import Attribute, Multiplicity
+from vicn.core.exception import ResourceNotFound
+from vicn.core.resource import Resource
+from vicn.core.task import BashTask, inline_task, EmptyTask
+from vicn.resource.node import Node
+
+CREATE_FOLDER_CMD = "mkdir -p {folder.foldername}"
+DELETE_FOLDER_CMD = "rm -f {folder.foldername}"
+
+GET_FOLDER_CMD = 'test -d {folder.foldername} && readlink -e {folder.foldername}'
+
+SET_FOLDER_PERMISSION_CMD = 'chmod {folder.permission} {folder.foldername}'
+
+class Folder(Resource):
+ """
+ Resource: Folder
+ """
+ foldername = Attribute(String, description = 'Path to the folder',
+ mandatory = True)
+ node = Attribute(Node, description = 'Node on which the directory is created',
+ mandatory = True,
+ multiplicity = Multiplicity.ManyToOne,
+ reverse_name = 'folders',
+ reverse_description = 'Folders created on the node')
+ overwrite = Attribute(Bool,
+ description = 'Determines whether an existing folder is overwritten',
+ default = False)
+ permission = Attribute(Integer,
+ description = 'Permission to set in the folder',
+ default = 775)
+
+ __key__ = Key(node, foldername)
+ #--------------------------------------------------------------------------
+ # Resource lifecycle
+ #--------------------------------------------------------------------------
+
+ @inline_task
+ def __get__(self):
+ # UGLY
+# @inline_task
+# def not_found():
+ raise ResourceNotFound
+
+ # if self.overwrite:
+ # return not_found()
+
+ # def is_path (rv):
+ # if rv is None or rv.stdout is None or len(rv.stdout) == 0 or \
+ # rv.return_value != 0:
+ # raise ResourceNotFound
+ # return {} # 'filename': rv.stdout}
+
+ # create = BashTask(self.node, GET_FOLDER_CMD, {"folder": self}, parse=is_path)
+
+ # return create
+
+ def __create__(self):
+ ctask = BashTask(self.node, CREATE_FOLDER_CMD, {"folder": self})
+
+ if self.overwrite:
+ ctask = BashTask(self.node, DELETE_FOLDER_CMD, {'folder': self}) > ctask
+
+ set_permission = BashTask(self.node, SET_FOLDER_PERMISSION_CMD, {"folder": self})
+
+ return ctask > set_permission
+
+ def __delete__(self):
+ return BashTask(self.node, DELETE_FOLFER_CMD, { "folder" : self})
diff --git a/vicn/resource/linux/gre_tunnel.py b/vicn/resource/linux/gre_tunnel.py
new file mode 100644
index 00000000..c5a25307
--- /dev/null
+++ b/vicn/resource/linux/gre_tunnel.py
@@ -0,0 +1,63 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2017 Cisco and/or its affiliates.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import string
+
+from netmodel.model.type import Integer, String
+from vicn.core.attribute import Attribute
+from vicn.core.resource import Resource
+from vicn.core.task import BashTask, inherit_parent, override_parent
+from vicn.resource.channel import Channel
+from vicn.resource.linux.net_device import NetDevice, SlaveNetDevice
+
+CMD_CREATE_GRE_TUNNEL='''
+ip tunnel add {device_name} mode gre remote {dst} local {src} ttl 255
+'''
+
+class GREChannel(Channel):
+ """
+ Resource: GRETunnel
+ """
+ pass
+
+class GREInterface(SlaveNetDevice):
+
+ remote_address = Attribute(String, description ='',
+ mandatory = True)
+
+ @override_parent
+ def __create__(self):
+ return BashTask(self.src_interface.node, CMD_CREATE_GRE_TUNNEL, {
+ 'device_name': self.device_name,
+ 'src': str(self.parent.ip4_address),
+ 'dst': self.remote_address})
+
+class GRETunnel(Resource):
+
+ src_interface = Attribute(NetDevice, description = 'source interface',
+ mandatory = True)
+ dst_interface = Attribute(NetDevice, description = 'destination interface',
+ mandatory = True)
+
+ @inherit_parent
+ def __subresources__(self):
+ channel = GREChannel()
+ src = GREInterface(node=src_interface.node, device_name="gre0",
+ parent=src_interface, channel=channel)
+ dst = GREInterface(node=dst_interface.node, device_name="gre0",
+ parent=dst_interface, channel=channel)
+ return (src | dst) | channel
diff --git a/vicn/resource/linux/iperf.py b/vicn/resource/linux/iperf.py
index a0780a1c..e4b8e94c 100644
--- a/vicn/resource/linux/iperf.py
+++ b/vicn/resource/linux/iperf.py
@@ -16,12 +16,10 @@
# limitations under the License.
#
-from abc import ABC
-
from netmodel.model.type import Integer
from vicn.core.attribute import Attribute
from vicn.resource.linux.application import LinuxApplication
-class Iperf3(LinuxApplication, ABC):
+class Iperf3(LinuxApplication):
__package_names__ = ['iperf3']
diff --git a/vicn/resource/linux/keypair.py b/vicn/resource/linux/keypair.py
index 66c98e5b..b748b756 100644
--- a/vicn/resource/linux/keypair.py
+++ b/vicn/resource/linux/keypair.py
@@ -23,6 +23,7 @@ from vicn.core.attribute import Attribute, Multiplicity, Reference
from vicn.core.exception import ResourceNotFound
from vicn.core.resource import Resource
from vicn.core.task import task, inline_task, BashTask
+from vicn.core.task import inherit_parent
from vicn.resource.linux.file import File
from vicn.resource.node import Node
@@ -48,8 +49,8 @@ class Keypair(Resource):
# Resource lifecycle
#--------------------------------------------------------------------------
- @inline_task
- def __initialize__(self):
+ def __init__(self, *args, **kwargs):
+ super().__init__(*args, **kwargs)
self._pubkey_file = File(node = Reference(self, 'node'),
filename = self.key + '.pub',
managed = False)
@@ -57,14 +58,17 @@ class Keypair(Resource):
filename = self.key,
managed = False)
+ @inherit_parent
def __get__(self):
return self._pubkey_file.__get__() | self._key_file.__get__()
+ @inherit_parent
def __create__(self):
return BashTask(self.node, CMD_CREATE, {
'dirname': os.path.dirname(self.key),
'self': self})
+ @inherit_parent
def __delete__(self):
return self._pubkey_file.__delete__() | self._key_file.__delete__()
diff --git a/vicn/resource/linux/link.py b/vicn/resource/linux/link.py
index da41fbe1..3ffaae97 100644
--- a/vicn/resource/linux/link.py
+++ b/vicn/resource/linux/link.py
@@ -20,12 +20,14 @@ import random
import string
import logging
+from netmodel.model.key import Key
from netmodel.model.type import Integer, String
from vicn.core.attribute import Attribute, Reference
from vicn.core.exception import ResourceNotFound
from vicn.core.state import ResourceState, AttributeState
from vicn.core.task import inline_task, async_task, run_task
from vicn.core.task import get_attributes_task, BashTask
+from vicn.core.task import inherit_parent
from vicn.resource.channel import Channel
from vicn.resource.interface import Interface
from vicn.resource.linux.net_device import NonTapBaseNetDevice
@@ -53,7 +55,7 @@ ip link set dev {tmp_src} netns {pid} name {interface.device_name}
ip link set dev {tmp_dst} up
ovs-vsctl add-port {host.bridge.device_name} {tmp_dst}'''
-CMD_UP='''
+CMD_SET_UP='''
ip link set dev {interface.device_name} up
'''
@@ -73,18 +75,19 @@ class Link(Channel):
delay = Attribute(String, description = 'Link propagation delay')
src_node = Attribute(Node, description = 'Source node',
- key = True,
mandatory = True)
dst_node = Attribute(Node, description = 'Destination node',
- key = True,
mandatory = True)
+ __key__ = Key(src_node, dst_node)
+
def __init__(self, *args, **kwargs):
assert 'src_node' in kwargs and 'dst_node' in kwargs
self._src = None
self._dst = None
super().__init__(*args, **kwargs)
+ @inherit_parent
@inline_task
def __initialize__(self):
# We create two managed net devices that are pre-setup
@@ -124,23 +127,27 @@ class Link(Channel):
vpp_src = VPPInterface(parent = self._src,
vpp = self.src_node.vpp,
ip4_address = Reference(self._src, 'ip4_address'),
- device_name = 'vpp' + self._src.device_name)
+ ip6_address = Reference(self._src, 'ip6_address'),
+ device_name = 'host-' + self._src.device_name)
manager.commit_resource(vpp_src)
if hasattr(self.dst_node, 'vpp') and not self.dst_node.vpp is None:
vpp_dst = VPPInterface(parent = self._dst,
vpp = self.dst_node.vpp,
ip4_address = Reference(self._dst, 'ip4_address'),
- device_name = 'vpp' + self._dst.device_name)
+ ip6_address = Reference(self._dst, 'ip6_address'),
+ device_name = 'host-' + self._dst.device_name)
manager.commit_resource(vpp_dst)
#--------------------------------------------------------------------------
# Resource lifecycle
#--------------------------------------------------------------------------
+ @inherit_parent
def __get__(self):
return (self._src.__get__() | self._dst.__get__()) > async_task(self._commit)()
+ @inherit_parent
def __create__(self):
assert self.src_node.get_type() == 'lxccontainer'
assert self.dst_node.get_type() == 'lxccontainer'
@@ -168,8 +175,8 @@ class Link(Channel):
host = src_host
create = BashTask(host, CMD_CREATE, {'interface': self,
'tmp_src': tmp_src, 'tmp_dst': tmp_dst})
- up_src = BashTask(self.src_node, CMD_UP, {'interface': self._src})
- up_dst = BashTask(self.dst_node, CMD_UP, {'interface': self._dst})
+ up_src = BashTask(self.src_node, CMD_SET_UP, {'interface': self._src})
+ up_dst = BashTask(self.dst_node, CMD_SET_UP, {'interface': self._dst})
up = up_src | up_dst
delif = delif_src | delif_dst
return ((delif > (pid @ create)) > up) > async_task(self._commit)()
@@ -178,10 +185,11 @@ class Link(Channel):
'tmp_src': tmp_src, 'tmp_dst': tmp_dst, 'host' : src_host})
create2 = BashTask(dst_host, CMD_CREATE_BR_TO_LXC, {'interface': self._dst,
'tmp_src': tmp_dst, 'tmp_dst': tmp_src, 'host' : dst_host})
- up_src = BashTask(self.src_node, CMD_UP, {'interface': self._src})
- up_dst = BashTask(self.dst_node, CMD_UP, {'interface': self._dst})
+ up_src = BashTask(self.src_node, CMD_SET_UP, {'interface': self._src})
+ up_dst = BashTask(self.dst_node, CMD_SET_UP, {'interface': self._dst})
return (((pid_src @ create) | (pid_dst @ create2)) > (up_src | up_dst)) > async_task(self._commit)()
+ @inherit_parent
def __delete__(self):
return self._src.__delete__() | self._dst.__delete__()
diff --git a/vicn/resource/linux/macvlan.py b/vicn/resource/linux/macvlan.py
index ea9c37c1..3c81cde1 100644
--- a/vicn/resource/linux/macvlan.py
+++ b/vicn/resource/linux/macvlan.py
@@ -18,14 +18,15 @@
from netmodel.model.type import String
from vicn.core.attribute import Attribute
-from vicn.core.task import BashTask
-from vicn.resource.linux.net_device import SlaveBaseNetDevice
+from vicn.core.task import BashTask, inherit
+from vicn.resource.interface import Interface
+from vicn.resource.linux.net_device import SlaveNetDevice
CMD_CREATE_PARENT = 'ip link add name {netdevice.device_name} ' \
'link {netdevice.parent.device_name} ' \
'type {netdevice.netdevice_type} mode {netdevice.mode}'
-class MacVlan(SlaveBaseNetDevice):
+class MacVlan(SlaveNetDevice):
"""
Resource: MacVlan
@@ -48,5 +49,6 @@ class MacVlan(SlaveBaseNetDevice):
# Resource lifecycle
#--------------------------------------------------------------------------
+ @inherit(Interface)
def __create__(self):
return BashTask(self.node, CMD_CREATE_PARENT, {'netdevice': self})
diff --git a/vicn/resource/linux/macvtap.py b/vicn/resource/linux/macvtap.py
index 82002e02..23176763 100644
--- a/vicn/resource/linux/macvtap.py
+++ b/vicn/resource/linux/macvtap.py
@@ -18,14 +18,15 @@
from netmodel.model.type import String
from vicn.core.attribute import Attribute
-from vicn.core.task import BashTask
-from vicn.resource.linux.net_device import SlaveBaseNetDevice
+from vicn.core.task import BashTask, inherit
+from vicn.resource.interface import Interface
+from vicn.resource.linux.net_device import SlaveNetDevice
CMD_CREATE_PARENT = 'ip link add name {netdevice.device_name} ' \
'link {netdevice.parent.device_name} ' \
'type {netdevice.netdevice_type} mode {netdevice.mode}'
-class MacVtap(SlaveBaseNetDevice):
+class MacVtap(SlaveNetDevice):
"""
Resource: MacVtap
@@ -48,5 +49,6 @@ class MacVtap(SlaveBaseNetDevice):
# Resource lifecycle
#--------------------------------------------------------------------------
+ @inherit(Interface)
def __create__(self):
return BashTask(self.node, CMD_CREATE_PARENT, {'netdevice': self})
diff --git a/vicn/resource/linux/net_device.py b/vicn/resource/linux/net_device.py
index c393ac1a..f9ab40b1 100644
--- a/vicn/resource/linux/net_device.py
+++ b/vicn/resource/linux/net_device.py
@@ -23,11 +23,13 @@ import random
import string
from netmodel.model.type import Integer, String, Bool
+from netmodel.model.type import Inet4Address, Inet6Address
from vicn.core.address_mgr import AddressManager
from vicn.core.attribute import Attribute
from vicn.core.exception import ResourceNotFound
from vicn.core.resource import BaseResource
-from vicn.core.task import BashTask, task, EmptyTask
+from vicn.core.task import BashTask, task, EmptyTask, inherit
+from vicn.core.task import inherit_parent, override_parent
from vicn.resource.linux.application import LinuxApplication as Application
from vicn.resource.interface import Interface
@@ -59,11 +61,11 @@ CMD_SET_MAC_ADDRESS = 'ip link set dev {netdevice.device_name} ' \
'address {netdevice.mac_address}'
CMD_GET_IP_ADDRESS = 'ip addr show {netdevice.device_name}'
CMD_SET_IP4_ADDRESS = 'ip addr add dev {netdevice.device_name} ' \
- '{netdevice.ip4_address} brd + || true'
+ '{netdevice.ip4_address}/{netdevice.ip4_address.prefix_len} brd + || true'
CMD_SET_IP6_ADDRESS = 'ip addr add dev {netdevice.device_name} ' \
- '{netdevice.ip6_address}/{netdevice.ip6_prefix} || true'
+ '{netdevice.ip6_address}/{netdevice.ip6_address.prefix_len} || true'
CMD_SET_PROMISC = 'ip link set dev {netdevice.device_name} promisc {on_off}'
-CMD_SET_UP = 'ip link set {netdevice.device_name} {up_down}'
+CMD_SET_UP = 'ip link set {netdevice.device_name} {state}'
CMD_SET_CAPACITY='\n'.join([
'tc qdisc del dev {netdevice.device_name} root || true',
'tc qdisc add dev {netdevice.device_name} root handle 1: tbf rate '
@@ -92,6 +94,10 @@ CMD_UNSET_IP6_FWD = 'sysctl -w net.ipv6.conf.{netdevice.device_name}.forwarding=
CMD_SET_IP6_FWD = 'sysctl -w net.ipv6.conf.{netdevice.device_name}.forwarding=1'
CMD_GET_IP6_FWD = 'sysctl -n net.ipv6.conf.{netdevice.device_name}.forwarding'
+DEFAULT_IP4_PREFIX_LEN = 31
+DEFAULT_IP6_PREFIX_LEN = 64
+
+NetDeviceName = String.restrict(max_size = MAX_DEVICE_NAME_SIZE)
#-------------------------------------------------------------------------------
@@ -265,22 +271,20 @@ def parse_ip_addr(data):
#------------------------------------------------------------------------------
-class BaseNetDevice(Interface, Application):
+class NetDevice(Interface, Application):
__type__ = BaseResource
# XXX note: ethtool only required if we need to get the pci address
__package_names__ = ['ethtool']
- device_name = Attribute(String, description = 'Name of the NetDevice',
- default = lambda x : x._default_device_name(),
- max_size = MAX_DEVICE_NAME_SIZE)
+ device_name = Attribute(NetDeviceName, description = 'Name of the NetDevice',
+ default = lambda x : x._default_device_name())
capacity = Attribute(Integer,
- description = 'Capacity for interface shaping (Mb/s)')
+ description = 'Capacity for interface shaping (Mb/s)',
+ default = None)
mac_address = Attribute(String, description = 'Mac address of the device')
- ip4_address = Attribute(String, description = 'IP address of the device')
- ip4_prefix = Attribute(Integer, description = 'Prefix for the IPv4link', default=31) #XXX 31?
- ip6_address = Attribute(String, description = 'IPv6 address of the device')
- ip6_prefix = Attribute(Integer, description = 'Prefix for the IPv6 link', default=64)
+ ip4_address = Attribute(Inet4Address, description = 'IP address of the device')
+ ip6_address = Attribute(Inet6Address, description = 'IPv6 address of the device')
ip6_forwarding = Attribute(Bool, description = 'IPv6 forwarding', default = True)
pci_address = Attribute(String,
description = 'PCI bus address of the device',
@@ -308,6 +312,7 @@ class BaseNetDevice(Interface, Application):
# Resource lifecycle
#--------------------------------------------------------------------------
+ @inherit_parent
def __get__(self):
def check(rv):
if not bool(rv):
@@ -315,8 +320,11 @@ class BaseNetDevice(Interface, Application):
return BashTask(self.node, CMD_GET, {'netdevice' : self}, output=True,
parse=check)
- __create__ = None
+ @inherit_parent
+ def __create__(self):
+ return BashTask(self.node, CMD_CREATE, {'netdevice': self})
+ @inherit_parent
def __delete__(self):
return BashTask(self.node, CMD_DELETE, {'netdevice': self})
@@ -369,7 +377,7 @@ class BaseNetDevice(Interface, Application):
if len(ips) > 1:
log.warning('Keeping only first of many IP addresses...')
ip = ips[0]
- attrs['ip4_address'] = ip['ip-address']
+ attrs['ip4_address'] = Inet4Address(ip['ip-address'], DEFAULT_IP4_PREFIX_LEN)
else:
attrs['ip4_address'] = None
return attrs
@@ -413,8 +421,7 @@ class BaseNetDevice(Interface, Application):
if len(ips) > 1:
log.warning('Keeping only first of many IPv6 addresses...')
ip = ips[0]
- attrs['ip6_address'] = ip['ip-address']
- attrs['ip6_prefix'] = ip['prefix']
+ attrs['ip6_address'] = Inet6Address(ip_address = ip['ip-address'], prefix_len = ip['prefix'])
else:
attrs['ip6_address'] = None
return attrs
@@ -457,9 +464,9 @@ class BaseNetDevice(Interface, Application):
return {'up': False}
def _set_up(self):
- up_down = 'up' if self.up else 'down'
+ state = 'up' if self.up else 'down'
return BashTask(self.node, CMD_SET_UP,
- {'netdevice': self, 'up_down': up_down})
+ {'netdevice': self, 'state': state})
@task
def _get_capacity(self):
@@ -526,7 +533,7 @@ class BaseNetDevice(Interface, Application):
#------------------------------------------------------------------------------
-class NonTapBaseNetDevice(BaseNetDevice):
+class NonTapBaseNetDevice(NetDevice):
# Tap devices for instance don't have offload
offload = Attribute(Bool, description = 'Offload', default=True)
@@ -534,59 +541,34 @@ class NonTapBaseNetDevice(BaseNetDevice):
# Attributes
#--------------------------------------------------------------------------
- def __init__(self, *args, **kwargs):
- super().__init__(*args, **kwargs)
-
def _get_offload(self):
return BashTask(self.node, CMD_GET_OFFLOAD, {'netdevice': self},
parse = lambda rv : rv.stdout.strip() == 'on')
def _set_offload(self):
- cmd = None
- if self.offload:
- cmd = CMD_SET_OFFLOAD
- else:
- cmd = CMD_UNSET_OFFLOAD
+ cmd = CMD_SET_OFFLOAD if self.offload else CMD_UNSET_OFFLOAD
return BashTask(self.node, cmd, {'netdevice' : self})
#------------------------------------------------------------------------------
-class NetDevice(NonTapBaseNetDevice):
-
- #--------------------------------------------------------------------------
- # Resource lifecycle
- #--------------------------------------------------------------------------
-
- def __create__(self):
- return BashTask(self.node, CMD_CREATE, {'netdevice': self})
-
-#------------------------------------------------------------------------------
-
-class SlaveBaseNetDevice(BaseNetDevice):
+class SlaveNetDevice(NetDevice):
parent = Attribute(NetDevice, description = 'Parent NetDevice')
- host = Attribute(NetDevice, description = 'Host interface',
- default = lambda x : x._default_host())
-
- def _default_host(self):
- if self.node.__class__.__name__ == 'LxcContainer':
- host = self.node.node
- else:
- host = self.node
- max_len = MAX_DEVICE_NAME_SIZE - len(self.node.name) - 1
- device_name = self.device_name[:max_len]
-
- return NetDevice(node = host,
- device_name = '{}-{}'.format(self.node.name, device_name),
- managed = False)
-
-#------------------------------------------------------------------------------
-
-class SlaveNetDevice(SlaveBaseNetDevice):
-
- #--------------------------------------------------------------------------
- # Resource lifecycle
- #--------------------------------------------------------------------------
+# host = Attribute(NetDevice, description = 'Host interface',
+# default = lambda x : x._default_host())
+#
+# def _default_host(self):
+# if self.node.__class__.__name__ == 'LxcContainer':
+# host = self.node.node
+# else:
+# host = self.node
+# max_len = MAX_DEVICE_NAME_SIZE - len(self.node.name) - 1
+# device_name = self.device_name[:max_len]
+#
+# return NetDevice(node = host,
+# device_name = '{}-{}'.format(self.node.name, device_name),
+# managed = False)
+ @override_parent
def __create__(self):
return BashTask(self.node, CMD_CREATE_PARENT, {'netdevice': self})
diff --git a/vicn/resource/linux/netmon.py b/vicn/resource/linux/netmon.py
index 8472f308..9c5c97fd 100644
--- a/vicn/resource/linux/netmon.py
+++ b/vicn/resource/linux/netmon.py
@@ -25,5 +25,5 @@ class NetMon(Service):
Generic network monitoring daemon, used internally by VICN for resource
monitoring.
"""
- __package_names__ = ['netmon']
+ __package_names__ = [] # XXX transition 'netmon']
__service_name__ = 'netmon'
diff --git a/vicn/resource/linux/ovs.py b/vicn/resource/linux/ovs.py
index d67e4bca..c0b57151 100644
--- a/vicn/resource/linux/ovs.py
+++ b/vicn/resource/linux/ovs.py
@@ -46,12 +46,12 @@ class OVS(BridgeManager):
#---------------------------------------------------------------------------
def add_bridge(self, bridge_name):
- return BashTask(self.node, CMD_ADD_BRIDGE,
+ return BashTask(self.node, CMD_ADD_BRIDGE,
{'bridge_name': bridge_name},
output = False, as_root = True)
def del_bridge(self, bridge_name):
- return BashTask(self.node, CMD_DEL_BRIDGE,
+ return BashTask(self.node, CMD_DEL_BRIDGE,
{'bridge_name': bridge_name},
output = False, as_root = True)
@@ -62,7 +62,7 @@ class OVS(BridgeManager):
output = False, as_root = True)
def del_interface(self, bridge_name, interface_name, vlan=None):
- return BashTask(self.node, CMD_DEL_INTERFACE,
+ return BashTask(self.node, CMD_DEL_INTERFACE,
{'bridge_name': bridge_name, 'interface_name': interface_name,
'vlan': vlan},
output = False, as_root = True)
diff --git a/vicn/resource/linux/package_manager.py b/vicn/resource/linux/package_manager.py
index 93241502..04a47986 100644
--- a/vicn/resource/linux/package_manager.py
+++ b/vicn/resource/linux/package_manager.py
@@ -19,13 +19,14 @@
import asyncio
import logging
+from netmodel.model.key import Key
from netmodel.model.type import String, Bool
from vicn.core.attribute import Attribute, Multiplicity
from vicn.core.exception import ResourceNotFound
from vicn.core.requirement import Requirement
from vicn.core.resource import Resource
from vicn.core.task import BashTask, EmptyTask, async_task
-from vicn.core.task import inline_task, run_task
+from vicn.core.task import inline_task, run_task, inherit_parent
from vicn.resource.node import Node
log = logging.getLogger(__name__)
@@ -78,12 +79,13 @@ class PackageManager(Resource):
reverse_name = 'package_manager',
reverse_auto = True,
mandatory = True,
- key = True,
multiplicity = Multiplicity.OneToOne)
trusted = Attribute(Bool,
description="Force repository trust",
default=False)
+ __key__ = Key(node)
+
#--------------------------------------------------------------------------
# Constructor and Accessors
#--------------------------------------------------------------------------
@@ -100,6 +102,7 @@ class PackageManager(Resource):
def __after__(self):
return ('Repository',)
+ @inherit_parent
@inline_task
def __get__(self):
raise ResourceNotFound
@@ -182,21 +185,25 @@ class Package(Resource):
package_name = Attribute(String, mandatory = True)
node = Attribute(Node,
mandatory = True,
- key = True,
requirements=[
Requirement('package_manager')
])
+ __key__ = Key(node)
+
#---------------------------------------------------------------------------
# Resource lifecycle
#---------------------------------------------------------------------------
+ @inherit_parent
def __get__(self):
return BashTask(self.node, CMD_PKG_TEST, {'self': self})
+ @inherit_parent
def __create__(self):
return self.node.package_manager.__method_install__(self.package_name)
+ @inherit_parent
@async_task
async def __delete__(self):
with await self.node.package_manager._lock:
@@ -218,15 +225,17 @@ class Packages(Resource):
names = Attribute(String, multiplicity = Multiplicity.OneToMany)
node = Attribute(Node,
mandatory = True,
- key = True,
requirements=[
Requirement('package_manager')
])
+ __key__ = Key(node)
+
#---------------------------------------------------------------------------
# Resource lifecycle
#---------------------------------------------------------------------------
+ @inherit_parent
def __subresources__(self):
"""
Note: Although packages are (rightfully) specified concurrent, apt tasks
diff --git a/vicn/resource/linux/phy_interface.py b/vicn/resource/linux/phy_interface.py
index 81d2950c..8d7f02c8 100644
--- a/vicn/resource/linux/phy_interface.py
+++ b/vicn/resource/linux/phy_interface.py
@@ -16,7 +16,8 @@
# limitations under the License.
#
-from netmodel.model.type import String
+from netmodel.model.type import String, Integer
+from netmodel.model.type import Inet4Address, Inet6Address
from vicn.core.attribute import Attribute
from vicn.core.resource import BaseResource
from vicn.resource.interface import Interface
@@ -34,17 +35,6 @@ class PhyInterface(Interface):
mandatory = True)
pci_address = Attribute(String, description = "Device's PCI bus address",
mandatory = True)
- mac_address = Attribute(String, description = "Device's MAC address",
- mandatory=True)
- ip4_address = Attribute(String, description = "Device's IP address")
- ip6_address = Attribute(String, description = "Device's IP address")
-
- #--------------------------------------------------------------------------
- # Constructor and Accessors
- #--------------------------------------------------------------------------
-
- def __init__(self, *args, **kwargs):
- super().__init__(*args, **kwargs)
-
- if not self.name:
- self.name = self.node.name + '-' + self.device_name
+ mac_address = Attribute(String, description = "Device's MAC address")
+ ip4_address = Attribute(Inet4Address, description = "Device's IP address")
+ ip6_address = Attribute(Inet6Address, description = "Device's IP address")
diff --git a/vicn/resource/linux/phy_link.py b/vicn/resource/linux/phy_link.py
index 878cf7c6..2976b7f0 100644
--- a/vicn/resource/linux/phy_link.py
+++ b/vicn/resource/linux/phy_link.py
@@ -16,10 +16,12 @@
# limitations under the License.
#
-from vicn.core.attribute import Attribute
-from vicn.core.task import inline_task
+from vicn.core.attribute import Attribute, Reference
+from vicn.core.task import inline_task, async_task
+from vicn.core.task import inherit_parent
from vicn.resource.channel import Channel
from vicn.resource.linux.phy_interface import PhyInterface
+from vicn.resource.vpp.interface import VPPInterface
class PhyLink(Channel):
"""
@@ -28,12 +30,53 @@ class PhyLink(Channel):
Physical Link to inform the orchestrator about Layer2 connectivity.
"""
- src = Attribute(PhyInterface, description = 'Source interface',
+ src = Attribute(PhyInterface, description = 'Source interface',
mandatory = True)
- dst = Attribute(PhyInterface, description = 'Destination interface',
+ dst = Attribute(PhyInterface, description = 'Destination interface',
mandatory = True)
+ @inherit_parent
@inline_task
def __initialize__(self):
self.src.set('channel', self)
self.dst.set('channel', self)
+
+ #--------------------------------------------------------------------------
+ # Internal methods
+ #--------------------------------------------------------------------------
+
+ async def _commit(self):
+ manager = self._state.manager
+
+ # Disable rp_filtering
+ # self.src.rp_filter = False
+ # self.dst.rp_filter = False
+
+ #XXX VPP
+ vpp_src = VPPInterface(parent = self.src,
+ vpp = self.src.node.vpp,
+ ip4_address = Reference(self.src, 'ip4_address'),
+ ip6_address = Reference(self.src, 'ip6_address'),
+ device_name = self.src.device_name)
+ manager.commit_resource(vpp_src)
+
+
+ vpp_dst = VPPInterface(parent = self.dst,
+ vpp = self.dst.node.vpp,
+ ip4_address = Reference(self.dst, 'ip4_address'),
+ ip6_address = Reference(self.dst, 'ip6_address'),
+ device_name = self.dst.device_name)
+ manager.commit_resource(vpp_dst)
+
+ #--------------------------------------------------------------------------
+ # Resource lifecycle
+ #--------------------------------------------------------------------------
+
+ def __get__(self):
+ return async_task(self._commit)()
+
+ def __create__(self):
+ assert self.src.node.get_type() == 'lxccontainer'
+ assert self.dst.node.get_type() == 'lxccontainer'
+
+ return async_task(self._commit)()
diff --git a/vicn/resource/linux/physical.py b/vicn/resource/linux/physical.py
index f71b5856..c058ff16 100644
--- a/vicn/resource/linux/physical.py
+++ b/vicn/resource/linux/physical.py
@@ -29,6 +29,7 @@ from vicn.core.attribute import Attribute
from vicn.core.commands import Command, ReturnValue
from vicn.core.exception import ResourceNotFound, VICNException
from vicn.core.task import Task, task, EmptyTask
+from vicn.core.task import inherit_parent
from vicn.resource.linux.keypair import Keypair
from vicn.resource.node import Node, DEFAULT_USERNAME
from vicn.resource.node import DEFAULT_SSH_PUBLIC_KEY
@@ -71,14 +72,16 @@ class Physical(Node):
# Resource lifecycle
#--------------------------------------------------------------------------
+ @inherit_parent
def __subresources__(self):
"""
Require a SSH keypair to be present for authentication on nodes
"""
return Keypair(node = self, key = FN_KEY)
+ @inherit_parent
def __initialize__(self):
- if not is_local_host(self.hostname):
+ if self.managed and not is_local_host(self.hostname):
"""
Initialization require the ssh port to be open on the node, and the ssh
public key to be copied on the remote node.
@@ -124,6 +127,7 @@ class Physical(Node):
p = subprocess.Popen(shlex.split(command), stdout=subprocess.PIPE)
if output:
out, err = p.communicate()
+ #print('error {}, output {}'.format(err,out))
return ReturnValue(p.returncode, stdout=out, stderr=err)
p.wait()
diff --git a/vicn/resource/linux/qtplayer.py b/vicn/resource/linux/qtplayer.py
new file mode 100644
index 00000000..44b10ccf
--- /dev/null
+++ b/vicn/resource/linux/qtplayer.py
@@ -0,0 +1,5 @@
+from vicn.resource.linux.application import LinuxApplication
+
+class QtPlayer(LinuxApplication):
+ pass
+
diff --git a/vicn/resource/linux/repository.py b/vicn/resource/linux/repository.py
index cd740d38..f07421ba 100644
--- a/vicn/resource/linux/repository.py
+++ b/vicn/resource/linux/repository.py
@@ -31,14 +31,14 @@ class Repository(Application):
part of any basic distribution install.
"""
- repo_name = Attribute(String, description = 'Name of the repository',
+ repo_name = Attribute(String, description = 'Name of the repository',
default = 'vicn')
- directory = Attribute(String, description = 'Directory holding packages',
+ directory = Attribute(String, description = 'Directory holding packages',
default = '')
sections = Attribute(String, description = 'Sections',
multiplicity = Multiplicity.OneToMany,
default = [])
- distributions = Attribute(String,
+ distributions = Attribute(String,
description = 'List of distributions served by this repository',
multiplicity = Multiplicity.ManyToMany,
default = ['sid', 'trusty', 'xenial'])
diff --git a/vicn/resource/linux/service.py b/vicn/resource/linux/service.py
index 3eb753fc..1143461a 100644
--- a/vicn/resource/linux/service.py
+++ b/vicn/resource/linux/service.py
@@ -21,6 +21,7 @@ import logging
from vicn.core.exception import ResourceNotFound
from vicn.core.resource import CategoryResource
from vicn.core.task import inline_task, BashTask, EmptyTask
+from vicn.core.task import inherit_parent
from vicn.resource.linux.application import LinuxApplication
log = logging.getLogger(__name__)
@@ -51,33 +52,33 @@ class Service(LinuxApplication):
__type__ = CategoryResource
-
+ @inherit_parent
@inline_task
def __get__(self):
raise ResourceNotFound
-
+
def __method_restart__(self):
- return BashTask(self.node, CMD_RESTART,
+ return BashTask(self.node, CMD_RESTART,
{'service_name': self.__service_name__})
-
+
def __method_start__(self):
return BashTask(self.node, CMD_START,
{'service_name': self.__service_name__})
-
- def __create__(self):
- if self.__service_name__ == 'lxd':
- log.warning('Not restarting LXD')
- return EmptyTask()
+ def __method_stop__(self):
+ return BashTask(self.node, CMD_STOP,
+ {'service_name': self.__service_name__})
- if self.__service_name__ == 'dnsmasq':
- return BashTask(self.node, CMD_STOP_START,
- {'service_name': self.__service_name__})
+ def __method_stop_start(self):
+ return BashTask(self.node, CMD_STOP_START,
+ {'service_name': self.__service_name__})
+ @inherit_parent
+ def __create__(self):
return self.__method_restart__()
-
+ @inherit_parent
def __delete__(self):
- return BashTask(self.node, CMD_STOP,
+ return BashTask(self.node, CMD_STOP,
{'service_name': self.__service_name__})
diff --git a/vicn/resource/linux/sym_veth_pair.py b/vicn/resource/linux/sym_veth_pair.py
index bf79a69b..ebfe2968 100644
--- a/vicn/resource/linux/sym_veth_pair.py
+++ b/vicn/resource/linux/sym_veth_pair.py
@@ -26,12 +26,12 @@ from vicn.core.resource import Resource
from vicn.core.state import ResourceState, AttributeState
from vicn.core.task import BashTask, get_attributes_task
from vicn.core.task import async_task, task, inline_task
-from vicn.core.task import run_task
+from vicn.core.task import run_task, inherit_parent
from vicn.resource.interface import Interface
from vicn.resource.node import Node
from vicn.resource.linux.net_device import NonTapBaseNetDevice
from vicn.resource.linux.link import CMD_DELETE_IF_EXISTS
-from vicn.resource.linux.link import CMD_UP
+from vicn.resource.linux.link import CMD_SET_UP
CMD_CREATE='''
# Create veth pair in the host node
@@ -48,13 +48,13 @@ class SymVethPair(Resource):
resource is that is it not a channel.
"""
- node1 = Attribute(Node,
+ node1 = Attribute(Node,
description = 'Node on which one side of the veth will sit',
mandatory = True)
- node2 = Attribute(Node,
+ node2 = Attribute(Node,
description = 'Node on which the other side of the veth will sit',
mandatory = True)
- capacity = Attribute(Integer,
+ capacity = Attribute(Integer,
description = 'Capacity of the veth pair (Mb/s)')
side1 = Attribute(Interface, description = 'Source interface')
side2 = Attribute(Interface, description = 'Destination interface')
@@ -66,21 +66,22 @@ class SymVethPair(Resource):
async def _commit(self):
# see link.py for explanations
manager = self._state.manager
- await manager._set_resource_state(self.side1,
+ await manager._set_resource_state(self.side1,
ResourceState.INITIALIZED)
- await manager._set_resource_state(self.side2,
+ await manager._set_resource_state(self.side2,
ResourceState.INITIALIZED)
await manager._set_resource_state(self.side1, ResourceState.CREATED)
await manager._set_resource_state(self.side2, ResourceState.CREATED)
await manager._set_attribute_state(self, 'side1', AttributeState.CLEAN)
await manager._set_attribute_state(self, 'side2', AttributeState.CLEAN)
manager.commit_resource(self.side1)
- manager.commit_resource(self.side2)
+ manager.commit_resource(self.side2)
#--------------------------------------------------------------------------
# Resource lifecycle
#--------------------------------------------------------------------------
+ @inherit_parent
@inline_task
def __initialize__(self):
self.side1 = NonTapBaseNetDevice(node = self.node1,
@@ -94,6 +95,7 @@ class SymVethPair(Resource):
self.side1.remote = self.side2
self.side2.remote = self.side1
+ @inherit_parent
@async_task
async def __get__(self):
manager = self._state.manager
@@ -106,46 +108,48 @@ class SymVethPair(Resource):
await self._commit()
+ @inherit_parent
def __create__(self):
assert self.node1.get_type() == 'lxccontainer'
assert self.node2.get_type() == 'lxccontainer'
-
+
node1_host = self.node1.node
node2_host = self.node2.node
-
+
assert node1_host == node2_host
host = node1_host
-
+
# Sometimes a down interface persists on one side
- delif_side1 = BashTask(self.node1, CMD_DELETE_IF_EXISTS,
+ delif_side1 = BashTask(self.node1, CMD_DELETE_IF_EXISTS,
{'interface': self.side1})
- delif_side2 = BashTask(self.node2, CMD_DELETE_IF_EXISTS,
+ delif_side2 = BashTask(self.node2, CMD_DELETE_IF_EXISTS,
{'interface': self.side2})
-
+
pid_node1 = get_attributes_task(self.node1, ['pid'])
pid_node2 = get_attributes_task(self.node2, ['pid'])
-
+
tmp_side1 = 'tmp-veth-' + ''.join(random.choice(
string.ascii_uppercase + string.digits) for _ in range(5))
tmp_side2 = 'tmp-veth-' + ''.join(random.choice(
string.ascii_uppercase + string.digits) for _ in range(5))
-
- create = BashTask(host, CMD_CREATE,
+
+ create = BashTask(host, CMD_CREATE,
{'side1_device_name': self.side1.device_name,
- 'side2_device_name': self.side2.device_name,
+ 'side2_device_name': self.side2.device_name,
'tmp_side1': tmp_side1, 'tmp_side2': tmp_side2})
-
- up_side1 = BashTask(self.node1, CMD_UP, {'interface': self.side1})
- up_side2 = BashTask(self.node2, CMD_UP, {'interface': self.side2})
-
+
+ up_side1 = BashTask(self.node1, CMD_SET_UP, {'interface': self.side1})
+ up_side2 = BashTask(self.node2, CMD_SET_UP, {'interface': self.side2})
+
@async_task
async def set_state():
await self._commit()
-
+
delif = delif_side1 | delif_side2
up = up_side1 | up_side2
pid = pid_node1 | pid_node2
return ((delif > (pid @ create)) > up) > set_state()
-
+
+ @inherit_parent
def __delete__(self):
raise NotImplementedError
diff --git a/vicn/resource/linux/tap_device.py b/vicn/resource/linux/tap_device.py
index b7c9f967..88ca055d 100644
--- a/vicn/resource/linux/tap_device.py
+++ b/vicn/resource/linux/tap_device.py
@@ -18,39 +18,22 @@
from netmodel.model.type import String
from vicn.core.attribute import Attribute
-from vicn.core.task import BashTask
-from vicn.resource.linux.net_device import BaseNetDevice, IPV4, IPV6, CMD_FLUSH_IP
+from vicn.core.task import BashTask, override_parent
+from vicn.resource.linux.net_device import NetDevice, IPV4, IPV6, CMD_FLUSH_IP
CMD_CREATE='ip tuntap add name {netdevice.device_name} mode tap'
-#CMD_SET_IP_ADDRESS='ip -{version} addr add dev {netdevice.device_name} 0.0.0.0'
-class TapDevice(BaseNetDevice):
+class TapDevice(NetDevice):
def __init__(self, *args, **kwargs):
super().__init__(self, *args, **kwargs)
self.prefix = 'tap'
self.netdevice_type = 'tap'
+ @override_parent
def __create__(self):
return BashTask(self.node, CMD_CREATE, {'netdevice': self})
-##mengueha: do we actually need that?
-# def _set_ip4_address(self):
-# if self.ip4_address is None:
-# # Unset IP
-# return BashTask(self.node, CMD_FLUSH_IP,
-# {'device_name': self.device_name})
-# return BashTask(self.node, CMD_SET_IP_ADDRESS,
-# {'netdevice': self})
-#
-# def _set_ip6_address(self):
-# if self.ip6_address is None:
-# # Unset IP
-# return BashTask(self.node, CMD_FLUSH_IP,
-# {'ip_version': IPV6, 'device_name': self.device_name})
-# return BashTask(self.node, CMD_SET_IP_ADDRESS,
-# {'netdevice': self})
-
class TapChannel(TapDevice):
station_name = Attribute(String)
channel_name = Attribute(String)
diff --git a/vicn/resource/linux/veth_pair.py b/vicn/resource/linux/veth_pair.py
index 53fa9bf8..52050074 100644
--- a/vicn/resource/linux/veth_pair.py
+++ b/vicn/resource/linux/veth_pair.py
@@ -15,48 +15,82 @@
# See the License for the specific language governing permissions and
# limitations under the License.
#
-import random
-import string
-from vicn.resource.linux.net_device import SlaveBaseNetDevice
-from vicn.core.task import BashTask, get_attributes_task
-
-# ip link add veth0 type veth peer name veth1
+from netmodel.model.key import Key
+from netmodel.model.type import String, Bool
+from vicn.core.attribute import Attribute, Reference
+from vicn.core.task import BashTask, inline_task, get_attributes_task
+from vicn.resource.linux.net_device import NetDevice, NetDeviceName
+from vicn.resource.node import Node
+from vicn.resource.symmetric_channel import SymmetricChannel
CMD_CREATE='''
# Create veth pair in the host node
-ip link add name {interface.host.device_name} type veth peer name {tmp_name}
+ip link add name {self.device_name} type veth peer name {self.peer_device_name}
+'''
+
+DEPRECATED_CMD_UP='''
# The host interface will always be up...
ip link set dev {interface.host.device_name} up
+
# Move interface into container and rename it
ip link set dev {tmp_name} netns {pid} name {interface.device_name}
-'''
-CMD_UP='''
ip link set dev {interface.device_name} up
'''
-# see:
-# http://stackoverflow.com/questions/22780927/lxc-linux-containers-add-new-network-interface-without-restarting
+# Forward declaration
+class VethPair(SymmetricChannel):
+ pass
+
+class VethNetDevice(NetDevice):
+ parent = Attribute(VethPair, mandatory = True, ro = True)
-class VethPair(SlaveBaseNetDevice):
- # Do not need the parent attribute...
+ __get__ = None
+ __create__ = None
+ __delete__ = None
- def __init__(self, *args, **kwargs):
- super().__init__(self, *args, **kwargs)
- self.prefix = 'veth'
- self.netdevice_type = 'veth'
+class VethPair(SymmetricChannel):
+ # Mimics NetDevice for using its __get__ and __delete__ functions
+ node = Attribute(Node)
+ device_name = Attribute(NetDeviceName)
+ peer_device_name = Attribute(NetDeviceName)
+ capacity = Attribute(String)
+ src = Attribute(ro = True, mandatory = False)
+ dst = Attribute(ro = True, mandatory = False)
+ auto_commit = Attribute(Bool, description = 'Auto commit interfaces')
+
+ __key1__ = Key(node, device_name)
+ __key2__ = Key(node, peer_device_name)
+
+ @inline_task
+ def _commit(self):
+ if self.auto_commit:
+ manager = self._state.manager
+
+ manager.commit_resource(self.src)
+ manager.commit_resource(self.dst)
+
+ def __initialize__(self):
+ # XXX owner prevents the resource to be committed
+ self.src = VethNetDevice(node = self.node,
+ parent = self,
+ device_name = self.device_name,
+ channel = self,
+ capacity = Reference(self, 'capacity'),
+ owner = self)
+ self.dst = VethNetDevice(node = self.node,
+ parent = self,
+ device_name = self.peer_device_name,
+ channel = self,
+ capacity = Reference(self, 'capacity'),
+ owner = self)
def __create__(self):
- assert self.node.__class__.__name__ == 'LxcContainer'
- host = self.node.node
- pid = get_attributes_task(self.node, ['pid'])
- tmp_name = 'tmp-veth-' + ''.join(random.choice(string.ascii_uppercase \
- + string.digits) for _ in range(5))
- create = BashTask(host, CMD_CREATE, {'tmp_name': tmp_name,
- 'interface': self})
- up = BashTask(self.node, CMD_UP, {'interface': self})
- bridge = host.bridge_manager.add_interface(host.bridge.device_name,
- self.host.device_name)
- return ((pid @ create) > up) > bridge
-
- # ... IP and UP missing...
+ veth = BashTask(self.node, CMD_CREATE, {'self': self})
+ return (veth > super().__create__()) > self._commit()
+
+ def __get__(self):
+ return NetDevice.__get__(self) > self._commit()
+
+ def __delete__(self):
+ return NetDevice.__delete__(self)
diff --git a/vicn/resource/linux/veth_pair_lxc.py b/vicn/resource/linux/veth_pair_lxc.py
new file mode 100644
index 00000000..dd26b7bb
--- /dev/null
+++ b/vicn/resource/linux/veth_pair_lxc.py
@@ -0,0 +1,74 @@
+#!/usr/bin/env python3
+# -*- coding: utf-8 -*-
+#
+# Copyright (c) 2017 Cisco and/or its affiliates.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at:
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+import random
+import string
+
+from vicn.core.attribute import Attribute
+from vicn.resource.linux.net_device import NetDevice, SlaveNetDevice
+from vicn.core.task import BashTask, get_attributes_task
+from vicn.core.task import override_parent
+from vicn.core.attribute import Attribute
+
+# ip link add veth0 type veth peer name veth1
+
+CMD_CREATE='''
+# Create veth pair in the host node
+ip link add name {interface.host.device_name} type veth peer name {tmp_name}
+# The host interface will always be up...
+ip link set dev {interface.host.device_name} up
+# Move interface into container and rename it
+ip link set dev {tmp_name} netns {pid} name {interface.device_name}
+'''
+CMD_UP='''
+ip link set dev {interface.device_name} up
+'''
+
+# see:
+# http://stackoverflow.com/questions/22780927/lxc-linux-containers-add-new-network-interface-without-restarting
+
+class VethPairLxc(SlaveNetDevice):
+
+ host = Attribute(NetDevice, description = 'Host interface',
+ default = lambda x : x._default_host())
+
+ def _default_host(self):
+ if self.node.__class__.__name__ == 'LxcContainer':
+ host = self.node.node
+ else:
+ host = self.node
+ max_len = MAX_DEVICE_NAME_SIZE - len(self.node.name) - 1
+ device_name = self.device_name[:max_len]
+
+ return NetDevice(node = host,
+ device_name = '{}-{}'.format(self.node.name, device_name),
+ managed = False)
+
+ def __create__(self):
+ assert self.node.__class__.__name__ == 'LxcContainer'
+ host = self.node.node
+ pid = get_attributes_task(self.node, ['pid'])
+ tmp_name = 'tmp-veth-' + ''.join(random.choice(string.ascii_uppercase \
+ + string.digits) for _ in range(5))
+ create = BashTask(host, CMD_CREATE, {'tmp_name': tmp_name,
+ 'interface': self})
+ up = BashTask(self.node, CMD_UP, {'interface': self})
+ bridge = host.bridge_manager.add_interface(host.bridge.device_name,
+ self.host.device_name)
+ return ((pid @ create) > up) > bridge
+
+ # ... IP and UP missing...