<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ihor Dotsenko</title>
    <description>The latest articles on DEV Community by Ihor Dotsenko (@garrisond).</description>
    <link>https://dev.to/garrisond</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F147654%2F1a4d7b05-de58-4bb1-b619-fbb6e4b0a0ab.jpeg</url>
      <title>DEV Community: Ihor Dotsenko</title>
      <link>https://dev.to/garrisond</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/garrisond"/>
    <language>en</language>
    <item>
      <title>The lesson learned from using ansible_user variable</title>
      <dc:creator>Ihor Dotsenko</dc:creator>
      <pubDate>Tue, 16 Aug 2022 17:53:23 +0000</pubDate>
      <link>https://dev.to/garrisond/the-lesson-learned-from-using-ansibleuser-variable-52ni</link>
      <guid>https://dev.to/garrisond/the-lesson-learned-from-using-ansibleuser-variable-52ni</guid>
      <description>&lt;p&gt;&lt;strong&gt;TL;DR&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Use &lt;code&gt;ansible_user&lt;/code&gt; &lt;strong&gt;ONLY&lt;/strong&gt; in &lt;code&gt;inventory&lt;/code&gt; / &lt;code&gt;group_vars&lt;/code&gt; / &lt;code&gt;host_vars&lt;/code&gt; files&lt;/p&gt;




&lt;p&gt;&lt;strong&gt;Problem: &lt;code&gt;ansible_user&lt;/code&gt; in my playbooks&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I wanted Ansible to setup Docker with the &lt;a href="https://github.com/geerlingguy/ansible-role-docker"&gt;geerlingguy/ansible-role-docker&lt;/a&gt;:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;playbook.yml&lt;/code&gt;👇&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;...&lt;/span&gt;

&lt;span class="na"&gt;roles&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;role&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;geerlingguy.docker&lt;/span&gt;
    &lt;span class="na"&gt;docker_users&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;{{&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;ansible_user&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;}}"&lt;/span&gt;&lt;span class="pi"&gt;]&lt;/span&gt;

&lt;span class="nn"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ran &lt;code&gt;vagrant provision&lt;/code&gt;: no errors 🎉&lt;/p&gt;

&lt;p&gt;Connected to a VM with &lt;code&gt;vagrant ssh&lt;/code&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;docker ps&lt;/code&gt;: no &lt;em&gt;permission denied&lt;/em&gt; errors 🎉&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;docker run hello-world&lt;/code&gt;: no errors 🎉 &lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;git commit&lt;/code&gt;, &lt;code&gt;git push&lt;/code&gt;, done... ✅&lt;/p&gt;




&lt;p&gt;I have wanted to try out &lt;a href="https://code.visualstudio.com/docs/remote/containers"&gt;dev containers&lt;/a&gt; for a long time, and my repository with Ansible stuff was a great choice.&lt;/p&gt;

&lt;p&gt;While dev containers have a lot of benefits, there are also some limitations. The one I faced was broken Vagrant integration.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Before migration to dev containers:&lt;/em&gt; Ansible and Vagrant live on a host and integrate perfectly.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;After the migration:&lt;/em&gt; Ansible lives in a dev container and Vagrant lives on the host. If you run &lt;code&gt;vagrant provision&lt;/code&gt;, you will see the error about missing &lt;code&gt;ansible-playbook&lt;/code&gt; executable on your PATH.&lt;/p&gt;

&lt;p&gt;While installing Vagrant in a Docker container is easy, it's not with VirtualBox. I found some threads on StackOverflow about getting VirtualBox up and running, &lt;em&gt;but&lt;/em&gt;...&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;It requires sticking to an image with &lt;code&gt;systemd&lt;/code&gt;. On Docker Hub you can find some &lt;code&gt;systemd-*&lt;/code&gt; images provided by &lt;em&gt;jrei&lt;/em&gt;, &lt;em&gt;but&lt;/em&gt;...&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;I have no idea who &lt;em&gt;jrei&lt;/em&gt; is and how long they will maintain the images (e. g. rebasing onto the latest  Debian/Ubuntu/etc. to grab all the security patches). I wouldn't like it resting on my shoulders one day.&lt;/li&gt;
&lt;li&gt;Just using one of these images in &lt;code&gt;.devcontainer/devcontainer.json&lt;/code&gt; is not enough; I would also need to create a &lt;code&gt;Dockerfile&lt;/code&gt; and copy everything from the &lt;a href="https://github.com/microsoft/vscode-dev-containers/tree/main/containers/python-3"&gt;Microsoft's Python 3 one&lt;/a&gt; to make it suitable for development. We need a dev container, remember? This way it starts resting on my shoulders immediately: periodically I need to check the changes commited to the Microsoft's Python 3 &lt;code&gt;Dockerfile&lt;/code&gt; and apply them to my &lt;code&gt;Dockerfile&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;
&lt;li&gt;&lt;p&gt;The fact that there is almost no info on the web about the setup like this says it's uncommon practice, and if I have any problems, there is nobody to help me.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;OK, but except the &lt;a href="https://www.vagrantup.com/docs/provisioning/ansible"&gt;Ansible provisioner&lt;/a&gt; Vagrant  has the &lt;a href="https://www.vagrantup.com/docs/provisioning/ansible_local"&gt;Ansible Local one&lt;/a&gt;!&lt;/p&gt;

&lt;p&gt;In a &lt;code&gt;Vagrantfile&lt;/code&gt; I changed one line:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gd"&gt;-  config.vm.provision 'ansible' do |ansible|
&lt;/span&gt;&lt;span class="gi"&gt;+  config.vm.provision 'ansible_local' do |ansible|
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;... and thought it was a quick win 🏆.&lt;/p&gt;

&lt;p&gt;I ran &lt;code&gt;vagrant provision&lt;/code&gt; and got saddened by the error:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;... {{ ansible_user }}: 'ansible_user' is undefined ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Hmm, where is &lt;code&gt;ansible_user&lt;/code&gt;? 🤔&lt;/p&gt;

&lt;p&gt;Let's take a step back and look at how Ansible &lt;del&gt;Local&lt;/del&gt; provisioning works under the hood. Vagrant generates an inventory and passes it to &lt;code&gt;ansible-playbook&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;&amp;lt;your-project&amp;gt;/.vagrant/provisioners/ansible/inventory/vagrant_ansible_inventory
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Generated by Vagrant

default ansible_ssh_host=127.0.0.1 ansible_ssh_port=2222 ansible_ssh_user='vagrant' ansible_ssh_private_key_file='&amp;lt;your-project&amp;gt;/.vagrant/machines/default/virtualbox/private_key'
                                                         ^^^^^^^^^^^^^^^^^^^^^^^^^^
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;ansible_ssh_user&lt;/code&gt; you can see here is the &lt;code&gt;ansible_user&lt;/code&gt; at the time of Ansible &amp;lt;2. You can find the deprecation notice &lt;a href="https://docs.ansible.com/ansible/2.3/intro_inventory.html"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I wish this deprecation didn't happen. So now I would not write these lines 😂&lt;/p&gt;

&lt;p&gt;Let's get back to the Ansible Local provisioning. Ansible doesn't connect to any machine with SSH ➡️ there is &lt;strong&gt;no need&lt;/strong&gt; for an inventory ➡️ there is &lt;strong&gt;no&lt;/strong&gt; &lt;code&gt;ansible_ssh_user&lt;/code&gt;/&lt;code&gt;ansible_user&lt;/code&gt; 🙃&lt;/p&gt;

&lt;p&gt;OK, googling for &lt;em&gt;undefined ansible_user&lt;/em&gt; gave me the solution:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="err"&gt;...&lt;/span&gt;

&lt;span class="p"&gt;roles:
&lt;/span&gt;  - role: geerlingguy.docker
&lt;span class="gd"&gt;-   docker_users: ["{{ ansible_user }}"]
&lt;/span&gt;&lt;span class="gi"&gt;+   docker_users: ["{{ ansible_env.USER }}"]
&lt;/span&gt;
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;that makes my &lt;code&gt;vagrant provision&lt;/code&gt; successful again 🎉&lt;/p&gt;

&lt;p&gt;&lt;code&gt;git commit&lt;/code&gt;, &lt;code&gt;git push&lt;/code&gt;, done... ✅&lt;/p&gt;




&lt;p&gt;It's time for production. I run &lt;code&gt;vagrant provision&lt;/code&gt; to provision my Raspberry Pi 4 (where my pet projects are hosted) and see how &lt;code&gt;docker_users&lt;/code&gt; variable evaluates to &lt;code&gt;[root]&lt;/code&gt; instead of &lt;code&gt;[pi]&lt;/code&gt; 🤦‍♂️&lt;/p&gt;

&lt;p&gt;The easy solution that can be found in some open-sourced Ansible roles:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="err"&gt;...&lt;/span&gt;

&lt;span class="p"&gt;roles:
&lt;/span&gt;  - role: geerlingguy.docker
&lt;span class="gd"&gt;-   docker_users: ["{{ ansible_env.USER }}"]
&lt;/span&gt;&lt;span class="gi"&gt;+   docker_users: ["{{ ansible_user | default(ansible_env.USER) }}"]
&lt;/span&gt;
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;p&gt;&lt;strong&gt;The root cause&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;I specified &lt;code&gt;ansible_user&lt;/code&gt; only in the inventory and used &lt;code&gt;{{ ansible_user }}&lt;/code&gt; to refer to it in my playbooks, in my roles, in variables to 3rd party roles (like in the one described above)... everywhere.&lt;/p&gt;

&lt;p&gt;Let's say the user is &lt;code&gt;ubuntu&lt;/code&gt;. Use cases:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Ansible used &lt;code&gt;ubuntu&lt;/code&gt; to SSH for provisioning.&lt;/li&gt;
&lt;li&gt;Ansible was configuring &lt;code&gt;ubuntu&lt;/code&gt; user according to my instructions, e.g. changing its shell preference from &lt;code&gt;bash&lt;/code&gt; to &lt;code&gt;zsh&lt;/code&gt; and configuring &lt;code&gt;.zshrc&lt;/code&gt; so when you SSH, you get connected to the running &lt;code&gt;tmux&lt;/code&gt; session or a new one created for you 👍 Did you get it? Ansible is configuring the user it's using to SSH... What if it gets broken as a result of provisioning? 🙃&lt;/li&gt;
&lt;li&gt;I used &lt;code&gt;ubuntu&lt;/code&gt; user to SSH...&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;At that time I thought: wow, how flexible it is 💪&lt;br&gt;
Now I think: how stupid and fragile it is 🤦‍♂️😂&lt;/p&gt;

&lt;p&gt;&lt;em&gt;The root cause is that I forgot about the single-responsibility principle, overloaded the user and thought it was cool. &lt;code&gt;ansible_user&lt;/code&gt; is just the possible implementation.&lt;/em&gt; The way I will re-write this Ansible setup and will use for all my future ones:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;vagrant&lt;/code&gt;/&lt;code&gt;ubuntu&lt;/code&gt;/&lt;code&gt;pi&lt;/code&gt;/whatever is used only by Ansible for SSHing, installing packages, blacklisting ports, etc., &lt;strong&gt;but&lt;/strong&gt; it stays pristine because it creates and configures 👇&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;dev&lt;/code&gt; user to have &lt;code&gt;zsh&lt;/code&gt; by default, &lt;code&gt;tmux&lt;/code&gt; hook described above, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;code&gt;vars/main.yml&lt;/code&gt; 👇&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;dev_user&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;dev&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I am using the variable for the case I find a better name one day... before the very first provisioning on a new project of course... changing this in-between would be too risky 💣 Also it simplifies searching across the project.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;playbook.yml&lt;/code&gt; 👇&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="err"&gt;...&lt;/span&gt;

&lt;span class="p"&gt;roles:
&lt;/span&gt;  - role: geerlingguy.docker
&lt;span class="gd"&gt;-   docker_users: ["{{ ansible_user | default(ansible_env.USER) }}"]
&lt;/span&gt;&lt;span class="gi"&gt;+   docker_users: ["{{ dev_user }}"]
&lt;/span&gt;
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This way you are in a safe place. No matter you are running Ansible Remote or Ansible Local provisioner. Also migration from one OS to another is an easy task:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;inventory&lt;/code&gt;👇&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight diff"&gt;&lt;code&gt;&lt;span class="gd"&gt;-some-host ansible_user=ubuntu
&lt;/span&gt;&lt;span class="gi"&gt;+some-host ansible_user=ec2-user
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;... with everything else being familiar: the same &lt;code&gt;ssh dev@some-host&lt;/code&gt; command, the same &lt;code&gt;dev&lt;/code&gt; user, etc.&lt;/p&gt;

&lt;p&gt;The less complex interpolations, conditions, loops you have - the better. These guys must be tested. Is it easy to test Ansible code? Would you like to test your Ansible code? I guess, no 🙂&lt;/p&gt;

</description>
      <category>ansible</category>
      <category>vagrant</category>
      <category>docker</category>
    </item>
  </channel>
</rss>
