I'm attempting to improve the performance for ansible playbooks. I have a test playbook as follows:
---
- name: Test
hosts: localhost
connection: local
gather_facts: false
tasks:
- name: Creating an empty file
file:
path: /tmp/hello
state: touch
- name: Test
command: "echo 'Hello, World!' >> /tmp/hello"
with_sequence: start=1 end=500
delegate_to: localhost
Running this takes a whopping 57 seconds. Comparing to a bash script doing the same thing:
test.sh
#!/bin/bash
touch /tmp/hello
for i in {1..500}
do
sh /home/admin/hello.sh
echo "This is iteration $i"
done
hello.sh
#!/bin/bash
echo "Hello, World!" >> /tmp/hello
That takes ~1.5 seconds to run.
I have already made some changes to ansible.cfg file
[ssh_connection]
ssh_args = -o ControlMaster=auto -o ControlPersist=18000s -o PreferredAuthentications=publickey
control_path = %(directory)s/ansible-ssh-%%h-%%p-%%r
pipelining = True
Is there anything else I can do to improve this abysmal performance?
With your code, ansible will connect 500 times to the host to run a command. You could create your desired file first, and then upload it to the host.
playbook.yml
---
- name: Test
hosts: localhost
connection: local
gather_facts: false
tasks:
- name: create 'hello' file
ansible.builtin.template:
src: "../templates/hello.j2"
dest: "/tmp/hello"
hello.j2
{% for i in range(500) %}
Hello, World!
{% endfor %}
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 need to throw a user prompt at task level hence, I cannot use var_prompt. For this I have a tiny shell script as follow which is running read command to catch user response and I am calling it from command module but its not working.
cat question.sh
read -r -p "Are you sure? [y/N] " response
case "$response" in
[yY][eE][sS]|[yY])
echo "do_something"
;;
*)
echo "do_something_else"
;;
esac
My playbook:
---
- hosts: localhost
tasks:
- name: "Do you want to proceed?"
command: bash question.sh
You still need to use var_prompt. Split your play into few, and place var_prompt in between.
Was:
- hosts: foo
tasks:
- name: task1
debug:
- name: asking for foo
debug:
- name: task2
debug:
Become:
- hosts: foo
tasks:
- name: task1
debug:
- hosts: foo
vars_prompt:
- name: foo
prompt: bar
tasks:
- name: task2
debug:
I have a playbook which is repeating one task, shell is invoked from ansible task, but it does not exit successful on completion of task and repeating the shell instructions again.
Playbook:
---
hosts: dev-servers
tasks:
- name: clean up directoty
shell: rm -rf /opt/data/latest/*
- name: copy the file
copy: src=/home/data/metadata.zip dest=/opt/data
- name: Change directoty
shell: cd /opt/data
- name: copy the file
copy: src=/root/Run_Build.sh dest=/opt/deployment_scripts
- name: permission
shell: chmod +x /opt/deployment_scripts/Run_Build.sh
- name: deploy
command: sh /opt/deployment_scripts/Run_Build.sh
run_once: true
register: result
- debug: msg="{{ result.stdout }}"
- debug: msg="{{ result.stderr }}"
Run_Build.sh:
#!/bin/bash
Jboss_logs=/opt/jboss/jboss-eap-6.4/standalone/log/server.log
for i in {1..100}; do
sleep 10
if [ -f $Jboss_logs/server.log ]; then
if grep -e 'Deployed "deploy.war"' $Jboss_logs/server.log ; then
echo "Code successfully deployed"
exit 0
else
echo "*****************************************************************************"
echo " JBOSS is still loading deployment - please be patient .... Loading again in 10 sec"
echo "*****************************************************************************"
fi
else
echo "server log file has not been created yet, please wait for sometime."
fi
done
I have a file(a_file.txt) like this:
22
23
8080
I need to loop each item in a_file.txt with my host and formatted to be host:22, host:23, host:8080...and so on, so I can use shell module in playbook like this:
---
- hosts: host1
tasks:
- name: Remote hostname
shell: hostname
register: hostname
- name: Read items from a_file.txt
shell: cat a_file.txt
register: item_output
- name: Run shell command
shell: someCommand {{hostname.stdout_line|nice_to_yaml}}:{{item}}
with_items: item_output.stdout_lines
However, my someCommand failed because I have:
{{hostname.stdout_line|nice_to_yaml}} = - hostname\n
{{<item in a_file.txt>}} = [u'\22, u'\23, u'\8080]
you have to use:
- name: Run shell command
shell: someCommand {{hostname.stdout_line|nice_to_yaml}}:{{item}}
with_items: "{{ item_output.stdout_lines }}"
Given the following playbook:
---
- name: test local_action with_items
hosts: localhost
gather_facts: false
tasks:
- name: "add something to a file"
shell: echo '{{item}}' >> foo.txt
with_items:
- "aaaaa"
- "aaaaa"
# using 40 items
or
---
- name: test local_action with_items
hosts: localhost
gather_facts: false
tasks:
- name: "add something to a file"
shell: echo '{{item}}' >> foo.txt
with_sequence: count=40
The latter playbook run 5 seconds.
Using a bash loop is obviously much (1000 times) faster and takes 5 ms:
time for i in $(seq 1 40); do echo $i >> foo.txt; done
Now it is clear that Ansible has some overhead, but is there any possibility to speed this up?
Instead of shell module, use raw module. It will be as quick as the bash loop.
---
- name: test local_action with_items
hosts: localhost
gather_facts: false
tasks:
- name: "add something to a file"
raw: echo '{{item}}' >> foo.txt
with_sequence: count=40
...
Anyway, if you want performance, maybe write your code in C.