1import logging 2import random 3import string 4 5import pytest 6import salt.config 7import salt.loader 8import salt.states.boto_elasticsearch_domain as boto_elasticsearch_domain 9from tests.support.mock import MagicMock, patch 10 11boto = pytest.importorskip("boto") 12boto3 = pytest.importorskip("boto3", "1.2.1") 13botocore = pytest.importorskip("botocore", "1.4.41") 14 15log = logging.getLogger(__name__) 16 17 18class GlobalConfig: 19 region = "us-east-1" 20 access_key = "GKTADJGHEIQSXMKKRBJ08H" 21 secret_key = "askdjghsdfjkghWupUjasdflkdfklgjsdfjajkghs" 22 conn_parameters = { 23 "region": region, 24 "key": access_key, 25 "keyid": secret_key, 26 "profile": {}, 27 } 28 error_message = ( 29 "An error occurred (101) when calling the {0} operation: Test-defined error" 30 ) 31 not_found_error = botocore.exceptions.ClientError( 32 { 33 "Error": { 34 "Code": "ResourceNotFoundException", 35 "Message": "Test-defined error", 36 } 37 }, 38 "msg", 39 ) 40 error_content = {"Error": {"Code": 101, "Message": "Test-defined error"}} 41 domain_ret = dict( 42 DomainName="testdomain", 43 ElasticsearchClusterConfig={}, 44 EBSOptions={}, 45 AccessPolicies={}, 46 SnapshotOptions={}, 47 AdvancedOptions={}, 48 ElasticsearchVersion="1.5", 49 ) 50 51 52@pytest.fixture 53def configure_loader_modules(): 54 opts = salt.config.DEFAULT_MINION_OPTS.copy() 55 opts["grains"] = salt.loader.grains(opts) 56 ctx = {} 57 utils = salt.loader.utils( 58 opts, 59 whitelist=["boto3", "args", "systemd", "path", "platform"], 60 context=ctx, 61 ) 62 serializers = salt.loader.serializers(opts) 63 funcs = funcs = salt.loader.minion_mods( 64 opts, context=ctx, utils=utils, whitelist=["boto_elasticsearch_domain"] 65 ) 66 salt_states = salt.loader.states( 67 opts=opts, 68 functions=funcs, 69 utils=utils, 70 whitelist=["boto_elasticsearch_domain"], 71 serializers=serializers, 72 ) 73 return { 74 boto_elasticsearch_domain: { 75 "__opts__": opts, 76 "__salt__": funcs, 77 "__utils__": utils, 78 "__states__": salt_states, 79 "__serializers__": serializers, 80 } 81 } 82 83 84def test_present_when_domain_does_not_exist(): 85 GlobalConfig.conn_parameters["key"] = "".join( 86 random.choice(string.ascii_lowercase + string.digits) for _ in range(50) 87 ) 88 patcher = patch("boto3.session.Session") 89 mock_session = patcher.start() 90 session_instance = mock_session.return_value 91 conn = MagicMock() 92 session_instance.client.return_value = conn 93 conn.describe_elasticsearch_domain.side_effect = GlobalConfig.not_found_error 94 conn.describe_elasticsearch_domain_config.return_value = { 95 "DomainConfig": GlobalConfig.domain_ret 96 } 97 conn.create_elasticsearch_domain.return_value = { 98 "DomainStatus": GlobalConfig.domain_ret 99 } 100 result = boto_elasticsearch_domain.__states__["boto_elasticsearch_domain.present"]( 101 "domain present", **GlobalConfig.domain_ret 102 ) 103 104 assert result["result"] 105 assert result["changes"]["new"]["domain"]["ElasticsearchClusterConfig"] is None 106 107 108def test_present_when_domain_exists(): 109 GlobalConfig.conn_parameters["key"] = "".join( 110 random.choice(string.ascii_lowercase + string.digits) for _ in range(50) 111 ) 112 patcher = patch("boto3.session.Session") 113 mock_session = patcher.start() 114 session_instance = mock_session.return_value 115 conn = MagicMock() 116 session_instance.client.return_value = conn 117 conn.describe_elasticsearch_domain.return_value = { 118 "DomainStatus": GlobalConfig.domain_ret 119 } 120 cfg = {} 121 for k, v in GlobalConfig.domain_ret.items(): 122 cfg[k] = {"Options": v} 123 cfg["AccessPolicies"] = {"Options": '{"a": "b"}'} 124 conn.describe_elasticsearch_domain_config.return_value = {"DomainConfig": cfg} 125 conn.update_elasticsearch_domain_config.return_value = {"DomainConfig": cfg} 126 result = boto_elasticsearch_domain.__states__["boto_elasticsearch_domain.present"]( 127 "domain present", **GlobalConfig.domain_ret 128 ) 129 assert result["result"] 130 assert result["changes"] == { 131 "new": {"AccessPolicies": {}}, 132 "old": {"AccessPolicies": {"a": "b"}}, 133 } 134 135 136def test_present_with_failure(): 137 GlobalConfig.conn_parameters["key"] = "".join( 138 random.choice(string.ascii_lowercase + string.digits) for _ in range(50) 139 ) 140 patcher = patch("boto3.session.Session") 141 mock_session = patcher.start() 142 session_instance = mock_session.return_value 143 conn = MagicMock() 144 session_instance.client.return_value = conn 145 conn.describe_elasticsearch_domain.side_effect = GlobalConfig.not_found_error 146 conn.describe_elasticsearch_domain_config.return_value = { 147 "DomainConfig": GlobalConfig.domain_ret 148 } 149 conn.create_elasticsearch_domain.side_effect = botocore.exceptions.ClientError( 150 GlobalConfig.error_content, "create_domain" 151 ) 152 result = boto_elasticsearch_domain.__states__["boto_elasticsearch_domain.present"]( 153 "domain present", **GlobalConfig.domain_ret 154 ) 155 assert not result["result"] 156 assert "An error occurred" in result["comment"] 157 158 159def test_absent_when_domain_does_not_exist(): 160 """ 161 Tests absent on a domain that does not exist. 162 """ 163 GlobalConfig.conn_parameters["key"] = "".join( 164 random.choice(string.ascii_lowercase + string.digits) for _ in range(50) 165 ) 166 patcher = patch("boto3.session.Session") 167 mock_session = patcher.start() 168 session_instance = mock_session.return_value 169 conn = MagicMock() 170 session_instance.client.return_value = conn 171 conn.describe_elasticsearch_domain.side_effect = GlobalConfig.not_found_error 172 result = boto_elasticsearch_domain.__states__["boto_elasticsearch_domain.absent"]( 173 "test", "mydomain" 174 ) 175 assert result["result"] 176 assert result["changes"] == {} 177 178 179def test_absent_when_domain_exists(): 180 GlobalConfig.conn_parameters["key"] = "".join( 181 random.choice(string.ascii_lowercase + string.digits) for _ in range(50) 182 ) 183 patcher = patch("boto3.session.Session") 184 mock_session = patcher.start() 185 session_instance = mock_session.return_value 186 conn = MagicMock() 187 session_instance.client.return_value = conn 188 conn.describe_elasticsearch_domain.return_value = { 189 "DomainStatus": GlobalConfig.domain_ret 190 } 191 conn.describe_elasticsearch_domain_config.return_value = { 192 "DomainConfig": GlobalConfig.domain_ret 193 } 194 result = boto_elasticsearch_domain.__states__["boto_elasticsearch_domain.absent"]( 195 "test", GlobalConfig.domain_ret["DomainName"] 196 ) 197 assert result["result"] 198 assert result["changes"]["new"]["domain"] is None 199 200 201def test_absent_with_failure(): 202 GlobalConfig.conn_parameters["key"] = "".join( 203 random.choice(string.ascii_lowercase + string.digits) for _ in range(50) 204 ) 205 patcher = patch("boto3.session.Session") 206 mock_session = patcher.start() 207 session_instance = mock_session.return_value 208 conn = MagicMock() 209 session_instance.client.return_value = conn 210 conn.describe_elasticsearch_domain.return_value = { 211 "DomainStatus": GlobalConfig.domain_ret 212 } 213 conn.describe_elasticsearch_domain_config.return_value = { 214 "DomainConfig": GlobalConfig.domain_ret 215 } 216 conn.delete_elasticsearch_domain.side_effect = botocore.exceptions.ClientError( 217 GlobalConfig.error_content, "delete_domain" 218 ) 219 result = boto_elasticsearch_domain.__states__["boto_elasticsearch_domain.absent"]( 220 "test", GlobalConfig.domain_ret["DomainName"] 221 ) 222 assert not result["result"] 223 assert "An error occurred" in result["comment"] 224