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