OpenStack Storage (Swift)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

164 lines
5.0KB

  1. #!/usr/bin/python -u
  2. # Copyright (c) 2010-2012 OpenStack Foundation
  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
  13. # implied.
  14. # See the License for the specific language governing permissions and
  15. # limitations under the License.
  16. import unittest
  17. import random
  18. from contextlib import contextmanager
  19. import eventlet
  20. from six.moves import http_client as httplib
  21. from swift.common.storage_policy import POLICIES
  22. from swift.common.ring import Ring
  23. from swift.common.manager import Manager
  24. from test.probe.common import resetswift
  25. def putrequest(conn, method, path, headers):
  26. conn.putrequest(method, path, skip_host=(headers and 'Host' in headers))
  27. if headers:
  28. for header, value in headers.items():
  29. conn.putheader(header, str(value))
  30. conn.endheaders()
  31. class TestWSGIServerProcessHandling(unittest.TestCase):
  32. def setUp(self):
  33. resetswift()
  34. def _check_reload(self, server_name, ip, port):
  35. manager = Manager([server_name])
  36. manager.start()
  37. starting_pids = {pid for server in manager.servers
  38. for (_, pid) in server.iter_pid_files()}
  39. body = b'test' * 10
  40. conn = httplib.HTTPConnection('%s:%s' % (ip, port))
  41. # sanity request
  42. putrequest(conn, 'PUT', 'blah',
  43. headers={'Content-Length': len(body)})
  44. conn.send(body)
  45. resp = conn.getresponse()
  46. self.assertEqual(resp.status // 100, 4)
  47. resp.read()
  48. # Start the request before reloading...
  49. putrequest(conn, 'PUT', 'blah',
  50. headers={'Content-Length': len(body)})
  51. manager.reload()
  52. post_reload_pids = {pid for server in manager.servers
  53. for (_, pid) in server.iter_pid_files()}
  54. # none of the pids we started with are being tracked after reload
  55. msg = 'expected all pids from %r to have died, but found %r' % (
  56. starting_pids, post_reload_pids)
  57. self.assertFalse(starting_pids & post_reload_pids, msg)
  58. # ... and make sure we can finish what we were doing, and even
  59. # start part of a new request
  60. conn.send(body)
  61. resp = conn.getresponse()
  62. self.assertEqual(resp.status // 100, 4)
  63. # We can even read the body
  64. self.assertTrue(resp.read())
  65. # After this, we're in a funny spot. With eventlet 0.22.0, the
  66. # connection's now closed, but with prior versions we could keep
  67. # going indefinitely. See https://bugs.launchpad.net/swift/+bug/1792615
  68. # Close our connection, to make sure old eventlet shuts down
  69. conn.close()
  70. # sanity
  71. post_close_pids = {pid for server in manager.servers
  72. for (_, pid) in server.iter_pid_files()}
  73. self.assertEqual(post_reload_pids, post_close_pids)
  74. def test_proxy_reload(self):
  75. self._check_reload('proxy-server', 'localhost', 8080)
  76. def test_object_reload(self):
  77. policy = random.choice(list(POLICIES))
  78. policy.load_ring('/etc/swift')
  79. node = random.choice(policy.object_ring.get_part_nodes(1))
  80. self._check_reload('object', node['ip'], node['port'])
  81. def test_account_container_reload(self):
  82. for server in ('account', 'container'):
  83. ring = Ring('/etc/swift', ring_name=server)
  84. node = random.choice(ring.get_part_nodes(1))
  85. self._check_reload(server, node['ip'], node['port'])
  86. @contextmanager
  87. def spawn_services(ip_ports, timeout=10):
  88. q = eventlet.Queue()
  89. def service(sock):
  90. try:
  91. conn, address = sock.accept()
  92. q.put(address)
  93. eventlet.sleep(timeout)
  94. conn.close()
  95. finally:
  96. sock.close()
  97. pool = eventlet.GreenPool()
  98. for ip, port in ip_ports:
  99. sock = eventlet.listen((ip, port))
  100. pool.spawn(service, sock)
  101. try:
  102. yield q
  103. finally:
  104. for gt in list(pool.coroutines_running):
  105. gt.kill()
  106. class TestHungDaemon(unittest.TestCase):
  107. def setUp(self):
  108. resetswift()
  109. self.ip_ports = [
  110. (dev['ip'], dev['port'])
  111. for dev in Ring('/etc/swift', ring_name='account').devs
  112. if dev
  113. ]
  114. def test_main(self):
  115. reconciler = Manager(['container-reconciler'])
  116. with spawn_services(self.ip_ports) as q:
  117. reconciler.start()
  118. # wait for the reconciler to connect
  119. q.get()
  120. # once it's hung in our connection - send it sig term
  121. print('Attempting to stop reconciler!')
  122. reconciler.stop()
  123. self.assertEqual(1, reconciler.status())
  124. if __name__ == '__main__':
  125. unittest.main()