Connection types determine how Ansible connects to managed hosts in order to communicate with them. By default, Ansible uses the SSH protocol for remote connection to target nodes. Assuming pipelining is not enabled, Ansible uses this SSH connection to transfer modules and template files, to run remote commands, and to run the plays in the playbook on managed hosts. Thus having a fast, stable, and secure SSH connection is of paramount importance to Ansible. Besides ssh, Ansible offers other connection types which can be used to connect to managedhosts, including paramiko, and local. The connection type can be specified in the Ansible configuration file (ansible.cfg), in the inventory on a host or group basis, inside a playbook, or
on the command-line interface.
The pipelining feature reduces the number of SSH operations required to execute a module on the remote server, by executing many ansible modules without actual file transfer. To support pipelining, the requiretty feature must be disabled in the sudoers file on the managed hosts. Pipelining is enabled by setting pipelining to true in the [ssh_connection] section of the Ansible configuration file.
Connection types
Various connection types supported by Ansible include:
• smart: This connection type checks if the locally installed SSH client supports the ControlPersist feature. If ControlPersist is supported, Ansible will use the local SSH client. If the SSH client does not support ControlPersist, the smart connection type will fall back to using paramiko. The smart connection type is the default. The ControlPersist feature is available in OpenSSH 5.6 or later. It allows SSH connections to persist so that when frequent commands run over SSH, they do not have to repeatedly go through the initial handshake. When the ControlPersist timeout is reached, the SSH connection goes through the TCP handshake again. This setting can be set in the OpenSSH
configuration, but is better done in the Ansible settings. In /etc/ansible/ansible.cfg,
the default setting is listed in a comment:
1 |
#ssh_args = -o ControlMaster=auto -o ControlPersist=60s |
The 60 second default value may be changed to something much higher to accept connections, even though the initial connection has exited and the connection is in an idle state for a longer time. This value should be set depending on the length of time it takes for playbooks to run and the frequency of running playbooks. A value of 30 minutes may be more
appropriate:
1 |
ssh_args = -o ControlMaster=auto -o ControlPersist=30m |
• paramiko: Paramiko is a Python implementation of the SSHv2 protocol. Ansible supports it as the connection type for backward compatibility for RHEL6 and earlier, which did not have support for the ControlPersist setting in their OpenSSH version.
• local: The local connection runs commands locally, instead of running over SSH.
• ssh: The ssh connection uses an OpenSSH-based connection, which supports ControlPersist technology.
• docker: Ansible offers a new docker connection type. It connects to containers using the docker exec command.
Ansible ships with other connection type plug-ins like chroot, libvirt_lxc, jail for FreeBSD jail environments, and the recently added winrm, which uses the Python pywinrm module to communicate to Windows remote hosts that do not have SSH but support PowerShell remoting. Ansible connection types are pluggable and extensible and additional connection types are
planned for future releases.
Configuring connection types
- Ansible configuration
The connection type can be specified in theansible.cfg
file under the [defaults] section of the file using the transport key.
1 2 3 4 |
[defaults] # some basic default values... ... Output omitted ... #transport = smart |
The transport global value can be overridden by using the -c TRANSPORTNAME option while running an ad hoc command with ansible or running a playbook with ansible-playbook. The default settings related to each individual connection type appear as comments beneath their respective connection headings in /etc/ansible/ansible.cfg
. They can be overridden
specifying that directive with a different value in the controlling ansible.cfg file. The settings for the ssh connection type are specified under the [ssh_connection] section. Likewise, the settings for paramiko can be found under the [paramiko_connection] section. The following example shows some of the default ssh connection type options.
1 2 3 4 5 6 7 |
[ssh_connection] ... Output omitted ... # control_path = %(directory)s/%%h-%%r #control_path = %(directory)s/ansible-ssh-%%h-%%p-%%r #pipelining = False #scp_if_ssh = True #sftp_batch_mode = False |
Important
Administrators should usually leave the connection type set to smart in
ansible.cfg
, and configure playbooks or inventory files to choose an alternative connection setting when necessary.
- Inventory file
The connection type can also be specified in inventory files on a per-host basis by using the ansible_connection variable. The following example shows an inventory file using the local connection type for localhost, and the ssh connection type for demo.
1 2 3 |
[targets] localhost ansible_connection=local demo.lab.example.com ansible_connection=ssh |
- Playbooks
Connection types can also be specified when running an entire playbook. Specify the--connection=CONNECTIONTYPE
option to the ansible-playbook command as shown in the following example.
1[user@host ~]$ ansible-playbook playbook.yml --connection=local
Alternatively, the connection type can be set with the connection: CONNECTIONTYPE parameter in a playbook as shown in the following example.
1 2 3 4 |
--- - name: Connection type in playbook hosts: 127.0.0.1 connection: local |
Setting environment variables in playbooks
Sometimes a managed host needs to configure some shell environment variables before executing commands. For example, a proxy server may need to be specified through an environment variable before installing packages or downloading files; a special $PATH variable may be needed; or certain other environment variables may need to be set. Ansible can make these types of environment settings by using the environment: parameter in a playbook.
Some Ansible modules, such as get_url, yum, and apt, use environment variables to set their proxy server. The following example shows how to set the proxy server for package installation using the environment:
parameter which sets the $http_proxy environment variable to
http://demo.example.com
.
1 2 3 4 5 6 7 8 9 |
--- - hosts: devservers tasks: - name: download a file using demo.lab.example.com as proxy get_url: url: http://materials.example.copm/file.tar.gz dest: ~/Downloads environment: http_proxy: http://demo.example.com:8080 |
An environment hash can be defined in a variable using the vars keyword in a playbook, or using the group_vars keyword. These variables can then be referenced inside a playbook using the environment parameter.
The following example shows how to define an environment variable and reference it using the environment keyword for an entire block of tasks.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
--- - name: Demonstrate environment variable in block hosts: localhost connection: local gather_facts: false vars: myname: ansible tasks: - block: - name: Print variable shell: "echo $name" register: result - debug: var=result.stdout environment: name: "{{ myname }}" |
When using Ansible roles, the environment variables can be passed at a playbook level. The following example shows how to pass the $http_proxy environment variable when using an Ansible role.
1 2 3 4 5 6 7 |
--- - hosts: example_host roles: - php - nginx environment: http_proxy: http://demo.example.com:8080 |
Example.
In this exercise, you will configure connection type and an environment using Ansible playbook. The playbook will copy a template file using the connection type defined in the inventory file, either using local or ssh connection type. The template file needs to be copied to managed hosts servera and workstation in the /tmp
directory.
Create an inventory file named hosts under ~/ansible/connection/
inventory with two different host names for controlnode
, controlnode
and
controlnode.example.com
, which would use two different connection types, local and ssh respectively. Also add an inventory line for managedhost1.example.com
that uses the connection type ssh.
1 2 3 4 5 6 7 8 |
[miro@controlnode ansible]# pwd /home/miro/ansible [miro@controlnode ansible]# mkdir connection [miro@controlnode connection]# cat inventory controlnode ansible_connection=local controlnode.example.com ansible_connection=ssh ansible_host=localhost managedhost1.example.com ansible_connection=ssh |
Create a new directory called templates
. Below it, create a file named template.j2
. This file should be copied to the managed host and changed based on the environment variables specified in the playbook. This template file replaces the variables to create an inventory file on the respective host under /tmp/hostname
. Insert a line that replaces the $GROUPNAME
environment variable (defined in the playbook later) with the inventory group name. Insert several lines to define the inventory_hostname
, the ansible_host
, and the connection_type
variables. Set these using magic variables and predefined variables. The file should contain the following:
1 2 3 4 5 6 7 8 9 |
[miro@controlnode connection]# mkdir templates [miro@controlnode connection]# cd templates [miro@controlnode templates]$ cat template.j2 # this is the template file [ {{ ansible_env['GROUPNAME'] }} ] inventory_hostname = {{ inventory_hostname }} ansible_host = {{ ansible_host }} connection_type = {{ ansible_connection }} |
Create a playbook named connection.yml
that copies the template template.j2
to the destination host under /tmp/
and names the file as that of its host name specified in the inventory file (for example, /tmp/hostname
).
The playbook should also define the environment variable named $GROUPNAME
and set its value to testservers, to define the group name in the inventory file when copied to respective managed hosts using the template template.j2
. The connection.yml
file should contain the following:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
[miro@controlnode connection]$ cat connection.yml --- # connection.yml - name: testing connection types hosts: all user: miro become: yes environment: GROUPNAME: testservers tasks: - name: template out hostfile template: src: template.j2 dest: "/tmp/{{ inventory_hostname }}" |
Execute the playbook connection.yml
from its the working directory
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
[miro@controlnode connection]$ ansible-playbook -i inventory connection.yml PLAY [testing connection types] ************************************************************************************************************************************** TASK [Gathering Facts] *********************************************************************************************************************************************** ok: [controlnode] ok: [managedhost1.example.com] ok: [controlnode.example.com] TASK [template out hostfile] ***************************************************************************************************************************************** ok: [controlnode] ok: [managedhost1.example.com] changed: [controlnode.example.com] PLAY RECAP *********************************************************************************************************************************************************** controlnode : ok=2 changed=0 unreachable=0 failed=0 controlnode.example.com : ok=2 changed=1 unreachable=0 failed=0 managedhost1.example.com : ok=2 changed=0 unreachable=0 failed=0 |
Verify the content of the file /tmp/controlnode
, /tmp/controlnode.example.com
, /tmp/managedhost1.example.com
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
[miro@controlnode connection]$ cat /tmp/controlnode # this is the template file [ testservers ] inventory_hostname = controlnode ansible_host = controlnode connection_type = local [miro@controlnode connection]$ cat /tmp/controlnode.example.com # this is the template file [ testservers ] inventory_hostname = controlnode.example.com ansible_host = localhost connection_type = ssh [miro@controlnode connection]$ ansible managedhost1.example.com -a 'cat /tmp/managedhost1.example.com' managedhost1.example.com | SUCCESS | rc=0 >> # this is the template file [ testservers ] inventory_hostname = managedhost1.example.com ansible_host = managedhost1.example.com connection_type = ssh |