Ansible - define variable inside groups - ansible

Folks,
I'm trying to achieve the below by using the groups parameter in Ansible.
{{ groups['kafka'] | map('extract',hostvars,'ansible_host') | list | join(':{{ zookeeper_port }},') + ':{{ zookeeper_port }}' }}
variable zookeeper_port is given as:
zookeeper_port: 2181
While running my playbook with the above parameter for groups included, it gives me the result as:
IP:{{ zookeeper_port }},IP:{{ zookeeper_port }}
instead I'm trying to get the result as :
IP:2181,IP:2181
Can anyone help me figuring out what went wrong at my groups parameter declaration.

Anything inside '' inside {{}} treated as literal string. To access variables you type them right away - without any surrounding characters. In your case you need something like:
{{ groups['kafka'] | map('extract',hostvars,'ansible_host') | list | join(':' + zookeeper_port|string + ',') + ':' + zookeeper_port|string }}"
Notice the string filter - if your zookeeper_port defined as integer, then without it the task will fail

Related

Ansible : Use regex replace for items in list and assign it back

I tried using regex_replace option this way:
Here groups[group_names[0]] is list of node names
"groups[group_names[0]]": [
"node1.in.labs.corp.netin",
"node2.in.labs.corp.netin"
]
- set_fact:
groups[group_names[0]]={{ groups[group_names[0]] |
map('regex_replace', _regex, _replace)|list }}
vars:
_regex: '^(.*?)\.(.*)$'
_replace: '-n \1'
Hitting the following error:
{"changed": false, "msg": "The variable name 'groups[group_names[0]]' is not valid. Variables must start with a letter or underscore character, and contain only letters, numbers and underscores."}
Can i assign back to same list ? after replacing the regex ?
Also -n option is using so that my expected output should be
-n node1 -n node2

Ansible string manipulation in list [duplicate]

I am using [file lookup] which reads the whole file and stores the content in a variable. My play looks something like this:
- name: Store foo.xml contents in a variable
set_fact:
foo_content: "{{ lookup('file', 'foo.xml' ) | replace('\n', '')}}"
So the above code reads the foo.xml file and stores it in the variable, but the problem is when the foo.xml has line breaks in it, it also includes the line break in the variable.
My foo.xml is this file:
<?xml version="1.0" encoding="utf-8"?>
<initialize_param>
<secrets>
<my_secret id="99">3VMjII6Hw+pd1zHV5THSI712y421USUS8124487128745812sajfhsakjfasbfvcasvnjasjkvbhasdfasgfsfaj5G8A9+n8CkLxk7Dqu0G8Jclg0eb1A5xeFzR3rrJHrb2GBBa7PJNVx8tFJP3AtF6ek/F/WvlBIs2leX2fq+/bGryKlySuFmbcwBsThmPJC5Z5AwPJgGZx</my_secret>
</secrets>
</initialize_param>
The output removes line break \n but also incudes the tabs \r & \t
I need to got rid of the \n , need to get rid of extra formatting too (\r & \t), Moreover after the replace filter I get the error while firing a DB Update query as
stderr: /bin/sh: 1: cannot open ?xml: No such file
Use the Jinja trim filter:
"{{ lookup('file', 'foo.xml' ) | trim }}"
You can do that with the replace filter?
contents: "{{ lookup('file', '/etc/foo.txt') | replace('\n', '')}}"
You may use the regex_replace filter since the trim doesn't clear other line break characters as you mentioned in the question.
"{{ some_stdout_to_clear | regex_replace('[\\r\\n\\t]+','') }}"

How to write a multiline Ansible Jinja2 variable?

I have a Ansible line that fails linting:
tags: "{{ deployment_id | resource_tags('asg', base_resource_tags, deployment=deployment_id, deployment_env=deployment_env, deployment_name=deployment_name, purpose=deployment_purpose_tag, cpu_utilization=deployment_cpu_utilization_tag, disk_io_class=deployment_disk_io_tag, prom_exporters=deployment_prom_exporter_tags) | asg_tag_list }}"
How do I make this pass linting?
You need to use YAML Folding Scalars, > without quotes. Then add 'block chomping' 'strip'docs indicator to remove the trailing newline. The below example will work correctly, with each newline translating to a space. Adding quotes will break it e.g.
tags: >-
{{ deployment_id | resource_tags('asg', base_resource_tags, deployment=deployment_id,
deployment_env=deployment_env, deployment_name=deployment_name, Purpose=deployment_purpose_tag,
cpu_utilization=deployment_cpu_utilization_tag, disk_io_class=deployment_disk_io_tag,
prom_exporters=deployment_prom_exporter_tags) | asg_tag_list }}

How can I escape single quotes for Ansible/Jinja2 ternary operator?

I have the snippet below. Basically, for an included task I would like to provide a variable whose contents look like the below string:
--date='something'
or it should be empty if the original variable is an empty string. The thing is, I need the string to be in the form above, including the single quotes around the value.
If I wouldn't need the single quotes, everything works perfectly! However, as I need them, I am trying to escape them using the below snippet. Unfortunately, what I have doesn't seem to work, as \' doesn't apply as expected. How can I properly escape ' so that get them in my string?
tasks:
- include_tasks: ../tasks/get_current.yml
- include_tasks: ../tasks/failed_jobs_stats.yml
vars:
date_param: "{{ date_start != '' | ternary('--date=\''+date_start+'\'', '') }}"
This is not a quoting problem, this is an operator precedence problem.
In your example, you:
apply the ternary filter to the empty string ''
compare the above result to date_start
What you need to do is to enclose the condition in parens:
date_param: "{{ (date_start != '') | ternary('--date=\''+date_start+'\'', '') }}"

Probable quoting issue using the stdin argument of ansible's shell module

I've got a playbook with the following tasks:
- set_fact:
asg_filter: >
.AutoScalingGroups[] |
select(.Tags[] | select(.Key == "Role").Value == "myrole")
- shell: aws autoscaling --region us-west-2 describe-auto-scaling-groups | jq --compact-output "{{ asg_filter }}"
register: asgs_result
- set_fact:
stale_instance_filter: >
.LaunchConfigurationName as $lc |
.Instances[] |
select(.LaunchConfigurationName != $lc) |
.InstanceId
Now I want to use stale_instance_filter on asgs_result.stdout. The following works:
- shell: echo '{{ asgs_result.stdout }}' | jq -r '{{ stale_instance_filter }}'
But this doesn't:
- shell: jq -r '{{ stale_instance_filter }}'
args:
stdin: "{{ asgs_result.stdout }}"
I get the following error message: parse error: Invalid numeric literal at line 1, column 23 (which I believe is from the account number in the ARN for the ASG.) I think it's a quoting issue (maybe something about the double quotes in the JSON), but I've also tried asgs_result.stdout | quote to no avail. I also tried the command module; it didn't help either. Of course this all works if I do it directly on the CLI.
I realize I could combine the two jq filters but I want to reuse asgs_result for other things and don't want to have to make the query multiple times. How can I fix this so I can use the stdin argument?
Edit: I was asked to provide an example of the value of asgs_result, well here you go, here's the stdout attribute in it (since I don't use anything else):
"stdout": "{\"AutoScalingGroupARN\":\"arn:aws:autoscaling:us-east-2:123456:autoScalingGroup:e75a213b-75fe-467c-8cf5-d7c51f76c471:autoScalingGroupName/myrole-dev\",\"TargetGroupARNs\":[],\"SuspendedProcesses\":[],\"DesiredCapacity\":4,\"Tags\":[{\"ResourceType\":\"auto-scaling-group\",\"ResourceId\":\"myrole-dev\",\"PropagateAtLaunch\":true,\"Value\":\"dev\",\"Key\":\"Dimension\"},{\"ResourceType\":\"auto-scaling-group\",\"ResouJceId\":\"myrole-dev\",\"PropagateAtLaunch\":true,\"Value\":\"true\",\"Key\":\"Monitored\"},{\"ResourceType\":\"auto-scaling-group\",\"ResourceId\":\"myrole-dev\",\"PropagateAtLaunch\":true,\"Value\":\"myrole\",\"Key\":\"Name\"},{\"ResourceType\":\"auto-scaling-group\",\"ResourceId\":\"myrole-dev\",\"PropagateAtLaunch\":true,\"Value\":\"myrole\",\"Key\":\"Role\"},{\"ResourceType\":\"auto-scaling-group\",\"ResourceId\":\"myrole-dev\",\"PropagateAtLaunch\":true,\"Value\":\"2035-09-30 18:55:31 +0000\",\"Key\":\"cleaner-destroy-after\"},{\"ResourceType\":\"auto-scaling-group\",\"ResourceId\":\"myrole-dev\",\"PropagateAtLaunch\":true,\"Value\":\"vpce-2c23ca45\",\"Key\":\"force_s3_endpoint_dependency\"},{\"ResourceType\":\"auto-scaling-group\",\"ResourceId\":\"myrole-dev\",\"PropagateAtLaunch\":true,\"Value\":\"owned\",\"Key\":\"kubernetes.io/cluster/dev\"}],\"EnabledMetrics\":[],\"LoadBalancerNames\":[],\"AutoScalingGroupName\":\"myrole-dev\",\"DefaultCooldown\":300,\"MinSize\":4,\"Instances\":[{\"ProtectedFromScaleIn\":false,\"AvailabilityZone\":\"us-east-2b\",\"InstanceId\":\"i-0141fd35e3cf3ad0a\",\"HealthStatus\":\"Healthy\",\"LifecycleState\":\"InService\",\"LaunchConfigurationName\":\"dev_myrole_20180511171410107500000002\"},{\"ProtectedFromScaleIn\":false,\"AvailabilityZone\":\"us-east-2c\",\"InstanceId\":\"i-01aec2b3546d75190\",\"HealthStatus\":\"Healthy\",\"LifecycleState\":\"InService\",\"LaunchConfigurationName\":\"dev_myrole_20180511171410107500000002\"},{\"ProtectedFromScaleIn\":false,\"AvailabilityZone\":\"us-east-2a\",\"InstanceId\":\"i-0830b227f034d2859\",\"HealthStatus\":\"Healthy\",\"LifecycleState\":\"InService\",\"LaunchConfigurationName\":\"dev_myrole_20180511171410107500000002\"},{\"ProtectedFromScaleIn\":false,\"AvailabilityZone\":\"us-east-2b\",\"InstanceId\":\"i-0f7d847e8c168040b\",\"HealthStatus\":\"Healthy\",\"LifecycleState\":\"InService\",\"LaunchConfigurationName\":\"dev_myrole_20180511171410107500000002\"}],\"MaxSize\":4,\"VPCZoneIdentifier\":\"subnet-c348988e,subnet-79743210,subnet-156ee36e\",\"HealthCheckGracePeriod\":300,\"TerminationPolicies\":[\"Default\"],\"LaunchConfigurationName\":\"dev_myrole_20180511171410107500000002\",\"CreatedTime\":\"2018-02-20T22:35:32.183Z\",\"AvailabilityZones\":[\"us-east-2a\",\"us-east-2b\",\"us-east-2c\"],\"HealthCheckType\":\"EC2\",\"NewInstancesProtectedFromScaleIn\":false}"
Sorry that it is all on one line but I don't want to make anyone think there is a newline in there, because there isn't.
The JSON content seems to be interpreted before sent to the stdin, so looks like simple quotes are sent (seen in verbose mode with -vvv):
"stdin": "{'AutoScalingGroupARN': 'arn:aws:autoscaling:us-east-2:123456:autoScalin
gGroup:e75a213b-75fe-467c-8cf5-d7c51f76c471:autoScalingGroupName/myrole-dev', ...,
'AvailabilityZones': ['us-east-2a', 'us-east-2b', 'us-east-2c']}"
Which is not JSON valid:
$ echo "{'AutoScalingGroupARN': 'arn:aws:autoscaling:us-east-2:123456:autoScalingGroup:e75a213b-75fe-467c-8cf5-d7c51f76c471:autoScalingGroupName/myrole-dev', 'HealthCheckGracePeriod': 300}" | jq
parse error: Invalid numeric literal at line 1, column 23
$ echo '{"AutoScalingGroupARN": "arn:aws:autoscaling:us-east-2:123456:autoScalingGroup:e75a213b-75fe-467c-8cf5-d7c51f76c471:autoScalingGroupName/myrole-dev", "HealthCheckGracePeriod": 300}' | jq
{
"AutoScalingGroupARN": "arn:aws:autoscaling:us-east-2:123456:autoScalingGroup:e75a213b-75fe-467c-8cf5-d7c51f76c471:autoScalingGroupName/myrole-dev",
"HealthCheckGracePeriod": 300
}
So, you need to "escape" it.
Unfortunately, the to_json filter, escape to much:
"stdin": "\"{\\\"AutoScalingGroupARN\\\":\\\"arn:aws:autosca...
But the string filter fits perfectly:
"stdin": "{\"AutoScalingGroupARN\":\"arn:aws:autosca...
So, the correct way with stdin is this:
- shell: jq -r '{{ stale_instance_filter }}'
args:
stdin: "{{ asgs_result.stdout | string }}"

Resources