Skip to content

Commit

Permalink
Re-enable and update integration tests for aws_ssm_parameter_store (a…
Browse files Browse the repository at this point in the history
…nsible-collections#1241)

Re-enable and update integration tests for aws_ssm_parameter_store

SUMMARY

Fixes exception when description was updated within passing value.
Rewrite and enable integration tests for module
Add some return values

While the integration tests don't include coverage for the more complex options for aws_ssm_parameter_store these have never existed.  Having something enabled gives future module developers something to build upon.
ISSUE TYPE

Bugfix Pull Request

COMPONENT NAME
aws_ssm_parameter_store
ADDITIONAL INFORMATION
Exception:
TASK [aws_ssm_parameter_store : Update description] ****************************
task path: /root/ansible_collections/community/aws/tests/output/.tmp/integration/aws_ssm_parameter_store-071mpr89-ÅÑŚÌβŁÈ/tests/integration/targets/aws_ssm_parameter_store/tasks/main.yml:64
Using module file /root/ansible_collections/community/aws/plugins/modules/aws_ssm_parameter_store.py
Pipelining is enabled.
<testhost> ESTABLISH LOCAL CONNECTION FOR USER: root
<testhost> EXEC /bin/sh -c 'ANSIBLE_DEBUG_BOTOCORE_LOGS=True /usr/bin/python3.10 && sleep 0'
The full traceback is:
Traceback (most recent call last):
  File "/tmp/ansible_aws_ssm_parameter_store_payload_13s3_ao3/ansible_aws_ssm_parameter_store_payload.zip/ansible_collections/community/aws/plugins/modules/aws_ssm_parameter_store.py", line 160, in update_parameter
  File "/usr/local/lib/python3.10/dist-packages/botocore/client.py", line 357, in _api_call
    return self._make_api_call(operation_name, kwargs)
  File "/usr/local/lib/python3.10/dist-packages/botocore/client.py", line 648, in _make_api_call
    request_dict = self._convert_to_request_dict(
  File "/usr/local/lib/python3.10/dist-packages/botocore/client.py", line 696, in _convert_to_request_dict
    request_dict = self._serializer.serialize_to_request(
  File "/usr/local/lib/python3.10/dist-packages/botocore/validate.py", line 293, in serialize_to_request
    raise ParamValidationError(report=report.generate_report())
botocore.exceptions.ParamValidationError: Parameter validation failed:
Invalid type for parameter Value, value: None, type: <class 'NoneType'>, valid types: <class 'str'>
fatal: [testhost]: FAILED! => {
    "boto3_version": "1.17.0",
    "botocore_version": "1.20.0",
    "changed": false,
    "invocation": {
        "module_args": {
            "aws_access_key": "ASIA6CCDWXDOM4BEFFL4",
            "aws_ca_bundle": null,
            "aws_config": null,
            "aws_secret_key": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
            "debug_botocore_endpoint_logs": true,
            "decryption": true,
            "description": "This is an updated example",
            "ec2_url": null,
            "key_id": "alias/aws/ssm",
            "name": "/ansible-test-12184966-mchappel/Simple",
            "overwrite_value": "changed",
            "profile": null,
            "region": "us-east-1",
            "security_token": "VALUE_SPECIFIED_IN_NO_LOG_PARAMETER",
            "state": "present",
            "string_type": "String",
            "tier": "Standard",
            "validate_certs": true,
            "value": null
        }
    },
    "msg": "setting parameter: Parameter validation failed:\nInvalid type for parameter Value, value: None, type: <class 'NoneType'>, valid types: <class 'str'>",
    "resource_actions": [
        "ssm:GetParameter"
    ]
}

Reviewed-by: Alina Buzachis <None>
  • Loading branch information
tremble authored Jun 21, 2022
1 parent a783f42 commit b1bd0d8
Showing 1 changed file with 117 additions and 31 deletions.
148 changes: 117 additions & 31 deletions aws_ssm_parameter_store.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,11 @@
---
module: aws_ssm_parameter_store
version_added: 1.0.0
short_description: Manage key-value pairs in aws parameter store.
short_description: Manage key-value pairs in AWS SSM parameter store
description:
- Manage key-value pairs in aws parameter store.
- Manage key-value pairs in AWS SSM parameter store.
- To retreive SSM parameters use the M(amazon.aws.aws_ssm_parameter) lookup
plugin.
options:
name:
description:
Expand Down Expand Up @@ -44,6 +46,7 @@
choices: ['String', 'StringList', 'SecureString']
default: String
type: str
aliases: ['type']
decryption:
description:
- Work with SecureString type to get plain text secrets
Expand Down Expand Up @@ -86,7 +89,7 @@
'''

EXAMPLES = '''
- name: Create or update key/value pair in aws parameter store
- name: Create or update key/value pair in AWS SSM parameter store
community.aws.aws_ssm_parameter_store:
name: "Hello"
description: "This is your first key"
Expand Down Expand Up @@ -120,7 +123,7 @@
value: "Test1234"
overwrite_value: "always"
- name: Create or update key/value pair in aws parameter store with tier
- name: Create or update key/value pair in AWS SSM parameter store with tier
community.aws.aws_ssm_parameter_store:
name: "Hello"
description: "This is your first key"
Expand All @@ -129,30 +132,92 @@
- name: recommend to use with aws_ssm lookup plugin
ansible.builtin.debug:
msg: "{{ lookup('amazon.aws.aws_ssm', 'hello') }}"
msg: "{{ lookup('amazon.aws.aws_ssm', 'Hello') }}"
'''

RETURN = '''
put_parameter:
description: Add one or more parameters to the system.
returned: success
type: dict
delete_parameter:
description: Delete a parameter from the system.
returned: success
type: dict
parameter_metadata:
type: dict
description:
- Information about a parameter.
- Does not include the value of the parameter as this can be sensitive
information.
returned: success
contains:
data_type:
type: str
description: Parameter Data type.
example: text
returned: success
description:
type: str
description: Parameter key description.
example: This is your first key
returned: success
last_modified_date:
type: str
description: Time and date that the parameter was last modified.
example: '2022-06-20T09:56:58.573000+00:00'
returned: success
last_modified_user:
type: str
description: ARN of the last user to modify the parameter.
example: 'arn:aws:sts::123456789012:assumed-role/example-role/session=example'
returned: success
name:
type: str
description: Parameter key name.
example: Hello
returned: success
policies:
type: list
description: A list of policies associated with a parameter.
elements: dict
returned: success
contains:
policy_text:
type: str
description: The JSON text of the policy.
returned: success
policy_type:
type: str
description: The type of policy.
example: Expiration
returned: success
policy_status:
type: str
description: The status of the policy.
example: Pending
returned: success
tier:
type: str
description: Parameter tier.
example: Standard
returned: success
type:
type: str
description: Parameter type
example: String
returned: success
version:
type: int
description: Parameter version number
example: 3
returned: success
'''

try:
import botocore
except ImportError:
pass # Handled by AnsibleAWSModule

from ansible.module_utils.common.dict_transformations import camel_dict_to_snake_dict

from ansible_collections.amazon.aws.plugins.module_utils.core import AnsibleAWSModule
from ansible_collections.amazon.aws.plugins.module_utils.core import is_boto3_error_code


def update_parameter(client, module, args):
def update_parameter(client, module, **args):
changed = False
response = {}

Expand All @@ -165,14 +230,23 @@ def update_parameter(client, module, args):
return changed, response


def describe_parameter(client, module, **args):
paginator = client.get_paginator('describe_parameters')
existing_parameter = paginator.paginate(**args).build_full_result()

if not existing_parameter['Parameters']:
return None

return existing_parameter['Parameters'][0]


def create_update_parameter(client, module):
changed = False
existing_parameter = None
response = {}

args = dict(
Name=module.params.get('name'),
Value=module.params.get('value'),
Type=module.params.get('string_type'),
Tier=module.params.get('tier')
)
Expand All @@ -182,6 +256,9 @@ def create_update_parameter(client, module):
else:
args.update(Overwrite=False)

if module.params.get('value') is not None:
args.update(Value=module.params.get('value'))

if module.params.get('description'):
args.update(Description=module.params.get('description'))

Expand All @@ -194,32 +271,32 @@ def create_update_parameter(client, module):
pass

if existing_parameter:
if (module.params.get('overwrite_value') == 'always'):
if 'Value' not in args:
args['Value'] = existing_parameter['Parameter']['Value']

(changed, response) = update_parameter(client, module, args)
if (module.params.get('overwrite_value') == 'always'):
(changed, response) = update_parameter(client, module, **args)

elif (module.params.get('overwrite_value') == 'changed'):
if existing_parameter['Parameter']['Type'] != args['Type']:
(changed, response) = update_parameter(client, module, args)
(changed, response) = update_parameter(client, module, **args)

if existing_parameter['Parameter']['Value'] != args['Value']:
(changed, response) = update_parameter(client, module, args)
elif existing_parameter['Parameter']['Value'] != args['Value']:
(changed, response) = update_parameter(client, module, **args)

if args.get('Description'):
elif args.get('Description'):
# Description field not available from get_parameter function so get it from describe_parameters
describe_existing_parameter = None
try:
describe_existing_parameter_paginator = client.get_paginator('describe_parameters')
describe_existing_parameter = describe_existing_parameter_paginator.paginate(
Filters=[{"Key": "Name", "Values": [args['Name']]}]).build_full_result()

describe_existing_parameter = describe_parameter(
client, module,
Filters=[{"Key": "Name", "Values": [args['Name']]}])
except (botocore.exceptions.ClientError, botocore.exceptions.BotoCoreError) as e:
module.fail_json_aws(e, msg="getting description value")

if describe_existing_parameter['Parameters'][0]['Description'] != args['Description']:
(changed, response) = update_parameter(client, module, args)
if describe_existing_parameter['Description'] != args['Description']:
(changed, response) = update_parameter(client, module, **args)
else:
(changed, response) = update_parameter(client, module, args)
(changed, response) = update_parameter(client, module, **args)

return changed, response

Expand Down Expand Up @@ -250,7 +327,7 @@ def setup_module_object():
description=dict(),
value=dict(required=False, no_log=True),
state=dict(default='present', choices=['present', 'absent']),
string_type=dict(default='String', choices=['String', 'StringList', 'SecureString']),
string_type=dict(default='String', choices=['String', 'StringList', 'SecureString'], aliases=['type']),
decryption=dict(default=True, type='bool'),
key_id=dict(default="alias/aws/ssm"),
overwrite_value=dict(default='changed', choices=['never', 'changed', 'always']),
Expand All @@ -272,7 +349,16 @@ def main():
"absent": delete_parameter,
}
(changed, response) = invocations[state](client, module)
module.exit_json(changed=changed, response=response)

result = {"response": response}

parameter_metadata = describe_parameter(
client, module,
Filters=[{"Key": "Name", "Values": [module.params.get('name')]}])
if parameter_metadata:
result['parameter_metadata'] = camel_dict_to_snake_dict(parameter_metadata)

module.exit_json(changed=changed, **result)


if __name__ == '__main__':
Expand Down

0 comments on commit b1bd0d8

Please sign in to comment.