162306a36Sopenharmony_ciimport os
262306a36Sopenharmony_ciimport signal
362306a36Sopenharmony_cifrom string import Template
462306a36Sopenharmony_ciimport subprocess
562306a36Sopenharmony_ciimport time
662306a36Sopenharmony_cifrom TdcPlugin import TdcPlugin
762306a36Sopenharmony_ci
862306a36Sopenharmony_cifrom tdc_config import *
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ciclass SubPlugin(TdcPlugin):
1162306a36Sopenharmony_ci    def __init__(self):
1262306a36Sopenharmony_ci        self.sub_class = 'ns/SubPlugin'
1362306a36Sopenharmony_ci        super().__init__()
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci    def pre_suite(self, testcount, testidlist):
1662306a36Sopenharmony_ci        '''run commands before test_runner goes into a test loop'''
1762306a36Sopenharmony_ci        super().pre_suite(testcount, testidlist)
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci        if self.args.namespace:
2062306a36Sopenharmony_ci            self._ns_create()
2162306a36Sopenharmony_ci        else:
2262306a36Sopenharmony_ci            self._ports_create()
2362306a36Sopenharmony_ci
2462306a36Sopenharmony_ci    def post_suite(self, index):
2562306a36Sopenharmony_ci        '''run commands after test_runner goes into a test loop'''
2662306a36Sopenharmony_ci        super().post_suite(index)
2762306a36Sopenharmony_ci        if self.args.verbose:
2862306a36Sopenharmony_ci            print('{}.post_suite'.format(self.sub_class))
2962306a36Sopenharmony_ci
3062306a36Sopenharmony_ci        if self.args.namespace:
3162306a36Sopenharmony_ci            self._ns_destroy()
3262306a36Sopenharmony_ci        else:
3362306a36Sopenharmony_ci            self._ports_destroy()
3462306a36Sopenharmony_ci
3562306a36Sopenharmony_ci    def add_args(self, parser):
3662306a36Sopenharmony_ci        super().add_args(parser)
3762306a36Sopenharmony_ci        self.argparser_group = self.argparser.add_argument_group(
3862306a36Sopenharmony_ci            'netns',
3962306a36Sopenharmony_ci            'options for nsPlugin(run commands in net namespace)')
4062306a36Sopenharmony_ci        self.argparser_group.add_argument(
4162306a36Sopenharmony_ci            '-N', '--no-namespace', action='store_false', default=True,
4262306a36Sopenharmony_ci            dest='namespace', help='Don\'t run commands in namespace')
4362306a36Sopenharmony_ci        return self.argparser
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci    def adjust_command(self, stage, command):
4662306a36Sopenharmony_ci        super().adjust_command(stage, command)
4762306a36Sopenharmony_ci        cmdform = 'list'
4862306a36Sopenharmony_ci        cmdlist = list()
4962306a36Sopenharmony_ci
5062306a36Sopenharmony_ci        if not self.args.namespace:
5162306a36Sopenharmony_ci            return command
5262306a36Sopenharmony_ci
5362306a36Sopenharmony_ci        if self.args.verbose:
5462306a36Sopenharmony_ci            print('{}.adjust_command'.format(self.sub_class))
5562306a36Sopenharmony_ci
5662306a36Sopenharmony_ci        if not isinstance(command, list):
5762306a36Sopenharmony_ci            cmdform = 'str'
5862306a36Sopenharmony_ci            cmdlist = command.split()
5962306a36Sopenharmony_ci        else:
6062306a36Sopenharmony_ci            cmdlist = command
6162306a36Sopenharmony_ci        if stage == 'setup' or stage == 'execute' or stage == 'verify' or stage == 'teardown':
6262306a36Sopenharmony_ci            if self.args.verbose:
6362306a36Sopenharmony_ci                print('adjust_command:  stage is {}; inserting netns stuff in command [{}] list [{}]'.format(stage, command, cmdlist))
6462306a36Sopenharmony_ci            cmdlist.insert(0, self.args.NAMES['NS'])
6562306a36Sopenharmony_ci            cmdlist.insert(0, 'exec')
6662306a36Sopenharmony_ci            cmdlist.insert(0, 'netns')
6762306a36Sopenharmony_ci            cmdlist.insert(0, self.args.NAMES['IP'])
6862306a36Sopenharmony_ci        else:
6962306a36Sopenharmony_ci            pass
7062306a36Sopenharmony_ci
7162306a36Sopenharmony_ci        if cmdform == 'str':
7262306a36Sopenharmony_ci            command = ' '.join(cmdlist)
7362306a36Sopenharmony_ci        else:
7462306a36Sopenharmony_ci            command = cmdlist
7562306a36Sopenharmony_ci
7662306a36Sopenharmony_ci        if self.args.verbose:
7762306a36Sopenharmony_ci            print('adjust_command:  return command [{}]'.format(command))
7862306a36Sopenharmony_ci        return command
7962306a36Sopenharmony_ci
8062306a36Sopenharmony_ci    def _ports_create(self):
8162306a36Sopenharmony_ci        cmd = '$IP link add $DEV0 type veth peer name $DEV1'
8262306a36Sopenharmony_ci        self._exec_cmd('pre', cmd)
8362306a36Sopenharmony_ci        cmd = '$IP link set $DEV0 up'
8462306a36Sopenharmony_ci        self._exec_cmd('pre', cmd)
8562306a36Sopenharmony_ci        if not self.args.namespace:
8662306a36Sopenharmony_ci            cmd = '$IP link set $DEV1 up'
8762306a36Sopenharmony_ci            self._exec_cmd('pre', cmd)
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci    def _ports_destroy(self):
9062306a36Sopenharmony_ci        cmd = '$IP link del $DEV0'
9162306a36Sopenharmony_ci        self._exec_cmd('post', cmd)
9262306a36Sopenharmony_ci
9362306a36Sopenharmony_ci    def _ns_create(self):
9462306a36Sopenharmony_ci        '''
9562306a36Sopenharmony_ci        Create the network namespace in which the tests will be run and set up
9662306a36Sopenharmony_ci        the required network devices for it.
9762306a36Sopenharmony_ci        '''
9862306a36Sopenharmony_ci        self._ports_create()
9962306a36Sopenharmony_ci        if self.args.namespace:
10062306a36Sopenharmony_ci            cmd = '$IP netns add {}'.format(self.args.NAMES['NS'])
10162306a36Sopenharmony_ci            self._exec_cmd('pre', cmd)
10262306a36Sopenharmony_ci            cmd = '$IP link set $DEV1 netns {}'.format(self.args.NAMES['NS'])
10362306a36Sopenharmony_ci            self._exec_cmd('pre', cmd)
10462306a36Sopenharmony_ci            cmd = '$IP -n {} link set $DEV1 up'.format(self.args.NAMES['NS'])
10562306a36Sopenharmony_ci            self._exec_cmd('pre', cmd)
10662306a36Sopenharmony_ci            if self.args.device:
10762306a36Sopenharmony_ci                cmd = '$IP link set $DEV2 netns {}'.format(self.args.NAMES['NS'])
10862306a36Sopenharmony_ci                self._exec_cmd('pre', cmd)
10962306a36Sopenharmony_ci                cmd = '$IP -n {} link set $DEV2 up'.format(self.args.NAMES['NS'])
11062306a36Sopenharmony_ci                self._exec_cmd('pre', cmd)
11162306a36Sopenharmony_ci
11262306a36Sopenharmony_ci    def _ns_destroy(self):
11362306a36Sopenharmony_ci        '''
11462306a36Sopenharmony_ci        Destroy the network namespace for testing (and any associated network
11562306a36Sopenharmony_ci        devices as well)
11662306a36Sopenharmony_ci        '''
11762306a36Sopenharmony_ci        if self.args.namespace:
11862306a36Sopenharmony_ci            cmd = '$IP netns delete {}'.format(self.args.NAMES['NS'])
11962306a36Sopenharmony_ci            self._exec_cmd('post', cmd)
12062306a36Sopenharmony_ci
12162306a36Sopenharmony_ci    def _exec_cmd(self, stage, command):
12262306a36Sopenharmony_ci        '''
12362306a36Sopenharmony_ci        Perform any required modifications on an executable command, then run
12462306a36Sopenharmony_ci        it in a subprocess and return the results.
12562306a36Sopenharmony_ci        '''
12662306a36Sopenharmony_ci        if '$' in command:
12762306a36Sopenharmony_ci            command = self._replace_keywords(command)
12862306a36Sopenharmony_ci
12962306a36Sopenharmony_ci        self.adjust_command(stage, command)
13062306a36Sopenharmony_ci        if self.args.verbose:
13162306a36Sopenharmony_ci            print('_exec_cmd:  command "{}"'.format(command))
13262306a36Sopenharmony_ci        proc = subprocess.Popen(command,
13362306a36Sopenharmony_ci            shell=True,
13462306a36Sopenharmony_ci            stdout=subprocess.PIPE,
13562306a36Sopenharmony_ci            stderr=subprocess.PIPE,
13662306a36Sopenharmony_ci            env=ENVIR)
13762306a36Sopenharmony_ci        (rawout, serr) = proc.communicate()
13862306a36Sopenharmony_ci
13962306a36Sopenharmony_ci        if proc.returncode != 0 and len(serr) > 0:
14062306a36Sopenharmony_ci            foutput = serr.decode("utf-8")
14162306a36Sopenharmony_ci        else:
14262306a36Sopenharmony_ci            foutput = rawout.decode("utf-8")
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci        proc.stdout.close()
14562306a36Sopenharmony_ci        proc.stderr.close()
14662306a36Sopenharmony_ci        return proc, foutput
14762306a36Sopenharmony_ci
14862306a36Sopenharmony_ci    def _replace_keywords(self, cmd):
14962306a36Sopenharmony_ci        """
15062306a36Sopenharmony_ci        For a given executable command, substitute any known
15162306a36Sopenharmony_ci        variables contained within NAMES with the correct values
15262306a36Sopenharmony_ci        """
15362306a36Sopenharmony_ci        tcmd = Template(cmd)
15462306a36Sopenharmony_ci        subcmd = tcmd.safe_substitute(self.args.NAMES)
15562306a36Sopenharmony_ci        return subcmd
156