I have a playbook which needs to be run based on the operating System.
UseCase: Lets assume there is a service that is running.
On Linux we can check if it is installed and running using the
systemctl status application.service
While command and on windows we will be using the
sc query "ServiceName" | find "RUNNING"
Now we have to install it based on the output of the above a commands which requires us to segregate the playbook based on the OS.
Classic Example: Create a directory based on the OS
- name: Install QCA Agent on Linux targets
hosts: all
gather_facts: true
remote_user: root
tasks:
- name: Create Directory for Downloading Qualys Cloud Agent
sudo: yes
sudo_user: root
file:
path: /usr/q1/
state: directory
owner: root
group: root
mode: 0777
recurse: no
- name: Create Directory for Downloading Qualys Cloud Agent
win_file:
path: c:\q1
state: directory
owner: Administrator
group: Administrator
mode: 0777
recurse: no
The playbook will alwayz be successful only if one of the condition is met and it is whether it is Windows or Unix OS. I can alwayz add a condition which will prompt based on:
when: ansible_distribution == 'Redhat' or ansible_distribution == 'CentOS'
However what i would like to achieve is based on a condition it should trigger my playbook.yml file.
name: Load a variable file based on the OS type, or a default if not found. Using free-form to specify the file.
include_vars: "{{ item }}"
with_first_found:
- "{{ ansible_distribution }}.yaml"
- "{{ ansible_os_family }}.yaml"
- default.yaml
https://docs.ansible.com/ansible/2.5/modules/include_vars_module.html?highlight=with_first_found
I would like to know if there is a better example explaining the same that i could implement or if there are other ways to achieve the same.
Thank you,
The example you show from the Ansible docs is pretty much the best practice and is common in many playbooks (and roles for that matter) that deal with multiple OSes. If you have code that is different (instead of the variable example here), you'll be using include_tasks instead of include_vars, but the concept is the same.
Related
I have a simple playbook that I run on new managed nodes for Ansible
the playbook has 3 roles : create ansible admin user on destination host , copy ssh key , sets sudo no passwd for ansible user
I have Rhel based nodes and also debian based nodes
for Rhel I use root , for debian root not used by default and I keep it that way so I have a different admin user called sysadmin
I am trying to find a way that the playbook will identify the OS and choose either root or sysadmin user to run the Play , and also use a proper password from a file in ansible vault
thanks
this is the playbook
name: init managed node
user: root
hosts: init_clients
become: yes
gather_facts: yes
ignore_errors: no
vars:
user: ansible-admin
passwd: password-hash
roles:
create_admin_user
set_authorized_key
set_no_pass
100% real code. But if I didn't have it at my fingertips, I would skip answering this question, as there's no indication of any effort on your part.
- name: Set the system user name for Ubuntu
set_fact:
linux_system_user: ubuntu
when: ansible_os_family == 'Debian'
- name: Set the system user name for CentOS
set_fact:
linux_system_user: centos
when: ansible_distribution == 'CentOS'
- name: Set the system user name for RedHat
set_fact:
linux_system_user: root
when: ansible_distribution == 'RedHat'
My issue is that Ansible still needs to run the first Playbook as some user
if that user is the same for all systems (root for example).
That's ok if the user is not the same.
I have to run the playbook once for Rhel and once for Debian and then change the "user" statement to a differener user.
I'm attempting to uninstall a list of packages from our RHEL servers. However, I need to account for servers where these packages to uninstall are needed for the application. An good example of this is httpd, which is listed on our uninstall list, but it is an dependency for the application running on the server. Basically I'm managing two states with one playbook.
So here is the list of packages to remove, which is in the role's defaults/main.yml
packagesRemove:
- telnet
- nfs
- nfs-server
- nfs-utils
- named
- httpd
- rsync
- postfix
- autofs
- cups
- smb
- squid
Currently, I'm doing something basic to uninstall the packages on the first run.
- name: Check for packageRemove file
stat:
path: /root/packageRemove.txt
register: stat_result
- name: remove packages not needed
yum:
name: "{{ packagesRemove }}"
autoremove: yes
register: packageRemove_output
when: not stat_result.stat.exists
- name: create packageRemove file
template:
src: output.txt.j2
dest: /root/packageRemove.txt
owner: root
group: root
mode: 0600
when: not stat_result.stat.exists
Basically if the /root/packageRemove.txt file exits, these tasks just get skipped. How can I make this more dynamic, and remove the need for the /root/packageRemove.txt file. I would like to make the packages that are needed into some sort of inventory variables.
Right now, I just have the following to gather a list of packages installed on the server.
- name: gather installed packages
dnf:
list: installed
no_log: true
register: yum_packages
- name: make installed packages a list
set_fact:
installed_packages: "{{ yum_packages.results | map(attribute='name') | list }}"
This is now where I'm stumped, and I'm not quite sure what my next step should be or if I'm on the right track. Any help would be great.
Is it possible to add a condition before to run a playbook which check if there is a title, a description, the environment and the versions on the playbook ?
For example my test.yml playbook:
---
#Apache servers
#Linux
#Ubuntu
#version 2.1.1
#Testing for secure the webserver
task:
xxxxxx
xxxxxx
And I would like to check if all the comment before are present before to run this task !
I tried to test this solution :
name: run Apachetest playbook
include: test.yml
when: "{{ lookup('file', 'test.yml').split('\n')[1] == '#Apache servers' }}"
But still not working...
BS
Comments are, well, comments. They do not impact the execution and are just ignored. So there is no way, and actually no real reason, to check if comments are present or not. You would need to implement that yourself.
To check playbooks, roles, etc. there is ansible-lint which will verify the syntax and some best practices (e.g. if you use a command or shell for something there is a module for) but this does not verify comments (again, checking for comments does not make sense from a execution perspective, as they are ignored).
You want some information to be present in your playbook, that is what I understand. If I was you, I would either create a git hook, that verifies if the information is present before letting you push that code to your repository or establish a proper review-process, where the reviewer only accepts a merge/pull request, if the information is present.
Otherwise, here is the code, that will do what you are trying to do:
---
#Apache server
- hosts: all
tasks:
- name: set fact
set_fact:
pb: "{{ lookup('file', 'test.yml').split('\n')[1] }}"
- name: check if we found it
debug:
msg: 'found'
when: "'#Apache server' in pb"
You could use the apache role for apache installed like that
---
- hosts: apache
sudo: yes
tasks:
- name: install apache2
apt: name=apache2 update_cache=yes state=latest
have a look here how-to-install-apache-on-ansible
A recurring theme that's in my ansible playbooks is that I often must execute a command with sudo privileges (sudo: yes) because I'd like to do it for a certain user. Ideally I'd much rather use sudo to switch to that user and execute the commands normally. Because then I won't have to do my usual post commands clean up such as chowning directories. Here's a snippet from one of my playbooks:
- name: checkout repo
git: repo=https://github.com/some/repo.git version=master dest={{ dst }}
sudo: yes
- name: change perms
file: dest={{ dst }} state=directory mode=0755 owner=some_user
sudo: yes
Ideally I could run commands or sets of commands as a different user even if it requires sudo to su to that user.
With Ansible 1.9 or later
Ansible uses the become, become_user, and become_method directives to achieve privilege escalation. You can apply them to an entire play or playbook, set them in an included playbook, or set them for a particular task.
- name: checkout repo
git: repo=https://github.com/some/repo.git version=master dest={{ dst }}
become: yes
become_user: some_user
You can use become_with to specify how the privilege escalation is achieved, the default being sudo.
The directive is in effect for the scope of the block in which it is used (examples).
See Hosts and Users for some additional examples and Become (Privilege Escalation) for more detailed documentation.
In addition to the task-scoped become and become_user directives, Ansible 1.9 added some new variables and command line options to set these values for the duration of a play in the absence of explicit directives:
Command line options for the equivalent become/become_user directives.
Connection specific variables which can be set per host or group.
As of Ansible 2.0.2.0, the older sudo/sudo_user syntax described below still works, but the deprecation notice states, "This feature will be removed in a future release."
Previous syntax, deprecated as of Ansible 1.9 and scheduled for removal:
- name: checkout repo
git: repo=https://github.com/some/repo.git version=master dest={{ dst }}
sudo: yes
sudo_user: some_user
In Ansible 2.x, you can use the block for group of tasks:
- block:
- name: checkout repo
git:
repo: https://github.com/some/repo.git
version: master
dest: "{{ dst }}"
- name: change perms
file:
dest: "{{ dst }}"
state: directory
mode: 0755
owner: some_user
become: yes
become_user: some user
In Ansible >1.4 you can actually specify a remote user at the task level which should allow you to login as that user and execute that command without resorting to sudo. If you can't login as that user then the sudo_user solution will work too.
---
- hosts: webservers
remote_user: root
tasks:
- name: test connection
ping:
remote_user: yourname
See http://docs.ansible.com/playbooks_intro.html#hosts-and-users
A solution is to use the include statement with remote_user var (describe there : http://docs.ansible.com/playbooks_roles.html) but it has to be done at playbook instead of task level.
You can specify become_method to override the default method set in ansible.cfg (if any), and which can be set to one of sudo, su, pbrun, pfexec, doas, dzdo, ksu.
- name: I am confused
command: 'whoami'
become: true
become_method: su
become_user: some_user
register: myidentity
- name: my secret identity
debug:
msg: '{{ myidentity.stdout }}'
Should display
TASK [my-task : my secret identity] ************************************************************
ok: [my_ansible_server] => {
"msg": "some_user"
}
I am a newbie to Ansible and I started to study deploying Openstack with Ansible recently.
Here is the git of openstack-ansible:
https://github.com/openstack/openstack-ansible
From the tutorial:
https://docs.openstack.org/project-deploy-guide/openstack-ansible/newton/run-playbooks.html
there is one command running playbook:
openstack-ansible setup-hosts.yml
I read this playbook, it includes another playbook at line 16:
include: openstack-hosts-setup.yml
Then I read the included openstack-hosts-setup.yml and following is the snippet from it:
- name: Basic host setup
hosts: "{{ openstack_host_group|default('hosts') }}"
gather_facts: "{{ gather_facts | default(True) }}"
max_fail_percentage: 20
user: root
pre_tasks:
- name: Check for a supported Operating System
assert:
that:
- (ansible_distribution == 'Ubuntu' and ansible_distribution_release == 'xenial') or
(ansible_os_family == 'RedHat' and ansible_distribution_major_version == '7')
msg: "The only supported platforms for this release are Ubuntu 16.04 LTS (Xenial) and CentOS 7 (WIP)"
roles:
- role: "openstack_hosts"
tags:
- openstack-hosts
I was confused about roles here
roles:
- role: "openstack_hosts"
As far as I know, there should be directory structure when using roles like:
roles/
openstack_hosts/
files/
templates/
tasks/
handlers/
vars/
defaults/
meta/
However, I can't find this structure in this openstack-ansible project.
So I have no idea where is the role(openstack_hosts) in this playbook.
When running this playbook , an error occurred just expected:
ERROR! the role 'openstack_hosts' was not found in /opt/openstack-ansible/playbooks/roles:/root/ansible/roles:/opt/openstack-ansible/playbooks
Also, I was wondering where the variablescome from:
hosts: "{{ openstack_host_group|default('hosts') }}"
I thought the variable will be found from the directory vars or defaults
under roles directory.
Since there is no such directory, I have no idea where this variable comes from.
Could any tell me where should I find the variable openstack_host_group
and explain how the role is used here?
Or did I miss something or I was wrong with some concepts about Ansible?
Thanks!!
By the way, this is the first time I ask question.
If the question is not clear enough or something not proper, please let me know :). Thanks again.
I guess you didn't complete bootstrap-ansible.sh from this guide. So you don't have required roles installed.
As for openstack_host_group, it seems that it is optional variable, so you can override default host pattern (which is hosts) if you want with extra variable (like -e openstack_host_group=my_other_group).