servermanager.py 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. #!/usr/bin/env python
  2. # Copyright 2011 Google Inc. All Rights Reserved.
  3. #
  4. # Licensed under the Apache License, Version 2.0 (the "License");
  5. # you may not use this file except in compliance with the License.
  6. # You may obtain a copy of the License at
  7. #
  8. # http://www.apache.org/licenses/LICENSE-2.0
  9. #
  10. # Unless required by applicable law or agreed to in writing, software
  11. # distributed under the License is distributed on an "AS IS" BASIS,
  12. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. # See the License for the specific language governing permissions and
  14. # limitations under the License.
  15. """Control "replay.py --server_mode" (e.g. switch from record to replay)."""
  16. import sys
  17. import time
  18. class ServerManager(object):
  19. """Run servers until is removed or an exception is raised.
  20. Servers start in the order they are appended and stop in the
  21. opposite order. Servers are started by calling the initializer
  22. passed to ServerManager.Append() and by calling __enter__(). Once an
  23. server's initializer is called successfully, the __exit__() function
  24. is guaranteed to be called when ServerManager.Run() completes.
  25. """
  26. def __init__(self, is_record_mode):
  27. """Initialize a server manager."""
  28. self.initializers = []
  29. self.record_callbacks = []
  30. self.replay_callbacks = []
  31. self.traffic_shapers = []
  32. self.is_record_mode = is_record_mode
  33. self.should_exit = False
  34. def Append(self, initializer, *init_args, **init_kwargs):
  35. """Append a server to the end of the list to run.
  36. Servers start in the order they are appended and stop in the
  37. opposite order.
  38. Args:
  39. initializer: a function that returns a server instance.
  40. A server needs to implement the with-statement interface.
  41. init_args: positional arguments for the initializer.
  42. init_args: keyword arguments for the initializer.
  43. """
  44. self.initializers.append((initializer, init_args, init_kwargs))
  45. def AppendTrafficShaper(self, initializer, *init_args, **init_kwargs):
  46. """Append a traffic shaper to the end of the list to run.
  47. Args:
  48. initializer: a function that returns a server instance.
  49. A server needs to implement the with-statement interface.
  50. init_args: positional arguments for the initializer.
  51. init_args: keyword arguments for the initializer.
  52. """
  53. self.traffic_shapers.append((initializer, init_args, init_kwargs))
  54. def AppendRecordCallback(self, func):
  55. """Append a function to the list to call when switching to record mode.
  56. Args:
  57. func: a function that takes no arguments and returns no value.
  58. """
  59. self.record_callbacks.append(func)
  60. def AppendReplayCallback(self, func):
  61. """Append a function to the list to call when switching to replay mode.
  62. Args:
  63. func: a function that takes no arguments and returns no value.
  64. """
  65. self.replay_callbacks.append(func)
  66. def IsRecordMode(self):
  67. """Call all the functions that have been registered to enter replay mode."""
  68. return self.is_record_mode
  69. def SetRecordMode(self):
  70. """Call all the functions that have been registered to enter record mode."""
  71. self.is_record_mode = True
  72. for record_func in self.record_callbacks:
  73. record_func()
  74. def SetReplayMode(self):
  75. """Call all the functions that have been registered to enter replay mode."""
  76. self.is_record_mode = False
  77. for replay_func in self.replay_callbacks:
  78. replay_func()
  79. def Run(self):
  80. """Create the servers and loop.
  81. The loop quits if a server raises an exception.
  82. Raises:
  83. any exception raised by the servers
  84. """
  85. server_exits = []
  86. server_ports = []
  87. exception_info = (None, None, None)
  88. try:
  89. for initializer, init_args, init_kwargs in self.initializers:
  90. server = initializer(*init_args, **init_kwargs)
  91. if server:
  92. server_exits.insert(0, server.__exit__)
  93. server.__enter__()
  94. if hasattr(server, 'server_port'):
  95. server_ports.append(server.server_port)
  96. for initializer, init_args, init_kwargs in self.traffic_shapers:
  97. init_kwargs['ports'] = server_ports
  98. shaper = initializer(*init_args, **init_kwargs)
  99. if server:
  100. server_exits.insert(0, shaper.__exit__)
  101. shaper.__enter__()
  102. while True:
  103. time.sleep(1)
  104. if self.should_exit:
  105. break
  106. except Exception:
  107. exception_info = sys.exc_info()
  108. finally:
  109. for server_exit in server_exits:
  110. try:
  111. if server_exit(*exception_info):
  112. exception_info = (None, None, None)
  113. except Exception:
  114. exception_info = sys.exc_info()
  115. if exception_info != (None, None, None):
  116. # pylint: disable=raising-bad-type
  117. raise exception_info[0], exception_info[1], exception_info[2]