Ansible Task to Generate an AWS SSM Activation Code with Multiple Tags

Viewed 165

In an effort to support dynamic key-value pairs in Ansible, I am looking to update an existing role which creates an AWS SSM activation to allow the passing of arbitrary tags during runtime.

So far, I have tried leveraging the following Ansible constructs, all to no success: list variable, dict variable, loop, with_dict, with_items and native Python dict methods.

Here are some details on my Ansible environment:

The current role/command with hard-coded tags looks like so:

- name: Generate SSM activation code and ID
  command: |
    aws ssm create-activation
    --tags "Key=key1,Value=value1" "Key=key2,Value=value2"
  register: ssm_activation_code

The idea is to update it to look like so:

 name: Generate SSM activation code and ID
  command: |
    aws ssm create-activation
    --tags "Key={{ item.key }},Value={{ item.value }}"
  register: ssm_activation_code
  with_items: "{{ aws_ssm_instance_tags }}"

And have the consumer of the role pass tags like so:

- role: ansible-role-aws-sm-agent
  vars:
    aws_ssm_instance_tags: {
      "key1": "value1",
      "key2": "value2",
      .....
    }

The issue with all loop structures is that the task runs once for each key-value pair, resulting in multiple SSM activations, which is incorrect. Instead, I would like to pass all tags in a single execution. I am happy to provide any additional details if needed. Any help on this is greatly appreciated.

2 Answers

It is my opinion that trying to coerce an already structured input back down into the "pseudo-grammar" used by awscli is the road to ruin when --cli-input-json exists if one wishes to specify multiple arguments, or --tags to just provide the tags

- name: Generate SSM activation code and ID
  command: >-
    aws ssm create-activation
    --tags {{ cli_tags | to_json | quote }}
  register: ssm_activation_code
  vars:
    cli_tags: >-
      {%- set results = [] -%}
      {%- for k, v in aws_ssm_instance_tags.items() -%}
      {%-   set _ = results.append({"Key": k, "Value": v}) -%}
      {%- endfor -%}
      {{ results }}

which given your example input generates the shlex-ed cmd:

 ["aws", "ssm", "create-activation", "--tags", "[{\"Key\": \"key1\", \"Value\": \"value1\"}, {\"Key\": \"key2\", \"Value\": \"value2\"}]"]

be aware: I updated your code snippet because there was a typo: command: | preserves linebreaks, and thus the shell command that originally was there would end up being two commands, since bash uses newlines to terminate commands in normal cases

A working copy of the code on the Ansible role:

- name: Generate SSM activation code and ID
  command: >-
    aws ssm create-activation
    --tags {{ cli_tags | to_json | quote }}
  register: ssm_activation
  vars:
    cli_tags: >-
      {%- set results = [] -%}
      {%- for k, v in aws_ssm_instance_tags.items() -%}
      {%-   set _ = results.append({"Key": k, "Value": v}) -%}
      {%- endfor -%}
      {{ results }}

And the code on the Ansible playbook which calls the role:

aws_ssm_instance_tags: {
    "key1": "value1",
    "key2": "value2",
    .....
}

A sincere thanks to mdaniel for helping me resolve this in a timely manner.

Related