1# 2# (c) 2017 Michael De La Rue 3# 4# This file is part of Ansible 5# 6# Ansible is free software: you can redistribute it and/or modify 7# it under the terms of the GNU General Public License as published by 8# the Free Software Foundation, either version 3 of the License, or 9# (at your option) any later version. 10# 11# Ansible is distributed in the hope that it will be useful, 12# but WITHOUT ANY WARRANTY; without even the implied warranty of 13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14# GNU General Public License for more details. 15# 16# You should have received a copy of the GNU General Public License 17# along with Ansible. If not, see <http://www.gnu.org/licenses/>. 18 19# Make coding more python3-ish 20from __future__ import (absolute_import, division, print_function) 21 22import pytest 23from copy import copy 24 25from ansible.errors import AnsibleError 26 27from ansible.plugins.lookup import aws_ssm 28 29try: 30 import boto3 31 from botocore.exceptions import ClientError 32except ImportError: 33 pytestmark = pytest.mark.skip("This test requires the boto3 and botocore Python libraries") 34 35simple_variable_success_response = { 36 'Parameters': [ 37 { 38 'Name': 'simple_variable', 39 'Type': 'String', 40 'Value': 'simplevalue', 41 'Version': 1 42 } 43 ], 44 'InvalidParameters': [], 45 'ResponseMetadata': { 46 'RequestId': '12121212-3434-5656-7878-9a9a9a9a9a9a', 47 'HTTPStatusCode': 200, 48 'HTTPHeaders': { 49 'x-amzn-requestid': '12121212-3434-5656-7878-9a9a9a9a9a9a', 50 'content-type': 'application/x-amz-json-1.1', 51 'content-length': '116', 52 'date': 'Tue, 23 Jan 2018 11:04:27 GMT' 53 }, 54 'RetryAttempts': 0 55 } 56} 57 58path_success_response = copy(simple_variable_success_response) 59path_success_response['Parameters'] = [ 60 {'Name': '/testpath/too', 'Type': 'String', 'Value': 'simple_value_too', 'Version': 1}, 61 {'Name': '/testpath/won', 'Type': 'String', 'Value': 'simple_value_won', 'Version': 1} 62] 63 64missing_variable_response = copy(simple_variable_success_response) 65missing_variable_response['Parameters'] = [] 66missing_variable_response['InvalidParameters'] = ['missing_variable'] 67 68some_missing_variable_response = copy(simple_variable_success_response) 69some_missing_variable_response['Parameters'] = [ 70 {'Name': 'simple', 'Type': 'String', 'Value': 'simple_value', 'Version': 1}, 71 {'Name': '/testpath/won', 'Type': 'String', 'Value': 'simple_value_won', 'Version': 1} 72] 73some_missing_variable_response['InvalidParameters'] = ['missing_variable'] 74 75 76dummy_credentials = {} 77dummy_credentials['boto_profile'] = None 78dummy_credentials['aws_secret_key'] = "notasecret" 79dummy_credentials['aws_access_key'] = "notakey" 80dummy_credentials['aws_security_token'] = None 81dummy_credentials['region'] = 'eu-west-1' 82 83 84def test_lookup_variable(mocker): 85 lookup = aws_ssm.LookupModule() 86 lookup._load_name = "aws_ssm" 87 88 boto3_double = mocker.MagicMock() 89 boto3_double.Session.return_value.client.return_value.get_parameters.return_value = simple_variable_success_response 90 boto3_client_double = boto3_double.Session.return_value.client 91 92 with mocker.patch.object(boto3, 'session', boto3_double): 93 retval = lookup.run(["simple_variable"], {}, **dummy_credentials) 94 assert(retval[0] == "simplevalue") 95 boto3_client_double.assert_called_with('ssm', 'eu-west-1', aws_access_key_id='notakey', 96 aws_secret_access_key="notasecret", aws_session_token=None) 97 98 99def test_path_lookup_variable(mocker): 100 lookup = aws_ssm.LookupModule() 101 lookup._load_name = "aws_ssm" 102 103 boto3_double = mocker.MagicMock() 104 get_path_fn = boto3_double.Session.return_value.client.return_value.get_parameters_by_path 105 get_path_fn.return_value = path_success_response 106 boto3_client_double = boto3_double.Session.return_value.client 107 108 with mocker.patch.object(boto3, 'session', boto3_double): 109 args = copy(dummy_credentials) 110 args["bypath"] = 'true' 111 retval = lookup.run(["/testpath"], {}, **args) 112 assert(retval[0]["/testpath/won"] == "simple_value_won") 113 assert(retval[0]["/testpath/too"] == "simple_value_too") 114 boto3_client_double.assert_called_with('ssm', 'eu-west-1', aws_access_key_id='notakey', 115 aws_secret_access_key="notasecret", aws_session_token=None) 116 get_path_fn.assert_called_with(Path="/testpath", Recursive=False, WithDecryption=True) 117 118 119def test_return_none_for_missing_variable(mocker): 120 """ 121 during jinja2 templates, we can't shouldn't normally raise exceptions since this blocks the ability to use defaults. 122 123 for this reason we return ```None``` for missing variables 124 """ 125 lookup = aws_ssm.LookupModule() 126 lookup._load_name = "aws_ssm" 127 128 boto3_double = mocker.MagicMock() 129 boto3_double.Session.return_value.client.return_value.get_parameters.return_value = missing_variable_response 130 131 with mocker.patch.object(boto3, 'session', boto3_double): 132 retval = lookup.run(["missing_variable"], {}, **dummy_credentials) 133 assert(retval[0] is None) 134 135 136def test_match_retvals_to_call_params_even_with_some_missing_variables(mocker): 137 """ 138 If we get a complex list of variables with some missing and some not, we still have to return a 139 list which matches with the original variable list. 140 """ 141 lookup = aws_ssm.LookupModule() 142 lookup._load_name = "aws_ssm" 143 144 boto3_double = mocker.MagicMock() 145 boto3_double.Session.return_value.client.return_value.get_parameters.return_value = some_missing_variable_response 146 147 with mocker.patch.object(boto3, 'session', boto3_double): 148 retval = lookup.run(["simple", "missing_variable", "/testpath/won", "simple"], {}, **dummy_credentials) 149 assert(retval == ["simple_value", None, "simple_value_won", "simple_value"]) 150 151 152error_response = {'Error': {'Code': 'ResourceNotFoundException', 'Message': 'Fake Testing Error'}} 153operation_name = 'FakeOperation' 154 155 156def test_warn_denied_variable(mocker): 157 lookup = aws_ssm.LookupModule() 158 lookup._load_name = "aws_ssm" 159 160 boto3_double = mocker.MagicMock() 161 boto3_double.Session.return_value.client.return_value.get_parameters.side_effect = ClientError(error_response, operation_name) 162 163 with pytest.raises(AnsibleError): 164 with mocker.patch.object(boto3, 'session', boto3_double): 165 lookup.run(["denied_variable"], {}, **dummy_credentials) 166