I am trying to copy files to a list of hosts and each file has the hostname present in the name. Here is my playbook:
---
- hosts: ibank
become: true
become_exe: 'sudo su -'
tasks:
- name:"copy ibank to {{ inventory_hostname }} qa"
copy:
src: "/usr/local/jenkins_workspace/Trunk_Ibank_Build_Ansible/ibank/DIST/ibank_{{ inventory_hostname }}_qa.war"
dest: "/usr/local/ibank/ibank_{{ inventory_hostname }}_qa.war"
command:
chdir: /usr/local/ibank
cmd: /usr/local/ibank/restart.sh
But when the file is run I get "ERROR! Syntax Error while loading YAML. mapping values are not allowed here"
Not sure what I am doing wrong at the moment.
line 7: column 10 error syntax error: mapping values are not allowed here (syntax) you forgot the space line6 :
name: "copy ibank to {{ inventory_hostname }} qa"
You should move "command" module usage to another task - you can't use 2 modules in one task.
Try something like this:
---
- hosts: ibank
become: true
become_exe: 'sudo su -'
tasks:
- name:"copy ibank to {{ inventory_hostname }} qa"
copy:
src: "/usr/local/jenkins_workspace/Trunk_Ibank_Build_Ansible/ibank/DIST/ibank_{{ inventory_hostname }}_qa.war"
dest: "/usr/local/ibank/ibank_{{ inventory_hostname }}_qa.war"
- name:"restart ibank after copy"
command:
chdir: /usr/local/ibank
cmd: /usr/local/ibank/restart.sh
Related
I have the following scenario:
The inventory file is laid out as below:
[my_host]
host
server
[host:children]
hostm
hosts
[hostm]
host01
[hosts]
host02
host03
The group_vars file(s) is as below:
host.yml
user: user01
ansible_python_interpreter: /usr/bin/python3
The host_vars file(s) is as below:
host01.yml
id: ABC
nr: 00
host02.yml
id: DEF
nr: 20
host03.yml
id: GHI
nr: 02
Now using the above, I'm trying to run a playbook as described below:
custom.yml
- hosts: "{{ v_host | default([]) }}"
remote_user: root
tasks:
- name: Run the shell script
become: true
become_user: "{{ user }}"
become_method: su
become_exe: "su -"
ansible.builtin.shell: cleanipc {{ item.nr }} remove
with_items:
- "{{ v_host }}"
register: shell_result
no_log: false
changed_when: false
- name: print message
ansible.builtin.debug:
var: shell_result.stdout_lines
To run the playbook, I use the below command:
>ansible-playbook -i /path-to-inventory-file/file custom.yml -e 'v_host=host'
I'm trying to get the playbook to run the shell command on all child nodes of 'host', i.e., 'host01', 'host02' and 'host03', with the value of the variable 'nr' automatically substituted for each host.
I tried changing the lookup of the variable using hostvars as below:
ansible.builtin.shell: cleanipc {{ hostvars[item]['nr'] }} remove
But this didn't work either. Thank you for any help or guidance you can provide.
Thank you!
I'm trying write role to install MySql 8, and get problem with this:
- name: Extract root password from logs into {{ mysql_root_old_password }} variable
ansible.builtin.slurp:
src: "{{ mysql_logfile_path }}"
register: mysql_root_old_password
#when: "'mysql' in ansible_facts.packages"
- name: Extract root password from logs into {{ mysql_root_old_password }} variable
set_fact:
mysql_root_old_password: "{{ mysql_root_old_password.content | b64decode | regex_findall('generated for root#localhost: (.*)$', 'multiline=true') }}"
#when: "'mysqld' in ansible_facts.packages"
- name: Get Server template
ansible.builtin.template:
src: "{{ item.name }}.j2"
dest: "{{ item.path }}"
loop:
- { name: "my.cnf", path: "/root/.my.cnf" }
notify:
- Restart mysqld
on the .my.cnf I get password with quotes and brackets:
[client]
user=root
password=['th6k(gZeJSt4']
How to trim that?
What I try:
- name: trim password
set_fact:
mysql_root_old_password2: "{{ mysql_root_old_password | regex_findall('[a-zA-Z0-9,()!##$%^&*]{12}')}}"
Thanks.
The result of regex_findall is a list because there might be more matches. Take the last item
- set_fact:
mysql_root_old_password: "{{ mysql_root_old_password.content|
b64decode|
regex_findall('generated for root#localhost: (.*)$', 'multiline=true')|
last }}"
From your description
on the .my.cnf I get password with quotes and brackets ... How to trim that
I understand that you like to read a INI file like my.cnf.ini
[client]
user=root
password=['A1234567890B']
where the value of the key password looks like a list with one element in YAML and the structure doesn't change, but you are interested in the value without leading and trailing square brackets and single quotes only.
To do so there are several possibilities.
Via Ansible Lookup plugins
---
- hosts: localhost
become: false
gather_facts: false
tasks:
- name: Extract root password from INI file
debug:
msg: "{{ lookup('ini', 'password section=client file=my.cnf.ini') }}"
register: result
- name: Show result with type
debug:
msg:
- "{{ result.msg }}"
- "result.msg is of type {{ result.msg | type_debug }}"
- "Show password only {{ result.msg[0] }}" # the first list element
Such approach will work on the Control Node.
Like all templating, lookups execute and are evaluated on the Ansible control machine.
Further Q&A
How to read a line from a file into an Ansible variable
What is the difference between .ini and .conf?
Further Documentation
ini lookup – read data from an INI file
Via Ansible shell module, sed and cut.
---
- hosts: localhost
become: false
gather_facts: false
tasks:
- name: Extract root password from INI file
shell:
cmd: echo $(sed -n 's/^password=//p' my.cnf.ini | cut -d "'" -f 2)
register: result
- name: Show result
debug:
msg: "{{ result.stdout }}"
Please take note regarding "I get password with quotes and brackets ... ['<pass>'] ... How to trim that?" that from perspective of the SQL service, .cnf file, [' and '] are actually part of the password!
- name: Server template
template:
src: "my.cnf.ini"
dest: "/root/.my.cnf"
If that is correct they will be necessary for proper function of the service.
I'm running an ansible playbook against a number of ec2 instances to check if a directory exists.
---
- hosts: all
become: true
tasks:
- name: Check if foo is installed
stat:
path:
/etc/foo
register: path
- debug: msg="{{path.stat.exists}}"
And I would like to generate a localfile that lists the private IP addresses of the ec2 instances and states whether or not the directory foo does exist.
I can get the private IP addresses of the instances with this task
- name: Get info from remote
shell: curl http://169.254.169.254/latest/meta-data/local-ipv4
register: bar
- debug: msg="{{bar.stdout}}"
How do I create a local file with content
IP address: 10.100.0.151 directory foo - false
IP address: 10.100.0.152 directory foo - true
I've tried adding a block for this as such
- hosts: localhost
become: false
vars:
installed: "{{bar.stdout}}"
status: "{{path.stat.exists}}"
local_file: "./Report.txt"
tasks:
- name: Create local file with info
copy:
dest: "{{ local_file }}"
content: |
"IP address {{ installed }} foo - {{ status }}"
But it doesn't look like I can read values of variables from earlier steps.
What am I doing wrong please?
A similar question has been answered here.
Basically what you want is to reference it through the host var variable.
This should work.
- hosts: localhost
become: false
vars:
local_file: "./Report.txt"
tasks:
- name: Create local file with info
lineinfile:
path: "{{ local_file }}"
line:
"IP Address: {{ hostvars[item]['bar'].stdout }} - Installed: {{ hostvars[item]['path'].stat.exists }}"
with_items: "{{ query('inventory_hostnames', 'all') }}"
And this should populate your local ./Report.txt file, with the info you need.
I've used the ec2_metadata_facts module to get the IP address us ingansible_ec2_local_ipv4
I've also created the directory /tmp/testdir on the second host.
- hosts: test_hosts
gather_facts: no
vars:
directory_name: /tmp/testdir
tasks:
- ec2_metadata_facts:
- name: check if directory '{{ directory_name }}' exsists
stat:
path: "{{ directory_name }}"
register: path
# I make the outputfile empty
# because the module lineinfile(as I know) can't overwrite a file
# but appends line to the old content
- name: create empty output file
copy:
content: ""
dest: outputfile
delegate_to: localhost
- name: write output to outputfile
lineinfile:
dest: outputfile
line: "IP Address: {{ ansible_ec2_local_ipv4 }} {{ directory_name }} - {{ path.stat.exists }}"
state: present
with_items: "{{ groups.all }}"
# with_items: "{{ ansible_play_hosts }}" can also be used here
delegate_to: localhost
The outputfile looks like:
IP Address: xxx.xx.x.133 /tmp/testdir - False
IP Address: xxx.xx.x.45 /tmp/testdir - True
Here is my Ansible playbook. It reads /etc/waagent.conf file and checks if variable AutoUpdate.Enabled=y or not.And it uses Jinja template to generate output.csv file.
ansibleuser#server:~/plays$ cat report_waagent_local.yaml
---
- name: waagent auto update report
hosts: localhost
connection: ssh
remote_user: ewxxxx
become: true
become_user: root
gather_facts: true
tasks:
- name: "Ensure status of AutoUpdate.Enabled in /etc/waagent.conf"
lineinfile:
name: /etc/waagent.conf
line: AutoUpdate.Enabled=y
state: present
check_mode: yes #means make no change , just check
register: conf
failed_when: (conf is changed) or (conf is failed)
ignore_errors: yes
# logic
# if "conf.changed": false --> that mean AutoUpdate.Enabled=y
# if "conf.changed": true --> that means value is not set in file.
- name: generate report
template:
src: report_waagent_local.j2
dest: ./output.csv
ansibleuser#server:~/plays$
And here is Jinja Template.
ansibleuser#server:~/plays$ cat templates/report_waagent_local.j2
{% if conf.changed == false %}
{{ ansible_host }} , AutoUpdate.Enabled=y
{% else %}
{{ ansible_host }} , AutoUpdate.Enabled=n
{% endif %}
ansibleuser#server:~/plays$
It produces output.csv as expected.
127.0.0.1, AutoUpdate.Enabled=y
Now, I need to fetch similar reports for all the servers present in the Azure subscription.
I modified my playbook. Note: I am using dynamic inventory in azure, I have a group named "all_pls" on which I need to run a playbook.
ansibleuser#server:~/plays$ cat report_waagent.yaml
---
- name: "generate waagent report"
hosts: all
connection: ssh
remote_user : ewxxxxx
become: True
become_user: root
gather_facts: True
tasks:
- name: "Ensure status of AutoUpdate.Enabled in /etc/waagent.conf"
lineinfile:
name: /etc/waagent.conf
line: AutoUpdate.Enabled=y
state: present
check_mode: yes #means make no change , just check
register: conf
failed_when: (conf is changed) or (conf is failed)
ignore_errors: yes
# if "conf.changed": false --> that mean AutoUpdate.Enabled=y
# if "conf.changed": true --> that means the value is not set in the file.
- name: generate report
template:
src: report_waagent_local.j2
dest: ./output.csv
ansibleuser#server:~/plays$
I am running my playbook and getting no issues.
But I am getting no output in output.csv.
ansible-playbook --limit all_pls report_waagent.yaml
I guess I need to loop over hosts in a group name and also check conf.changed in the Jinja template. Can someone help please?
I fixed the issue.
- name: log conf.changed in output.csv using a template
lineinfile:
line: "{{ lookup('template', 'report_waagent_local.j2') }}"
insertafter: EOF
dest: output.csv
delegate_to: localhost
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.