1import os 2import signal 3from string import Template 4import subprocess 5import time 6from TdcPlugin import TdcPlugin 7 8from tdc_config import * 9 10class SubPlugin(TdcPlugin): 11 def __init__(self): 12 self.sub_class = 'ns/SubPlugin' 13 super().__init__() 14 15 def pre_suite(self, testcount, testidlist): 16 '''run commands before test_runner goes into a test loop''' 17 super().pre_suite(testcount, testidlist) 18 19 if self.args.namespace: 20 self._ns_create() 21 else: 22 self._ports_create() 23 24 def post_suite(self, index): 25 '''run commands after test_runner goes into a test loop''' 26 super().post_suite(index) 27 if self.args.verbose: 28 print('{}.post_suite'.format(self.sub_class)) 29 30 if self.args.namespace: 31 self._ns_destroy() 32 else: 33 self._ports_destroy() 34 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 44 45 def adjust_command(self, stage, command): 46 super().adjust_command(stage, command) 47 cmdform = 'list' 48 cmdlist = list() 49 50 if not self.args.namespace: 51 return command 52 53 if self.args.verbose: 54 print('{}.adjust_command'.format(self.sub_class)) 55 56 if not isinstance(command, list): 57 cmdform = 'str' 58 cmdlist = command.split() 59 else: 60 cmdlist = command 61 if stage == 'setup' or stage == 'execute' or stage == 'verify' or stage == 'teardown': 62 if self.args.verbose: 63 print('adjust_command: stage is {}; inserting netns stuff in command [{}] list [{}]'.format(stage, command, cmdlist)) 64 cmdlist.insert(0, self.args.NAMES['NS']) 65 cmdlist.insert(0, 'exec') 66 cmdlist.insert(0, 'netns') 67 cmdlist.insert(0, 'ip') 68 else: 69 pass 70 71 if cmdform == 'str': 72 command = ' '.join(cmdlist) 73 else: 74 command = cmdlist 75 76 if self.args.verbose: 77 print('adjust_command: return command [{}]'.format(command)) 78 return command 79 80 def _ports_create(self): 81 cmd = 'ip link add $DEV0 type veth peer name $DEV1' 82 self._exec_cmd('pre', cmd) 83 cmd = 'ip link set $DEV0 up' 84 self._exec_cmd('pre', cmd) 85 if not self.args.namespace: 86 cmd = 'ip link set $DEV1 up' 87 self._exec_cmd('pre', cmd) 88 89 def _ports_destroy(self): 90 cmd = 'ip link del $DEV0' 91 self._exec_cmd('post', cmd) 92 93 def _ns_create(self): 94 ''' 95 Create the network namespace in which the tests will be run and set up 96 the required network devices for it. 97 ''' 98 self._ports_create() 99 if self.args.namespace: 100 cmd = 'ip netns add {}'.format(self.args.NAMES['NS']) 101 self._exec_cmd('pre', cmd) 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) 111 112 def _ns_destroy(self): 113 ''' 114 Destroy the network namespace for testing (and any associated network 115 devices as well) 116 ''' 117 if self.args.namespace: 118 cmd = 'ip netns delete {}'.format(self.args.NAMES['NS']) 119 self._exec_cmd('post', cmd) 120 121 def _exec_cmd(self, stage, command): 122 ''' 123 Perform any required modifications on an executable command, then run 124 it in a subprocess and return the results. 125 ''' 126 if '$' in command: 127 command = self._replace_keywords(command) 128 129 self.adjust_command(stage, command) 130 if self.args.verbose: 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() 138 139 if proc.returncode != 0 and len(serr) > 0: 140 foutput = serr.decode("utf-8") 141 else: 142 foutput = rawout.decode("utf-8") 143 144 proc.stdout.close() 145 proc.stderr.close() 146 return proc, foutput 147 148 def _replace_keywords(self, cmd): 149 """ 150 For a given executable command, substitute any known 151 variables contained within NAMES with the correct values 152 """ 153 tcmd = Template(cmd) 154 subcmd = tcmd.safe_substitute(self.args.NAMES) 155 return subcmd 156