{"id":3588,"date":"2020-03-01T13:26:44","date_gmt":"2020-03-01T12:26:44","guid":{"rendered":"http:\/\/miro.borodziuk.eu\/?p=3588"},"modified":"2020-05-19T17:40:14","modified_gmt":"2020-05-19T15:40:14","slug":"ansible-connection-type","status":"publish","type":"post","link":"http:\/\/miro.borodziuk.eu\/index.php\/2020\/03\/01\/ansible-connection-type\/","title":{"rendered":"Ansible Connection Type"},"content":{"rendered":"<p>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<br \/>\non the command-line interface.<\/p>\n<p><!--more--><\/p>\n<p>The <span style=\"color: #3366ff;\">pipelining <\/span>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.<\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"color: #3366ff;\">Connection types<\/span><br \/>\nVarious connection types supported by Ansible include:<\/p>\n<p>\u2022 <strong>smart<\/strong>: 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<br \/>\nconfiguration, but is better done in the Ansible settings. In <code>\/etc\/ansible\/ansible.cfg,<\/code> the default setting is listed in a comment:<\/p>\n<pre class=\"lang:sh decode:true\">#ssh_args = -o ControlMaster=auto -o ControlPersist=60s<\/pre>\n<p>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<br \/>\nappropriate:<\/p>\n<pre class=\"lang:sh decode:true\">ssh_args = -o ControlMaster=auto -o ControlPersist=30m<\/pre>\n<p>\u2022 <strong>paramiko<\/strong>: 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.<br \/>\n\u2022 <strong>local<\/strong>: The local connection runs commands locally, instead of running over SSH.<br \/>\n\u2022 <strong>ssh<\/strong>: The ssh connection uses an OpenSSH-based connection, which supports ControlPersist technology.<br \/>\n\u2022 <strong>docker<\/strong>: Ansible offers a new docker connection type. It connects to containers using the docker exec command.<\/p>\n<p>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<br \/>\nplanned for future releases.<\/p>\n<p>&nbsp;<\/p>\n<p><span style=\"color: #3366ff;\"> Configuring connection types<\/span><\/p>\n<ul>\n<li><strong> Ansible configuration<\/strong><br \/>\nThe connection type can be specified in the <code>ansible.cfg<\/code> file under the [defaults] section of the file using the transport key.<\/li>\n<\/ul>\n<pre class=\"lang:sh decode:true \">[defaults]\r\n# some basic default values...\r\n... Output omitted ...\r\n#transport = smart<\/pre>\n<p>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 <code>\/etc\/ansible\/ansible.cfg<\/code>. They can be overridden<br \/>\nspecifying 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.<\/p>\n<pre class=\"lang:sh decode:true\">[ssh_connection]\r\n... Output omitted ...\r\n# control_path = %(directory)s\/%%h-%%r\r\n#control_path = %(directory)s\/ansible-ssh-%%h-%%p-%%r\r\n#pipelining = False\r\n#scp_if_ssh = True\r\n#sftp_batch_mode = False<\/pre>\n<p><em>Important<\/em><br \/>\nAdministrators should usually leave the connection type set to <strong>smart<\/strong> in<br \/>\n<code>ansible.cfg<\/code>, and configure playbooks or inventory files to choose an alternative connection setting when necessary.<\/p>\n<ul>\n<li><strong>Inventory file<\/strong><br \/>\nThe 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.<\/li>\n<\/ul>\n<pre class=\"lang:sh decode:true\">[targets]\r\nlocalhost ansible_connection=local\r\ndemo.lab.example.com ansible_connection=ssh<\/pre>\n<ul>\n<li><strong>Playbooks<\/strong><br \/>\nConnection types can also be specified when running an entire playbook. Specify the<code> --connection=CONNECTIONTYPE<\/code> option to the ansible-playbook command as shown in the following example.<\/p>\n<pre class=\"lang:sh decode:true \">[user@host ~]$ ansible-playbook playbook.yml --connection=local<\/pre>\n<\/li>\n<\/ul>\n<p>Alternatively, the connection type can be set with the connection: CONNECTIONTYPE parameter in a playbook as shown in the following example.<\/p>\n<pre class=\"lang:sh decode:true \">---\r\n- name: Connection type in playbook\r\n  hosts: 127.0.0.1\r\n  connection: local<\/pre>\n<p>&nbsp;<\/p>\n<p><span style=\"color: #3366ff;\"> Setting environment variables in playbooks<\/span><br \/>\nSometimes 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<em> $PATH<\/em> 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.<br \/>\nSome Ansible modules, such as <em>get_url<\/em>, <em>yum<\/em>, and <em>apt<\/em>, use environment variables to set their proxy server. The following example shows how to set the proxy server for package installation using the <code>environment:<\/code> parameter which sets the <em>$http_proxy<\/em> environment variable to<br \/>\n<code>http:\/\/demo.example.com<\/code>.<\/p>\n<pre class=\"lang:sh decode:true\">---\r\n- hosts: devservers\r\n  tasks:\r\n  - name: download a file using demo.lab.example.com as proxy\r\n    get_url:\r\n      url: http:\/\/materials.example.copm\/file.tar.gz\r\n      dest: ~\/Downloads\r\n    environment:\r\n      http_proxy: http:\/\/demo.example.com:8080<\/pre>\n<p>An environment hash can be defined in a variable using the <em>vars<\/em> keyword in a playbook, or using the <em>group_vars<\/em> keyword. These variables can then be referenced inside a playbook using the environment parameter.<br \/>\nThe following example shows how to define an environment variable and reference it using the environment keyword for an entire block of tasks.<\/p>\n<pre class=\"lang:sh decode:true\">---\r\n- name: Demonstrate environment variable in block\r\n  hosts: localhost\r\n  connection: local\r\n  gather_facts: false\r\n  vars:\r\n    myname: ansible\r\n  tasks:\r\n  - block:\r\n    - name: Print variable\r\n      shell: \"echo $name\"\r\n      register: result\r\n    - debug: var=result.stdout\r\n      environment:\r\n        name: \"{{ myname }}\"<\/pre>\n<p>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.<\/p>\n<pre class=\"lang:sh decode:true\">---\r\n- hosts: example_host\r\n  roles:\r\n    - php\r\n    - nginx\r\n  environment:\r\n    http_proxy: http:\/\/demo.example.com:8080<\/pre>\n<p>&nbsp;<\/p>\n<p><span style=\"color: #3366ff;\">Example.<\/span><\/p>\n<p>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 <code>\/tmp<\/code> directory.<\/p>\n<p>Create an inventory file named hosts under<code> ~\/ansible\/connection\/<\/code><br \/>\ninventory with two different host names for <code>controlnode<\/code>, <code>controlnode<\/code> and<br \/>\n<code>controlnode.example.com<\/code>, which would use two different connection types, local and ssh respectively. Also add an inventory line for <code>managedhost1.example.com<\/code> that uses the connection type ssh.<\/p>\n<pre class=\"lang:sh decode:true \">[miro@controlnode ansible]# pwd\r\n\/home\/miro\/ansible\r\n[miro@controlnode ansible]# mkdir connection\r\n[miro@controlnode connection]# cat inventory\r\n\r\ncontrolnode ansible_connection=local\r\ncontrolnode.example.com  ansible_connection=ssh ansible_host=localhost\r\nmanagedhost1.example.com ansible_connection=ssh<\/pre>\n<p>Create a new directory called <code>templates<\/code>. Below it, create a file named <code>template.j2<\/code>. 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<code> \/tmp\/hostname<\/code>. Insert a line that replaces the <code>$GROUPNAME<\/code> environment variable (defined in the playbook later) with the inventory group name. Insert several lines to define the <code>inventory_hostname<\/code>, the <code>ansible_host<\/code>, and the <code>connection_type<\/code> variables. Set these using magic variables and predefined variables. The file should contain the following:<\/p>\n<pre class=\"lang:sh decode:true\">[miro@controlnode connection]# mkdir templates\r\n[miro@controlnode connection]# cd templates\r\n[miro@controlnode templates]$ cat template.j2\r\n\r\n# this is the template file\r\n[ {{ ansible_env['GROUPNAME'] }} ]\r\ninventory_hostname = {{ inventory_hostname }}\r\nansible_host = {{ ansible_host }}\r\nconnection_type = {{ ansible_connection }}<\/pre>\n<p>Create a playbook named<code> connection.yml<\/code> that copies the template<code> template.j2<\/code> to the destination host under <code>\/tmp\/<\/code> and names the file as that of its host name specified in the inventory file (for example, <code>\/tmp\/hostname<\/code>).<br \/>\nThe playbook should also define the environment variable named <code>$GROUPNAME<\/code> and set its value to testservers, to define the group name in the inventory file when copied to respective managed hosts using the template <code>template.j2<\/code>. The <code>connection.yml<\/code> file should contain the following:<\/p>\n<pre class=\"lang:sh decode:true\">[miro@controlnode connection]$ cat connection.yml\r\n---\r\n# connection.yml\r\n- name: testing connection types\r\n  hosts: all\r\n  user: miro\r\n  become: yes\r\n  environment:\r\n    GROUPNAME: testservers\r\n  tasks:\r\n    - name: template out hostfile\r\n      template:\r\n        src: template.j2\r\n        dest: \"\/tmp\/{{ inventory_hostname }}\"<\/pre>\n<p>Execute the playbook <code>connection.yml<\/code> from its the working directory<\/p>\n<pre class=\"lang:sh decode:true \">[miro@controlnode connection]$ ansible-playbook -i inventory connection.yml\r\n\r\nPLAY [testing connection types] **************************************************************************************************************************************\r\n\r\nTASK [Gathering Facts] ***********************************************************************************************************************************************\r\nok: [controlnode]\r\nok: [managedhost1.example.com]\r\nok: [controlnode.example.com]\r\n\r\nTASK [template out hostfile] *****************************************************************************************************************************************\r\nok: [controlnode]\r\nok: [managedhost1.example.com]\r\nchanged: [controlnode.example.com]\r\n\r\nPLAY RECAP ***********************************************************************************************************************************************************\r\ncontrolnode : ok=2 changed=0 unreachable=0 failed=0\r\ncontrolnode.example.com : ok=2 changed=1 unreachable=0 failed=0\r\nmanagedhost1.example.com : ok=2 changed=0 unreachable=0 failed=0<\/pre>\n<p>Verify the content of the file <code>\/tmp\/controlnode<\/code>, <code>\/tmp\/controlnode.example.com<\/code>, <code>\/tmp\/managedhost1.example.com<\/code>:<\/p>\n<pre class=\"lang:sh decode:true\">[miro@controlnode connection]$ cat \/tmp\/controlnode\r\n# this is the template file\r\n[ testservers ]\r\ninventory_hostname = controlnode\r\nansible_host = controlnode\r\nconnection_type = local\r\n\r\n[miro@controlnode connection]$ cat \/tmp\/controlnode.example.com\r\n# this is the template file\r\n[ testservers ]\r\ninventory_hostname = controlnode.example.com\r\nansible_host = localhost\r\nconnection_type = ssh\r\n\r\n[miro@controlnode connection]$ ansible managedhost1.example.com -a 'cat \/tmp\/managedhost1.example.com'\r\nmanagedhost1.example.com | SUCCESS | rc=0 &gt;&gt;\r\n# this is the template file\r\n[ testservers ]\r\ninventory_hostname = managedhost1.example.com\r\nansible_host = managedhost1.example.com\r\nconnection_type = ssh<\/pre>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>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 &hellip; <\/p>\n<p class=\"link-more\"><a href=\"http:\/\/miro.borodziuk.eu\/index.php\/2020\/03\/01\/ansible-connection-type\/\" class=\"more-link\">Continue reading<span class=\"screen-reader-text\"> &#8220;Ansible Connection Type&#8221;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":3590,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[86],"tags":[],"_links":{"self":[{"href":"http:\/\/miro.borodziuk.eu\/index.php\/wp-json\/wp\/v2\/posts\/3588"}],"collection":[{"href":"http:\/\/miro.borodziuk.eu\/index.php\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"http:\/\/miro.borodziuk.eu\/index.php\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"http:\/\/miro.borodziuk.eu\/index.php\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"http:\/\/miro.borodziuk.eu\/index.php\/wp-json\/wp\/v2\/comments?post=3588"}],"version-history":[{"count":16,"href":"http:\/\/miro.borodziuk.eu\/index.php\/wp-json\/wp\/v2\/posts\/3588\/revisions"}],"predecessor-version":[{"id":3606,"href":"http:\/\/miro.borodziuk.eu\/index.php\/wp-json\/wp\/v2\/posts\/3588\/revisions\/3606"}],"wp:featuredmedia":[{"embeddable":true,"href":"http:\/\/miro.borodziuk.eu\/index.php\/wp-json\/wp\/v2\/media\/3590"}],"wp:attachment":[{"href":"http:\/\/miro.borodziuk.eu\/index.php\/wp-json\/wp\/v2\/media?parent=3588"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"http:\/\/miro.borodziuk.eu\/index.php\/wp-json\/wp\/v2\/categories?post=3588"},{"taxonomy":"post_tag","embeddable":true,"href":"http:\/\/miro.borodziuk.eu\/index.php\/wp-json\/wp\/v2\/tags?post=3588"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}