Helpers for writing Ceph OpenStack Charms
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.

test_ceph.py 8.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. # Copyright 2016 Canonical Ltd
  2. #
  3. # Licensed under the Apache License, Version 2.0 (the "License");
  4. # you may not use this file except in compliance with the License.
  5. # You may obtain a copy of the License at
  6. #
  7. # http://www.apache.org/licenses/LICENSE-2.0
  8. #
  9. # Unless required by applicable law or agreed to in writing, software
  10. # distributed under the License is distributed on an "AS IS" BASIS,
  11. # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. # See the License for the specific language governing permissions and
  13. # limitations under the License.
  14. import mock
  15. import unittest
  16. import ceph
  17. from subprocess import CalledProcessError
  18. class TestDevice():
  19. """Test class to mock out pyudev Device"""
  20. def __getitem__(**kwargs):
  21. """
  22. Mock [].
  23. We need this method to be present in the test class mock even
  24. though we mock the return value with the MagicMock later
  25. """
  26. return "Some device type"
  27. def device_node():
  28. "/dev/test_device"
  29. class CephTestCase(unittest.TestCase):
  30. def setUp(self):
  31. super(CephTestCase, self).setUp()
  32. @mock.patch.object(ceph, 'check_output')
  33. def test_get_osd_weight(self, output):
  34. """It gives an OSD's weight"""
  35. output.return_value = """{
  36. "nodes": [{
  37. "id": -1,
  38. "name": "default",
  39. "type": "root",
  40. "type_id": 10,
  41. "children": [-4, -3, -2]
  42. }, {
  43. "id": -2,
  44. "name": "ip-172-31-11-147",
  45. "type": "host",
  46. "type_id": 1,
  47. "children": [0]
  48. }, {
  49. "id": 0,
  50. "name": "osd.0",
  51. "type": "osd",
  52. "type_id": 0,
  53. "crush_weight": 0.002899,
  54. "depth": 2,
  55. "exists": 1,
  56. "status": "up",
  57. "reweight": 1.000000,
  58. "primary_affinity": 1.000000
  59. }, {
  60. "id": -3,
  61. "name": "ip-172-31-56-198",
  62. "type": "host",
  63. "type_id": 1,
  64. "children": [2]
  65. }, {
  66. "id": 2,
  67. "name": "osd.2",
  68. "type": "osd",
  69. "type_id": 0,
  70. "crush_weight": 0.002899,
  71. "depth": 2,
  72. "exists": 1,
  73. "status": "up",
  74. "reweight": 1.000000,
  75. "primary_affinity": 1.000000
  76. }, {
  77. "id": -4,
  78. "name": "ip-172-31-24-103",
  79. "type": "host",
  80. "type_id": 1,
  81. "children": [1]
  82. }, {
  83. "id": 1,
  84. "name": "osd.1",
  85. "type": "osd",
  86. "type_id": 0,
  87. "crush_weight": 0.002899,
  88. "depth": 2,
  89. "exists": 1,
  90. "status": "up",
  91. "reweight": 1.000000,
  92. "primary_affinity": 1.000000
  93. }],
  94. "stray": []
  95. }"""
  96. weight = ceph.get_osd_weight('osd.0')
  97. self.assertEqual(weight, 0.002899)
  98. def test_get_named_key_with_pool(self):
  99. with mock.patch.object(ceph, "ceph_user", return_value="ceph"):
  100. with mock.patch.object(ceph, "check_output") \
  101. as subprocess:
  102. with mock.patch.object(ceph.socket, "gethostname",
  103. return_value="osd001"):
  104. subprocess.side_effect = [
  105. CalledProcessError(0, 0, 0), ""]
  106. ceph.get_named_key(name="rgw001",
  107. pool_list=["rbd", "block"])
  108. subprocess.assert_has_calls([
  109. mock.call(['sudo', '-u', 'ceph', 'ceph', '--name',
  110. 'mon.', '--keyring',
  111. '/var/lib/ceph/mon/ceph-osd001/keyring',
  112. 'auth', 'get', 'client.rgw001']),
  113. mock.call(['sudo', '-u', 'ceph', 'ceph', '--name',
  114. 'mon.', '--keyring',
  115. '/var/lib/ceph/mon/ceph-osd001/keyring',
  116. 'auth', 'get-or-create', 'client.rgw001',
  117. 'mon', 'allow r', 'osd',
  118. 'allow rwx pool=rbd pool=block'])])
  119. def test_get_named_key(self):
  120. with mock.patch.object(ceph, "ceph_user", return_value="ceph"):
  121. with mock.patch.object(ceph, "check_output") \
  122. as subprocess:
  123. subprocess.side_effect = [
  124. CalledProcessError(0, 0, 0),
  125. ""]
  126. with mock.patch.object(ceph.socket, "gethostname",
  127. return_value="osd001"):
  128. ceph.get_named_key(name="rgw001")
  129. for call in subprocess.mock_calls:
  130. print("Subprocess: {}".format(call))
  131. subprocess.assert_has_calls([
  132. mock.call(['sudo', '-u', 'ceph', 'ceph', '--name',
  133. 'mon.', '--keyring',
  134. '/var/lib/ceph/mon/ceph-osd001/keyring',
  135. 'auth', 'get', 'client.rgw001']),
  136. mock.call(['sudo', '-u', 'ceph', 'ceph', '--name',
  137. 'mon.', '--keyring',
  138. '/var/lib/ceph/mon/ceph-osd001/keyring',
  139. 'auth', 'get-or-create', 'client.rgw001',
  140. 'mon', 'allow r', 'osd',
  141. 'allow rwx'])])
  142. def test_parse_key_with_caps_existing_key(self):
  143. expected = "AQCm7aVYQFXXFhAAj0WIeqcag88DKOvY4UKR/g=="
  144. with_caps = "[client.osd-upgrade]\n" \
  145. " key = AQCm7aVYQFXXFhAAj0WIeqcag88DKOvY4UKR/g==\n" \
  146. " caps mon = \"allow command \"config-key\";"
  147. key = ceph.parse_key(with_caps)
  148. print("key: {}".format(key))
  149. self.assertEqual(key, expected)
  150. def test_parse_key_without_caps(self):
  151. expected = "AQCm7aVYQFXXFhAAj0WIeqcag88DKOvY4UKR/g=="
  152. without_caps = "[client.osd-upgrade]\n" \
  153. " key = AQCm7aVYQFXXFhAAj0WIeqcag88DKOvY4UKR/g=="
  154. key = ceph.parse_key(without_caps)
  155. print("key: {}".format(key))
  156. self.assertEqual(key, expected)
  157. def test_list_unmounted_devices(self):
  158. dev1 = mock.MagicMock(spec=TestDevice)
  159. dev1.__getitem__.return_value = "block"
  160. dev1.device_node = '/dev/sda'
  161. dev2 = mock.MagicMock(spec=TestDevice)
  162. dev2.__getitem__.return_value = "block"
  163. dev2.device_node = '/dev/sdb'
  164. dev3 = mock.MagicMock(spec=TestDevice)
  165. dev3.__getitem__.return_value = "block"
  166. dev3.device_node = '/dev/loop1'
  167. devices = [dev1, dev2, dev3]
  168. with mock.patch(
  169. 'pyudev.Context.list_devices',
  170. return_value=devices):
  171. with mock.patch.object(ceph,
  172. 'is_device_mounted',
  173. return_value=False):
  174. devices = ceph.unmounted_disks()
  175. self.assertEqual(devices, ['/dev/sda', '/dev/sdb'])
  176. with mock.patch.object(ceph,
  177. 'is_device_mounted',
  178. return_value=True):
  179. devices = ceph.unmounted_disks()
  180. self.assertEqual(devices, [])
  181. @mock.patch.object(ceph, 'check_output')
  182. def test_get_partition_list(self, output):
  183. with open('unit_tests/partx_output', 'r') as partx_out:
  184. output.return_value = partx_out.read()
  185. partition_list = ceph.get_partition_list('/dev/xvdb')
  186. self.assertEqual(len(partition_list), 2)
  187. class CephVersionTestCase(unittest.TestCase):
  188. @mock.patch.object(ceph, 'get_os_codename_install_source')
  189. def test_resolve_ceph_version_trusty(self, get_os_codename_install_source):
  190. get_os_codename_install_source.return_value = 'juno'
  191. self.assertEqual(ceph.resolve_ceph_version('cloud:trusty-juno'),
  192. 'firefly')
  193. get_os_codename_install_source.return_value = 'kilo'
  194. self.assertEqual(ceph.resolve_ceph_version('cloud:trusty-kilo'),
  195. 'hammer')
  196. get_os_codename_install_source.return_value = 'liberty'
  197. self.assertEqual(ceph.resolve_ceph_version('cloud:trusty-liberty'),
  198. 'hammer')
  199. get_os_codename_install_source.return_value = 'mitaka'
  200. self.assertEqual(ceph.resolve_ceph_version('cloud:trusty-mitaka'),
  201. 'jewel')