Allow certain roles to be run multiple times in an Ansible playbook - ansible

I made a role whose only job is to download and unpack binary packages from Artifactory. Just about everything I want to install requires me to use this role.
I have a deployment with three major components, and each component will be pulled from Artifactory using this same reusable role. The role takes parameters, for example the name of the package being installed, the Artifactory URL where the binary can be downloaded from.
The reusable role is called from /meta/dependancies.
The problem is that the reusable role only runs once. The second time it's run Ansible skips it (even though the parameters are different).
Is there a way I can tell Ansible that this role must always be run, even if has previously run with different parameters?

Just include the role multiple times in the playbook using different parameter values.
This should do the trick:
---
- hosts: server
tasks:
- include_role:
name: artifactory
vars:
artifact: 'artifact_1'
- include_role:
name: artifactory
vars:
artifact: 'artifact_2'

Related

How to have multiple tasks under one role in Ansible?

I am setting up Ansible as a newbie. I would like to group a few tasks under an Nginx role.
See my folder structure
The only way I could get this to work is to use include statements in my playbooks... but that means I needed to start changing everything to relative paths since Ansible stopped being able to find things.
My playbook currently:
- name:
Install Nginx, Node, and Verdeccia
hosts:
all
remote_user:
root
tasks:
- include: ../roles/nginx/tasks/install.yml
- include: ../roles/nginx/tasks/create_node_config.yml
vars:
hostname: daz.com
How can I reference the sub task in the playbook to be something like
tasks:
- nginx.install
and still be within best practices.
Your use of roles so far is not in line with the norm or the idea of Ansible. From a purely technical point of view, it is quite possible that you have multiple task bundles in yml files that you include in the playbook.
If you want to include a specific task file from a role, you should better do this via the module include_role with the parameter tasks_from.
However, the workflow with roles usually looks different.
in the folder tasks should always be a file main.yml, this is called automatically, if simply the role is included, no matter over which way.
in this main.yml you can then add further control logic to include your yml files as required.
As it looks to me, for example, you always need to install, but depending on the use case you want to have different configurations.
create in your nginx role a file defaults/main.yml.
---
config_flavor: none
This initializes the config_flavor variable with the string none.
create in your nginx role a file tasks/main.yml.
---
- name: include installation process
include_tasks: install.yml
- name: configure node
include_tasks: create_node_config.yml
when: config_flavor == "node"
- name: configure symfony
include_tasks: create_symfony_config.yml
when: config_flavor == "symfony"
- name: configure wordpress
include_tasks: create_wordpress_config.yml
when: config_flavor == "wordpress"
The main.yml will be included by default when the role is applied.
This is where the installation is done first, then the proper configuration is done.
Which configuration should be done is defined by the variable config_flavor. In the listed example the values are node, symfony and wordpress. In all other cases the installation will be done, but no configuration (so in the default case with none).
include your role in the playbook as follows
---
- name: Install Nginx, Node, and Verdeccia
hosts: all
remote_user: root
vars:
hostname: daz.com
roles:
- role: nginx
config_flavor: node
At this point you can set the value for config_flavor. If you set wordpress instead, the tasks create_wordpress_config.yml will be included automatically, using the logic from tasks/main.yml.
You can find more about roles in the Ansible Docs.
There are many more possibilities and ways, you will get to know them in the course of your learning. Basically I would recommend you to read a lot in the Ansible docs and to use them as a reference book.
Please refer to bellow document. you can use "include_role" with "tasks_from" attribute. you don't need to provide full path of task files, Just file names.
https://docs.ansible.com/ansible/latest/collections/ansible/builtin/include_role_module.html
Example:
- name: Run tasks/other.yaml instead of 'main'
ansible.builtin.include_role:
name: myrole
tasks_from: other

How can I run an ansible role locally?

I want to build a docker image locally and deploy it so it can then be pulled on the remote server I'm deploying to. To do this I first need to check out code from git to be built.
I have an existing role which installs git, sets up keys for reading from our repo etc. I want to run this role locally to check out the code I care about.
I looked at local action, delegate_to, etc but haven't figured out an easy way to do this. The best approach I could find was:
- name: check out project from git
delegate_to: localhost
include_role:
name: configure_git
However, this doesn't work I get a complaint that there is a syntax error on the name line. If I remove the delegate_to line it works (but runs on the wrong server). If I replace include_role with debug it will run locally. It's almost as if ansible explicitly refuses to run an included role locally, not that I can find that anywhere in the documentation.
Is there a clean way to run this, or other roles, locally?
Extract from the include_role module documentation
Task-level keywords, loops, and conditionals apply only to the include_role statement itself.
To apply keywords to the tasks within the role, pass them using the apply option or use ansible.builtin.import_role instead.
Ignores some keywords, like until and retries.
I actually don't know if the error you get is linked to delegate_to being ignored (I seriously doubt it is the case...). Meanwhile it's not the correct way to use it here:
- name: check out project from git
include_role:
name: configure_git
apply:
delegate_to: localhost
Moreover, this is most probably a bad idea. Let's imagine your play targets 100 servers: the role will run one hundred time (unless you also apply run_once: true). I would run my role "normally" on localhost in a dedicated play then do the rest of the job on my targets in the next one(s).
- name: Prepare env on localhost
hosts: localhost
roles:
- role: configure_git
- name: Do the rest on other hosts
hosts: my_group
tasks:
- name: dummy.
debug:
msg: "Dummy"

Ansible - Difference Between Tags and Roles

Similar question to this, but I know what a task is and cannot find much differentiation between tags and roles.
It seems to me, that tags may be a simpler version of roles, with their only use being accessible via the --tags and --skip-tags CLI parameters.
Roles on the other hand, are used for "automatically loading" things like tasks and variables?
Please, explain the benefits to using roles, because it seems to me like roles require you to have different yaml files for the different parts (tasks, vars, etc) which I could accomplish with less code using the include and tags
directives.
It seems to me, that tags may be a simpler version of roles.
Sorry, but this is completely wrong.
Roles are self-contained reusable units (with own variables, tasks, handlers and even plugins and modules!). You can use them in multiple playbooks and/or plays in your project. You can share them between multiple projects. You can use role dependencies. You can redistribute them via external resources (e.g. Ansible Galaxy). For example, role nginx to install and configure nginx server, and role apache for apache server.
Tags are used to make it possible to execute only specific tasks in your project. You can mark plays/roles/tasks with tags. For example, tag config to mark only configuration-related tasks inside our nginx and apache role. So later you can execute ansible-playbook -t config site.yml to run configuration only tasks for all type of servers instead of whole playbook.
Tags and roles are different things.
Roles are used to aggregate some group of tasks which do certain thing, e.g. one role can contain tasks that install some service and a second role tasks to configure this service.
Each role has its own directory structure:
site.yml
webservers.yml
fooservers.yml
roles/
common/
tasks/
handlers/
files/
templates/
vars/
defaults/
meta/
webservers/
tasks/
defaults/
meta/
So for each role you can define e.g. variables, templates, tasks etc. It makes Ansible scripts clear and transparent. Another advantage is that you can reuse roles in different playbooks.
So instead of defining all tasks in a single playbook, which can become a little messy if playbook contained many tasks:
- name: Install nginx and mysql
hosts: all
become: yes
tasks:
- name: Install nginx
...
- name: Configure nginx
...
- name: Install mysql
...
- name: Configure mysql
...
You can create roles and include them:
- name: Install nginx and mysql
hosts: all
become: yes
roles:
- nginx
- mysql
I suggest to take a look at the examples where roles are used.
Tags are used while running ansible-playbook command to indicate which tasks should be executed.
If you have a large playbook it may become useful to be able to run a specific part of the configuration without running the whole playbook.
So it is possible to tag some roles/tasks and run/skip only them while executing playbook.

Run Ansible role without running dependencies defined in the role's meta

I have a role wp-vhost that has one role it depends on:
// roles/wp-vhost/meta/main.yml
---
dependencies:
- { role: nginx }
Each time I run wp-vhost, the nginx role will also run. I understand that this is fine and it's a desired behavior.
However, during my local development, time is unnecessarily lost on running the nginx role, when I want to run only the tasks defined in wp-vhosts since I know that nginx had run before and set-up the necessary environment for wp-vhost.
Is there a way to execute a playbook with roles, without executing roles' dependencies?
The way I would do this is to use Ansible tags and apply them to your "wp-vhost" specific code.
Assuming your wp-vhost role's main playbook is in main.yml, a good pattern is to spin out the actual tasks into a sub-playbook called something like wp-vhost.yml, included from main.yml, so the non-nginx code gets a tag that doesn't get applied to the nginx role. In this case:
- include: wp-vhost.yml
tags: wp-vhost
In order to use a tag for every chunk of Ansible code (whether an included tasks file or a role), try writing every role mentioned in dependencies like this:
- role: nginx
tags: nginx
When in testing mode, you can run just the wp-vhost specific parts like this:
$ ansible-playbook --tags wp-vhost main.yml
Or you can run the whole playbook including any dependencies like this - default is to run everything ignoring tags:
$ ansible-playbook main.yml
This makes it easy to quickly run just parts of a complex set of cascading roles and include files when testing, and also use the wp-vhost role normally in other roles' dependencies.
Impact on role structure
Careful use of tags doesn't affect role structure or use at all, and you would typically use tags only for testing.
For more complex roles, it's common to structure the tasks into separate files in any case, keeping the main.yml simple, like this:
- name: Set up base OS
include: base_os.yml
tags: base_os
- name: Ensure logs are rotated
include: logrotate.yml
tags: logrotate
- name: Create users and groups
include: users_groups.yml
tags: users_groups
Solution without include files
If you don't want to change the wp-vhosts use of include files, you would need to use blocks in the playbook (Ansible 2.0+):
- hosts: all
roles:
- role: nginx
tags: nginx
tasks:
- block:
- debug: msg=hello
- someaction: ...
tags: wp-vhosts
Note that the final tags: is aligned with the block: so applies to all tasks in that block. This is cleaner than splitting the playbook into multiple plays.
Non-tag alternative
You can use a when: condition on the role invocation in the wp-vhost role dependencies, and define a variable such as debug_mode to control this. However, such debug/test logic will clutter your codebase compared to defining a tag per role invocation or task file.

Ansible: playbooks and roles difference

I have 4 servers: production web, production db, staging web+db, development web+db (actually there are many dev servers, but they are used on localhosts using vagrant).
Config vars are different for these playbooks.
Actually I can use 4 playbooks, which include other yml files (nginx.yml, php.yml, mysql.yml), and I don't have to use roles.
Is it correct?
How should I organize my ansible files?
Ansible is flexile enough to work either way.
You can proceed with two aproaches
Define roles (i.e. production web, production db, staging web+db, development web+db) and under roles have tasks (nginx, php, mysql)
Define each module as role (i.e. nginx role, php role, mysql role) and then specify which roles are included in which playbook.
First way is better for cases that every php setup is different for every environment.
Second way is better for cases that all your php setups are the same, and it would be cumbersome to maintain 4 similar setup/config; you would write them once, and call them by their local variables.
Example of second one
./ansible-playbook roles/role1/tasks/production-web.yml -i hosts.yml
- name: playbook name
hosts: host1
sudo: yes
vars:
- php_version: 5.6.16
vars_files:
- "vars/local_vars"
pre_tasks:
- include: system-preparation.yml
- include: user-setup.yml
tasks:
- debug: msg="Installing and configuring PHP"
- include: php-setup.yml
- include: php-configuration.yml
post_tasks:
- include: health-check.yml
handlers:

Resources