ansible wget then exec scripts => get_url equivalent - bash

I always wonder what is the good way to replace the following shell tasks using the "ansible way" (with get_url, etc.):
- name: Install oh-my-zsh
shell: wget -qO - https://raw.github.com/robbyrussell/oh-my-zsh/master/tools/install.sh | bash -
or
- name: Install nodesource repo
shell: curl -sL https://deb.nodesource.com/setup_5.x | bash -

This worked for me:
- name: Download zsh installer
get_url:
url: https://raw.github.com/robbyrussell/oh-my-zsh/master/tools/install.sh dest=/tmp/zsh-installer.sh
- name: Execute the zsh-installer.sh
shell: /tmp/zsh-installer.sh
- name: Remove the zsh-installer.sh
file:
path: /tmp/zsh-installer.sh
state: absent

#RaviTezu solution doesn't work because the file/script that you wish to execute must be on the machine where you execute your play/role.
As per the documentation here
The local script at path will be transferred to the remote node and then executed.
So one way to do it is by downloading the file locally and using a task like below:
- name: execute the script.sh
script: /local/path/to/script.sh
Or you can do this:
- name: download setup_5.x file to tmp dir
get_url:
url: https://deb.nodesource.com/setup_5.x
dest: /tmp/
mode: 0755
- name: execute setup_5.x script
shell: setup_5.x
args:
chdir: /tmp/
I would go for the first method if you are uploading your own script, the second method is more useful in your case because the script might gets updated in time so you are sure each time you execute it it uses the latest script.

For me, the following statement worked:
- name: "Execute Script"
shell: curl -sL https://rpm.nodesource.com/setup_6.x | bash -

Consider using the get_url or uri module rather than running curl.
For example:
- name: Download setup_8.x script
get_url: url=https://deb.nodesource.com/setup_8.x dest=/opt mode=755
- name: Setup Node.js
command: /opt/setup_8.x
- name: Install Node.js (JavaScript run-time environment)
apt: name=nodejs state=present

This playbook is what I've come up with. So far, it's as close to an idiomatic solution as I have come, and seems to be idempotent.
It will check for the existence of a command (in this case, starship) and if/when the test fails it will download the script.
---
- name: Check for Starship command
command: command -v starship >/dev/null 2>&1
register: installed
no_log: true
ignore_errors: yes
- name: Download Starship installer
get_url:
url: https://starship.rs/install.sh
dest: /tmp/starship-installer.sh
mode: 'u+rwx'
when: installed.rc != 0
register: download
- name: Run the install script
shell: /tmp/starship-installer.sh
when: download.changed
- name: Remove the starship-installer.sh
file:
path: /tmp/starship-installer.sh
state: absent

May be this basic example can help you to start:
---
- name: Installing Zsh and git
apt: pkg=zsh,git state=latest
register: installation
- name: Backing up existing ~/.zshrc
shell: if [ -f ~/.zshrc ]; then mv ~/.zshrc{,.orig}; fi
when: installation|success
sudo: no
- name: Cloning oh-my-zsh
git:
repo=https://github.com/robbyrussell/oh-my-zsh
dest=~/.oh-my-zsh
when: installation|success
register: cloning
sudo: no
- name: Creating new ~/.zshrc
copy:
src=~/.oh-my-zsh/templates/zshrc.zsh-template
dest=~/.zshrc
when: cloning|success
sudo: no

Note the: "force=yes", which will always download the script, overriding the old one.
Also note the "changed_when", which you can refine per your case.
- name: 'Download {{ helm.install_script_url }}'
environment:
http_proxy: '{{proxy_env.http_proxy | default ("") }}'
https_proxy: '{{proxy_env.https_proxy | default ("") }}'
no_proxy: '{{proxy_env.no_proxy | default ("") }}'
get_url: url={{ helm.install_script_url | default ("") }} dest=/tmp/helm_install_script force=yes mode="0755"
when: helm.install_script_url is defined
tags:
- helm_x
- name: Run {{ helm.install_script_url }}
environment:
http_proxy: '{{proxy_env.http_proxy | default ("") }}'
https_proxy: '{{proxy_env.https_proxy | default ("") }}'
no_proxy: '{{proxy_env.no_proxy | default ("") }}'
command: "/tmp/helm_install_script"
register: command_result
changed_when: "'is up-to-date' not in command_result.stdout"
when: helm.install_script_url is defined
args:
chdir: /tmp/
tags:
- helm_x

Related

Ansible: how can I use a wildcard or an alternative?

I recently learned that it's not possible to use the wildcard on Ansible. So I would like to know how could I run the next command with a Role.
cat /sys/class/net/*/address | while read mac
I tried to do it so, but it doesn't work.
- name: Cat address file
command: 'cat /sys/class/net/lo/address'
register: my_items
- name: Cat address file 2
command: 'cat /sys/class/net/enp2s0/address'
register: my_items
- name: Cat address file 3
command: 'cat /sys/class/net/wlo1/address'
register: my_items
- name: Read address file
command: read
with_items: my_items.stout_lines
I don't know whats your error but I used this and it works for me:
---
- hosts: dev
become: yes
tasks:
- name: get mac
shell: cat /sys/class/net/*/address
register: items
- name: debug
debug:
msg: "{{items.stdout_lines}}"
Result:

Ansible | ERROR! no action detected in task. This often indicates a misspelled module name, or incorrect module path

Below is Ansible script which will delete existing Zip file if exists, generate src html files using python commands and after html files generated, script will zip them:-
---
- name: run playbook locally
hosts: 127.0.0.1
connection: local
become: yes
gather_facts: yes
tasks:
- name: "CODE | PyDoc | Delete Zip"
file:
path: "{{ code_source_dev }}/doc/pydoc.zip"
state: absent
- name: CODE | Doc | Generating src html documents
shell: "python -m pydoc -w src/*.py"
ignore_errors: yes
args:
chdir: "{{ code_source_dev }}"
executable: /bin/bash
- name: CODE | Doc | Generating injectionModules html documents
shell: "python -m pydoc -w injectionModules/*.py"
ignore_errors: yes
args:
chdir: "{{ code_source_dev }}"
executable: /bin/bash
- name: CODE | Doc | Generating Test cases html documents
shell: "python -m pydoc -w test/template_unit_test_framework.py"
ignore_errors: yes
args:
chdir: "{{ code_source_dev }}"
executable: /bin/bash
- name: CODE | Doc | Zip html documents
shell: "zip -r code-pydoc/pydoc.zip *.html"
ignore_errors: yes
args:
chdir: "{{ code_source_dev }}"
executable: /bin/bash
Ansible command :-
ANSIBLE_HOST_KEY_CHECKING=False ansible-playbook -K acm/plays/emr/pydocs.yml
below error logs after executing from Jenkins:-
ERROR! no action detected in task. This often indicates a misspelled module name, or incorrect module path.
The error appears to have been in '/data/jenkins/workspace/cng-tesie-master-ci/acm/plays/emr/pydocs.yml': line 2, column 3, but may
be elsewhere in the file depending on the exact syntax problem.
The offending line appears to be:
---
- name: run playbook locally
^ here
Ansible version used:-
+ ansible-playbook --version
ansible-playbook 2.7.5
config file = None
configured module search path = [u'/home/ec2-user/.ansible/plugins/modules', u'/usr/share/ansible/plugins/modules']
ansible python module location = /usr/lib/python2.7/site-packages/ansible
executable location = /usr/bin/ansible-playbook
python version = 2.7.5 (default, Sep 12 2018, 05:31:16) [GCC 4.8.5 20150623 (Red Hat 4.8.5-36)]
Play specifications don't have a 'name' field. So this is wrong:
- name: run playbook locally
hosts: 127.0.0.1
connection: local
become: yes
gather_facts: yes
tasks:
It should look just like this:
- hosts: 127.0.0.1
connection: local
become: yes
gather_facts: yes
tasks:

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

Use the response from shell inside yml for Ansible playbook

I want to install MongoDB via Ansible playbook, I am following the instruction in:
https://www.howtoforge.com/tutorial/install-mongodb-on-ubuntu-16.04/
For the step about "Step 2 - Create source list file MongoDB"
I should use:
echo "deb http://repo.mongodb.org/apt/ubuntu "$(lsb_release -sc)"/mongodb-org/3.2 multiverse" | sudo tee /etc/apt/sources.list.d/mongodb-org-3.2.list
while it get the ubuntu version with the following command:
$(lsb_release -sc)
How can I do it via yml file and run it via ansible palybook?
I used the below yml command but it is not working and gives me error since I use shell command "$(lsb_release -sc)" inside my script
- name: Create source list file MongoDB
sudo: yes
lineinfile: >
line="deb http://repo.mongodb.org/apt/ubuntu "$(lsb_release -sc)"/mongodb-org/3.2 multiverse"
dest=/etc/apt/sources.list.d/mongodb-org-3.2.list
state=present
create=yes
There is apt_repository module in Ansible:
- apt_repository:
repo: deb http://repo.mongodb.org/apt/ubuntu {{ ansible_distribution_release | lower }}/mongodb-org/3.2 multiverse
state: present
You can register the result of one task, including its stdout, as a variable then use it in later tasks:
- name: Work out the distribution
command: lsb_release -sc
register: result
- name: Create source list file MongoDB
sudo: yes
lineinfile: >
line="deb http://repo.mongodb.org/apt/ubuntu {{ result.stdout }}/mongodb-org/3.2 multiverse"
dest=/etc/apt/sources.list.d/mongodb-org-3.2.list
state=present
create=yes

Check authenticity of file in ansible

I have ansible role that downloads a script file, how can i check the authenticity of the file using md5sum before executing?
- name: Add xx official repository for ubuntu/debain
get_url:
url: https://script.deb.sh
dest: /opt/script.db.sh
- name: Execute the script
script: /opt/script.db.sh
i want to check the authenticity before downloading the file - can this be achieved in ansible?
If you're not using the get_url option, after the file is in the location, call the stat module using the get_checksum option as documented here.
- name: Get sha256 sum of script
stat:
path: /opt/script.db.sh
checksum_algorithm: sha256
get_checksum: yes
register: shell_stat
- name: Verify sha256sum of script before execution.
fail:
msg: "Failure, file is not correct."
when: shell_stat.stat.checksum != '19d6105fa1a581cf3ad38f67080b6d55cb152b5441ae8bdf194e593f292f31e9'
- name: Execute the script
script: /opt/script.db.sh
Update the sum on the when: line to match the file you expect.
Generating the checksum (sha256 in this example) vary on your operating system. On most Linux distributions use the sha256sum {filename} command, on OSX, use shasum -a 256 {filename}.
get_url has a checksum parameter that you could use.
- name: Add xx official repository for ubuntu/debain
get_url:
url: https://script.deb.sh
dest: /opt/script.db.sh
checksum: md5:1234
http://docs.ansible.com/ansible/latest/get_url_module.html
you can use the "checksum" parameter "get_url" module. I show you an example of a playbook that executes a "role" to download OpenJDK8 only if the md5sum is correct.
File: playbook.yml
---
- name: "Download binaries"
hosts: localhost
roles:
- openjdk
File: openjdk/tasks/main.yml
- name: "Download OpenJDK {{ openjdk_version }} binaries"
get_url:
url: https://download.java.net/openjdk/jdk8u40/ri/{{ openjdk_file }}
dest: "{{ download_destination }}"
checksum: "{{ openjdk_md5 }}"
mode: 0750
tags:
- always
File: openjdk/vars/main.yml
---
download_destination: /var/tmp
openjdk_version: "8u40-b25"
openjdk_file: "openjdk-{{ openjdk_version }}-linux-x64-10_feb_2015.tar.gz"
openjdk_md5: "md5: 4980716637f353cfb27467d57f2faf9b"
The available cryptographic algorithms in Ansible 2.7 are: sha1, sha224, sha384, sha256, sha512, md5.
It works for me, I hope for you too.

Resources