diff options
Diffstat (limited to 'vicn/resource/lxd/lxc_container.py')
-rw-r--r-- | vicn/resource/lxd/lxc_container.py | 69 |
1 files changed, 54 insertions, 15 deletions
diff --git a/vicn/resource/lxd/lxc_container.py b/vicn/resource/lxd/lxc_container.py index 8c8b4816..5b1d4e3b 100644 --- a/vicn/resource/lxd/lxc_container.py +++ b/vicn/resource/lxd/lxc_container.py @@ -32,9 +32,11 @@ from vicn.core.exception import ResourceNotFound from vicn.core.requirement import Requirement from vicn.core.resource_mgr import wait_resource_task from vicn.core.task import task, inline_task, BashTask, EmptyTask +from vicn.core.task import inherit_parent from vicn.resource.linux.net_device import NetDevice from vicn.resource.node import Node from vicn.resource.vpp.scripts import APPARMOR_VPP_PROFILE +from vicn.resource.lxd.lxc_image import LxcImage from vicn.resource.lxd.lxd_profile import LXD_PROFILE_DEFAULT_IFNAME log = logging.getLogger(__name__) @@ -54,9 +56,20 @@ CMD_GET_IP6_FWD = 'sysctl -n net.ipv6.conf.all.forwarding' CMD_NETWORK_DHCP='dhclient {container.management_interface.device_name}' +CMD_MOUNT_FOLDER=''' +lxc config device add {container.name} {device-name} disk source={host_path} path={container_path} +sleep 1 +''' + # Type: ContainerName -ContainerName = String(max_size = 64, ascii = True, - forbidden = ('/', ',', ':')) +# https://github.com/lxc/lxd/issues/1431 +# [...] all container names must be a valid hostname under the most +#restrictive definition of this, that is, maximum 63 characters, may not contain +#dots, may not start by a digit or dash, may not end by a dash and must be made +#entirely of letters, digits or hyphens. +# XXX better have a allowed property +ContainerName = String.restrict(max_size = 63, ascii = True, + forbidden = ('/', ',', ':', '_')) class LxcContainer(Node): """ @@ -93,9 +106,9 @@ class LxcContainer(Node): ]) profiles = Attribute(String, multiplicity = Multiplicity.OneToMany, default = ['vicn']) - image = Attribute(String, description = 'image', default = None) - is_image = Attribute(Bool, defaut = False) - pid = Attribute(Integer, description = 'PID of the container') + image = Attribute(LxcImage, description = 'image', default = None) + is_image = Attribute(Bool, default = False) + pid = Attribute(Integer, description = 'PID of the container', ro = True) ip6_forwarding = Attribute(Bool, default=True) #-------------------------------------------------------------------------- @@ -110,6 +123,7 @@ class LxcContainer(Node): # Resource lifecycle #-------------------------------------------------------------------------- + @inherit_parent @inline_task def __initialize__(self): """ @@ -128,6 +142,7 @@ class LxcContainer(Node): if iface.get_type() == "dpdkdevice": self.node.vpp_host.dpdk_devices.append(iface.pci_address) + @inherit_parent @task def __get__(self): client = self.node.lxd_hypervisor.client @@ -136,6 +151,7 @@ class LxcContainer(Node): except pylxd.exceptions.NotFound: raise ResourceNotFound + @inherit_parent def __create__(self): """ Make sure vpp_host is instanciated before starting the container. @@ -153,6 +169,7 @@ class LxcContainer(Node): def _create_container(self): container = self._get_container_description() log.debug('Container description: {}'.format(container)) + print('Container description: {}'.format(container)) client = self.node.lxd_hypervisor.client self._container = client.containers.create(container, wait=True) @@ -188,13 +205,13 @@ class LxcContainer(Node): # SOURCE image_names = [alias['name'] for alias in self.node.lxd_hypervisor.aliases] - image_exists = self.image is not None and self.image in image_names + image_exists = self.image.image is not None and self.image.image in image_names if image_exists: container['source'] = { 'type' : 'image', 'mode' : 'local', - 'alias' : self.image, + 'alias' : self.image.image, } else: container['source'] = { @@ -234,6 +251,7 @@ class LxcContainer(Node): Method: Start the container """ self._container.start(wait = True) + import time; time.sleep(1) @task def __method_stop__(self): @@ -288,10 +306,35 @@ class LxcContainer(Node): """ if not self._container: - log.error("Executing command on uninitialized container", self, command) + log.error("Executing command on uninitialized container {} {}".format(self, command)) import os; os._exit(1) - ret = self._container.execute(shlex.split(command)) + if 'vppctl_wrapper' in command: + vpp_log = '{}/vpp-{}.sh'.format(self._state.manager._base, self.name) + with open(vpp_log, 'a') as f: + print("lxc exec {} -- {}".format(self.name, command), file=f) + + # XXX Workaround: pylxd 2.2.3 buggy (w/ lxd 2.14) ? + # But this workaround is broken with lxd 2.15 and pylxd 2.2.4 works + # lxc exec freezes + #return self.node.execute('lxc exec {} -- {}'.format(self.name, command), + # output = output, as_root = as_root) + + print("lxc exec {} -- {}".format(self.name, command)) + while True: + try: + ret = self._container.execute(shlex.split(command)) + break + except pylxd.exceptions.NotFound: + print("=====> pylxd not found during {}".format(command)) + time.sleep(1) + except pylxd.exceptions.ClientConnectionFailed: + print("=====> pylxd connection failed during {}".format(command)) + time.sleep(1) + except requests.exceptions.SSLError: + print("=====> ssl error during {}".format(command)) + time.sleep(1) + # NOTE: pylxd documents the return value as a tuple, while it is in # fact a ContainerExecuteResult object @@ -306,12 +349,8 @@ class LxcContainer(Node): return ReturnValue(*args) def _get_ip6_forwarding(self): - def parse(rv): - ret = {"ip6_forwarding" : False} - if rv.stdout == "1": - ret["ip6_forwarding"] = True - return ret - return BashTask(self, CMD_GET_IP6_FWD, parse=parse) + return BashTask(self, CMD_GET_IP6_FWD, + parse = lambda rv: {'ip6_forwarding' : rv.stdout == "1"}) def _set_ip6_forwarding(self): cmd = CMD_SET_IP6_FWD if self.ip6_forwarding else CMD_UNSET_IP6_FWD |