1 import os 1 import os 2 import signal 2 import signal 3 from string import Template 3 from string import Template 4 import subprocess 4 import subprocess 5 import time 5 import time 6 from multiprocessing import Pool << 7 from functools import cached_property << 8 from TdcPlugin import TdcPlugin 6 from TdcPlugin import TdcPlugin 9 7 10 from tdc_config import * 8 from tdc_config import * 11 9 12 try: << 13 from pyroute2 import netns << 14 from pyroute2 import IPRoute << 15 netlink = True << 16 except ImportError: << 17 netlink = False << 18 print("!!! Consider installing pyroute2 !! << 19 << 20 class SubPlugin(TdcPlugin): 10 class SubPlugin(TdcPlugin): 21 def __init__(self): 11 def __init__(self): 22 self.sub_class = 'ns/SubPlugin' 12 self.sub_class = 'ns/SubPlugin' 23 super().__init__() 13 super().__init__() 24 14 25 def pre_suite(self, testcount, testlist): !! 15 def pre_suite(self, testcount, testidlist): 26 super().pre_suite(testcount, testlist) !! 16 '''run commands before test_runner goes into a test loop''' 27 !! 17 super().pre_suite(testcount, testidlist) 28 def prepare_test(self, test): << 29 if 'skip' in test and test['skip'] == << 30 return << 31 << 32 if 'nsPlugin' not in test['plugins']: << 33 return << 34 << 35 if netlink == True: << 36 self._nl_ns_create() << 37 else: << 38 self._ipr2_ns_create() << 39 << 40 # Make sure the netns is visible in th << 41 ticks = 20 << 42 while True: << 43 if ticks == 0: << 44 raise TimeoutError << 45 self._proc_check() << 46 try: << 47 ns = self.args.NAMES['NS'] << 48 f = open('/run/netns/{}'.forma << 49 f.close() << 50 break << 51 except: << 52 time.sleep(0.1) << 53 ticks -= 1 << 54 continue << 55 << 56 def pre_case(self, test, test_skip): << 57 if self.args.verbose: << 58 print('{}.pre_case'.format(self.su << 59 << 60 if test_skip: << 61 return << 62 << 63 self.prepare_test(test) << 64 << 65 def post_case(self): << 66 if self.args.verbose: << 67 print('{}.post_case'.format(self.s << 68 18 69 if netlink == True: !! 19 if self.args.namespace: 70 self._nl_ns_destroy() !! 20 self._ns_create() 71 else: 21 else: 72 self._ipr2_ns_destroy() !! 22 self._ports_create() 73 23 74 def post_suite(self, index): 24 def post_suite(self, index): >> 25 '''run commands after test_runner goes into a test loop''' >> 26 super().post_suite(index) 75 if self.args.verbose: 27 if self.args.verbose: 76 print('{}.post_suite'.format(self. 28 print('{}.post_suite'.format(self.sub_class)) 77 29 78 # Make sure we don't leak resources !! 30 if self.args.namespace: 79 cmd = self._replace_keywords("$IP -a n !! 31 self._ns_destroy() 80 !! 32 else: 81 if self.args.verbose > 3: !! 33 self._ports_destroy() 82 print('_exec_cmd: command "{}"'.f << 83 34 84 subprocess.run(cmd, shell=True, stdout !! 35 def add_args(self, parser): >> 36 super().add_args(parser) >> 37 self.argparser_group = self.argparser.add_argument_group( >> 38 'netns', >> 39 'options for nsPlugin(run commands in net namespace)') >> 40 self.argparser_group.add_argument( >> 41 '-N', '--no-namespace', action='store_false', default=True, >> 42 dest='namespace', help='Don\'t run commands in namespace') >> 43 return self.argparser 85 44 86 def adjust_command(self, stage, command): 45 def adjust_command(self, stage, command): 87 super().adjust_command(stage, command) 46 super().adjust_command(stage, command) 88 cmdform = 'list' 47 cmdform = 'list' 89 cmdlist = list() 48 cmdlist = list() 90 49 >> 50 if not self.args.namespace: >> 51 return command >> 52 91 if self.args.verbose: 53 if self.args.verbose: 92 print('{}.adjust_command'.format(s 54 print('{}.adjust_command'.format(self.sub_class)) 93 55 94 if not isinstance(command, list): 56 if not isinstance(command, list): 95 cmdform = 'str' 57 cmdform = 'str' 96 cmdlist = command.split() 58 cmdlist = command.split() 97 else: 59 else: 98 cmdlist = command 60 cmdlist = command 99 if stage == 'setup' or stage == 'execu 61 if stage == 'setup' or stage == 'execute' or stage == 'verify' or stage == 'teardown': 100 if self.args.verbose: 62 if self.args.verbose: 101 print('adjust_command: stage 63 print('adjust_command: stage is {}; inserting netns stuff in command [{}] list [{}]'.format(stage, command, cmdlist)) 102 cmdlist.insert(0, self.args.NAMES[ 64 cmdlist.insert(0, self.args.NAMES['NS']) 103 cmdlist.insert(0, 'exec') 65 cmdlist.insert(0, 'exec') 104 cmdlist.insert(0, 'netns') 66 cmdlist.insert(0, 'netns') 105 cmdlist.insert(0, self.args.NAMES[ 67 cmdlist.insert(0, self.args.NAMES['IP']) 106 else: 68 else: 107 pass 69 pass 108 70 109 if cmdform == 'str': 71 if cmdform == 'str': 110 command = ' '.join(cmdlist) 72 command = ' '.join(cmdlist) 111 else: 73 else: 112 command = cmdlist 74 command = cmdlist 113 75 114 if self.args.verbose: 76 if self.args.verbose: 115 print('adjust_command: return com 77 print('adjust_command: return command [{}]'.format(command)) 116 return command 78 return command 117 79 118 def _nl_ns_create(self): !! 80 def _ports_create(self): 119 ns = self.args.NAMES["NS"]; !! 81 cmd = '$IP link add $DEV0 type veth peer name $DEV1' 120 dev0 = self.args.NAMES["DEV0"]; !! 82 self._exec_cmd('pre', cmd) 121 dev1 = self.args.NAMES["DEV1"]; !! 83 cmd = '$IP link set $DEV0 up' 122 dummy = self.args.NAMES["DUMMY"]; !! 84 self._exec_cmd('pre', cmd) 123 !! 85 if not self.args.namespace: 124 if self.args.verbose: !! 86 cmd = '$IP link set $DEV1 up' 125 print('{}._nl_ns_create'.format(se !! 87 self._exec_cmd('pre', cmd) 126 !! 88 127 netns.create(ns) !! 89 def _ports_destroy(self): 128 netns.pushns(newns=ns) !! 90 cmd = '$IP link del $DEV0' 129 with IPRoute() as ip: !! 91 self._exec_cmd('post', cmd) 130 ip.link('add', ifname=dev1, kind=' << 131 ip.link('add', ifname=dummy, kind= << 132 ticks = 20 << 133 while True: << 134 if ticks == 0: << 135 raise TimeoutError << 136 try: << 137 dev1_idx = ip.link_lookup( << 138 dummy_idx = ip.link_lookup << 139 ip.link('set', index=dev1_ << 140 ip.link('set', index=dummy << 141 break << 142 except: << 143 time.sleep(0.1) << 144 ticks -= 1 << 145 continue << 146 netns.popns() << 147 << 148 with IPRoute() as ip: << 149 ticks = 20 << 150 while True: << 151 if ticks == 0: << 152 raise TimeoutError << 153 try: << 154 dev0_idx = ip.link_lookup( << 155 ip.link('set', index=dev0_ << 156 break << 157 except: << 158 time.sleep(0.1) << 159 ticks -= 1 << 160 continue << 161 << 162 def _ipr2_ns_create_cmds(self): << 163 cmds = [] << 164 << 165 ns = self.args.NAMES['NS'] << 166 << 167 cmds.append(self._replace_keywords('ne << 168 cmds.append(self._replace_keywords('li << 169 cmds.append(self._replace_keywords('li << 170 cmds.append(self._replace_keywords('li << 171 cmds.append(self._replace_keywords('li << 172 cmds.append(self._replace_keywords('ne << 173 cmds.append(self._replace_keywords('ne << 174 cmds.append(self._replace_keywords('li << 175 << 176 if self.args.device: << 177 cmds.append(self._replace_keywords << 178 cmds.append(self._replace_keywords << 179 92 180 return cmds !! 93 def _ns_create(self): 181 << 182 def _ipr2_ns_create(self): << 183 ''' 94 ''' 184 Create the network namespace in which 95 Create the network namespace in which the tests will be run and set up 185 the required network devices for it. 96 the required network devices for it. 186 ''' 97 ''' 187 self._exec_cmd_batched('pre', self._ip !! 98 self._ports_create() 188 !! 99 if self.args.namespace: 189 def _nl_ns_destroy(self): !! 100 cmd = '$IP netns add {}'.format(self.args.NAMES['NS']) 190 ns = self.args.NAMES['NS'] !! 101 self._exec_cmd('pre', cmd) 191 netns.remove(ns) !! 102 cmd = '$IP link set $DEV1 netns {}'.format(self.args.NAMES['NS']) >> 103 self._exec_cmd('pre', cmd) >> 104 cmd = '$IP -n {} link set $DEV1 up'.format(self.args.NAMES['NS']) >> 105 self._exec_cmd('pre', cmd) >> 106 if self.args.device: >> 107 cmd = '$IP link set $DEV2 netns {}'.format(self.args.NAMES['NS']) >> 108 self._exec_cmd('pre', cmd) >> 109 cmd = '$IP -n {} link set $DEV2 up'.format(self.args.NAMES['NS']) >> 110 self._exec_cmd('pre', cmd) 192 111 193 def _ipr2_ns_destroy_cmd(self): !! 112 def _ns_destroy(self): 194 return self._replace_keywords('netns d << 195 << 196 def _ipr2_ns_destroy(self): << 197 ''' 113 ''' 198 Destroy the network namespace for test 114 Destroy the network namespace for testing (and any associated network 199 devices as well) 115 devices as well) 200 ''' 116 ''' 201 self._exec_cmd('post', self._ipr2_ns_d !! 117 if self.args.namespace: 202 !! 118 cmd = '$IP netns delete {}'.format(self.args.NAMES['NS']) 203 @cached_property !! 119 self._exec_cmd('post', cmd) 204 def _proc(self): << 205 ip = self._replace_keywords("$IP -b -" << 206 proc = subprocess.Popen(ip, << 207 shell=True, << 208 stdin=subprocess.PIPE, << 209 env=ENVIR) << 210 << 211 return proc << 212 << 213 def _proc_check(self): << 214 proc = self._proc << 215 << 216 proc.poll() << 217 << 218 if proc.returncode is not None and pro << 219 raise RuntimeError("iproute2 exite << 220 120 221 def _exec_cmd(self, stage, command): 121 def _exec_cmd(self, stage, command): 222 ''' 122 ''' 223 Perform any required modifications on 123 Perform any required modifications on an executable command, then run 224 it in a subprocess and return the resu 124 it in a subprocess and return the results. 225 ''' 125 ''' >> 126 if '$' in command: >> 127 command = self._replace_keywords(command) 226 128 227 if self.args.verbose > 3: !! 129 self.adjust_command(stage, command) >> 130 if self.args.verbose: 228 print('_exec_cmd: command "{}"'.f 131 print('_exec_cmd: command "{}"'.format(command)) >> 132 proc = subprocess.Popen(command, >> 133 shell=True, >> 134 stdout=subprocess.PIPE, >> 135 stderr=subprocess.PIPE, >> 136 env=ENVIR) >> 137 (rawout, serr) = proc.communicate() 229 138 230 proc = self._proc !! 139 if proc.returncode != 0 and len(serr) > 0: 231 !! 140 foutput = serr.decode("utf-8") 232 proc.stdin.write((command + '\n').enco !! 141 else: 233 proc.stdin.flush() !! 142 foutput = rawout.decode("utf-8") 234 << 235 if self.args.verbose > 3: << 236 print('_exec_cmd proc: {}'.format( << 237 << 238 self._proc_check() << 239 143 240 def _exec_cmd_batched(self, stage, command !! 144 proc.stdout.close() 241 for cmd in commands: !! 145 proc.stderr.close() 242 self._exec_cmd(stage, cmd) !! 146 return proc, foutput 243 147 244 def _replace_keywords(self, cmd): 148 def _replace_keywords(self, cmd): 245 """ 149 """ 246 For a given executable command, substi 150 For a given executable command, substitute any known 247 variables contained within NAMES with 151 variables contained within NAMES with the correct values 248 """ 152 """ 249 tcmd = Template(cmd) 153 tcmd = Template(cmd) 250 subcmd = tcmd.safe_substitute(self.arg 154 subcmd = tcmd.safe_substitute(self.args.NAMES) 251 return subcmd 155 return subcmd
Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.