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 22 def post_suite(self, index): 23 '''run commands after test_runner goes into a test loop''' 24 super().post_suite(index) 25 if self.args.verbose: 26 print('{}.post_suite'.format(self.sub_class)) 27 28 if self.args.namespace: 29 self._ns_destroy() 30 31 def add_args(self, parser): 32 super().add_args(parser) 33 self.argparser_group = self.argparser.add_argument_group( 34 'netns', 35 'options for nsPlugin(run commands in net namespace)') 36 self.argparser_group.add_argument( 37 '-n', '--namespace', action='store_true', 38 help='Run commands in namespace') 39 return self.argparser 40 41 def adjust_command(self, stage, command): 42 super().adjust_command(stage, command) 43 cmdform = 'list' 44 cmdlist = list() 45 46 if not self.args.namespace: 47 return command 48 49 if self.args.verbose: 50 print('{}.adjust_command'.format(self.sub_class)) 51 52 if not isinstance(command, list): 53 cmdform = 'str' 54 cmdlist = command.split() 55 else: 56 cmdlist = command 57 if stage == 'setup' or stage == 'execute' or stage == 'verify' or stage == 'teardown': 58 if self.args.verbose: 59 print('adjust_command: stage is {}; inserting netns stuff in command [{}] list [{}]'.format(stage, command, cmdlist)) 60 cmdlist.insert(0, self.args.NAMES['NS']) 61 cmdlist.insert(0, 'exec') 62 cmdlist.insert(0, 'netns') 63 cmdlist.insert(0, 'ip') 64 else: 65 pass 66 67 if cmdform == 'str': 68 command = ' '.join(cmdlist) 69 else: 70 command = cmdlist 71 72 if self.args.verbose: 73 print('adjust_command: return command [{}]'.format(command)) 74 return command 75 76 def _ns_create(self): 77 ''' 78 Create the network namespace in which the tests will be run and set up 79 the required network devices for it. 80 ''' 81 if self.args.namespace: 82 cmd = 'ip netns add {}'.format(self.args.NAMES['NS']) 83 self._exec_cmd('pre', cmd) 84 cmd = 'ip link add $DEV0 type veth peer name $DEV1' 85 self._exec_cmd('pre', cmd) 86 cmd = 'ip link set $DEV1 netns {}'.format(self.args.NAMES['NS']) 87 self._exec_cmd('pre', cmd) 88 cmd = 'ip link set $DEV0 up' 89 self._exec_cmd('pre', cmd) 90 cmd = 'ip -n {} link set $DEV1 up'.format(self.args.NAMES['NS']) 91 self._exec_cmd('pre', cmd) 92 if self.args.device: 93 cmd = 'ip link set $DEV2 netns {}'.format(self.args.NAMES['NS']) 94 self._exec_cmd('pre', cmd) 95 cmd = 'ip -n {} link set $DEV2 up'.format(self.args.NAMES['NS']) 96 self._exec_cmd('pre', cmd) 97 98 def _ns_destroy(self): 99 ''' 100 Destroy the network namespace for testing (and any associated network 101 devices as well) 102 ''' 103 if self.args.namespace: 104 cmd = 'ip netns delete {}'.format(self.args.NAMES['NS']) 105 self._exec_cmd('post', cmd) 106 107 def _exec_cmd(self, stage, command): 108 ''' 109 Perform any required modifications on an executable command, then run 110 it in a subprocess and return the results. 111 ''' 112 if '$' in command: 113 command = self._replace_keywords(command) 114 115 self.adjust_command(stage, command) 116 if self.args.verbose: 117 print('_exec_cmd: command "{}"'.format(command)) 118 proc = subprocess.Popen(command, 119 shell=True, 120 stdout=subprocess.PIPE, 121 stderr=subprocess.PIPE, 122 env=ENVIR) 123 (rawout, serr) = proc.communicate() 124 125 if proc.returncode != 0 and len(serr) > 0: 126 foutput = serr.decode("utf-8") 127 else: 128 foutput = rawout.decode("utf-8") 129 130 proc.stdout.close() 131 proc.stderr.close() 132 return proc, foutput 133 134 def _replace_keywords(self, cmd): 135 """ 136 For a given executable command, substitute any known 137 variables contained within NAMES with the correct values 138 """ 139 tcmd = Template(cmd) 140 subcmd = tcmd.safe_substitute(self.args.NAMES) 141 return subcmd 142