Using Ansible through Windows 10's Subsystem for Linux

Ever since I heard about the new 'Beta' Windows Subsystem for Linux, which basically installs an Ubuntu LTS release inside of Windows 10 (currently 14.04), I've been meaning to give it a spin, and see if it can be a worthy replacement for Cygwin, Git shell, Cmder, etc. And what I was most interested in was whether I could finally point people to a more stable and friendly way of using Ansible on a Windows workstation.

In the past, there was the option of running Ansible inside Cygwin (and this is still the best way to try getting Ansible working in an older Windows environment), but this always felt kludgy to me, and I hated having to recommend either that or forcing Windows users to do a full Linux VM installation just to run Ansible commands. I finally updated my PC laptop to the latest Windows 10 Anniversary Update, and installed the Windows Subsystem for Linux, and lo and behold, Ansible works!

Ansible running on Windows in the Ubuntu Bash shell

In this blog post, I'll show you how to install and use Ansible on Windows 10.

Installing Bash on Windows 10

For reference, here are the official instructions from Microsoft: Bash on Ubuntu on Windows - Installation Guide.

Before installing the Linux Subsystem, you have to have:

  • Windows 10 (Anniversary update or later version)
  • 64-bit installation (can't run on 32-bit systems)

Once you verify your system is 64-bit and up to date, you have to do a few manual steps to enable the 'Windows Subsystem for Linux':

  1. Open 'Settings' (the cog in the start menu)
  2. Click 'Update & Security', then click the 'For developers' option on the left.
  3. Toggle the 'Developer mode' option, and accept any warnings Windows pops up.

Wait a minute for Windows to install a few things in the background (it will eventually let you know a restart may be required for changes to take effect—ignore that for now). Next, to install the actual Linux Subsystem, you have to jump over to 'Control Panel' (why is this separate from 'Settings'?), and do the following:

  1. Click on 'Programs'
  2. Click on 'Turn Windows features on or off'
  3. Scroll down and check 'Windows Subsystem for Linux (Beta)', and then click OK.

The subsystem will be installed, then Windows will require a reboot. Reboot, then open up the start menu and enter 'bash' (to open up 'Bash' installation in a new command prompt). Fill out all the questions (it will have you create a separate user account for the Linux subsystem), and once that's all done (it takes a few minutes to install), you will finally have Ubuntu running on your Windows laptop, somewhat integrated with Windows.

Installing Ansible

To install Ansible, since we're basically in an Ubuntu environment, it's as simple as installing pip, then installing Ansible:

  1. Open a bash prompt (from start menu, type 'bash' and hit enter).
  2. Install Pip: sudo apt-get -y install python-pip python-dev libffi-dev libssl-dev
  3. Install Ansible: pip install ansible --user (--user installs packages local to the user account instead of globally to avoid permissions issues with Pip and the Linux Subsystem)
  4. Since the ansible* commands are installed under ~/.local/bin, we need to add that to the $PATH, so run the command: echo 'PATH=$HOME/.local/bin:$PATH' >> ~/.bashrc
  5. Either exit out of the bash prompt and start it again from the Windows menu, or run source .bashrc to update your $PATH to include Ansible.

Note the use of --user for the pip install command; due to some peculiarities of the way the Linux subsystem works, Pip can't easily install packages globally, so we install packages just for the user account we set up for bash.

Using Ansible

At this point, which ansible should show the path to Ansible, ansible --version should show you Ansible's version, and you should be able to use ansible and the rest of the command-line tools (e.g. ansible-playbook, ansible-galaxy, etc.) as you would on any common environment.

If you get the error message ImportError: No module named markupsafe, try installing markupsafe manually with pip install markupsafe --user. See this GitHub issue for more detail.

If you want to run a playbook that's stored in your Windows user account's Documents folder (e.g. C:\Users\jgeerling\Documents), you can do so by navigating to /mnt/c/Users/jgeerling/Documents (where jgeerling is your username). Windows drives are mounted in the Subsystem inside the /mnt directory. Let's create a test playbook and see if it works!

  1. Open a bash prompt, and cd into your Windows user's Documents directory: cd /mnt/c/Users/jgeerling/Documents.
  2. Create a new test playbook: touch test.yml
  3. User nano or some other editor to add the following contents:

      ---
      - hosts: localhost
        tasks:
          - debug: msg="Ansible is working!"
    
  4. Run the playbook with the command ansible-playbook test.yml --connection=local

Ansible should run the command and print out the debug message. Ansible might warn about no inventory file being present, but since you're using --connection=local, the localhost host should automatically work.

Ansible test playbook running on Windows in the Ubuntu Bash shell

Going further

Now that you have Ansible installed, you can start automating everything (even including the rest of the bash environment)! If you need to, you can generate an SSH key for use connecting to servers, use ssh to directly connect to servers, etc. It's basically a full Ubuntu LTS install running inside Windows!

Comments

I just got bogged down in the installation of subsystem, just got an error when I was trying to activate this windows feature.

Any particular reason for using pip rather than the Ansible PPA (e.g. PPAs don't work on WSfL)?

Hi,

When running "sudo apt-get -y install pip python-dev", I received an error
I changed this to "sudo apt-get install python-pip python-dev", and it resolved the issue

Also prior to this I was receiving an "unable to resolve host" error which was resolved with

sudo su
echo 127.0.0.1 your_pc_name >> /etc/hosts

Thanks for the tutorial and hope this can help!

Same thing here regarding pip and python-pip.

Hi,
After having lots of errors trying to run the pip installed version, I used the steps described in the documentation (http://docs.ansible.com/ansible/intro_installation.html#latest-releases-...) and it worked great.

$ sudo apt-get install software-properties-common
$ sudo apt-add-repository ppa:ansible/ansible
$ sudo apt-get update
$ sudo apt-get install ansible

thank you very much for this - very helpful and saved me loads of time compared to other how-tos I found.

For some reason the pip package is named wrong or has been renamed to python-pip.

So use this command in step 2: sudo apt-get -y install python-pip python-dev

Sorry about that, I've since updated the post!

This sudo apt-get -y install python-pip python-dev should be sudo apt-get -y install python-pip python-dev libffi-dev libssl-dev. Otherwise the compilation of the crypto-extensions won't work.

Confirmed.

Thanks! I've updated the article.

There seems to be permission issue when trying to install a role from the ansible-galaxy after following this guide.

$ ansible-galaxy install geerlingguy.git
- downloading role 'git', owned by geerlingguy
- downloading role from https://github.com/geerlingguy/ansible-role-git/archive/1.2.1.tar.gz
- extracting geerlingguy.git to /etc/ansible/roles/geerlingguy.git
[WARNING]: - geerlingguy.git was NOT installed successfully: Could not update files in
/etc/ansible/roles/geerlingguy.git: [Errno 13] Permission denied: '/etc/ansible'

ERROR! - you can use --ignore-errors to skip failed roles and finish processing the list.

By default, Ansible installs roles into /etc/ansible, which is a path owned by root. Thus, you'd need to use sudo with galaxy install—sudo ansible-galaxy install geerlingguy.git.

Otherwise, you can also set a roles_path in /etc/ansible/ansible.cfg and set a directory to which you have write access (e.g. ~/ansible/roles or something like that). Additionally, you can add an ansible.cfg file in your project root that sets a path for that specific project's roles.

Hi,

First of all, thank you very much for this great tutorial.
So far I managed to get the test.yml to work with no issue.
I am now trying to set a real life scenario and create an ansible hosts but when I go to /etc there isn't an ansible directory..
Do I need to makdir /etc/ansible and then touch /etc/ansible/hosts ?

Could you please assist

Thank you in advance
Fred

Yes, if that directory doesn't exist, run sudo mkdir /etc/ansible, then touch /etc/ansible/hosts.

Great work Jeff, appreciate your time invested in this post as it saved me the need from running an additional VM

Ansible-galaxy will throw an error unless you add markupsafe package:

sudo pip install markupsafe

Once installed you will be now able to init new boiler plate for ansible galaxy roles or retrieve galaxy roles.

We can also try to install ansible using package manager but it will fail and throw a lot of errors.

Any idea if this works around Ansible issue #9963 (https://github.com/ansible/ansible/issues/9963)?

I encountered this when I created a vault on Mac OS but Windows user using Ansible via Cygwin couldn't decrypt. Would be helpful to hear your experience while I schedule time with one of my colleagues with Windows 10 to try, too.

There's a good chance it will work correctly—if you do everything within WSL, and don't use any windows-based tools to touch the vault file (e.g. no Git Bash for Windows, no Cygwin, no Powershell...).

getting a syntax error... not very familiar with yaml... i just copy / pasted your test file. any ideas?

drew@DREWTOP:~/playbooks$ ansible-playbook test.yml --connection=local
[WARNING]: Host file not found: /etc/ansible/hosts

[WARNING]: provided hosts list is empty, only localhost is available

ERROR! Syntax Error while loading YAML.


The error appears to have been in '/home/drew/playbooks/test.yml': line 2, column 10, but may
be elsewhere in the file depending on the exact syntax problem.

The offending line appears to be:

  ---
  - hosts: localhost
         ^ here

Try running the command like so:

ansible-playbook -i 'localhost,'​ test.yml --connection=local

same error :/

here is the paste of the test.yml file:

---
  - hosts: localhost
    tasks:
      - debug: msg="Ansible is working!"

Another option is to create an inventory file at /etc/ansible/hosts (sudo nano /etc/ansible/hosts) then add a line localhost to that file. Or a one-liner: echo "localhost" | sudo tee -a /etc/ansible/hosts > /dev/null. If the ansible directory doesn't exist, create it with sudo mkdir /etc/ansible first.

1 more thing - i installed the ansible packages globally (not to a user)... could that be causing the error?

That can definitely cause some issues, since the WSL/Ubuntu Bash is not a normal Linux environment.

I istalled Ansible on ubuntu machine and now trying to make connectivity with a windows 2012 server.
To automate the setup of WinRM, I am running ./ConfigureRemotingForAnsible.ps1 script on the remote machine in a PowerShell console as an administrator.It throws error.
copied upgrade_to_ps3.ps1 script onto the remote host and run a PowerShell console as an administrator. It also throws an error. Do you happen to know the fix or if you have steps for windows connectivity then do share the steps.

Best regards,
Shakti

You need to make sure there are no spaces before the '---' on the first line.
Hope this helps!
Rik

Hey Jeff,
Any ideas about installing custom ansible modules with this setup? Trying to get win_dsc5 to work and while `ansible windows -m win_dsc5` returns correctly, attempting to call a playbook that leverages the same module fails to find the module. This occurs even with an ansible.cfg defined that calls out the library path...
Thanks

Hi Jeff!

Thanks for a detailed and well presented post. I managed to get ansible working on the Ubuntu subsystem no problem at all controlling remote machines as well as some basic things through the local connection.

I have run into an issue while trying to get ansible to 'become' / sudo on the local ubuntu subsystem. Have you had any issues here or worked around the problem?
I have:
- Tried adding become to tasks, although ansible seems to ignore this
- Tried running ansible-playbook with sudo, which of course doesn't work as the above post only installs it for the one user
- Tried specifying a default sudo user and pass in vars, but it seems to get ignored
- Tried specifying a user when running ansible-playbook and a password using -K

This seems to be the last blocker to being able to use ansible for managing my local system.

Thanks again.
Addshore

Thanks you Jeff for great info.
But I've met with some difficulties. I've installed Zookeeper server and zookeeperd.
But when I tried to monitor service with:
sudo service zookeeper status

I've got that error
Failed to connect to socket /com/ubuntu/upstart

Is any way to fix this problem?

I've not tried using Zookeeper under Ubuntu Bash, but I'm guessing that the zookeeper service is misconfigured in that case.

Interesting approach - thanks for posting it! Presumably(?) if you run commands on localhost using this setup, they run under the bash for windows environment? Is there a way to tell ansible to run a task on the "Windows side" of the machine (i.e. using winrm to treat the machine as a Windows host)?

Yes, all this would be run within Bash on Ubuntu—and if you have the Creators Update or later, you should be able to at least call out to windows executables... but there's not any deeper integration between the two at this time.

Hi Jeff. Thanks so much for this! Was fairly simple to setup and run a playbook to install and configure packages on a Vagrant Ubuntu machine from Windows!

---
- hosts: localhost
  tasks:
    - debug: msg="Ansible is working!"

use the above code to avoid syntax errors

Thank you! Appreciate this very much

Make sure to add to your apt-get line sshpass.

sudo apt-get -y install python-pip python-dev libffi-dev libssl-dev sshpass

Note that sshpass is only required if you need to log into servers using SSH password authentication (as opposed to key-based auth). This is not recommended, as it's slightly less secure, and has other deployment issues associated with it too. However, if you must use it, you can use it if you install sshpass.

On Windows 10 with ansible 2.1.0.0, when running the yaml example I get the following error:

(lvenv)vagrant@DESKTOP-T091QJO:$ ansible-playbook -vvv -i 'localhost,' /mnt/
c/Users/Admin/Documents/test.yml --connection=local
Using /mnt/c/code/custos-bots/custosbotscitests/ansible.cfg as config file

PLAYBOOK: test.yml *************************************************************
1 plays in /mnt/c/Users/Admin/Documents/test.yml

PLAY [localhost] ***************************************************************

TASK [setup] *******************************************************************
<localhost> ESTABLISH LOCAL CONNECTION FOR USER: vagrant
<localhost> EXEC /bin/sh -c '( umask 77 && mkdir -p "` echo $HOME/.ansible/tmp/ansible-tmp-1498677017.51-150964564686249 `" && echo ansible-tmp-1498677017.51-150964564686249="` echo $HOME/.ansible/tmp/ansible-tmp-1498677017.51-150964564686249 `" ) && sleep 0'
<localhost> PUT /tmp/tmp6mFX1r TO /home/vagrant/.ansible/tmp/ansible-tmp-1498677017.51-150964564686249/setup
<localhost> EXEC /bin/sh -c 'LANG=en_ZA.UTF-8 LC_ALL=en_ZA.UTF-8 LC_MESSAGES=en_ZA.UTF-8 /usr/bin/python /home/vagrant/.ansible/tmp/ansible-tmp-1498677017.51-150964564686249/setup; rm -rf "/home/vagrant/.ansible/tmp/ansible-tmp-1498677017.51-150964564686249/" > /dev/null 2>&1 && sleep 0'
An exception occurred during task execution. The full traceback is:
Traceback (most recent call last):
  File "/tmp/ansible_1neMDM/ansible_module_setup.py", line 127, in <module>
    main()
  File "/tmp/ansible_1neMDM/ansible_module_setup.py", line 119, in main
    data = get_all_facts(module)
  File "/tmp/ansible_1neMDM/ansible_modlib.zip/ansible/module_utils/facts.py", line 3177, in get_all_facts
  File "/tmp/ansible_1neMDM/ansible_modlib.zip/ansible/module_utils/facts.py", line 3123, in ansible_facts
  File "/tmp/ansible_1neMDM/ansible_modlib.zip/ansible/module_utils/facts.py", line 919, in populate
  File "/tmp/ansible_1neMDM/ansible_modlib.zip/ansible/module_utils/facts.py", line 107, in wrapper
  File "/tmp/ansible_1neMDM/ansible_modlib.zip/ansible/module_utils/facts.py", line 1142, in get_mount_facts
IndexError: list index out of range

fatal: [localhost]: FAILED! => {"changed": false, "failed": true, "invocation": {"module_name": "setup"}, "module_stderr": "Traceback (most recent call last):\n  File "/tmp/ansible_1neMDM/ansible_module_setup.py", line 127, in <module>\n    main()\n  File "/tmp/ansible_1neMDM/ansible_module_setup.py", line 119, in main\n    data = get_all_facts(module)\n  File "/tmp/ansible_1neMDM/ansible_modlib.zip/ansible/module_utils/facts.py", line 3177, in get_all_facts\n  File "/tmp/ansible_1neMDM/ansible_modlib.zip/ansible/module_utils/facts.py", line 3123, in ansible_facts\n  File "/tmp/ansible_1neMDM/ansible_modlib.zip/ansible/module_utils/facts.py", line 919, in populate\n  File "/tmp/ansible_1neMDM/ansible_modlib.zip/ansible/module_utils/facts.py", line 107, in wrapper\n  File "/tmp/ansible_1neMDM/ansible_modlib.zip/ansible/module_utils/facts.py", line 1142, in get_mount_facts\nIndexError: list index out of range\n", "module_stdout": "", "msg": "MODULE FAILURE", "parsed": false}

NO MORE HOSTS LEFT *************************************************************
        to retry, use: --limit @/mnt/c/Users/Admin/Documents/test.retry

PLAY RECAP *********************************************************************
localhost                  : ok=0    changed=0    unreachable=0    failed=1

Any ideas? I did add localhost to my `/bin/ansible/hosts` file

Hi,

I have installed the Ubuntu package under windows as per the instructions above and when i try and run the pip installation it fails with unable to resolve URL error messages. Have tried looking down this page for others who had the same problems and tried the fixes they suggested and it still fails. Is the archive URL still in place to download these packages?

All help gratefully received

Thanks

David

Are you on a network behind a corporate proxy? If so you would need to configure it in the Ubuntu bash environment.

Hi Jeff,

no, I am a home user.

Thanks

Regards

David

Cheers for putting this tutorial together!

I was only half paying attention as I was reading and ended up just installing the Ansible package from the Ubuntu repositories via:

apt-get install ansible

I haven't gotten much farther than your debug step, but it looks good so far.

The package manager version is 2.0.0.2, which looks to date from January 2016 (https://releases.ansible.com/ansible/), so fairly out of date in comparison to 2.3.2.0 from July 2017, but we'll see how we go!

Excellent blog

I hit an issue running apt-get and found it was linked to IPv4 where apt-get would get stuck at "Connecting to archive.ubuntu.com"

Answered originally here : https://askubuntu.com/questions/574569/apt-get-stuck-at-0-connecting-to-...

I wonder if there is a way for ansible to check if it is running under WSL, so that you could use it for conditionals.

Thanks for putting together this guide, it's great to be able to use Ansible from my laptop. And thanks for all the other Ansible and Drupal resources you have made available.

Have you come across this issue with trying to encrypt files into Ansible Vault?

*****@*****:/mnt/c/dev/ansible$ ansible-vault encrypt restric.yml -vvv
Using /mnt/c/dev/ansible/ansible.cfg as config file
New Vault password:
Confirm New Vault password:
ERROR! Unexpected Exception: /home/********/.local/lib/python2.7/site-packages/cryptography/hazmat/bindings/_openssl.so: cannot enable executable stack as shared object requires: Invalid argument
the full traceback was:

Traceback (most recent call last):
  File "/home/********/.local/bin/ansible-vault", line 109, in <module>
    exit_code = cli.run()
  File "/home/********/.local/lib/python2.7/site-packages/ansible/cli/vault.py", line 158, in run
    self.execute()
...
ImportError: /home/********/.local/lib/python2.7/site-packages/cryptography/hazmat/bindings/_openssl.so: cannot enable executable stack as shared object requires: Invalid argument

Sorry, I haven't seen that one before—I would imagine asking on the Ansible Project Google group might get some more opinions though! (Or maybe even the #ansible channel on Freenode IRC).

Thanks for looking.

I have since found that this seems to fix it:

sudo execstack -c /home/MY_USER_NAME/.local/lib/python2.7/site-packages/cryptography/hazmat/bindings/_openssl.so

Hi all,

i'm getting error in the initial steps. After enabled bash cmd. it asking 'type y to continue' to install ubuntu in windows. them pressing y, downloading start. cmd line window automatically closed after reached 100%. again hit bash cmd, show same error. anyone assist me