From 91694ef382747a46aad640ba568fe3c091241cfe Mon Sep 17 00:00:00 2001 From: "patchback[bot]" <45432694+patchback[bot]@users.noreply.github.com> Date: Fri, 30 Aug 2024 17:02:31 +0000 Subject: [PATCH] Create droppath option in ssm_parameter.py (#1756) (#2274) This is a backport of PR #1756 as merged into main (c535e63). SUMMARY In the event that there exists two parameters in Parameter Store path/to/params/foo/bar/param and path/to/params/x/y/param, a user attempting to recursively pull all parameters under the path/to/params path with the command {{ lookup('amazon.aws.aws_ssm', '/PATH/to/params', region='ap-southeast-2', shortnames=true, bypath=true, recursive=true ) }}" will be unable to use the shortnames argument without creating a conflict between the two param results. Only one param key will exist in the resulting dictionary. This is problematic for users that wish to lookup a parameter hierarchy with repetitive names in the final value of the parameter path. In this scenario, users are currently forced to use the fully qualified parameter name when interacting with their dictionary results. This pull request introduces the droppath option, which will drop the common lookup path from the names of all parameters. In the scenario above, the resulting dictionary would contain both a foo/bar/param and a /x/y/param allowing users to refer to them by their minimally differentiated name. ISSUE TYPE Feature Pull Request COMPONENT NAME lookup ADDITIONAL INFORMATION Step by step Setup Create parameter path/to/params/foo/bar/param with value abc Create parameter path/to/params/x/y/param with value 123 Run shortnames name: return a dictionary of ssm parameters from a hierarchy path with shortened names (param instead of /PATH/to/param) debug: msg="{{ lookup('amazon.aws.aws_ssm', '/PATH/to/params', region='ap-southeast-2', shortnames=true, bypath=true, recursive=true ) }}" Observe result {'param': '123'} Run droppath name: return a dictionary of ssm parameters from a hierarchy path with shortened names (param instead of /PATH/to/param) debug: msg="{{ lookup('amazon.aws.aws_ssm', '/PATH/to/params', region='ap-southeast-2', droppath=true, bypath=true, recursive=true ) }}" Observe result {'/foo/bar/param': 'abc', '/x/y/param': '123'} Run both name: return a dictionary of ssm parameters from a hierarchy path with shortened names (param instead of /PATH/to/param) debug: msg="{{ lookup('amazon.aws.aws_ssm', '/PATH/to/params', region='ap-southeast-2', droppath=true, shortnames = true, bypath=true, recursive=true ) }}" Observe error shortnames and droppath are mutually exclusive. They cannot both be set to true. Reviewed-by: Mark Chappell --- .../add-droppath-option-to-ssm-lookup.yml | 3 ++ plugins/lookup/ssm_parameter.py | 29 ++++++++++++--- .../lookup_ssm_parameter/tasks/main.yml | 37 ++++++++++++++++++- 3 files changed, 62 insertions(+), 7 deletions(-) create mode 100644 changelogs/fragments/add-droppath-option-to-ssm-lookup.yml diff --git a/changelogs/fragments/add-droppath-option-to-ssm-lookup.yml b/changelogs/fragments/add-droppath-option-to-ssm-lookup.yml new file mode 100644 index 00000000000..3e9d1e6e378 --- /dev/null +++ b/changelogs/fragments/add-droppath-option-to-ssm-lookup.yml @@ -0,0 +1,3 @@ +--- +minor_changes: + - ssm parameter lookup - add new option ``droppath`` to drop the hierarchical search path from ssm parameter lookup results (https://github.com/ansible-collections/amazon.aws/pull/1756). diff --git a/plugins/lookup/ssm_parameter.py b/plugins/lookup/ssm_parameter.py index 0ca3afdd8a8..9fb4cea1018 100644 --- a/plugins/lookup/ssm_parameter.py +++ b/plugins/lookup/ssm_parameter.py @@ -44,15 +44,24 @@ default: false type: boolean shortnames: - description: Indicates whether to return the name only without path if using a parameter hierarchy. + description: + - Indicates whether to return the name only without path if using a parameter hierarchy. + - The O(shortnames) and O(droppath) options are mutually exclusive. + default: false + type: boolean + droppath: + description: + - Indicates whether to return the parameter name with the searched parameter heirarchy removed. + - The O(shortnames) and O(droppath) options are mutually exclusive. default: false type: boolean + version_added: 8.2.0 on_missing: description: - Action to take if the SSM parameter is missing. - - C(error) will raise a fatal error when the SSM parameter is missing. - - C(skip) will silently ignore the missing SSM parameter. - - C(warn) will skip over the missing SSM parameter but issue a warning. + - V(error) will raise a fatal error when the SSM parameter is missing. + - V(skip) will silently ignore the missing SSM parameter. + - V(warn) will skip over the missing SSM parameter but issue a warning. default: error type: string choices: ['error', 'skip', 'warn'] @@ -112,9 +121,12 @@ - name: return a dictionary of ssm parameters from a hierarchy path debug: msg="{{ lookup('amazon.aws.aws_ssm', '/PATH/to/params', region='ap-southeast-2', bypath=true, recursive=true ) }}" -- name: return a dictionary of ssm parameters from a hierarchy path with shortened names (param instead of /PATH/to/param) +- name: return a dictionary of ssm parameters from a hierarchy path with shortened names (param instead of /PATH/to/params/foo/bar/param) debug: msg="{{ lookup('amazon.aws.aws_ssm', '/PATH/to/params', region='ap-southeast-2', shortnames=true, bypath=true, recursive=true ) }}" +- name: return a dictionary of ssm parameters from a hierarchy path with the heirarchy path dropped (foo/bar/param instead of /PATH/to/params/foo/bar/param) + debug: msg="{{ lookup('amazon.aws.aws_ssm', '/PATH/to/params', region='ap-southeast-2', droppath=true, bypath=true, recursive=true ) }}" + - name: Iterate over a parameter hierarchy (one iteration per parameter) debug: msg='Key contains {{ item.key }} , with value {{ item.value }}' loop: "{{ lookup('amazon.aws.aws_ssm', '/demo/', region='ap-southeast-2', bypath=True) | dict2items }}" @@ -173,6 +185,9 @@ def run(self, terms, variables, **kwargs): f'"on_denied" must be a string and one of "error", "warn" or "skip", not {on_denied}' ) + if self.get_option("shortnames") and self.get_option("droppath"): + raise AnsibleLookupError("shortnames and droppath are mutually exclusive. They cannot both be set to true.") + ret = [] ssm_dict = {} @@ -193,6 +208,10 @@ def run(self, terms, variables, **kwargs): for x in paramlist: x["Name"] = x["Name"][x["Name"].rfind("/") + 1:] # fmt: skip + if self.get_option("droppath"): + for x in paramlist: + x["Name"] = x["Name"].replace(ssm_dict["Path"], "") + display.vvvv(f"AWS_ssm path lookup returned: {to_native(paramlist)}") ret.append( diff --git a/tests/integration/targets/lookup_ssm_parameter/tasks/main.yml b/tests/integration/targets/lookup_ssm_parameter/tasks/main.yml index b96307d877b..83a8dcce1cd 100644 --- a/tests/integration/targets/lookup_ssm_parameter/tasks/main.yml +++ b/tests/integration/targets/lookup_ssm_parameter/tasks/main.yml @@ -28,14 +28,21 @@ path_name: /{{ ssm_key_prefix }}/path path_name_a: "{{ path_name }}/key_one" path_shortname_a: key_one + path_droppath_name_a: /key_one path_name_b: "{{ path_name }}/keyTwo" path_shortname_b: keyTwo + path_droppath_name_b: /keyTwo path_name_c: "{{ path_name }}/Nested/Key" path_shortname_c: Key + path_droppath_name_c: /Nested/Key + path_name_d: "{{ path_name }}/AnotherNested/Key" + path_shortname_d: Key + path_droppath_name_d: /AnotherNested/Key path_description: This is somewhere to store a set of keys path_value_a: value_one path_value_b: valueTwo path_value_c: Value Three + path_value_d: value-fou missing_name: "{{ path_name }}/IDoNotExist" block: # ============================================================ @@ -131,7 +138,14 @@ description: "{{ path_description }}" value: "{{ path_value_c }}" + - name: Create nested key/value pair in aws parameter store (4) + ssm_parameter: + name: '{{ path_name_d }}' + description: '{{ path_description }}' + value: '{{ path_value_d }}' + # ============================================================ + - name: Lookup a keys using bypath ansible.builtin.set_fact: lookup_value: "{{ lookup('amazon.aws.aws_ssm', path_name, bypath=True, wantlist=True, **connection_args ) | first }}" @@ -154,7 +168,9 @@ - lookup_value[path_name_b] == path_value_b - path_name_c in lookup_value - lookup_value[path_name_c] == path_value_c - - lookup_value | length == 3 + - path_name_d in lookup_value + - lookup_value[path_name_d] == path_value_d + - lookup_value | length == 4 - name: Lookup a keys using bypath and shortname ansible.builtin.set_fact: @@ -180,6 +196,21 @@ - lookup_value[path_shortname_c] == path_value_c - lookup_value | length == 3 + - name: Lookup a keys using bypath and recursive and droppath + ansible.builtin.set_fact: + lookup_value: "{{ lookup('amazon.aws.aws_ssm', path_name, bypath=True, recursive=True, droppath=True, wantlist=True, **connection_args ) | first }}" + - ansible.builtin.assert: + that: + - path_droppath_name_a in lookup_value + - lookup_value[path_droppath_name_a] == path_value_a + - path_droppath_name_b in lookup_value + - lookup_value[path_droppath_name_b] == path_value_b + - path_droppath_name_c in lookup_value + - lookup_value[path_droppath_name_c] == path_value_c + - path_droppath_name_d in lookup_value + - lookup_value[path_droppath_name_d] == path_value_d + - lookup_value | length == 4 + # ============================================================ - name: Explicitly lookup two keys @@ -259,7 +290,9 @@ - lookup_value[0][path_name_b] == path_value_b - path_name_c in lookup_value[0] - lookup_value[0][path_name_c] == path_value_c - - lookup_value[0] | length == 3 + - path_name_d in lookup_value[0] + - lookup_value[0][path_name_d] == path_value_d + - lookup_value[0] | length == 4 always: # ============================================================