ansible only first shell command is executed - ansible

Following is my yamal file,
---
- hosts: qa-workstations
tasks:
- name: update java version
shell: echo "asdfasdf" > /tmp/abc
shell: echo "asdf" >> /tmp/abc
If I execute ansible using below command,
ansible-playbook test.yml -k
It executes only 1st shell. How to solve this issue?

If you want a task execute many commands, you can use with_items loop:
Example:
tasks:
- name: test
shell: "{{ item }}"
with_items:
- echo Ansible
- df -h
But if you have many commands, you should use script module. script module copies your shell script to remote machine and executes it.

You've actually only defined a single task here. The second shell line simply overrides the first. The proper way to write this is:
---
- hosts: qa-workstations
tasks:
- name: create /tmp/abc
shell: echo "asdfasdf" > /tmp/abc
- name: Append to /tmp/abc
shell: echo "asdf" >> /tmp/abc

Related

How to Use command in Envoirment Variable Ansible Playbook

I am trying to use hostname -f command in variable with ansible-playbook. After I set the variable, I will use it in sed command. When manually execute the commands it works but with Ansible, variable does not work.
When I echo $hostn output is empty.
---
- hosts: test
become: true
become_user: root
tasks:
- name: test
shell: "{{ item }}"
with_items:
- hostn=`hostname -f` <<<<<< not working
- echo $hostn <<<<<< not working
- sed -i "s/test/$hostn/g" /file <<<< manually works
Can you help me?
My advise would be that you should not try to fit all your commands in Ansible shell this way, but rather translate them into the corresponding Ansible modules.
What you are looking to achieve can be done with the replace module — in place of sed — and the Ansible fact ansible_hostname — in place of hostname -f.
This would be the equivalent playbook:
- hosts: test
become: true
become_user: root
tasks:
- replace:
path: /file
regexp: test
replace: "{{ ansible_hostname }}"

How to execute shell commands in ansible containing special characters

How to execute shell commands in ansible along with special characters?
---
- name: Displaying the ORACLE_HOME
hosts: "{{ hostname }}"
tasks:
- name:
shell: echo $ORACLE_HOME
I want the output of echo $ORACLE_HOME
You need to write something like this :
---
- name: Displaying the ORACLE_HOME
hosts: "{{ hostname }}"
tasks:
- name:
shell: echo $ORACLE_HOME
register: var
- debug: msg="{{ var }}"
or
you can use the registered variable as var.stdout in your code.
As per your comment, use below command to use the shell variable in your playbook :
shell: source <Absolute-Path>/.bash_profile && echo $ORACLE_HOME

Ansible how to use looping to run multiple tasks one host at time

I have playbook like this:
---
- hosts: {{ lookup('env','hostname') }}
tasks:
- name: Run shell command
shell: date
- name: Another shell command
shell: ls -ltr
If I have multiple hosts from {{ lookup('env','hostname') }} like:
host1, host2, host3...
how do I run above tasks one host at time using looping over hosts? With above playbook, it runs multiple hosts at same time.
You can try serial: 1
---
- hosts: {{ lookup('env','hostname') }}
serial: 1
tasks:
- name: Run shell command
shell: date
- name: Another shell command
shell: ls -ltr
you can do using forks option
ansible-playbook --forks=1 .. <playbook_name.yml>

Ansible: playbook name and task step index on variables

In my playbook I have several shell task per playbook, like ten or more. I want to use creates shell arg to avoid executing them over and over.
Currently I have this:
- name: Download sonar-runner
get_url:
url: http://repo1.maven.org/maven2/org/codehaus/sonar/runner/sonar- runner-dist/2.4/sonar-runner-dist-2.4.zip
dest: /tmp
mode: 0755
- name: Unarchive
unarchive:
src: /tmp/sonar-runner-dist-2.4.zip
dest: /opt/tools/sonar-runner-2.4
- name: Sym link
shell: ln -s sonar-runner-2.4 sonar-runner
args:
creates: ~/.ansible/sonar-runner.task/step.3
- name: Configure profile
shell: |
echo 'export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64/' > /etc/profile.d/maven.sh
echo 'export M2_HOME=/opt/maven/apache-maven-3.5.3' >> /etc/profile.d/maven.sh
echo 'export PATH=${M2_HOME}/bin:${PATH}' >> /etc/profile.d/maven.sh
args:
creates: ~/.ansible/sonar-runner.task/step.4
Is there any way to achieve this using variables. I'm thinking something like this:
- name: Sym link
shell: ln -s sonar-runner-2.4 sonar-runner
args:
creates: ~/.ansible/{{playbook_name}}/{{task_index}}
- name: Configure profile
shell: |
echo 'export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64/' > /etc/profile.d/maven.sh
echo 'export M2_HOME=/opt/maven/apache-maven-3.5.3' >> /etc/profile.d/maven.sh
echo 'export PATH=${M2_HOME}/bin:${PATH}' >> /etc/profile.d/maven.sh
args:
creates: ~/.ansible/{{playbook_name}}/{{task_index}}
Is there any way to do this? Am I missing something? Or isn't that the way Ansible works?
Is there any way to do this? Am I missing something? Or isn't that the way Ansible works?
Yes, yes, and no :-)
Is there any way to do this?
The shell: and command: support inline creates= declarations, so you can keep all of that together in one block (and thus it is a candidate for being a variable, or a yaml anchor):
- shell: |
creates=/etc/profile.d/maven.sh
echo 'hello' > /etc/profile.d/maven.sh
- command: |
creates=/etc/profile.d/maven.sh
cp /something /etc/profile.d/maven.sh
However, I just told you that for your information, and for the circumstances where these next set of steps won't work because ...
Am I missing something?
You want to use the built-in idempotency whenever possible, to get you out of the business of having to do manual "has this task run" bookkeeping. Thus:
- file:
src: sonar-runner-2.4
dest: sonar-runner
state: link
- copy:
dest: /etc/profile.d/maven.sh
content: |
export JAVA_HOME=/usr/lib/jvm/java-8-openjdk-amd64/
export M2_HOME=/opt/maven/apache-maven-3.5.3
export PATH=${M2_HOME}/bin:${PATH}
I'm genuinely surprised ansible didn't whine when you tried to use ln manually, as it knows about common shell commands and will nudge you to switch to the built-in module file:
Well, finally I've managed to solve this using a mix of vars, facts and roles.
testfacts.yml playbook
---
- hosts: all
vars:
current_role: 'testfacts'
roles:
- testfacts
roles/testfacts/tasks/main.yml
---
- name: Import task1
import_tasks: task1.yml
- name: Import task2
import_tasks: task2.yml
roles/testfacts/tasks/task1.yml
---
- name: Prepare task
include_role:
name: common
tasks_from: set_facts
vars:
current_task: 'task1'
- name: Test facts in task step 1
shell: "echo foo > /home/awx/outp"
args:
creates: "{{ creates_dir }}/test-fact-tasks-step-1"
# this never gets executed
- name: Test facts in task 2 step 2
shell: "echo bar > /home/awx/outp"
args:
creates: "{{ creates_dir }}/test-fact-tasks-step-1"
roles/common/tasks/set_facts.yml
---
- name: set_facts
set_fact:
creates_dir: "{{ bookeeping_dir }}/roles.d/{{ current_role }}/tasks.d/{{ current_task }}/steps.d"
inventories/prod/group_vars/group_vars.yml
---
bookeeping_dir: /home/awx/.ansible/ansible_bookeeping

Ansible writing output from multiple task to a single file

In Ansible, I have written an Yaml playbook that takes list of host name and the executes command for each host. I have registered a variable for these task and at the end of executing a task I append output of each command to a single file.
But every time I try to append to my output file, only the last record is getting persisted.
---
- hosts: list_of_hosts
become_user: some user
vars:
output: []
tasks:
- name: some name
command: some command
register: output
failed_when: "'FAILED' in output"
- debug: msg="{{output | to_nice_json}}"
- local_action: copy content='{{output | to_nice_json}}' dest="/path/to/my/local/file"
I even tried to append using lineinfile using insertafter parameter yet was not successful.
Anything that I am missing?
You can try something like this:
- name: dummy
hosts: myhosts
serial: 1
tasks:
- name: create file
file:
dest: /tmp/foo
state: touch
delegate_to: localhost
- name: run cmd
shell: echo "{{ inventory_hostname }}"
register: op
- name: append
lineinfile:
dest: /tmp/foo
line: "{{ op }}"
insertafter: EOF
delegate_to: localhost
I have used serial: 1 as I am not sure if lineinfile tasks running in parallel will garble the output file.
Ansible doc recommend use copy:
- name: get jstack
shell: "/usr/lib/jvm/java/bin/jstack -l {{PID_JAVA_APP}}"
args:
executable: /bin/bash
register: jstackOut
- name: write jstack
copy:
content: "{{jstackOut.stdout}}"
dest: "tmp/jstack.txt"
If you want write local file, add this:
delegate_to: localhost
Why to complicate things ?
I did this like that and it worked:
ansible-playbook your_playbook.yml >> /file/you/want/to/redirect/output.txt
you can also try some parsing with grep or some other stuff with tee -a.

Resources