Ansible: Filtering with "contains" - amazon-ec2

I am searching for AMI IDs created on today's date.
My Ansible playbook is
---
- name: List of AMIs created today
hosts: localhost
tasks:
- name: Get today's date
command: "date +'%Y-%m-%d'"
register: result
- name: Get AMIs list
ec2_ami_info:
filters:
owner: self
creation_date: "{{ result }}"
The Ansible module ec2_ami_info needs the exact creation_date which is like 2018-11-30T08:33:08.000Z. But the date command result value is 2018-11-30.
Can I get AMI IDs which creation_date contains 2018-11-30?

Related

Ansible filter AWS AMI ID with dates

- name: gather information about all AMIs with tag key Name and value webapp
amazon.aws.ec2_ami_info:
filters:
"tag:Version": "*"
register: ec2ami_result
- debug:
msg: "{{ ec2ami_result }}"
- set_fact:
AMI_newid: "{{ ec2ami_result | json_query ('images[?(#.creation_date=='2020-06-30T05:17:36.000Z')].image_id') }}"
I am getting ec2ami json data with bunch of images, now i want to filter them using creation_date and then get its image_id.
I get error
fatal: [localhost]: FAILED! => {"msg": "template error while
templating string: expected token ',', got 'integer'. String: {{
ec2ami_result | json_query
('images[?(#.creation_date=='2020-06-30T05:17:36.000Z')].image_id')
}}"}
Is there is something i need to fix, also is there is way i can only get image_ids before date specified so lets say 2020-05-20, all image id created before this date ?
fix:
just use
amazon.aws.ec2_ami_info:
filters:
creation-date: "2020-*"
This way you can get any ami belonging to that year.
To filter ami for year just use Filters
amazon.aws.ec2_ami_info: filters: creation-date: "2020-*"
This will return only value from creation-date

How to pass today's date and time as argument in ansible

I am running python script using ansible.
Here is my playbook -
- name: Run python script
command: python Test.py -StartDate 2020-10-01T00:00:00 -EndDate 2020-11-05T00:00:00
register: result
- debug: msg="{{result.stdout}}"
I want this playbook to use EndDate as todays date when I run script. How can I use latest date and time in same format I have written every time I run script without having to change manually every day?
Q: "How can I use the latest date and time ...?"
A: Use Ansible facts variable ansible_date_time. For example, given the script below
shell> cat test.sh
#!/bin/sh
echo $1 $2
The playbook
shell> cat playbook.yml
- hosts: localhost
tasks:
- name: Run script
command: "{{ playbook_dir }}/test.sh
2020-10-01T00:00:00
{{ ansible_date_time.date }}T00:00:00"
register: result
- debug:
var: result.stdout
gives (abridged)
shell> ansible-playbook playbook.yml
result.stdout: 2020-10-01T00:00:00 2020-11-07T00:00:00
Notes
"gather_facts: true" (default) is needed to collect Ansible facts.
The values of date and time will be collected on a remote host when a playbook starts.
If needed there are other attributes in the dictionary
ansible_date_time:
date: '2020-11-07'
day: '07'
epoch: '1604779525'
hour: '21'
iso8601: '2020-11-07T20:05:25Z'
iso8601_basic: 20201107T210525040700
iso8601_basic_short: 20201107T210525
iso8601_micro: '2020-11-07T20:05:25.040817Z'
minute: '05'
month: '11'
second: '25'
time: '21:05:25'
tz: CET
tz_offset: '+0100'
weekday: Saturday
weekday_number: '6'
weeknumber: '44'
year: '2020'
The variable ansible_date_time will not be updated automatically when a playbook runs. For example
- debug:
var: ansible_date_time.iso8601_micro
- debug:
var: ansible_date_time.iso8601_micro
- debug:
var: ansible_date_time.iso8601_micro
give (abridged)
ansible_date_time.iso8601_micro: '2020-11-07T20:16:09.481237Z'
ansible_date_time.iso8601_micro: '2020-11-07T20:16:09.481237Z'
ansible_date_time.iso8601_micro: '2020-11-07T20:16:09.481237Z'
Run module setup to update Ansible facts including the variable ansible_date_time. For example
- debug:
var: ansible_date_time.iso8601_micro
- setup:
- debug:
var: ansible_date_time.iso8601_micro
- setup:
- debug:
var: ansible_date_time.iso8601_micro
give (abridged)
ansible_date_time.iso8601_micro: '2020-11-07T20:16:09.481237Z'
ansible_date_time.iso8601_micro: '2020-11-07T20:16:10.759533Z'
ansible_date_time.iso8601_micro: '2020-11-07T20:16:11.475873Z'
Frequently running setup to update the date and time only is overkill. In this case, consider running command and register result instead.
assuming the T00:00:00 is always fixed, you could declare a variable using the lookup plugin, see an example below the exec_date variable and the modified command task:
---
- hosts: localhost
gather_facts: false
vars:
exec_date: "{{ lookup('pipe', 'date +%Y-%m-%d') }}T00:00:00"
tasks:
- name: print
debug: var=exec_date
- name: Run python script
command: "python Test.py -StartDate 2020-10-01T00:00:00 -EndDate {{ exec_date }}"
register: result
- debug: msg="{{result.stdout}}"
If you want to pass the current time too instead of a fixed T00:00:00, you could use the below:
vars:
exec_date: "{{ lookup('pipe', 'date +%Y-%m-%dT%H:%M:%S') }}"
cheers

How do I select a variable using a fact in my ansible playbook?

I want to select different options based on the aws region and availability zone of my instances.
As a very simple example, I'd like to set the timezone of the instance to the correct timezone based on the region.
I can get the region and the availability zone from the ohai_ec2 facts.
How do I use the fact to select from a list of variables?
I tried referencing the variable directly, and that works for when statements e.g.
when: ohai_ec2.region == "us-east-1"
I tried a lookup as in Create Variable From Ansible Facts , but have not gotten the format correct.
This works
# find the region
- name: Base - find the region
debug:
msg: "Region is {{ ohai_ec2.region }} and zone is {{ ohai_ec2.availability_zone }}"
#Task: Base - Sets the timezone
- name: Base - Set timezone to US East
when: ohai_ec2.region == "us-east-1"
timezone:
name: US/Eastern
- name: Base - Set timezone to CEST
when: ohai_ec2.region == "eu-central-1"
timezone:
name: Europe/Madrid
- name: Base - Set timezone to US West
when: ohai_ec2.region == "us-west-2"
timezone:
name: US/Pacific
but this doesn't
...
vars:
mytz:
us-east-1: "US/Eastern"
us-west-2: "US/Pacific"
eu-central-1: "Europe/Madrid"
...
- name: Base - Set timezone to US East
timezone:
name: "{{ lookup ('vars', 'mytz'.'[ohai_ec2.region]') }}"
nor
- name: Base - Set timezone to US East
timezone:
name: "{{ mytz.'[ohai_ec2.region]' }}"
I get this result
fatal: [xxxxxxxxxx-xxxx]: FAILED! => {"msg": "template error while templating string: expected name or number. String: {{ mytz.[ohai_ec2.region] }}"}
What is the correct way of using the fact and variable?
If you have a dictionary named mytz (which you do), and you have a dictionary ohai_ec2 with a region key, you can use the value of that key to select a value from mytz like this:
{{ mytz[ohai_ec2.region] }}
Here's a runnable example:
---
- hosts: localhost
gather_facts: false
vars:
mytz:
us-east-1: "US/Eastern"
us-west-2: "US/Pacific"
eu-central-1: "Europe/Madrid"
ohai_ec2:
region: us-east-1
tasks:
- name: Base - Set timezone to US East
timezone:
name: "{{ mytz[ohai_ec2.region] }}"

Loop through list variable in Ansable

I am making an ansible script where a variable file will hold a list of servers, where I will loop through and power them down. It appears that Ansible is changing my list to a string, but maybe I am wrong.
I've tried using "loop", "with_items", and having them on the same line. serverA and ServerB does indeed exist
File dir:
taskName/vars/ServerListA.yaml
taskName/tasks/main.yaml
taskName/tasks/shutdown.yaml
ServerListA.yaml:
---
evenServers:
- serverB
- serverA
main.yaml:
---
- import_tasks: shutdown.yaml
shutdown.yaml:
---
- name: get vars
include_vars:
file: ServerListA.yaml
name: evenServers
- name: shutdown guest
vmware_guest_powerstate:
hostname: virtualCenterName
state: powered-on
username: user
name: "{{ item }}"
password: pass
validate_certs: no
loop:
- "{{ evenServers }}"
output:
TASK [vCenter_Infra_HA_Test : shutdown guest]
********************************************************************************************************* [WARNING]: The value {'evenServers': ['serverA', 'serverB']} (type
dict) in a string field was converted to u"{'evenServers': ['serverA',
'serverB']}" (type string). If this does not look like what you
expect, quote the entire value to ensure it does not change.
failed: [localServer] (item={u'evenServers': [u'serverA',
u'serverB']}) => {"ansible_loop_var": "item", "changed": false,
"item": {"evenServers": ["serverA", "serverB"]}, "msg": "Unable to set
power state for non-existing virtual machine : '{'evenServers':
['serverA', 'serverB']}'"}
You are including vars inside a top level 'namespace' with the same name as the first var defined in your included file. Thus, after inclusion, you data looks like this:
evenServers:
evenServers:
- serverA
- serverB
Since ansible cannot loop over the first level hash (without any other instructions) it transforms it to a string representation to have something to use.
You should transfrom your tasks file like this:
---
- name: get vars
include_vars:
file: ServerListA.yaml
- name: shutdown guest
vmware_guest_powerstate:
hostname: virtualCenterName
state: powered-on
username: user
name: "{{ item }}"
password: pass
validate_certs: no
loop: "{{ evenServers }}"
I also suggest you fix the indentation in your var file
---
evenServers:
- serverB
- serverA

Ansible set_fact across plays

I have to run an ansible playbook to execute the following tasks
1) Calculate date in YYYY_MM_DD format and then use this prefix to download some file from aws to my local machine. The filename is of the following format 2015_06_04_latest_file.csv
2) I have to then create a folder by the name 2015_06_04 into multiple hosts and upload this file there.
This is my current playbook -
---
- hosts: 127.0.0.1
connection: local
sudo: yes
gather_facts: no
tasks:
- name: calculate date
shell: date "+%Y_%m_%d" --date="1 days ago"
register: output
- name: set date variable
set_fact: latest_date={{ item }}
with_items: output.stdout_lines
- local_action: command mkdir -p /tmp/latest_contracts/{{ latest_date }}
- local_action: command /root/bin/aws s3 cp s3://primarydatafolder/data/{{ latest_date }}_latest_data.csv /tmp/latest_contracts/{{ latest_date }}/ creates=/tmp/latest_contracts/{{ latest_date }}/latest_data.csv
register: result
ignore_errors: true
- local_action: command /root/bin/aws s3 cp s3://secondarydatafolder/data/{{ latest_date }}_latest_data.csv /tmp/latest_contracts/{{ latest_date }}/ creates=/tmp/latest_contracts/{{ latest_date }}/latest_data.csv
when: result|failed
# remove the date prefix from the downloaded file
- local_action: command ./rename_date.sh {{ latest_date }}
ignore_errors: true
- hosts: contractsServers
sudo: yes
gather_facts: no
tasks:
- name: create directory
file: path={{item.path}} state=directory mode=0775 owner=root group=root
with_items:
- {path: '/var/mukul/contracts/{{ latest_date }}' }
- {path: '/var/mukul/contracts/dummy' }
- name: copy dummy contracts
copy: src=dummy dest=/var/mukul/contracts/
- name: delete previous symlink
shell: unlink /var/mukul/contracts/latest
ignore_errors: true
- name: upload the newly created latest date folder to the host
copy: src=/tmp/latest_contracts/{{ latest_date }} dest=/var/mukul/contracts/
- name: create a symbolic link to the folder on the host and call it latest
action: file state=link src=/var/mukul/contracts/{{ latest_date }} dest=/var/mukul/contracts/latest
As per ansible's documentation on set_fact variable, this variable latest_date should be available across plays. However, ansible fails with the following message
failed: [192.168.101.177] => (item={'path': u'/var/mukul/contracts/{# latest_date #}'}) => {"failed": true, "item": {"path": "/var/mukul/contracts/{# latest_date #}"}}
msg: this module requires key=value arguments (['path=/var/mukul/contracts/{#', 'latest_date', '#}', 'state=directory', 'mode=0775', 'owner=root', 'group=root'])
It looks as if the second playbook is unable to get the value of the latest_date fact. Can you please tell me where i'm making a mistake?
Facts are host specific. As the documentation about set_fact says, "[v]ariables [set with set_fact] are set on a host-by-host basis".
Instead, I'd try using run_once as defined in Delegation, rolling updates, and local actions, like this:
- hosts: contractsServers
tasks:
- name: Determine date
local_action: shell: date "+%Y_%m_%d" --date="1 days ago"
register: yesterday
always_run: True
changed_when: False
run_once: True
- name: Do something else locally
local_action: ...
register: some_variable_name
always_run: True
changed_when: False
run_once: True
- name: Do something remotely using the variables registered above
...
You could enable fact-caching. You will need to set up a local redis instance where facts then will be stored.

Resources