Subtract date from Jinja expression - date

I want to remove 1 month from current_date_operation in Ansible task. This is what I tried:
vars:
# for example current
current_date_operation: "{{ ansible_date_time.date }}"
previous_date_operation : "{{ '%Y-%m-%d'|strftime(current_date_operation.epoch|int - 2592000) }}"
Unfortunately, the above code is giving the following error:
"msg": "The task includes an option with an undefined variable. The error was: 'ansible.utils.unsafe_proxy.AnsibleUnsafeText object' has no attribute 'epoch'
Any idea?
Thanks

In your vars declaration, your are first getting the date key from object ansible_date_time.
On the next line, you are using that set variable (which is a string) and call on it the key epoch which does not exists as it is a property of the parent object (i.e. ansible_date_time). Since your var declaration cannot be parsed correctly, the var in itself is undefined.
The following playbook demonstrate you can get the expected result by fixing your vars definition:
---
- hosts: localhost
vars:
current_date_operation: "{{ ansible_date_time.date }}"
previous_date_operation : "{{ '%Y-%m-%d' | strftime(ansible_date_time.epoch | int - 2592000) }}"
tasks:
- debug:
var: current_date_operation
- debug:
var: previous_date_operation
Test run:
$ ansible-playbook playbook.yml
PLAY [localhost] **************************************************************************************************************************************************************************************************
TASK [Gathering Facts] ********************************************************************************************************************************************************************************************
ok: [localhost]
TASK [debug] ******************************************************************************************************************************************************************************************************
ok: [localhost] => {
"current_date_operation": "2020-01-14"
}
TASK [debug] ******************************************************************************************************************************************************************************************************
ok: [localhost] => {
"previous_date_operation": "2019-12-15"
}
PLAY RECAP ********************************************************************************************************************************************************************************************************
localhost : ok=3 changed=0 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0

Related

Ansible: How to read file and push results to templates

I have task to read data from csv file and push result to templates and copy those templates to different servers. however, i am getting error while writing to template. below are details -
main.yml
- name: Print return information from the previous task
vars:
test_csv: "{{ lookup('file', '/u00/ansible/Playbooks/files/newrelic_test.csv', wantlist=True) }}"
ansible.builtin.debug:
var: test_csv
- name: copy template
template:
src: /u00/ansible/Playbooks/files/infra-config.yml_template
dest: /u00/app/monitor/infra-config.yml
with_items: test_csv
notify: confirm copy done
- name: Start the New Relic Service
ansible.builtin.systemd:
name: infra.service
state: started
become: yes
become_user: root
infra-config.yml_template -
custom_attributes:
application : {{ item.Application }}
env : {{ item.env }}
datacenter : {{ item.Datacenter }}
log:
file: /u00/app/monitor/infra.log
csv file content
Application,Host,env,Datacenter
Microsoft,testserver1,TEST,DC1
Apple,testserver2,TEST,DC2
error -
> TASK [config-update : copy template]
> ******************************************* [0;31mAn exception occurred during task execution. To see the full traceback, use -vvv.
> The error was: ansible.errors.AnsibleUndefinedVariable:
> 'ansible.utils.unsafe_proxy.AnsibleUnsafeText object' has no attribute
> 'db_name'[0m [0;31mfailed: [testserver1]
> (item=test_csv) => {"ansible_loop_var": "item", "changed": false,
> "item": "test_csv", "msg": "AnsibleUndefinedVariable:
> 'ansible.utils.unsafe_proxy.AnsibleUnsafeText object' has no attribute
> 'db_name'"}
Expectation is to read csv file and use variables in template in different servers.
testserver1 -
> custom_attributes: application : Microsoft env : Test datacenter : DC1
> log: file: /u00/app/monitor/infra.log
testserver2 -
> custom_attributes: application : Apple env : Test datacenter : DC1
> log: file: /u00/app/monitor/infra.log
There are few things to fix in your playbook. First, you are defining your test_csv variable inside a task and it cannot be accessible by other tasks. You can use register instead. However, the first task returns a list but with one string like this "test_csv": ["Application,Host,env,Datacenter\nMicrosoft,testserver1,TEST,DC1 \nApple,testserver2,TEST,DC2"] which only results one item in the test_csv list.
You can achieve this by using read_csv module as well. Below I demonstrate how:
Note that I have added a condition using inventory_hostname on the copy template task since you might want to target each csv line according to its hostname. You can modify this according to your needs.
Csv file content:
Application,Host,env,Datacenter
Microsoft,localhost,TEST,DC1
Apple,testserver2,TEST,DC2
Example of playbook for testing:
- name: Check status
hosts: localhost
gather_facts: no
tasks:
- name: read csv file and return a list
read_csv:
path: test.csv
register: applications
- name: Ouput applications from previous task
debug:
msg: "{{ item.Application }}"
loop: "{{ applications.list }}"
- name: copy template
template:
src: src.yml_template ##I would recommendr to use .j2 jinja template instead.
dest: dest.yml
loop: "{{ applications.list }}"
when: inventory_hostname == item.Host
src.yml_template content:
custom_attributes:
application : {{ item.Application }}
env : {{ item.env }}
datacenter : {{ item.Datacenter }}
log:
file: /u00/app/monitor/infra.log
Gives in dest.yml:
custom_attributes:
application : Microsoft
env : TEST
datacenter : DC1
log:
file: /u00/app/monitor/infra.log
Cli output:
PLAY [Check status] **********************************************************************************************************************************************************
TASK [read csv file and return a list] ***************************************************************************************************************************************
ok: [localhost]
TASK [Ouput applications from previous task] *********************************************************************************************************************************
ok: [localhost] => (item={'Application': 'Microsoft', 'Host': 'localhost', 'env': 'TEST', 'Datacenter': 'DC1 '}) => {
"msg": "Microsoft"
}
ok: [localhost] => (item={'Application': 'Apple', 'Host': 'testserver2', 'env': 'TEST', 'Datacenter': 'DC2'}) => {
"msg": "Apple"
}
TASK [copy template] *********************************************************************************************************************************************************
changed: [localhost] => (item={'Application': 'Microsoft', 'Host': 'localhost', 'env': 'TEST', 'Datacenter': 'DC1 '})
skipping: [localhost] => (item={'Application': 'Apple', 'Host': 'testserver2', 'env': 'TEST', 'Datacenter': 'DC2'})

How can I use '--extra-vars' for replicas in Ansible playbooks?

I am trying to set a default value of 1 replicas for pod deployment but also I would like to have the option to change the value by using --extra-vars="pod_replicas=2". I have tried the following but it doesn't work for me.
vars:
- pod_replicas: 1
spec:
replicas: "{{ pod_replicas }}"
ERROR:
TASK [Create a deployment]
fatal: [localhost]: FAILED! => {"changed": false, "error": 422, "msg": "Failed to patch object: b'{\"kind\":\"Status\",\"apiVersion\":\"v1\",\"metadata\":{},\"status\":\"Failure\",\"m essage\":\" \\\\\"\\\\\" is invalid: patch: Invalid value: \\\\\"{\\\\\\\\\\\\\"apiVersion\\\\\\\\\\\\\":\\\\\\\\\\\\\"apps/v1\\\\\\\\\\\\\",\\\\\\\\\\\\\"kind\\\\\\\\\\\\\":\\\\\\\\\ \\\\"Deployment\\\\\\\\\\\\\",\\\\\\\\\\\\\"metadata\\\\\\\\\\\\\":{\\\\\\\\\\\\\"annotations\\\\\\\\\\\\\":{\\\\\\\\\\\\\"deployment.kubernetes.io/revision\\\\\\\\\\\\\":\\\\\\\\\\\\ \"1\\\\\\\\\\\\\"},\\\\\\\\\\\\\
(...)
\\"2022-02-14T12:13:38Z\\\\\\\\\\\\\",\\\\\\\\\\\\\"lastTransitionTime\\\\\\\\\\\\\":\\\\\\\\\\\\\"2022-02-14T12:13:33Z\\\\\\\\\\\\\",\\\\\\\\\\\\\"reason\\\\\\\\\\\\\":\\\\\\\\\\ \\\"NewReplicaSetAvailable\\\\\\\\\\\\\",\\\\\\\\\\\\\"message\\\\\\\\\\\\\":\\\\\\\\\\\\\"ReplicaSet \\\\\\\\\\\\\\\\\\\\\\\\\\\\\"ovms-deployment-57c9bbdfb8\\\\\\\\\\\\\\\\\\\\\\\\\ \\\\" has successfully progressed.\\\\\\\\\\\\\"},{\\\\\\\\\\\\\"type\\\\\\\\\\\\\":\\\\\\\\\\\\\"Available\\\\\\\\\\\\\",\\\\\\\\\\\\\"status\\\\\\\\\\\\\":\\\\\\\\\\\\\"True\\\\\\\\ \\\\\",\\\\\\\\\\\\\"lastUpdateTime\\\\\\\\\\\\\":\\\\\\\\\\\\\"2022-02-14T14:18:33Z\\\\\\\\\\\\\",\\\\\\\\\\\\\"lastTransitionTime\\\\\\\\\\\\\":\\\\\\\\\\\\\"2022-02-14T14:18:33Z\\\ \\\\\\\\\\",\\\\\\\\\\\\\"reason\\\\\\\\\\\\\":\\\\\\\\\\\\\"MinimumReplicasAvailable\\\\\\\\\\\\\",\\\\\\\\\\\\\"message\\\\\\\\\\\\\":\\\\\\\\\\\\\"Deployment has minimum availabili ty.\\\\\\\\\\\\\"}]}}\\\\\": v1.Deployment.Spec: v1.DeploymentSpec.Replicas: readUint32: unexpected character: \\\\ufffd, error found in #10 byte of ...|eplicas\\\\\":\\\\\"1\\\\\",\\ \\\"revisi|..., bigger context ...|\\\\\"spec\\\\\":{\\\\\"progressDeadlineSeconds\\\\\":600,\\\\\"replicas\\\\\":\\\\\"1\\\\\",\\\\\"revisionHistoryLimit\\\\\":10,\\\\\"selector\\\\\ ":{\\\\\"matchLab|...\",\"field\":\"patch\"}]},\"code\":422}\\n'", "reason": "Unprocessable Entity", "status": 422}
Any idea how I can fix this?? Thank you!
Regarding your question
How can I use --extra-vars in Ansible playbooks?
you may have a look into Understanding variable precedence, Using -e extra variables at the command line and the following small test setup
---
- hosts: localhost
become: false
gather_facts: false
vars:
REPLICAS: 1
tasks:
- name: Show value
debug:
msg: "{{ REPLICAS }} in {{ REPLICAS | type_debug }}"
which will for a run with
ansible-playbook vars.yml
result into an output of
TASK [Show value] ******
ok: [localhost] =>
msg: 1 in int
and for a run with
ansible-playbook --extra-vars="REPLICAS=2" vars.yml
into an output of
TASK [Show value] ******
ok: [localhost] =>
msg: 2 in unicode
Because of the error message
v1.Deployment.Spec: v1.DeploymentSpec.Replicas: readUint32: unexpected character: \\\\ufffd, error found in #10 byte of ...|eplicas\\\\\":\\\\\"1\\\\\"
I've introduced the type_debug filter. Maybe it will be necessary to cast the data type to integer.
- name: Show value
debug:
msg: "{{ REPLICAS }} in {{ REPLICAS | int | type_debug }}"
Further Occurences
When I've been tying numeric values from a variable file, they've been resolved as string not numbers
I have found a solution. Using a json object as an argumet seems to work:
ansible-playbook --extra-vars '{ "pod_replicas":2 }' <playbook>.yaml

how openstack remove offline host node by kolla-ansible

I have an offline host node which includes (compute node, control node and storage node). This host node was shutdown by accident and can't recover to online. All services about that node are down and enable but I can't set to disable.
So I can't remove the host by:
kolla-ansible -i multinode stop --yes-i-really-really-mean-it --limit node-17
I get this error:
TASK [Gather facts] ********************************************************************************************************************************************************************************************************************
fatal: [node-17]: UNREACHABLE! => {"changed": false, "msg": "Failed to connect to the host via ssh: ssh: connect to host node-17 port 22: Connection timed out", "unreachable": true}
PLAY RECAP *****************************************************************************************************************************************************************************************************************************
node-17 : ok=0 changed=0 unreachable=1 failed=0 skipped=0 rescued=0 ignored=0
How can I remove that offline host node? THX.
PS: Why I remove that offline host?
node-14(online) : **manage node which kolla-ansible installed**; compute node, control node and storage node
node-15(online) : compute node, control node and storage node
node-17(offline) : compute node, control node and storage node
osc99 (adding) : compute node, control node and storage node
Because when I deploy a new host(osc99) with (the multinode file had comment the node-17 line):
kolla-ansible -i multinode deploy --limit osc99
kolla-ansible will report error:
TASK [keystone : include_tasks] ********************************************************************************************************************************************************************************************************
included: .../share/kolla-ansible/ansible/roles/keystone/tasks/init_fernet.yml for osc99
TASK [keystone : Waiting for Keystone SSH port to be UP] *******************************************************************************************************************************************************************************
ok: [osc99]
TASK [keystone : Initialise fernet key authentication] *********************************************************************************************************************************************************************************
ok: [osc99 -> node-14]
TASK [keystone : Run key distribution] *************************************************************************************************************************************************************************************************
fatal: [osc99 -> node-14]: FAILED! => {"changed": true, "cmd": ["docker", "exec", "-t", "keystone_fernet", "/usr/bin/fernet-push.sh"], "delta": "0:00:04.006900", "end": "2021-07-12 10:14:05.217609", "msg": "non-zero return code", "rc": 255, "start": "2021-07-12 10:14:01.210709", "stderr": "", "stderr_lines": [], "stdout": "Warning: Permanently added '[node.15]:8023' (ECDSA) to the list of known hosts.\r\r\nssh: connect to host node.17 port 8023: No route to host\r\r\nrsync: connection unexpectedly closed (0 bytes received so far) [sender]\r\nrsync error: unexplained error (code 255) at io.c(235) [sender=3.1.2]", "stdout_lines": ["Warning: Permanently added '[node.15]:8023' (ECDSA) to the list of known hosts.", "", "ssh: connect to host node.17 port 8023: No route to host", "", "rsync: connection unexpectedly closed (0 bytes received so far) [sender]", "rsync error: unexplained error (code 255) at io.c(235) [sender=3.1.2]"]}
NO MORE HOSTS LEFT *********************************************************************************************************************************************************************************************************************
PLAY RECAP *****************************************************************************************************************************************************************************************************************************
osc99 : ok=120 changed=55 unreachable=0 failed=1 skipped=31 rescued=0 ignored=1
How could I fixed this error, this is the main point whether or not I can remove the offline host.
Maybe I could fixed that by change the init_fernet.yml file:
node-14:~$ cat .../share/kolla-ansible/ansible/roles/keystone/tasks/init_fernet.yml
---
- name: Waiting for Keystone SSH port to be UP
wait_for:
host: "{{ api_interface_address }}"
port: "{{ keystone_ssh_port }}"
connect_timeout: 1
register: check_keystone_ssh_port
until: check_keystone_ssh_port is success
retries: 10
delay: 5
- name: Initialise fernet key authentication
become: true
command: "docker exec -t keystone_fernet kolla_keystone_bootstrap {{ keystone_username }} {{ keystone_groupname }}"
register: fernet_create
changed_when: fernet_create.stdout.find('localhost | SUCCESS => ') != -1 and (fernet_create.stdout.split('localhost | SUCCESS => ')[1]|from_json).changed
until: fernet_create.stdout.split()[2] == 'SUCCESS' or fernet_create.stdout.find('Key repository is already initialized') != -1
retries: 10
delay: 5
run_once: True
delegate_to: "{{ groups['keystone'][0] }}"
- name: Run key distribution
become: true
command: docker exec -t keystone_fernet /usr/bin/fernet-push.sh
run_once: True
delegate_to: "{{ groups['keystone'][0] }}"
by changing the delegate_to: "{{ groups['keystone'][0] }}? But I can't implement that.

Having issues with rs.add() in ansible playbook for mongo

I am using below tasks in my playbook to initialize cluster and add secondary to primary:
- name: Initialize replica set
run_once: true
delegate_to: host1
shell: >
mongo --eval 'printjson(rs.initiate())'
- name: Format secondaries
run_once: true
local_action:
module: debug
msg: '"{{ item }}:27017"'
with_items: ['host2', 'host3']
register: secondaries
- name: Add secondaries
run_once: true
delegate_to: host1
shell: >
/usr/bin/mongo --eval 'printjson(rs.add({{ item.msg }}))'
with_items: secondaries.results
I am getting below error:
TASK [mongodb-setup : Add secondaries] *******************************
fatal: [host1]: FAILED! => {"msg": "The task includes an option with an undefined variable. The error was: 'ansible.utils.unsafe_proxy.AnsibleUnsafeText object' has no attribute 'msg'\n\nThe error appears to have been in '/var/lib/awx/projects/_dev/roles/mongodb-setup/tasks/users.yml': line 15, column 3, but may\nbe elsewhere in the file depending on the exact syntax problem.\n\nThe offending line appears to be:\n\n\n- name: Add secondaries\n ^ here\n"}
Thanks for the response, I have amended my code as below
- name: Add secondaries
run_once: true
delegate_to: host-1
shell: >
/usr/bin/mongo --eval 'printjson(rs.add({{ item }}:27017))'
with_items:
- host2
- host3
but getting below error
failed: [host-2 -> host-1] (item=host-2) => {"changed": true, "cmd": "/usr/bin/mongo --eval 'printjson(rs.add(host-2:27017))'", "delta": "0:00:00.173077", "end": "2019-08-06 13:29:09.422560", "item": "host-2", "msg": "non-zero return code", "rc": 252, "start": "2019-08-06 13:29:09.249483", "stderr": "", "stderr_lines": [], "stdout": "MongoDB shell version: 3.2.22\nconnecting to: test\n2019-08-06T13:29:09.419-0500 E QUERY [thread1] SyntaxError: missing ) after argument list #(shell eval):1:37", "stdout_lines": ["MongoDB shell version: 3.2.22", "connecting to: test", "2019-08-06T13:29:09.419-0500 E QUERY [thread1] SyntaxError: missing ) after argument list #(shell eval):1:37"]}
You issue is not with rs.add() but with the data you loop over. In your last task, your item list is a single string.
# Wrong #
with_items: secondaries.results
You want to pass an actual list form your previously registered result:
with_items: "{{ secondaries.results }}"
That being said, registering the result of a debug task is rather odd. You should use set_fact to register what you need in a var, or better directly loop other your list of hosts in your task. It also looks like the rs.add funcion is exepecting a string so you should quote the argument in your eval. Something like:
- name: Add secondaries
shell: >
/usr/bin/mongo --eval 'printjson(rs.add("{{ item }}:27017"))'
with_items:
- host2
- host3
And the way you use delegation seems rather strange to me in this context but it's hard to give any valid clues without a complete playbook example of what you are trying to do (that you might give in a new question if necessary).

How to skip role executing in Ansible

I try to write the playbook.yml for my vagrant machine and I'm faced with the following problem.
Ansible prompt me to set these variables and I set these variables to null/false/no/[just enter], but the roles is executed no matter! How can I prevent this behavior? I just want no actions if no vars are set..
---
- name: Deploy Webserver
hosts: webservers
vars_prompt:
run_common: "Run common tasks?"
run_wordpress: "Run Wordpress tasks?"
run_yii: "Run Yii tasks?"
run_mariadb: "Run MariaDB tasks?"
run_nginx: "Run Nginx tasks?"
run_php5: "Run PHP5 tasks?"
roles:
- { role: common, when: run_common is defined }
- { role: mariadb, when: run_mariadb is defined }
- { role: wordpress, when: run_wordpress is defined }
- { role: yii, when: run_yii is defined }
- { role: nginx, when: run_nginx is defined }
- { role: php5, when: run_php5 is defined }
I believe the variables will always be defined when you use vars_prompt, so "is defined" will always be true. What you probably want is something along these lines:
- name: Deploy Webserver
hosts: webservers
vars_prompt:
- name: run_common
prompt: "Product release version"
default: "Y"
roles:
- { role: common, when: run_common == "Y" }
Edit: To answer your question, no it does not throw an error. I made a slightly different version and tested it using ansible 1.4.4:
- name: Deploy Webserver
hosts: localohst
vars_prompt:
- name: run_common
prompt: "Product release version"
default: "N"
roles:
- { role: common, when: run_common == "Y" or run_common == "y" }
And roles/common/tasks/main.yml contains:
- local_action: debug msg="Debug Message"
If you run the above example and just hit Enter, accepting the default, then the role is skipped:
Product release version [N]:
PLAY [Deploy Webserver] *******************************************************
GATHERING FACTS ***************************************************************
ok: [localhost]
TASK: [common | debug msg="Debug Message"] ************************************
skipping: [localhost]
PLAY RECAP ********************************************************************
localhost : ok=1 changed=0 unreachable=0 failed=0
But if you run this and enter Y or y when prompted then the role is executed as desired:
Product release version [N]:y
PLAY [Deploy Webserver] *******************************************************
GATHERING FACTS ***************************************************************
ok: [localhost]
TASK: [common | debug msg="Debug Message"] ************************************
ok: [localhost] => {
"item": "",
"msg": "Debug Message"
}
PLAY RECAP ********************************************************************
localhost : ok=2 changed=0 unreachable=0 failed=0