ansible: run role as a different user - ansible

I have two roles that run in a playbook, one that creates a user and the other which runs through a series of tasks that I want to run as the newly created user on the server.
The playbook is written as follows:
- hosts: centos
connection: ssh
gather_facts: false
become: true
roles:
- ../roles/user_setup
- ../roles/tasks
Let's say the user created from the user_setup role is called user1: I basically want the role named tasks to run as user1. What would be the best way to do this? Thanks.

This question almost provides you a solution. You can use something like:
- hosts: centos
connection: ssh
gather_facts: false
roles:
- role: ../roles/user_setup
become: true
- role: ../roles/tasks
become: true
become_user: user1
If you want to connect directly as user1 (rather than escalating to it), you can replace the latest role call with:
- role: ../roles/tasks
become: false
remote_user: user1

Related

Ansible. Reconnecting the playbook connection

The server is being created. Initially there is user root, his password and ssh on 22 port (default).
There is a written playbook, for example, for a react application.
When you start playbook'a, everything is deployed for it, but before deploying, you need to configure the server to a minimum. Those. create a new sudo user, change the ssh port and copy the ssh key to the server. I think this is probably needed for any server.
After this setting, yaml appears in the host_vars directory with the variables for this server (ansible_user, ansible_sudo_pass, etc.)
For example, there are 2 roles: initial-server, deploy-react-app.
And the playbook itself (main.yml) for a specific application:
- name: Deploy
hosts: prod
roles:
- role: initial-server
- role: deploy-react-app
How to make it so that when you run ansible-playbook main.yml, the initial-server role is executed from the root user with his password, and the deploy-react-app role from the newly created one user and connection was by ssh key and not by password (root)? Or is it, in principle, not the correct approach?
Note: using dashes (-) in role names is deprecated. I fixed that in my below example
Basically:
- name: initialize server
hosts: prod
remote_user: root
roles:
- role: initial_server
- name: deploy application
hosts: prod
# That one will prevent to gather facts twice but is not mandatory
gather_facts: false
remote_user: reactappuser
roles:
- role: deploy_react_app
You could also set the ansible_user for each role vars in a single play:
- name: init and deploy
hosts: prod
roles:
- role: initial_server
vars:
ansible_user: root
- role: deploy_react_app
vars:
ansible_user: reactappuser
There are other possibilities (using an include_role task). This really depends on your precise requirement.

How to skip role when host is unreachable?

I have disable_root role, which creates admin user and disables root user from connecting to server via ssh.
When I rerun playbook with this role for second time I get unreachable error (which is ok, as I just disabled it).
I'd like to skip this role in such case and continue with other roles (which would run as a admin user). How can I do this?
This is my playbook (disbale_root uses ansible_user: root var)
- hosts: webservers
roles:
- disable_root
- common
- nginx
One playbook shall connect to the remote host as root, if necessary, or as admin if this user has already been created. This can be done with remote_user (see Ansible remote_user vs ansible_user
).
Let's create the playbook to disable root and enable admin
> cat play-disable-root.yml
- hosts: webservers
remote_user: 'root'
tasks:
- include_role:
name: disable_root
when: play_disable_root|default(false)
In the first play import this playbook if admin can't connect to the remote host
- hosts: webservers
remote_user: 'admin'
tasks:
- delegate_to: localhost
command: ping -c1 "{{ inventory_hostname }}"
register: result
ignore_errors: true
- set_fact:
play_disable_root: true
when: result.rc != 0
- import_playbook: play-disable-root.yml
in the second play proceed with remaining roles
- hosts: webservers
remote_user: 'admin'
roles:
- common
- nginx
Both first and second play may be put into one playbook.
(code not tested)
Updates:
it's not possible to conditionally import playbooks

Parameter remote_user in role include is deprecated, what's the workaround?

I'm using Ansible to do the automation of my systems.
I have an Ansible playbook that depends on two roles.
The first role creates a user ("specific_user") on a remote server.
The second role uses this user to do a bunch of stuff.
My first solution was the following (my playbook) :
---
- hosts: all
roles:
- { role: ansible-role1, remote_user: root }
- { role: ansible-role2, remote_user: specific_user }
...
However, I'm getting the following warning from Ansible when running it:
Using 'remote_user' as a role param has been deprecated.
In the future, these values should be entered in the `vars:` section for
roles, but for now we'll store it as both a param and an attribute..
What is the alternative ?
Currently this is only a warning message (until version 2.7 of Ansible).
As the message suggests, you need to change syntax to (using YAML in the example below, because it's more readable):
roles:
- role: ansible-role1
vars:
remote_user: root
- role: ansible-role2
vars:
remote_user: specific_user
...

Ansible: How can I deploy the roles on paralel to different hosts

I have the next main.yml, and I would like to run the roles one by one but in parallel for diferent hosts:
For example, first I would like to run "cluster-prerequisites" role on all the host in paralel, when it finish run the "docker" role etc..
- hosts: masters:private_agent:public_agent
remote_user: "{{user}}"
become: True
serial: 1
roles:
- role: cluster_prerequisites
- hosts: bootstrap:masters:private_agent:public_agent
remote_user: "{{user}}"
become: True
serial: 1
roles:
- role: docker
- hosts: bootstrap
remote_user: "{{user}}"
become: True
serial: 1
roles:
- role: prepare_bootstrap
- hosts: masters
remote_user: "{{user}}"
become: True
serial: 1
roles:
- role: run_masters
- hosts: private_agent
remote_user: "{{user}}"
become: True
serial: 1
roles:
- role: run_private_agents
- hosts: public_agent
remote_user: "{{user}}"
become: True
serial: 1
roles:
- role: run_public_agents
From Rolling Update Batch Size chapter:
By default, Ansible will try to manage all of the machines referenced in a play in parallel. For a rolling updates use case, you can define how many hosts Ansible should manage at a single time by using the serial keyword...
So, if you remove serial: 1 from your plays, Ansible will run tasks on all hosts in play in parallel.
By setting serial: 1 you tell Ansible to take hosts one by one, and move to next one only when all tasks gets completed on previous one.
Usually you want to do serial runs on bunch of backend servers to update them in batches to prevent service downtime, because part of servers can still serve client's requests.

Run a playbook on hosts with a specific parameter

In my host file I have:
[web]
192.168.1.1:8682 master="yes"
192.168.1.1:8682 master="no"
and in my playbook I would like to run roles only on the server with master=yes like:
---
- name: Switch MySQL master
hosts: web[master=yes]
remote_user: andy
become: yes
roles:
- replication_setup_switch_server
...
Is it possible to do that with Ansible ?
In Ansible you can create ad-hoc groups based on facts using group_by module.
Add a new play before Switch MySQL master and create a new group in it. I called the new play Create groups by role in the example below. You could maybe rename the variable master to role to make the playbook more intuitive. So, the inventory and the playbook would become:
---
[web]
192.168.1.1:8682 role="master"
192.168.1.1:8682 role="slave"
---
- name: Create groups by role
hosts: web
tasks:
- name: Group by web role
group_by:
key: "web_{{ role }}"
- name: Switch MySQL master
hosts: web_master
remote_user: andy
become: yes
roles:
- replication_setup_switch_server

Resources