1
0

test_boto_elasticsearch_domain.py 8.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. # -*- coding: utf-8 -*-
  2. # Import Python libs
  3. from __future__ import absolute_import, print_function, unicode_literals
  4. import logging
  5. import random
  6. import string
  7. import salt.loader
  8. import salt.states.boto_elasticsearch_domain as boto_elasticsearch_domain
  9. # Import Salt libs
  10. from salt.ext import six
  11. # Import 3rd-party libs
  12. from salt.ext.six.moves import range # pylint: disable=import-error,redefined-builtin
  13. from salt.utils.versions import LooseVersion
  14. # Import Salt Testing libs
  15. from tests.support.mixins import LoaderModuleMockMixin
  16. from tests.support.mock import MagicMock, patch
  17. from tests.support.unit import TestCase, skipIf
  18. # pylint: disable=import-error,no-name-in-module,unused-import
  19. from tests.unit.modules.test_boto_elasticsearch_domain import (
  20. BotoElasticsearchDomainTestCaseMixin,
  21. )
  22. # Import test suite libs
  23. try:
  24. import boto
  25. import boto3
  26. from botocore.exceptions import ClientError
  27. HAS_BOTO = True
  28. except ImportError:
  29. HAS_BOTO = False
  30. # pylint: enable=import-error,no-name-in-module,unused-import
  31. # the boto_elasticsearch_domain module relies on the connect_to_region() method
  32. # which was added in boto 2.8.0
  33. # https://github.com/boto/boto/commit/33ac26b416fbb48a60602542b4ce15dcc7029f12
  34. required_boto3_version = "1.2.1"
  35. log = logging.getLogger(__name__)
  36. def _has_required_boto():
  37. """
  38. Returns True/False boolean depending on if Boto is installed and correct
  39. version.
  40. """
  41. if not HAS_BOTO:
  42. return False
  43. elif LooseVersion(boto3.__version__) < LooseVersion(required_boto3_version):
  44. return False
  45. else:
  46. return True
  47. if _has_required_boto():
  48. region = "us-east-1"
  49. access_key = "GKTADJGHEIQSXMKKRBJ08H"
  50. secret_key = "askdjghsdfjkghWupUjasdflkdfklgjsdfjajkghs"
  51. conn_parameters = {
  52. "region": region,
  53. "key": access_key,
  54. "keyid": secret_key,
  55. "profile": {},
  56. }
  57. error_message = (
  58. "An error occurred (101) when calling the {0} operation: Test-defined error"
  59. )
  60. not_found_error = ClientError(
  61. {
  62. "Error": {
  63. "Code": "ResourceNotFoundException",
  64. "Message": "Test-defined error",
  65. }
  66. },
  67. "msg",
  68. )
  69. error_content = {"Error": {"Code": 101, "Message": "Test-defined error"}}
  70. domain_ret = dict(
  71. DomainName="testdomain",
  72. ElasticsearchClusterConfig={},
  73. EBSOptions={},
  74. AccessPolicies={},
  75. SnapshotOptions={},
  76. AdvancedOptions={},
  77. ElasticsearchVersion="1.5",
  78. )
  79. class BotoElasticsearchDomainStateTestCaseBase(TestCase, LoaderModuleMockMixin):
  80. conn = None
  81. def setup_loader_modules(self):
  82. ctx = {}
  83. utils = salt.loader.utils(
  84. self.opts,
  85. whitelist=["boto3", "args", "systemd", "path", "platform"],
  86. context=ctx,
  87. )
  88. serializers = salt.loader.serializers(self.opts)
  89. self.funcs = funcs = salt.loader.minion_mods(
  90. self.opts, context=ctx, utils=utils, whitelist=["boto_elasticsearch_domain"]
  91. )
  92. self.salt_states = salt.loader.states(
  93. opts=self.opts,
  94. functions=funcs,
  95. utils=utils,
  96. whitelist=["boto_elasticsearch_domain"],
  97. serializers=serializers,
  98. )
  99. return {
  100. boto_elasticsearch_domain: {
  101. "__opts__": self.opts,
  102. "__salt__": funcs,
  103. "__utils__": utils,
  104. "__states__": self.salt_states,
  105. "__serializers__": serializers,
  106. }
  107. }
  108. @classmethod
  109. def setUpClass(cls):
  110. cls.opts = salt.config.DEFAULT_MINION_OPTS.copy()
  111. cls.opts["grains"] = salt.loader.grains(cls.opts)
  112. @classmethod
  113. def tearDownClass(cls):
  114. del cls.opts
  115. # Set up MagicMock to replace the boto3 session
  116. def setUp(self):
  117. self.addCleanup(delattr, self, "funcs")
  118. self.addCleanup(delattr, self, "salt_states")
  119. # Set up MagicMock to replace the boto3 session
  120. # connections keep getting cached from prior tests, can't find the
  121. # correct context object to clear it. So randomize the cache key, to prevent any
  122. # cache hits
  123. conn_parameters["key"] = "".join(
  124. random.choice(string.ascii_lowercase + string.digits) for _ in range(50)
  125. )
  126. self.patcher = patch("boto3.session.Session")
  127. self.addCleanup(self.patcher.stop)
  128. self.addCleanup(delattr, self, "patcher")
  129. mock_session = self.patcher.start()
  130. session_instance = mock_session.return_value
  131. self.conn = MagicMock()
  132. self.addCleanup(delattr, self, "conn")
  133. session_instance.client.return_value = self.conn
  134. @skipIf(HAS_BOTO is False, "The boto module must be installed.")
  135. @skipIf(
  136. _has_required_boto() is False,
  137. "The boto3 module must be greater than"
  138. " or equal to version {0}".format(required_boto3_version),
  139. )
  140. class BotoElasticsearchDomainTestCase(
  141. BotoElasticsearchDomainStateTestCaseBase, BotoElasticsearchDomainTestCaseMixin
  142. ):
  143. """
  144. TestCase for salt.modules.boto_elasticsearch_domain state.module
  145. """
  146. def test_present_when_domain_does_not_exist(self):
  147. """
  148. Tests present on a domain that does not exist.
  149. """
  150. self.conn.describe_elasticsearch_domain.side_effect = not_found_error
  151. self.conn.describe_elasticsearch_domain_config.return_value = {
  152. "DomainConfig": domain_ret
  153. }
  154. self.conn.create_elasticsearch_domain.return_value = {
  155. "DomainStatus": domain_ret
  156. }
  157. result = self.salt_states["boto_elasticsearch_domain.present"](
  158. "domain present", **domain_ret
  159. )
  160. self.assertTrue(result["result"])
  161. self.assertEqual(
  162. result["changes"]["new"]["domain"]["ElasticsearchClusterConfig"], None
  163. )
  164. def test_present_when_domain_exists(self):
  165. self.conn.describe_elasticsearch_domain.return_value = {
  166. "DomainStatus": domain_ret
  167. }
  168. cfg = {}
  169. for k, v in six.iteritems(domain_ret):
  170. cfg[k] = {"Options": v}
  171. cfg["AccessPolicies"] = {"Options": '{"a": "b"}'}
  172. self.conn.describe_elasticsearch_domain_config.return_value = {
  173. "DomainConfig": cfg
  174. }
  175. self.conn.update_elasticsearch_domain_config.return_value = {
  176. "DomainConfig": cfg
  177. }
  178. result = self.salt_states["boto_elasticsearch_domain.present"](
  179. "domain present", **domain_ret
  180. )
  181. self.assertTrue(result["result"])
  182. self.assertEqual(
  183. result["changes"],
  184. {"new": {"AccessPolicies": {}}, "old": {"AccessPolicies": {"a": "b"}}},
  185. )
  186. def test_present_with_failure(self):
  187. self.conn.describe_elasticsearch_domain.side_effect = not_found_error
  188. self.conn.describe_elasticsearch_domain_config.return_value = {
  189. "DomainConfig": domain_ret
  190. }
  191. self.conn.create_elasticsearch_domain.side_effect = ClientError(
  192. error_content, "create_domain"
  193. )
  194. result = self.salt_states["boto_elasticsearch_domain.present"](
  195. "domain present", **domain_ret
  196. )
  197. self.assertFalse(result["result"])
  198. self.assertTrue("An error occurred" in result["comment"])
  199. def test_absent_when_domain_does_not_exist(self):
  200. """
  201. Tests absent on a domain that does not exist.
  202. """
  203. self.conn.describe_elasticsearch_domain.side_effect = not_found_error
  204. result = self.salt_states["boto_elasticsearch_domain.absent"](
  205. "test", "mydomain"
  206. )
  207. self.assertTrue(result["result"])
  208. self.assertEqual(result["changes"], {})
  209. def test_absent_when_domain_exists(self):
  210. self.conn.describe_elasticsearch_domain.return_value = {
  211. "DomainStatus": domain_ret
  212. }
  213. self.conn.describe_elasticsearch_domain_config.return_value = {
  214. "DomainConfig": domain_ret
  215. }
  216. result = self.salt_states["boto_elasticsearch_domain.absent"](
  217. "test", domain_ret["DomainName"]
  218. )
  219. self.assertTrue(result["result"])
  220. self.assertEqual(result["changes"]["new"]["domain"], None)
  221. def test_absent_with_failure(self):
  222. self.conn.describe_elasticsearch_domain.return_value = {
  223. "DomainStatus": domain_ret
  224. }
  225. self.conn.describe_elasticsearch_domain_config.return_value = {
  226. "DomainConfig": domain_ret
  227. }
  228. self.conn.delete_elasticsearch_domain.side_effect = ClientError(
  229. error_content, "delete_domain"
  230. )
  231. result = self.salt_states["boto_elasticsearch_domain.absent"](
  232. "test", domain_ret["DomainName"]
  233. )
  234. self.assertFalse(result["result"])
  235. self.assertTrue("An error occurred" in result["comment"])