nsPlugin.py 4.7 KB

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