diff --git a/grains/ec2_info.py b/grains/ec2_info.py index a6eb8ae..5bd6808 100644 --- a/grains/ec2_info.py +++ b/grains/ec2_info.py @@ -38,35 +38,36 @@ def _get_ec2_hostinfo(path=""): resp = _call_aws("/latest/meta-data/{0}".format(path)) resp_data = resp.read().decode('utf-8').strip() d = {} - for line in resp_data.split("\n"): - if path == "public-keys/": - line = line.split("=")[0] + "/" - if path == "instance-id/": - return {'instance-id': line} - if line[-1] != "/": - call_response = _call_aws("/latest/meta-data/{0}".format(path + line)) - call_response_data = call_response.read().decode('utf-8') - # avoid setting empty grain - if call_response_data == '': - d[line] = None - elif call_response_data is not None: - line = _dash_to_snake_case(line) - try: - data = json.loads(call_response_data) - if isinstance(data, dict): - data = _snake_caseify_dict(data) - d[line] = data - except ValueError: - if "\n" in call_response_data: - d[line] = [] - for dline in call_response_data.split("\n"): - d[line].append(dline) - else: - d[line] = call_response_data + if resp_data: + for line in resp_data.split("\n"): + if path == "public-keys/": + line = line.split("=")[0] + "/" + if path == "instance-id/": + return {'instance-id': line} + if line[-1] != "/": + call_response = _call_aws("/latest/meta-data/{0}".format(path + line)) + call_response_data = call_response.read().decode('utf-8') + # avoid setting empty grain + if call_response_data == '': + d[line] = None + elif call_response_data is not None: + line = _dash_to_snake_case(line) + try: + data = json.loads(call_response_data) + if isinstance(data, dict): + data = _snake_caseify_dict(data) + d[line] = data + except ValueError: + if "\n" in call_response_data: + d[line] = [] + for dline in call_response_data.split("\n"): + d[line].append(dline) + else: + d[line] = call_response_data + else: + return line else: - return line - else: - d[_dash_to_snake_case(line[:-1])] = _get_ec2_hostinfo(path + line) + d[_dash_to_snake_case(line[:-1])] = _get_ec2_hostinfo(path + line) return d diff --git a/tests/unit/grains/test_ec2_info.py b/tests/unit/grains/test_ec2_info.py new file mode 100644 index 0000000..a9c8c87 --- /dev/null +++ b/tests/unit/grains/test_ec2_info.py @@ -0,0 +1,74 @@ +# -*- coding: utf-8 -*- +''' + :codeauthor: :email:`Faye Salwin ` +''' + +# Import python libs +from __future__ import absolute_import + +# Import Salt Testing libs +from salttesting.helpers import ensure_in_syspath +from tests.support.unit import TestCase, skipIf +from tests.support.mock import ( + patch, + mock_open, + MagicMock, + NO_MOCK, + NO_MOCK_REASON +) + +# Import Salt Libs +import salt.grains.ec2_info as ec2_info + +@skipIf(NO_MOCK, NO_MOCK_REASON) + +def mock_call_aws(url): + class MockResponse: + def __init__(self, data, status_code): + self.data = data + self.status_code = status_code + + def read(self): + return self.data + + result = { "latest": { "meta-data": { "first": "value", "second": {}, "third": None}}} + path = url.split("/") + path.pop(0) + val = result + for k in path: + if k: + if isinstance(val, dict): + if k in val: + val = val[k] + else: + return MockResponse("", 404) + else: + return MockResponse("", 404) + else: + if isinstance(val, dict): + # return a slash-terminated value if the value is a dictionary + v = map(lambda k: k+"/" if isinstance(val[k],dict) else k, val) + return MockResponse("\n".join(v), 200) + else: + return MockResponse("", 404) + if val: + return MockResponse(val, 200) + else: + return MockResponse("", 404) + +class Ec2InfoTestCase(TestCase): + ''' + Test cases for ec2_info + ''' + + def test_mock_call_aws(self): + self.assertEqual(mock_call_aws("/latest/meta-data/").read(),"second/\nthird\nfirst") + self.assertEqual(mock_call_aws("/latest/meta-data/second/").read(),"") + + def test__get_ec2_hostinfo(self): + with patch('salt.grains.ec2_info._call_aws', side_effect=mock_call_aws): + self.assertEqual(ec2_info._get_ec2_hostinfo(""), {"first": "value", "second": {}, "third": None}) + +if __name__ == '__main__': + from integration import run_tests + run_tests(Ec2InfoTestCase, needs_daemon=False)