bind10_control.py 9.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233
  1. # Copyright (C) 2011 Internet Systems Consortium.
  2. #
  3. # Permission to use, copy, modify, and distribute this software for any
  4. # purpose with or without fee is hereby granted, provided that the above
  5. # copyright notice and this permission notice appear in all copies.
  6. #
  7. # THE SOFTWARE IS PROVIDED "AS IS" AND INTERNET SYSTEMS CONSORTIUM
  8. # DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
  9. # IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL
  10. # INTERNET SYSTEMS CONSORTIUM BE LIABLE FOR ANY SPECIAL, DIRECT,
  11. # INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING
  12. # FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT,
  13. # NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION
  14. # WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. from lettuce import *
  16. import subprocess
  17. import re
  18. @step('start bind10(?: with configuration (\S+))?' +\
  19. '(?: with cmdctl port (\d+))?' +\
  20. '(?: with msgq socket file (\S+))?' +\
  21. '(?: as (\S+))?')
  22. def start_bind10(step, config_file, cmdctl_port, msgq_sockfile, process_name):
  23. """
  24. Start BIND 10 with the given optional config file, cmdctl port, and
  25. store the running process in world with the given process name.
  26. Parameters:
  27. config_file ('with configuration <file>', optional): this configuration
  28. will be used. The path is relative to the base lettuce
  29. directory.
  30. cmdctl_port ('with cmdctl port <portnr>', optional): The port on which
  31. b10-cmdctl listens for bindctl commands. Defaults to 47805.
  32. msgq_sockfile ('with msgq socket file', optional): The msgq socket file
  33. that will be used for internal communication
  34. process_name ('as <name>', optional). This is the name that can be used
  35. in the following steps of the scenario to refer to this
  36. BIND 10 instance. Defaults to 'bind10'.
  37. This call will block until BIND10_STARTUP_COMPLETE or BIND10_STARTUP_ERROR
  38. is logged. In the case of the latter, or if it times out, the step (and
  39. scenario) will fail.
  40. It will also fail if there is a running process with the given process_name
  41. already.
  42. """
  43. args = [ 'bind10', '-v' ]
  44. if config_file is not None:
  45. args.append('-p')
  46. args.append("configurations/")
  47. args.append('-c')
  48. args.append(config_file)
  49. if cmdctl_port is None:
  50. args.append('--cmdctl-port=47805')
  51. else:
  52. args.append('--cmdctl-port=' + cmdctl_port)
  53. if process_name is None:
  54. process_name = "bind10"
  55. else:
  56. args.append('-m')
  57. args.append(process_name + '_msgq.socket')
  58. world.processes.add_process(step, process_name, args)
  59. # check output to know when startup has been completed
  60. (message, line) = world.processes.wait_for_stderr_str(process_name,
  61. ["BIND10_STARTUP_COMPLETE",
  62. "BIND10_STARTUP_ERROR"])
  63. assert message == "BIND10_STARTUP_COMPLETE", "Got: " + str(line)
  64. @step('wait for bind10 auth (?:of (\w+) )?to start')
  65. def wait_for_auth(step, process_name):
  66. """Wait for b10-auth to run. This is done by blocking until the message
  67. AUTH_SERVER_STARTED is logged.
  68. Parameters:
  69. process_name ('of <name', optional): The name of the BIND 10 instance
  70. to wait for. Defaults to 'bind10'.
  71. """
  72. if process_name is None:
  73. process_name = "bind10"
  74. world.processes.wait_for_stderr_str(process_name, ['AUTH_SERVER_STARTED'],
  75. False)
  76. @step('wait for bind10 xfrout (?:of (\w+) )?to start')
  77. def wait_for_xfrout(step, process_name):
  78. """Wait for b10-xfrout to run. This is done by blocking until the message
  79. XFROUT_NEW_CONFIG_DONE is logged.
  80. Parameters:
  81. process_name ('of <name', optional): The name of the BIND 10 instance
  82. to wait for. Defaults to 'bind10'.
  83. """
  84. if process_name is None:
  85. process_name = "bind10"
  86. world.processes.wait_for_stderr_str(process_name,
  87. ['XFROUT_NEW_CONFIG_DONE'],
  88. False)
  89. @step('have bind10 running(?: with configuration ([\S]+))?' +\
  90. '(?: with cmdctl port (\d+))?' +\
  91. '(?: as ([\S]+))?')
  92. def have_bind10_running(step, config_file, cmdctl_port, process_name):
  93. """
  94. Compound convenience step for running bind10, which consists of
  95. start_bind10 and wait_for_auth.
  96. Currently only supports the 'with configuration' option.
  97. """
  98. start_step = 'start bind10 with configuration ' + config_file
  99. wait_step = 'wait for bind10 auth to start'
  100. if cmdctl_port is not None:
  101. start_step += ' with cmdctl port ' + str(cmdctl_port)
  102. if process_name is not None:
  103. start_step += ' as ' + process_name
  104. wait_step = 'wait for bind10 auth of ' + process_name + ' to start'
  105. step.given(start_step)
  106. step.given(wait_step)
  107. # function to send lines to bindctl, and store the result
  108. def run_bindctl(commands, cmdctl_port=None):
  109. """Run bindctl.
  110. Parameters:
  111. commands: a sequence of strings which will be sent.
  112. cmdctl_port: a port number on which cmdctl is listening, is converted
  113. to string if necessary. If not provided, or None, defaults
  114. to 47805
  115. bindctl's stdout and stderr streams are stored (as one multiline string
  116. in world.last_bindctl_stdout/stderr.
  117. Fails if the return code is not 0
  118. """
  119. if cmdctl_port is None:
  120. cmdctl_port = 47805
  121. args = ['bindctl', '-p', str(cmdctl_port)]
  122. bindctl = subprocess.Popen(args, 1, None, subprocess.PIPE,
  123. subprocess.PIPE, None)
  124. for line in commands:
  125. bindctl.stdin.write(line + "\n")
  126. (stdout, stderr) = bindctl.communicate()
  127. result = bindctl.returncode
  128. world.last_bindctl_stdout = stdout
  129. world.last_bindctl_stderr = stderr
  130. assert result == 0, "bindctl exit code: " + str(result) +\
  131. "\nstdout:\n" + str(stdout) +\
  132. "stderr:\n" + str(stderr)
  133. @step('last bindctl( stderr)? output should( not)? contain (\S+)')
  134. def check_bindctl_output(step, stderr, notv, string):
  135. """Checks the stdout (or stderr) stream of the last run of bindctl,
  136. fails if the given string is not found in it (or fails if 'not' was
  137. set and it is found
  138. Parameters:
  139. stderr ('stderr'): Check stderr instead of stdout output
  140. notv ('not'): reverse the check (fail if string is found)
  141. string ('contain <string>') string to look for
  142. """
  143. if stderr is None:
  144. output = world.last_bindctl_stdout
  145. else:
  146. output = world.last_bindctl_stderr
  147. found = False
  148. if string in output:
  149. found = True
  150. if notv is None:
  151. assert found == True, "'" + string +\
  152. "' was not found in bindctl output:\n" +\
  153. output
  154. else:
  155. assert not found, "'" + string +\
  156. "' was found in bindctl output:\n" +\
  157. output
  158. @step('set bind10 configuration (\S+) to (.*)(?: with cmdctl port (\d+))?')
  159. def config_set_command(step, name, value, cmdctl_port):
  160. """
  161. Run bindctl, set the given configuration to the given value, and commit it.
  162. Parameters:
  163. name ('configuration <name>'): Identifier of the configuration to set
  164. value ('to <value>'): value to set it to.
  165. cmdctl_port ('with cmdctl port <portnr>', optional): cmdctl port to send
  166. the command to. Defaults to 47805.
  167. Fails if cmdctl does not exit with status code 0.
  168. """
  169. commands = ["config set " + name + " " + value,
  170. "config commit",
  171. "quit"]
  172. run_bindctl(commands, cmdctl_port)
  173. @step('remove bind10 configuration (\S+)(?: value (\S+))?(?: with cmdctl port (\d+))?')
  174. def config_remove_command(step, name, value, cmdctl_port):
  175. """
  176. Run bindctl, remove the given configuration item, and commit it.
  177. Parameters:
  178. name ('configuration <name>'): Identifier of the configuration to remove
  179. value ('value <value>'): if name is a named set, use value to identify
  180. item to remove
  181. cmdctl_port ('with cmdctl port <portnr>', optional): cmdctl port to send
  182. the command to. Defaults to 47805.
  183. Fails if cmdctl does not exit with status code 0.
  184. """
  185. cmd = "config remove " + name
  186. if value is not None:
  187. cmd = cmd + " " + value
  188. commands = [cmd,
  189. "config commit",
  190. "quit"]
  191. run_bindctl(commands, cmdctl_port)
  192. @step('send bind10 the command (.+)(?: with cmdctl port (\d+))?')
  193. def send_command(step, command, cmdctl_port):
  194. """
  195. Run bindctl, send the given command, and exit bindctl.
  196. Parameters:
  197. command ('the command <command>'): The command to send.
  198. cmdctl_port ('with cmdctl port <portnr>', optional): cmdctl port to send
  199. the command to. Defaults to 47805.
  200. Fails if cmdctl does not exit with status code 0.
  201. """
  202. commands = [command,
  203. "quit"]
  204. run_bindctl(commands, cmdctl_port)
  205. @step('bind10 module (\S+) should( not)? be running')
  206. def module_is_running(step, name, not_str):
  207. """
  208. Convenience step to check if a module is running; can only work with
  209. default cmdctl port; sends a 'help' command with bindctl, then
  210. checks if the output contains the given name.
  211. Parameters:
  212. name ('module <name>'): The name of the module (case sensitive!)
  213. not ('not'): Reverse the check (fail if it is running)
  214. """
  215. if not_str is None:
  216. not_str = ""
  217. step.given('send bind10 the command help')
  218. step.given('last bindctl output should' + not_str + ' contain ' + name)