diff options
Diffstat (limited to 'resources/libraries/python/ContainerUtils.py')
-rw-r--r-- | resources/libraries/python/ContainerUtils.py | 690 |
1 files changed, 362 insertions, 328 deletions
diff --git a/resources/libraries/python/ContainerUtils.py b/resources/libraries/python/ContainerUtils.py index b552e4d9e6..fc61eea3bd 100644 --- a/resources/libraries/python/ContainerUtils.py +++ b/resources/libraries/python/ContainerUtils.py @@ -16,21 +16,24 @@ """Library to manipulate Containers.""" -from string import Template from collections import OrderedDict, Counter +from io import open +from string import Template -from resources.libraries.python.ssh import SSH from resources.libraries.python.Constants import Constants +from resources.libraries.python.ssh import SSH from resources.libraries.python.topology import Topology, SocketType from resources.libraries.python.VppConfigGenerator import VppConfigGenerator -__all__ = ["ContainerManager", "ContainerEngine", "LXC", "Docker", "Container"] +__all__ = [ + u"ContainerManager", u"ContainerEngine", u"LXC", u"Docker", u"Container" +] -SUPERVISOR_CONF = '/etc/supervisor/supervisord.conf' +SUPERVISOR_CONF = u"/etc/supervisor/supervisord.conf" -class ContainerManager(object): +class ContainerManager: """Container lifecycle management class.""" def __init__(self, engine): @@ -43,8 +46,7 @@ class ContainerManager(object): try: self.engine = globals()[engine]() except KeyError: - raise NotImplementedError('{engine} is not implemented.'. - format(engine=engine)) + raise NotImplementedError(f"{engine} is not implemented.") self.containers = OrderedDict() def get_container_by_name(self, name): @@ -59,8 +61,7 @@ class ContainerManager(object): try: return self.containers[name] except KeyError: - raise RuntimeError('Failed to get container with name: {name}'. - format(name=name)) + raise RuntimeError(f"Failed to get container with name: {name}") def construct_container(self, **kwargs): """Construct container object on node with specified parameters. @@ -75,11 +76,13 @@ class ContainerManager(object): setattr(self.engine.container, key, kwargs[key]) # Set additional environmental variables - setattr(self.engine.container, 'env', - 'MICROSERVICE_LABEL={label}'.format(label=kwargs['name'])) + setattr( + self.engine.container, u"env", + f"MICROSERVICE_LABEL={kwargs[u'name']}" + ) # Store container instance - self.containers[kwargs['name']] = self.engine.container + self.containers[kwargs[u"name"]] = self.engine.container def construct_containers(self, **kwargs): """Construct 1..N container(s) on node with specified name. @@ -90,10 +93,10 @@ class ContainerManager(object): :param kwargs: Named parameters. :param kwargs: dict """ - name = kwargs['name'] - for i in range(kwargs['count']): + name = kwargs[u"name"] + for i in range(kwargs[u"count"]): # Name will contain ordinal suffix - kwargs['name'] = ''.join([name, str(i+1)]) + kwargs[u"name"] = u"".join([name, str(i+1)]) # Create container self.construct_container(i=i, **kwargs) @@ -163,9 +166,15 @@ class ContainerManager(object): :param kwargs: dict """ # Count number of DUTs based on node's host information - dut_cnt = len(Counter([self.containers[container].node['host'] - for container in self.containers])) - mod = len(self.containers)/dut_cnt + dut_cnt = len( + Counter( + [ + self.containers[container].node[u"host"] + for container in self.containers + ] + ) + ) + mod = len(self.containers) // dut_cnt for i, container in enumerate(self.containers): mid1 = i % mod + 1 @@ -173,36 +182,37 @@ class ContainerManager(object): sid1 = i % mod * 2 + 1 sid2 = i % mod * 2 + 2 self.engine.container = self.containers[container] - guest_dir = self.engine.container.mnt[0].split(':')[1] - - if chain_topology == 'chain': - self._configure_vpp_chain_l2xc(mid1=mid1, mid2=mid2, - sid1=sid1, sid2=sid2, - guest_dir=guest_dir, - **kwargs) - elif chain_topology == 'cross_horiz': - self._configure_vpp_cross_horiz(mid1=mid1, mid2=mid2, - sid1=sid1, sid2=sid2, - guest_dir=guest_dir, - **kwargs) - elif chain_topology == 'chain_functional': - self._configure_vpp_chain_functional(mid1=mid1, mid2=mid2, - sid1=sid1, sid2=sid2, - guest_dir=guest_dir, - **kwargs) - elif chain_topology == 'chain_ip4': - self._configure_vpp_chain_ip4(mid1=mid1, mid2=mid2, - sid1=sid1, sid2=sid2, - guest_dir=guest_dir, - **kwargs) - elif chain_topology == 'pipeline_ip4': - self._configure_vpp_pipeline_ip4(mid1=mid1, mid2=mid2, - sid1=sid1, sid2=sid2, - guest_dir=guest_dir, - **kwargs) + guest_dir = self.engine.container.mnt[0].split(u":")[1] + + if chain_topology == u"chain": + self._configure_vpp_chain_l2xc( + mid1=mid1, mid2=mid2, sid1=sid1, sid2=sid2, + guest_dir=guest_dir, **kwargs + ) + elif chain_topology == u"cross_horiz": + self._configure_vpp_cross_horiz( + mid1=mid1, mid2=mid2, sid1=sid1, sid2=sid2, + guest_dir=guest_dir, **kwargs + ) + elif chain_topology == u"chain_functional": + self._configure_vpp_chain_functional( + mid1=mid1, mid2=mid2, sid1=sid1, sid2=sid2, + guest_dir=guest_dir, **kwargs + ) + elif chain_topology == u"chain_ip4": + self._configure_vpp_chain_ip4( + mid1=mid1, mid2=mid2, sid1=sid1, sid2=sid2, + guest_dir=guest_dir, **kwargs + ) + elif chain_topology == u"pipeline_ip4": + self._configure_vpp_pipeline_ip4( + mid1=mid1, mid2=mid2, sid1=sid1, sid2=sid2, + guest_dir=guest_dir, **kwargs + ) else: - raise RuntimeError('Container topology {name} not implemented'. - format(name=chain_topology)) + raise RuntimeError( + f"Container topology {chain_topology} not implemented" + ) def _configure_vpp_chain_l2xc(self, **kwargs): """Configure VPP in chain topology with l2xc. @@ -212,13 +222,14 @@ class ContainerManager(object): """ self.engine.create_vpp_startup_config() self.engine.create_vpp_exec_config( - 'memif_create_chain_l2xc.exec', - mid1=kwargs['mid1'], mid2=kwargs['mid2'], - sid1=kwargs['sid1'], sid2=kwargs['sid2'], - socket1='{guest_dir}/memif-{c.name}-{sid1}'. - format(c=self.engine.container, **kwargs), - socket2='{guest_dir}/memif-{c.name}-{sid2}'. - format(c=self.engine.container, **kwargs)) + u"memif_create_chain_l2xc.exec", + mid1=kwargs[u"mid1"], mid2=kwargs[u"mid2"], + sid1=kwargs[u"sid1"], sid2=kwargs[u"sid2"], + socket1=f"{kwargs[u'guest_dir']}/memif-" + f"{self.engine.container.name}-{kwargs[u'sid1']}", + socket2=f"{kwargs[u'guest_dir']}/memif-" + f"{self.engine.container.name}-{kwargs[u'sid2']}" + ) def _configure_vpp_cross_horiz(self, **kwargs): """Configure VPP in cross horizontal topology (single memif). @@ -226,22 +237,23 @@ class ContainerManager(object): :param kwargs: Named parameters. :param kwargs: dict """ - if 'DUT1' in self.engine.container.name: + if u"DUT1" in self.engine.container.name: if_pci = Topology.get_interface_pci_addr( - self.engine.container.node, kwargs['dut1_if']) + self.engine.container.node, kwargs[u"dut1_if"]) if_name = Topology.get_interface_name( - self.engine.container.node, kwargs['dut1_if']) - if 'DUT2' in self.engine.container.name: + self.engine.container.node, kwargs[u"dut1_if"]) + if u"DUT2" in self.engine.container.name: if_pci = Topology.get_interface_pci_addr( - self.engine.container.node, kwargs['dut2_if']) + self.engine.container.node, kwargs[u"dut2_if"]) if_name = Topology.get_interface_name( - self.engine.container.node, kwargs['dut2_if']) + self.engine.container.node, kwargs[u"dut2_if"]) self.engine.create_vpp_startup_config_dpdk_dev(if_pci) self.engine.create_vpp_exec_config( - 'memif_create_cross_horizon.exec', - mid1=kwargs['mid1'], sid1=kwargs['sid1'], if_name=if_name, - socket1='{guest_dir}/memif-{c.name}-{sid1}'. - format(c=self.engine.container, **kwargs)) + u"memif_create_cross_horizon.exec", + mid1=kwargs[u"mid1"], sid1=kwargs[u"sid1"], if_name=if_name, + socket1=f"{kwargs[u'guest_dir']}/memif-" + f"{self.engine.container.name}-{kwargs[u'sid1']}" + ) def _configure_vpp_chain_functional(self, **kwargs): """Configure VPP in chain topology with l2xc (functional). @@ -251,14 +263,15 @@ class ContainerManager(object): """ self.engine.create_vpp_startup_config_func_dev() self.engine.create_vpp_exec_config( - 'memif_create_chain_functional.exec', - mid1=kwargs['mid1'], mid2=kwargs['mid2'], - sid1=kwargs['sid1'], sid2=kwargs['sid2'], - socket1='{guest_dir}/memif-{c.name}-{sid1}'. - format(c=self.engine.container, **kwargs), - socket2='{guest_dir}/memif-{c.name}-{sid2}'. - format(c=self.engine.container, **kwargs), - rx_mode='interrupt') + u"memif_create_chain_functional.exec", + mid1=kwargs[u"mid1"], mid2=kwargs[u"mid2"], + sid1=kwargs[u"sid1"], sid2=kwargs[u"sid2"], + socket1=f"{kwargs[u'guest_dir']}/memif-" + f"{self.engine.container.name}-{kwargs[u'sid1']}", + socket2=f"{kwargs[u'guest_dir']}/memif-" + f"{self.engine.container.name}-{kwargs[u'sid2']}", + rx_mode=u"interrupt" + ) def _configure_vpp_chain_ip4(self, **kwargs): """Configure VPP in chain topology with ip4. @@ -268,23 +281,24 @@ class ContainerManager(object): """ self.engine.create_vpp_startup_config() - vif1_mac = kwargs['tg_if1_mac'] \ - if (kwargs['mid1'] - 1) % kwargs['nodes'] + 1 == 1 \ - else '52:54:00:00:{0:02X}:02'.format(kwargs['mid1'] - 1) - vif2_mac = kwargs['tg_if2_mac'] \ - if (kwargs['mid2'] - 1) % kwargs['nodes'] + 1 == kwargs['nodes'] \ - else '52:54:00:00:{0:02X}:01'.format(kwargs['mid2'] + 1) + vif1_mac = kwargs[u"tg_if1_mac"] \ + if (kwargs[u"mid1"] - 1) % kwargs[u"nodes"] + 1 == 1 \ + else f"52:54:00:00:{(kwargs[u'mid1'] - 1):02X}:02" + vif2_mac = kwargs[u"tg_if2_mac"] \ + if (kwargs[u"mid2"] - 1) % kwargs[u"nodes"] + 1 == kwargs[u"nodes"]\ + else f"52:54:00:00:{(kwargs['mid2'] + 1):02X}:01" self.engine.create_vpp_exec_config( - 'memif_create_chain_ip4.exec', - mid1=kwargs['mid1'], mid2=kwargs['mid2'], - sid1=kwargs['sid1'], sid2=kwargs['sid2'], - socket1='{guest_dir}/memif-{c.name}-{sid1}'. - format(c=self.engine.container, **kwargs), - socket2='{guest_dir}/memif-{c.name}-{sid2}'. - format(c=self.engine.container, **kwargs), - mac1='52:54:00:00:{0:02X}:01'.format(kwargs['mid1']), - mac2='52:54:00:00:{0:02X}:02'.format(kwargs['mid2']), - vif1_mac=vif1_mac, vif2_mac=vif2_mac) + u"memif_create_chain_ip4.exec", + mid1=kwargs[u"mid1"], mid2=kwargs[u"mid2"], + sid1=kwargs[u"sid1"], sid2=kwargs[u"sid2"], + socket1=f"{kwargs[u'guest_dir']}/memif-" + f"{self.engine.container.name}-{kwargs[u'sid1']}", + socket2=f"{kwargs[u'guest_dir']}/memif-" + f"{self.engine.container.name}-{kwargs[u'sid2']}", + mac1=f"52:54:00:00:{kwargs[u'mid1']:02X}:01", + mac2=f"52:54:00:00:{kwargs[u'mid2']:02X}:02", + vif1_mac=vif1_mac, vif2_mac=vif2_mac + ) def _configure_vpp_pipeline_ip4(self, **kwargs): """Configure VPP in pipeline topology with ip4. @@ -293,40 +307,36 @@ class ContainerManager(object): :param kwargs: dict """ self.engine.create_vpp_startup_config() - node = (kwargs['mid1'] - 1) % kwargs['nodes'] + 1 - mid1 = kwargs['mid1'] - mid2 = kwargs['mid2'] - role1 = 'master' - role2 = 'master' \ - if node == kwargs['nodes'] or node == kwargs['nodes'] and node == 1\ - else 'slave' - kwargs['mid2'] = kwargs['mid2'] \ - if node == kwargs['nodes'] or node == kwargs['nodes'] and node == 1\ - else kwargs['mid2'] + 1 - vif1_mac = kwargs['tg_if1_mac'] \ - if (kwargs['mid1'] - 1) % kwargs['nodes'] + 1 == 1 \ - else '52:54:00:00:{0:02X}:02'.format(kwargs['mid1'] - 1) - vif2_mac = kwargs['tg_if2_mac'] \ - if (kwargs['mid2'] - 1) % kwargs['nodes'] + 1 == kwargs['nodes'] \ - else '52:54:00:00:{0:02X}:01'.format(kwargs['mid2'] + 1) - socket1 = '{guest_dir}/memif-{c.name}-{sid1}'.\ - format(c=self.engine.container, **kwargs) \ - if node == 1 else '{guest_dir}/memif-pipe-{mid1}'.\ - format(c=self.engine.container, **kwargs) - socket2 = '{guest_dir}/memif-{c.name}-{sid2}'.\ - format(c=self.engine.container, **kwargs) \ - if node == 1 and kwargs['nodes'] == 1 or node == kwargs['nodes'] \ - else '{guest_dir}/memif-pipe-{mid2}'.\ - format(c=self.engine.container, **kwargs) + node = (kwargs[u"mid1"] - 1) % kwargs[u"nodes"] + 1 + mid1 = kwargs[u"mid1"] + mid2 = kwargs[u"mid2"] + role1 = u"master" + role2 = u"master" if node in (kwargs[u"nodes"], 1) else u"slave" + kwargs[u"mid2"] = kwargs[u"mid2"] if node in (kwargs[u"nodes"], 1) \ + else kwargs[u"mid2"] + 1 + vif1_mac = kwargs[u"tg_if1_mac"] \ + if (kwargs[u"mid1"] - 1) % kwargs[u"nodes"] + 1 == 1 \ + else f"52:54:00:00:{(kwargs[u'mid1'] - 1):02X}:02" + vif2_mac = kwargs[u"tg_if2_mac"] \ + if (kwargs[u"mid2"] - 1) % kwargs[u"nodes"] + 1 == kwargs[u"nodes"]\ + else f"52:54:00:00:{(kwargs[u'mid2'] + 1):02X}:01" + socket1 = f"{kwargs[u'guest_dir']}/memif-{self.engine.container.name}-"\ + f"{kwargs[u'sid1']}" if node == 1 \ + else f"{kwargs[u'guest_dir']}/memif-pipe-{kwargs[u'mid1']}" + socket2 = f"{kwargs[u'guest_dir']}/memif-{self.engine.container.name}-"\ + f"{kwargs[u'sid2']}" \ + if node == 1 and kwargs[u"nodes"] == 1 or node == kwargs[u"nodes"] \ + else f"{kwargs[u'guest_dir']}/memif-pipe-{kwargs[u'mid2']}" self.engine.create_vpp_exec_config( - 'memif_create_pipeline_ip4.exec', - mid1=kwargs['mid1'], mid2=kwargs['mid2'], - sid1=kwargs['sid1'], sid2=kwargs['sid2'], + u"memif_create_pipeline_ip4.exec", + mid1=kwargs[u"mid1"], mid2=kwargs[u"mid2"], + sid1=kwargs[u"sid1"], sid2=kwargs[u"sid2"], socket1=socket1, socket2=socket2, role1=role1, role2=role2, - mac1='52:54:00:00:{0:02X}:01'.format(mid1), - mac2='52:54:00:00:{0:02X}:02'.format(mid2), - vif1_mac=vif1_mac, vif2_mac=vif2_mac) + mac1=f"52:54:00:00:{mid1:02X}:01", + mac2=f"52:54:00:00:{mid2:02X}:02", + vif1_mac=vif1_mac, vif2_mac=vif2_mac + ) def stop_all_containers(self): """Stop all containers.""" @@ -341,7 +351,7 @@ class ContainerManager(object): self.engine.destroy() -class ContainerEngine(object): +class ContainerEngine: """Abstract class for container engine.""" def __init__(self): @@ -395,61 +405,67 @@ class ContainerEngine(object): def install_supervisor(self): """Install supervisord inside a container.""" if isinstance(self, LXC): - self.execute('sleep 3; apt-get update') - self.execute('apt-get install -y supervisor') - self.execute('echo "{config}" > {config_file} && ' - 'supervisord -c {config_file}'. - format( - config='[unix_http_server]\n' - 'file = /tmp/supervisor.sock\n\n' - '[rpcinterface:supervisor]\n' - 'supervisor.rpcinterface_factory = supervisor.' - 'rpcinterface:make_main_rpcinterface\n\n' - '[supervisorctl]\n' - 'serverurl = unix:///tmp/supervisor.sock\n\n' - '[supervisord]\n' - 'pidfile = /tmp/supervisord.pid\n' - 'identifier = supervisor\n' - 'directory = /tmp\n' - 'logfile = /tmp/supervisord.log\n' - 'loglevel = debug\n' - 'nodaemon = false\n\n', - config_file=SUPERVISOR_CONF)) + self.execute(u"sleep 3; apt-get update") + self.execute(u"apt-get install -y supervisor") + config = \ + u"[unix_http_server]\n" \ + u"file = /tmp/supervisor.sock\n\n" \ + u"[rpcinterface:supervisor]\n" \ + u"supervisor.rpcinterface_factory = " \ + u"supervisor.rpcinterface:make_main_rpcinterface\n\n" \ + u"[supervisorctl]\n" \ + u"serverurl = unix:///tmp/supervisor.sock\n\n" \ + u"[supervisord]\n" \ + u"pidfile = /tmp/supervisord.pid\n" \ + u"identifier = supervisor\n" \ + u"directory = /tmp\n" \ + u"logfile = /tmp/supervisord.log\n" \ + u"loglevel = debug\n" \ + u"nodaemon = false\n\n" + self.execute( + f'echo "{config}" > {SUPERVISOR_CONF} && ' + f'supervisord -c {SUPERVISOR_CONF}' + ) def start_vpp(self): """Start VPP inside a container.""" - self.execute('echo "{config}" >> {config_file} && ' - 'supervisorctl reload'. - format( - config='[program:vpp]\n' - 'command = /usr/bin/vpp -c /etc/vpp/startup.conf\n' - 'autostart = false\n' - 'autorestart = false\n' - 'redirect_stderr = true\n' - 'priority = 1', - config_file=SUPERVISOR_CONF)) - self.execute('supervisorctl start vpp') + config = \ + u"[program:vpp]\n" \ + u"command = /usr/bin/vpp -c /etc/vpp/startup.conf\n" \ + u"autostart = false\n" \ + u"autorestart = false\n" \ + u"redirect_stderr = true\n" \ + u"priority = 1" + self.execute( + f'echo "{config}" >> {SUPERVISOR_CONF} && supervisorctl reload' + ) + self.execute(u"supervisorctl start vpp") + + # pylint: disable=import-outside-toplevel from robot.libraries.BuiltIn import BuiltIn topo_instance = BuiltIn().get_library_instance( - 'resources.libraries.python.topology.Topology') + u"resources.libraries.python.topology.Topology" + ) topo_instance.add_new_socket( self.container.node, SocketType.PAPI, self.container.name, - '{root}/tmp/vpp_sockets/{name}/api.sock'. - format(root=self.container.root, name=self.container.name)) + f"{self.container.root}/tmp/vpp_sockets/{self.container.name}/" + f"api.sock" + ) topo_instance.add_new_socket( self.container.node, SocketType.STATS, self.container.name, - '{root}/tmp/vpp_sockets/{name}/stats.sock'. - format(root=self.container.root, name=self.container.name)) + f"{self.container.root}/tmp/vpp_sockets/{self.container.name}/" + f"stats.sock" + ) def restart_vpp(self): """Restart VPP service inside a container.""" - self.execute('supervisorctl restart vpp') - self.execute('cat /tmp/supervisord.log') + self.execute(u"supervisorctl restart vpp") + self.execute(u"cat /tmp/supervisord.log") def create_base_vpp_startup_config(self): """Create base startup configuration of VPP on container. @@ -464,14 +480,14 @@ class ContainerEngine(object): vpp_config.set_node(self.container.node) vpp_config.add_unix_cli_listen() vpp_config.add_unix_nodaemon() - vpp_config.add_unix_exec('/tmp/running.exec') + vpp_config.add_unix_exec(u"/tmp/running.exec") vpp_config.add_socksvr(socket=Constants.SOCKSVR_PATH) - vpp_config.add_statseg_per_node_counters(value='on') + vpp_config.add_statseg_per_node_counters(value=u"on") # We will pop the first core from the list to be a main core vpp_config.add_cpu_main_core(str(cpuset_cpus.pop(0))) # If more cores in the list, the rest will be used as workers. if cpuset_cpus: - corelist_workers = ','.join(str(cpu) for cpu in cpuset_cpus) + corelist_workers = u",".join(str(cpu) for cpu in cpuset_cpus) vpp_config.add_cpu_corelist_workers(corelist_workers) return vpp_config @@ -480,12 +496,14 @@ class ContainerEngine(object): """Create startup configuration of VPP without DPDK on container. """ vpp_config = self.create_base_vpp_startup_config() - vpp_config.add_plugin('disable', 'dpdk_plugin.so') + vpp_config.add_plugin(u"disable", u"dpdk_plugin.so") # Apply configuration - self.execute('mkdir -p /etc/vpp/') - self.execute('echo "{config}" | tee /etc/vpp/startup.conf' - .format(config=vpp_config.get_config_str())) + self.execute(u"mkdir -p /etc/vpp/") + self.execute( + f'echo "{vpp_config.get_config_str()}" | ' + f'tee /etc/vpp/startup.conf' + ) def create_vpp_startup_config_dpdk_dev(self, *devices): """Create startup configuration of VPP with DPDK on container. @@ -496,15 +514,17 @@ class ContainerEngine(object): vpp_config = self.create_base_vpp_startup_config() vpp_config.add_dpdk_dev(*devices) vpp_config.add_dpdk_no_tx_checksum_offload() - vpp_config.add_dpdk_log_level('debug') - vpp_config.add_plugin('disable', 'default') - vpp_config.add_plugin('enable', 'dpdk_plugin.so') - vpp_config.add_plugin('enable', 'memif_plugin.so') + vpp_config.add_dpdk_log_level(u"debug") + vpp_config.add_plugin(u"disable", u"default") + vpp_config.add_plugin(u"enable", u"dpdk_plugin.so") + vpp_config.add_plugin(u"enable", u"memif_plugin.so") # Apply configuration - self.execute('mkdir -p /etc/vpp/') - self.execute('echo "{config}" | tee /etc/vpp/startup.conf' - .format(config=vpp_config.get_config_str())) + self.execute(u"mkdir -p /etc/vpp/") + self.execute( + f'echo "{vpp_config.get_config_str()}" | ' + f'tee /etc/vpp/startup.conf' + ) def create_vpp_startup_config_func_dev(self): """Create startup configuration of VPP on container for functional @@ -515,15 +535,17 @@ class ContainerEngine(object): vpp_config.set_node(self.container.node) vpp_config.add_unix_cli_listen() vpp_config.add_unix_nodaemon() - vpp_config.add_unix_exec('/tmp/running.exec') + vpp_config.add_unix_exec(u"/tmp/running.exec") vpp_config.add_socksvr(socket=Constants.SOCKSVR_PATH) - vpp_config.add_statseg_per_node_counters(value='on') - vpp_config.add_plugin('disable', 'dpdk_plugin.so') + vpp_config.add_statseg_per_node_counters(value=u"on") + vpp_config.add_plugin(u"disable", u"dpdk_plugin.so") # Apply configuration - self.execute('mkdir -p /etc/vpp/') - self.execute('echo "{config}" | tee /etc/vpp/startup.conf' - .format(config=vpp_config.get_config_str())) + self.execute(u"mkdir -p /etc/vpp/") + self.execute( + f'echo "{vpp_config.get_config_str()}" | ' + f'tee /etc/vpp/startup.conf' + ) def create_vpp_exec_config(self, template_file, **kwargs): """Create VPP exec configuration on container. @@ -533,15 +555,13 @@ class ContainerEngine(object): :type template_file: str :type kwargs: dict """ - running = '/tmp/running.exec' + running = u"/tmp/running.exec" - template = '{res}/{tpl}'.format( - res=Constants.RESOURCES_TPL_CONTAINER, tpl=template_file) + template = f"{Constants.RESOURCES_TPL_CONTAINER}/{template_file}" - with open(template, 'r') as src_file: + with open(template, "r") as src_file: src = Template(src_file.read()) - self.execute('echo "{out}" > {running}'.format( - out=src.safe_substitute(**kwargs), running=running)) + self.execute(f'echo "{src.safe_substitute(**kwargs)}" > {running}') def is_container_running(self): """Check if container is running.""" @@ -566,29 +586,34 @@ class ContainerEngine(object): :raises RuntimeError: If applying cgroup settings via cgset failed. """ ret, _, _ = self.container.ssh.exec_command_sudo( - 'cgset -r cpuset.cpu_exclusive=0 /') + u"cgset -r cpuset.cpu_exclusive=0 /" + ) if int(ret) != 0: - raise RuntimeError('Failed to apply cgroup settings.') + raise RuntimeError(u"Failed to apply cgroup settings.") ret, _, _ = self.container.ssh.exec_command_sudo( - 'cgset -r cpuset.mem_exclusive=0 /') + u"cgset -r cpuset.mem_exclusive=0 /" + ) if int(ret) != 0: - raise RuntimeError('Failed to apply cgroup settings.') + raise RuntimeError(u"Failed to apply cgroup settings.") ret, _, _ = self.container.ssh.exec_command_sudo( - 'cgcreate -g cpuset:/{name}'.format(name=name)) + f"cgcreate -g cpuset:/{name}" + ) if int(ret) != 0: - raise RuntimeError('Failed to copy cgroup settings from root.') + raise RuntimeError(u"Failed to copy cgroup settings from root.") ret, _, _ = self.container.ssh.exec_command_sudo( - 'cgset -r cpuset.cpu_exclusive=0 /{name}'.format(name=name)) + f"cgset -r cpuset.cpu_exclusive=0 /{name}" + ) if int(ret) != 0: - raise RuntimeError('Failed to apply cgroup settings.') + raise RuntimeError(u"Failed to apply cgroup settings.") ret, _, _ = self.container.ssh.exec_command_sudo( - 'cgset -r cpuset.mem_exclusive=0 /{name}'.format(name=name)) + f"cgset -r cpuset.mem_exclusive=0 /{name}" + ) if int(ret) != 0: - raise RuntimeError('Failed to apply cgroup settings.') + raise RuntimeError(u"Failed to apply cgroup settings.") class LXC(ContainerEngine): @@ -611,21 +636,21 @@ class LXC(ContainerEngine): else: return - target_arch = 'arm64' \ - if Topology.get_node_arch(self.container.node) == 'aarch64' \ - else 'amd64' + target_arch = u"arm64" \ + if Topology.get_node_arch(self.container.node) == u"aarch64" \ + else u"amd64" - image = self.container.image if self.container.image else\ - "-d ubuntu -r bionic -a {arch}".format(arch=target_arch) + image = self.container.image if self.container.image \ + else f"-d ubuntu -r bionic -a {target_arch}" - cmd = 'lxc-create -t download --name {c.name} -- {image} '\ - '--no-validate'.format(c=self.container, image=image) + cmd = f"lxc-create -t download --name {self.container.name} " \ + f"-- {image} --no-validate" ret, _, _ = self.container.ssh.exec_command_sudo(cmd, timeout=1800) if int(ret) != 0: - raise RuntimeError('Failed to create container.') + raise RuntimeError(u"Failed to create container.") - self._configure_cgroup('lxc') + self._configure_cgroup(u"lxc") def create(self): """Create/deploy an application inside a container on system. @@ -635,54 +660,61 @@ class LXC(ContainerEngine): if self.container.mnt: # LXC fix for tmpfs # https://github.com/lxc/lxc/issues/434 + mnt_e = u"lxc.mount.entry = tmpfs run tmpfs defaults" ret, _, _ = self.container.ssh.exec_command_sudo( - "sh -c 'echo \"{e}\" >> /var/lib/lxc/{c.name}/config'". - format(e="lxc.mount.entry = tmpfs run tmpfs defaults", - c=self.container)) + f"sh -c \"echo '{mnt_e}' >> " + f"/var/lib/lxc/{self.container.name}/config\"" + ) if int(ret) != 0: - raise RuntimeError('Failed to write {c.name} config.'. - format(c=self.container)) + raise RuntimeError( + f"Failed to write {self.container.name} config." + ) for mount in self.container.mnt: - host_dir, guest_dir = mount.split(':') - options = 'bind,create=dir' \ - if guest_dir.endswith('/') else 'bind,create=file' - entry = 'lxc.mount.entry = {host_dir} {guest_dir} none ' \ - '{options} 0 0'.format( - host_dir=host_dir, guest_dir=guest_dir[1:], - options=options) + host_dir, guest_dir = mount.split(u":") + options = u"bind,create=dir" if guest_dir.endswith(u"/") \ + else u"bind,create=file" + entry = f"lxc.mount.entry = {host_dir} {guest_dir[1:]} " \ + f"none {options} 0 0" self.container.ssh.exec_command_sudo( - "sh -c 'mkdir -p {host_dir}'".format(host_dir=host_dir)) + f"sh -c \"mkdir -p {host_dir}\"" + ) ret, _, _ = self.container.ssh.exec_command_sudo( - "sh -c 'echo \"{e}\" >> /var/lib/lxc/{c.name}/config'". - format(e=entry, c=self.container)) + f"sh -c \"echo '{entry}' " + f">> /var/lib/lxc/{self.container.name}/config\"" + ) if int(ret) != 0: - raise RuntimeError('Failed to write {c.name} config.' - .format(c=self.container)) + raise RuntimeError( + f"Failed to write {self.container.name} config." + ) - cpuset_cpus = '{0}'.format( - ','.join('%s' % cpu for cpu in self.container.cpuset_cpus))\ - if self.container.cpuset_cpus else '' + cpuset_cpus = u",".join( + f"{cpu!s}" for cpu in self.container.cpuset_cpus) \ + if self.container.cpuset_cpus else u"" ret, _, _ = self.container.ssh.exec_command_sudo( - 'lxc-start --name {c.name} --daemon'.format(c=self.container)) + f"lxc-start --name {self.container.name} --daemon" + ) if int(ret) != 0: - raise RuntimeError('Failed to start container {c.name}.'. - format(c=self.container)) - self._lxc_wait('RUNNING') + raise RuntimeError( + f"Failed to start container {self.container.name}." + ) + self._lxc_wait(u"RUNNING") # Workaround for LXC to be able to allocate all cpus including isolated. ret, _, _ = self.container.ssh.exec_command_sudo( - 'cgset --copy-from / lxc/') + u"cgset --copy-from / lxc/" + ) if int(ret) != 0: - raise RuntimeError('Failed to copy cgroup to LXC') + raise RuntimeError(u"Failed to copy cgroup to LXC") ret, _, _ = self.container.ssh.exec_command_sudo( - 'lxc-cgroup --name {c.name} cpuset.cpus {cpus}'. - format(c=self.container, cpus=cpuset_cpus)) + f"lxc-cgroup --name {self.container.name} cpuset.cpus {cpuset_cpus}" + ) if int(ret) != 0: - raise RuntimeError('Failed to set cpuset.cpus to container ' - '{c.name}.'.format(c=self.container)) + raise RuntimeError( + f"Failed to set cpuset.cpus to container {self.container.name}." + ) def execute(self, command): """Start a process inside a running container. @@ -694,65 +726,69 @@ class LXC(ContainerEngine): :type command: str :raises RuntimeError: If running the command failed. """ - env = '--keep-env {0}'.format( - ' '.join('--set-var %s' % env for env in self.container.env))\ - if self.container.env else '' + env = u"--keep-env " + u" ".join( + f"--set-var {env!s}" for env in self.container.env) \ + if self.container.env else u"" - cmd = "lxc-attach {env} --name {c.name} -- /bin/sh -c '{command}; "\ - "exit $?'".format(env=env, c=self.container, command=command) + cmd = f"lxc-attach {env} --name {self.container.name} " \ + f"-- /bin/sh -c '{command}; exit $?'" ret, _, _ = self.container.ssh.exec_command_sudo(cmd, timeout=180) if int(ret) != 0: - raise RuntimeError('Failed to run command inside container ' - '{c.name}.'.format(c=self.container)) + raise RuntimeError( + f"Failed to run command inside container {self.container.name}." + ) def stop(self): """Stop a container. :raises RuntimeError: If stopping the container failed. """ - cmd = 'lxc-stop --name {c.name}'.format(c=self.container) + cmd = f"lxc-stop --name {self.container.name}" ret, _, _ = self.container.ssh.exec_command_sudo(cmd) if int(ret) != 0: - raise RuntimeError('Failed to stop container {c.name}.' - .format(c=self.container)) - self._lxc_wait('STOPPED|FROZEN') + raise RuntimeError( + f"Failed to stop container {self.container.name}." + ) + self._lxc_wait(u"STOPPED|FROZEN") def destroy(self): """Destroy a container. :raises RuntimeError: If destroying container failed. """ - cmd = 'lxc-destroy --force --name {c.name}'.format(c=self.container) + cmd = f"lxc-destroy --force --name {self.container.name}" ret, _, _ = self.container.ssh.exec_command_sudo(cmd) if int(ret) != 0: - raise RuntimeError('Failed to destroy container {c.name}.' - .format(c=self.container)) + raise RuntimeError( + f"Failed to destroy container {self.container.name}." + ) def info(self): """Query and shows information about a container. :raises RuntimeError: If getting info about a container failed. """ - cmd = 'lxc-info --name {c.name}'.format(c=self.container) + cmd = f"lxc-info --name {self.container.name}" ret, _, _ = self.container.ssh.exec_command_sudo(cmd) if int(ret) != 0: - raise RuntimeError('Failed to get info about container {c.name}.' - .format(c=self.container)) + raise RuntimeError( + f"Failed to get info about container {self.container.name}." + ) def system_info(self): """Check the current kernel for LXC support. :raises RuntimeError: If checking LXC support failed. """ - cmd = 'lxc-checkconfig' + cmd = u"lxc-checkconfig" ret, _, _ = self.container.ssh.exec_command_sudo(cmd) if int(ret) != 0: - raise RuntimeError('Failed to check LXC support.') + raise RuntimeError(u"Failed to check LXC support.") def is_container_running(self): """Check if container is running on node. @@ -761,14 +797,14 @@ class LXC(ContainerEngine): :rtype: bool :raises RuntimeError: If getting info about a container failed. """ - cmd = 'lxc-info --no-humanize --state --name {c.name}'\ - .format(c=self.container) + cmd = f"lxc-info --no-humanize --state --name {self.container.name}" ret, stdout, _ = self.container.ssh.exec_command_sudo(cmd) if int(ret) != 0: - raise RuntimeError('Failed to get info about container {c.name}.' - .format(c=self.container)) - return True if 'RUNNING' in stdout else False + raise RuntimeError( + f"Failed to get info about container {self.container.name}." + ) + return u"RUNNING" in stdout def is_container_present(self): """Check if container is existing on node. @@ -777,10 +813,10 @@ class LXC(ContainerEngine): :rtype: bool :raises RuntimeError: If getting info about a container failed. """ - cmd = 'lxc-info --no-humanize --name {c.name}'.format(c=self.container) + cmd = f"lxc-info --no-humanize --name {self.container.name}" ret, _, _ = self.container.ssh.exec_command_sudo(cmd) - return False if int(ret) else True + return not ret def _lxc_wait(self, state): """Wait for a specific container state. @@ -789,13 +825,14 @@ class LXC(ContainerEngine): :type state: str :raises RuntimeError: If waiting for state of a container failed. """ - cmd = 'lxc-wait --name {c.name} --state "{s}"'\ - .format(c=self.container, s=state) + cmd = f"lxc-wait --name {self.container.name} --state '{state}'" ret, _, _ = self.container.ssh.exec_command_sudo(cmd) if int(ret) != 0: - raise RuntimeError('Failed to wait for state "{s}" of container ' - '{c.name}.'.format(s=state, c=self.container)) + raise RuntimeError( + f"Failed to wait for state '{state}' " + f"of container {self.container.name}." + ) class Docker(ContainerEngine): @@ -818,61 +855,58 @@ class Docker(ContainerEngine): if not self.container.image: img = Constants.DOCKER_SUT_IMAGE_UBUNTU_ARM \ - if Topology.get_node_arch(self.container.node) == 'aarch64' \ + if Topology.get_node_arch(self.container.node) == u"aarch64" \ else Constants.DOCKER_SUT_IMAGE_UBUNTU - setattr(self.container, 'image', img) + setattr(self.container, u"image", img) - cmd = 'docker pull {image}'.format(image=self.container.image) + cmd = f"docker pull {self.container.image}" ret, _, _ = self.container.ssh.exec_command_sudo(cmd, timeout=1800) if int(ret) != 0: - raise RuntimeError('Failed to create container {c.name}.' - .format(c=self.container)) + raise RuntimeError( + f"Failed to create container {self.container.name}." + ) if self.container.cpuset_cpus: - self._configure_cgroup('docker') + self._configure_cgroup(u"docker") def create(self): """Create/deploy container. :raises RuntimeError: If creating a container failed. """ - cpuset_cpus = '--cpuset-cpus={0}'.format( - ','.join('%s' % cpu for cpu in self.container.cpuset_cpus))\ - if self.container.cpuset_cpus else '' + cpuset_cpus = u"--cpuset-cpus=" + u",".join( + f"{cpu!s}" for cpu in self.container.cpuset_cpus) \ + if self.container.cpuset_cpus else u"" - cpuset_mems = '--cpuset-mems={0}'.format(self.container.cpuset_mems)\ - if self.container.cpuset_mems is not None else '' + cpuset_mems = f"--cpuset-mems={self.container.cpuset_mems}" \ + if self.container.cpuset_mems is not None else u"" # Temporary workaround - disabling due to bug in memif - cpuset_mems = '' + cpuset_mems = u"" - env = '{0}'.format( - ' '.join('--env %s' % env for env in self.container.env))\ - if self.container.env else '' + env = u" ".join(f"--env {env!s}" for env in self.container.env) \ + if self.container.env else u"" - command = '{0}'.format(self.container.command)\ - if self.container.command else '' + command = str(self.container.command) if self.container.command else u"" - publish = '{0}'.format( - ' '.join('--publish %s' % var for var in self.container.publish))\ - if self.container.publish else '' + publish = u" ".join( + f"--publish {var!s}" for var in self.container.publish + ) if self.container.publish else u"" - volume = '{0}'.format( - ' '.join('--volume %s' % mnt for mnt in self.container.mnt))\ - if self.container.mnt else '' + volume = u" ".join( + f"--volume {mnt!s}" for mnt in self.container.mnt) \ + if self.container.mnt else u"" - cmd = 'docker run '\ - '--privileged --detach --interactive --tty --rm '\ - '--cgroup-parent docker {cpuset_cpus} {cpuset_mems} {publish} '\ - '{env} {volume} --name {container.name} {container.image} '\ - '{command}'.format(cpuset_cpus=cpuset_cpus, cpuset_mems=cpuset_mems, - container=self.container, command=command, - env=env, publish=publish, volume=volume) + cmd = f"docker run --privileged --detach --interactive --tty --rm " \ + f"--cgroup-parent docker {cpuset_cpus} {cpuset_mems} {publish} " \ + f"{env} {volume} --name {self.container.name} " \ + f"{self.container.image} {command}" ret, _, _ = self.container.ssh.exec_command_sudo(cmd) if int(ret) != 0: - raise RuntimeError('Failed to create container {c.name}' - .format(c=self.container)) + raise RuntimeError( + f"Failed to create container {self.container.name}" + ) self.info() @@ -886,60 +920,64 @@ class Docker(ContainerEngine): :type command: str :raises RuntimeError: If running the command in a container failed. """ - cmd = "docker exec --interactive {c.name} /bin/sh -c '{command}; "\ - "exit $?'".format(c=self.container, command=command) + cmd = f"docker exec --interactive {self.container.name} " \ + f"/bin/sh -c '{command}; exit $?'" ret, _, _ = self.container.ssh.exec_command_sudo(cmd, timeout=180) if int(ret) != 0: - raise RuntimeError('Failed to execute command in container ' - '{c.name}.'.format(c=self.container)) + raise RuntimeError( + f"Failed to execute command in container {self.container.name}." + ) def stop(self): """Stop running container. :raises RuntimeError: If stopping a container failed. """ - cmd = 'docker stop {c.name}'.format(c=self.container) + cmd = f"docker stop {self.container.name}" ret, _, _ = self.container.ssh.exec_command_sudo(cmd) if int(ret) != 0: - raise RuntimeError('Failed to stop container {c.name}.' - .format(c=self.container)) + raise RuntimeError( + f"Failed to stop container {self.container.name}." + ) def destroy(self): """Remove a container. :raises RuntimeError: If removing a container failed. """ - cmd = 'docker rm --force {c.name}'.format(c=self.container) + cmd = f"docker rm --force {self.container.name}" ret, _, _ = self.container.ssh.exec_command_sudo(cmd) if int(ret) != 0: - raise RuntimeError('Failed to destroy container {c.name}.' - .format(c=self.container)) + raise RuntimeError( + f"Failed to destroy container {self.container.name}." + ) def info(self): """Return low-level information on Docker objects. :raises RuntimeError: If getting info about a container failed. """ - cmd = 'docker inspect {c.name}'.format(c=self.container) + cmd = f"docker inspect {self.container.name}" ret, _, _ = self.container.ssh.exec_command_sudo(cmd) if int(ret) != 0: - raise RuntimeError('Failed to get info about container {c.name}.' - .format(c=self.container)) + raise RuntimeError( + f"Failed to get info about container {self.container.name}." + ) def system_info(self): """Display the docker system-wide information. :raises RuntimeError: If displaying system information failed. """ - cmd = 'docker system info' + cmd = u"docker system info" ret, _, _ = self.container.ssh.exec_command_sudo(cmd) if int(ret) != 0: - raise RuntimeError('Failed to get system info.') + raise RuntimeError(u"Failed to get system info.") def is_container_present(self): """Check if container is present on node. @@ -948,14 +986,14 @@ class Docker(ContainerEngine): :rtype: bool :raises RuntimeError: If getting info about a container failed. """ - cmd = 'docker ps --all --quiet --filter name={c.name}'\ - .format(c=self.container) + cmd = f"docker ps --all --quiet --filter name={self.container.name}" ret, stdout, _ = self.container.ssh.exec_command_sudo(cmd) if int(ret) != 0: - raise RuntimeError('Failed to get info about container {c.name}.' - .format(c=self.container)) - return True if stdout else False + raise RuntimeError( + f"Failed to get info about container {self.container.name}." + ) + return bool(stdout) def is_container_running(self): """Check if container is running on node. @@ -964,23 +1002,19 @@ class Docker(ContainerEngine): :rtype: bool :raises RuntimeError: If getting info about a container failed. """ - cmd = 'docker ps --quiet --filter name={c.name}'\ - .format(c=self.container) + cmd = f"docker ps --quiet --filter name={self.container.name}" ret, stdout, _ = self.container.ssh.exec_command_sudo(cmd) if int(ret) != 0: - raise RuntimeError('Failed to get info about container {c.name}.' - .format(c=self.container)) - return True if stdout else False + raise RuntimeError( + f"Failed to get info about container {self.container.name}." + ) + return bool(stdout) -class Container(object): +class Container: """Container class.""" - def __init__(self): - """Initialize Container object.""" - pass - def __getattr__(self, attr): """Get attribute custom implementation. @@ -1007,9 +1041,9 @@ class Container(object): self.__dict__[attr] except KeyError: # Creating new attribute - if attr == 'node': - self.__dict__['ssh'] = SSH() - self.__dict__['ssh'].connect(value) + if attr == u"node": + self.__dict__[u"ssh"] = SSH() + self.__dict__[u"ssh"].connect(value) self.__dict__[attr] = value else: # Updating attribute base of type |