I have a main playbook which imports other playbooks to perform actions in several machines.
machine1 is a hub where test results are collected, after being executed on other machines:
- name: clear state
import_playbook: playbook-clear-machines-state.yml
- name: prepare run
hosts: machine1
roles:
- prepare_test_run
- name: run_tests_in_machine2
import_playbook: playbook-run-tests-machine2.yml
ignore_error: yes
...
What I would like to guarantee is that only an instance is running at a time (i.e. no one is able to run tests if an user is already doing so).
I thought of using a lock file in machine1 as a way of preventing that, in the following manner:
- name: check temp file
hosts: machine1
tasks:
- name: get stats of lock file
stat:
path: ./ansible.lock
register: st
- fail:
msg: "tests already running"
when:
- st.stat.isreg is defined and st.stat.isreg
- name: create lock file
file:
path: ./ansible.lock
state: touch
- name: run all tests
import_playbook: playbook-main.yml
ignore_errors: yes
- name: delete lock file
hosts: machine1
tasks:
- name: delete ansible.lock file
file:
path: ./ansible.lock
state: absent
The problem here is that I need to make sure the lock file is always deleted in the end - even if there was an error at an earlier play.
How could I accomplish this? I tried to look into blocks and handlers but they don't seem appropriate to use at this level. Can anybody point me to a strategy/way to accomplish this?
Many thanks, José.
For this needs, you have rescue and always mechanism that must corresponding to your use case.
You have more details here.
So with your example code, this must looks like this :
- name: check temp file
hosts: machine1
tasks:
- name: get stats of lock file
stat:
path: ./ansible.lock
register: st
- fail:
msg: "tests already running"
when:
- st.stat.isreg is defined and st.stat.isreg
- name: run all tests
block:
- name: create lock file
file:
path: ./ansible.lock
state: touch
- name: 'playbook-main.yml'
# import_playbook: playbook-main.yml
# Paste the content of this playbook here
ignore_errors: yes
always:
- name: delete lock file
file:
path: ./ansible.lock
state: absent
In a context really close to you, you have this reponse to.
Related
I am trying to create a Galaxy role for our org's internal galaxy, which I am testing first locally. In our org we use a common list of defaults across all roles.
Ansible is throwing me a "The task includes an option with an undefined variable The error was: 'redis_download_url' is undefined" error when running my playbook, despite me having defined the variable in defaults/main.yml:
# Download
redis_version: "6.2.3"
redis_download_url: "https://download.redis.io/releases/redis-{{ redis_version }}.tar.gz"
When running my simple role/playbook.yml
---
- hosts: all
become: true
tasks:
- include: tasks/main.yml
Linked to tasks/main.yml
---
- name: Check ansible version
assert:
that: "ansible_version.full is version_compare('2.4', '>=')"
msg: "Please use Ansible 2.4 or later"
- include: download.yml
tags:
- download
- include: install.yml
tags:
- install
It should pull the tar file from tasks/download.yml as stated:
---
- name: Download Redis
get_url:
url: "{{ redis_download_url }}"
dest: /usr/local/src/redis-{{ redis_version }}.tar.gz
- name: Extract Redis tarball
unarchive:
src: /usr/local/src/redis-{{ redis_version }}.tar.gz
dest: /usr/local/src
creates: /usr/local/src/redis-{{ redis_version }}/Makefile
copy: no
The redis_download_url var is defined in defaults/main.yml which as I understand ansible should be able to locate there. I also have similar vars defined in defaults/task.yml eg.
redis_user: redis
redis_group: "{{ redis_user }}"
redis_port: "6379"
redis_root_dir: "/opt/redis"
redis_config_dir: "/etc/redis"
redis_conf_file: "{{ redis_config_dir }}/{{ redis_port }}.conf"
redis_password: "change-me"
redis_protected_mode: "yes"
and I assume they are also not able to be found/seen by ansible (but it does not get that far). I have also checked all file permissions and they seem to be fine.
Apologies in advance if the question is badly formatted.
As per documentation:
If you include a task file from a role, it will NOT trigger role behavior, this only happens when running as a role, include_role will work.
To get the role functionality of reading variables from defaults/main.yml, you'll need to use include_role or roles: [].
- hosts: all
become: true
tasks:
- include_role:
name: myrole
OR
- hosts: all
become: true
roles:
- myrole
So I'm trying to run a little playbook to test out the openssl_certificate module documented here: https://docs.ansible.com/ansible/2.7/modules/openssl_certificate_module.html
My playbook:
---
- name: play to run opensll verification
hosts: localhost
tasks:
- name: Running OpenSSL Module.
openssl_certificate:
path: "bleh.crt"
provider: assertonly
valid_in: "{{ (20*3600*24) | int }}"
register: VALIDATION_OUTPUT
ignore_errors: true
Basically I wanna see if the cert is valid in the given time frame. However, when I run
ansible-playbook openssl_test.yml
I get:
ERROR! 'openssl_certificate' is not a valid attribute for a Play
The error appears to be in '/path/to/my/yaml/openssl_test.yml': line 6, column 3, but may
be elsewhere in the file depending on the exact syntax problem.
The offending line appears to be:
tasks:
- name: Running OpenSSL Module.
^ here
What am I doing wrong here? I'm sure it's something small.
Your indentation is wrong. while copying the yaml data, you may use :set paste if using vim editor to persevere the indentation.
---
- name: play to run opensll verification
hosts: localhost
tasks:
- name: Running OpenSSL Module.
openssl_certificate:
path: "bleh.crt"
provider: assertonly
valid_in: "{{ (20*3600*24) | int }}"
register: VALIDATION_OUTPUT
ignore_errors: true
Concerning: Ansible-Playbooks
Is it possible to run a command on the remote machine and store the resulting output into a variable?
I am trying to get the kernel version and install the matching headers like this:
---
- hosts: all
tasks:
- name: install headers
become: yes
become_method: sudo
apt:
name: "{{ packages }}"
vars:
packages:
- linux-headers-`uname -r`
#- a lot of other packages here
Unfortunately uname -r is not executed here.
I am aware of this question: Ansible: Store command's stdout in new variable?
But it looks like this is another topic.
By definition:
Ansible facts are data related to your remote systems, including
operating systems, IP addresses, attached filesystems, and more.
In this link you can see all ansible facts that you can use.
https://docs.ansible.com/ansible/latest/user_guide/playbooks_vars_facts.html
One of those variables is ansible_kernel, this is the version of the kernel of your remote system. By default ansible gets this variables, but if you want to be sure that ansible will get this variables you have to use gather_facts: yes.
---
- hosts: all
gather_facts: yes
tasks:
- name: install
become: yes
become_method: sudo
apt:
name: "{{ packages }}"
vars:
packages:
- linux-headers-{{ ansible_kernel }}
I found a solution but I am not sure if this is really elegant
---
- hosts: all
tasks:
- name: Getting Kernel Version
command: "uname -r"
register: kernel_version
- name: install
become: yes
become_method: sudo
apt:
name: "{{ packages }}"
vars:
packages:
- linux-headers-{{ kernel_version.stdout }}
How can I set in Ansible block vars (visible only for tasks in block) ?
I tried:
---
- hosts: test
tasks:
- block:
- name: task 1
shell: "echo {{item}}"
with_items:
- one
- two
but it seems that it's a wrong way.
If you want to define a variable for a block:
- block:
- debug:
var: var_for_block
vars:
var_for_block: "value for var_for_block"
If you want to "loop over blocks" as your code suggests - you can't. It's not implemented in Ansible.
Follow this thread.
For now consider saving the tasks to a separate file and use include instead.
#Shasha99
you might be able to include a file with a block in it so you can still benefit from the try/catch
includeFile.yml :
- block
- name: Finding the package.
shell: rpm -qa | grep "{{pkgName}}"
register: package
- name: Uninstalling the package.
shell: rpm -e "{{package}}"
always:
- debug: msg="this always executes"
main.yml:
---
- hosts: all
vars:
- packageList : ["pkg1","pkg2","pkg3","pkg4"]
tasks:
- include: includeFile.yml pkgName="{{item}}"
with_items: packageList
I have an ansible variable passed in on the command line as such:
ansible-playbook -e environment=staging ansible/make_server.yml
I want to load in some variables in my role dependeing on the value of environment. I have tried a lot of different methods such as:
- include_vars: staging_vars.yml
when: environment | staging
and
- include_vars: staging_vars.yml
when: "{{environment}} == "staging"
and
- include_vars: staging_vars.yml
when: "{{environment}} | match('staging')"
but nothing seems to work. How do I do this?
Details:
I am using ansible 1.7.2
Be careful with a variable called environment, it can cause problems because Ansible uses it internally. I can't remember if it's in the docs, but here's a mailing list thread:
https://groups.google.com/forum/#!topic/ansible-project/fP0hX2Za4I0
We use a variable called stage.
It looks like you'll end up with a bunch of these in a row:
- include_vars: testing_vars.yml
when: stage == "testing"
- include_vars: staging_vars.yml
when: stage == "staging"
- include_vars: production_vars.yml
when: stage == "production"
But you could also just include your environment:
- include_vars: "{{ stage }}_vars.yml"
Or, use the vars_files on a playbook level:
vars_files:
- vars/{{ stage }}_vars.yml