0001 import os
0002 import signal
0003 from string import Template
0004 import subprocess
0005 import time
0006 from TdcPlugin import TdcPlugin
0007
0008 from tdc_config import *
0009
0010 class SubPlugin(TdcPlugin):
0011 def __init__(self):
0012 self.sub_class = 'ns/SubPlugin'
0013 super().__init__()
0014
0015 def pre_suite(self, testcount, testidlist):
0016 '''run commands before test_runner goes into a test loop'''
0017 super().pre_suite(testcount, testidlist)
0018
0019 if self.args.namespace:
0020 self._ns_create()
0021 else:
0022 self._ports_create()
0023
0024 def post_suite(self, index):
0025 '''run commands after test_runner goes into a test loop'''
0026 super().post_suite(index)
0027 if self.args.verbose:
0028 print('{}.post_suite'.format(self.sub_class))
0029
0030 if self.args.namespace:
0031 self._ns_destroy()
0032 else:
0033 self._ports_destroy()
0034
0035 def add_args(self, parser):
0036 super().add_args(parser)
0037 self.argparser_group = self.argparser.add_argument_group(
0038 'netns',
0039 'options for nsPlugin(run commands in net namespace)')
0040 self.argparser_group.add_argument(
0041 '-N', '--no-namespace', action='store_false', default=True,
0042 dest='namespace', help='Don\'t run commands in namespace')
0043 return self.argparser
0044
0045 def adjust_command(self, stage, command):
0046 super().adjust_command(stage, command)
0047 cmdform = 'list'
0048 cmdlist = list()
0049
0050 if not self.args.namespace:
0051 return command
0052
0053 if self.args.verbose:
0054 print('{}.adjust_command'.format(self.sub_class))
0055
0056 if not isinstance(command, list):
0057 cmdform = 'str'
0058 cmdlist = command.split()
0059 else:
0060 cmdlist = command
0061 if stage == 'setup' or stage == 'execute' or stage == 'verify' or stage == 'teardown':
0062 if self.args.verbose:
0063 print('adjust_command: stage is {}; inserting netns stuff in command [{}] list [{}]'.format(stage, command, cmdlist))
0064 cmdlist.insert(0, self.args.NAMES['NS'])
0065 cmdlist.insert(0, 'exec')
0066 cmdlist.insert(0, 'netns')
0067 cmdlist.insert(0, self.args.NAMES['IP'])
0068 else:
0069 pass
0070
0071 if cmdform == 'str':
0072 command = ' '.join(cmdlist)
0073 else:
0074 command = cmdlist
0075
0076 if self.args.verbose:
0077 print('adjust_command: return command [{}]'.format(command))
0078 return command
0079
0080 def _ports_create(self):
0081 cmd = '$IP link add $DEV0 type veth peer name $DEV1'
0082 self._exec_cmd('pre', cmd)
0083 cmd = '$IP link set $DEV0 up'
0084 self._exec_cmd('pre', cmd)
0085 if not self.args.namespace:
0086 cmd = '$IP link set $DEV1 up'
0087 self._exec_cmd('pre', cmd)
0088
0089 def _ports_destroy(self):
0090 cmd = '$IP link del $DEV0'
0091 self._exec_cmd('post', cmd)
0092
0093 def _ns_create(self):
0094 '''
0095 Create the network namespace in which the tests will be run and set up
0096 the required network devices for it.
0097 '''
0098 self._ports_create()
0099 if self.args.namespace:
0100 cmd = '$IP netns add {}'.format(self.args.NAMES['NS'])
0101 self._exec_cmd('pre', cmd)
0102 cmd = '$IP link set $DEV1 netns {}'.format(self.args.NAMES['NS'])
0103 self._exec_cmd('pre', cmd)
0104 cmd = '$IP -n {} link set $DEV1 up'.format(self.args.NAMES['NS'])
0105 self._exec_cmd('pre', cmd)
0106 if self.args.device:
0107 cmd = '$IP link set $DEV2 netns {}'.format(self.args.NAMES['NS'])
0108 self._exec_cmd('pre', cmd)
0109 cmd = '$IP -n {} link set $DEV2 up'.format(self.args.NAMES['NS'])
0110 self._exec_cmd('pre', cmd)
0111
0112 def _ns_destroy(self):
0113 '''
0114 Destroy the network namespace for testing (and any associated network
0115 devices as well)
0116 '''
0117 if self.args.namespace:
0118 cmd = '$IP netns delete {}'.format(self.args.NAMES['NS'])
0119 self._exec_cmd('post', cmd)
0120
0121 def _exec_cmd(self, stage, command):
0122 '''
0123 Perform any required modifications on an executable command, then run
0124 it in a subprocess and return the results.
0125 '''
0126 if '$' in command:
0127 command = self._replace_keywords(command)
0128
0129 self.adjust_command(stage, command)
0130 if self.args.verbose:
0131 print('_exec_cmd: command "{}"'.format(command))
0132 proc = subprocess.Popen(command,
0133 shell=True,
0134 stdout=subprocess.PIPE,
0135 stderr=subprocess.PIPE,
0136 env=ENVIR)
0137 (rawout, serr) = proc.communicate()
0138
0139 if proc.returncode != 0 and len(serr) > 0:
0140 foutput = serr.decode("utf-8")
0141 else:
0142 foutput = rawout.decode("utf-8")
0143
0144 proc.stdout.close()
0145 proc.stderr.close()
0146 return proc, foutput
0147
0148 def _replace_keywords(self, cmd):
0149 """
0150 For a given executable command, substitute any known
0151 variables contained within NAMES with the correct values
0152 """
0153 tcmd = Template(cmd)
0154 subcmd = tcmd.safe_substitute(self.args.NAMES)
0155 return subcmd