Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Packer, Hyper-V, Ansible, Windows, WLS

Create Linux images on Windows with Packer

Prerequisites:

  • Windows 10 Pro
  • WLS, Ubuntu 16.04 (a.k.a.: Bash on Ubuntu on Windows)
  • Hyper-V
  • Packer (1.0.0, added to path)
  • Ansible (2.3.0, installed on WSL)
  • qemu-img (2.3.0, added to path)

Prepare envitonment to run Ansible provisioner

  • Add ansible.cmd and ansible-playbook.cmd to your PATH
  • Either set USER environment variable in command line or configure ansible_user in packer template to the default user of th WLS

Packer template

Builder

I am using the Hyper-V sample template with the sample preseed

Provisioner

Sample playbook: ansible-bootstrap-ubuntu-16.04.yml

"provisioners": [
  {
    "type": "ansible",
    "playbook_file": "./ansible/ansible-bootstrap-ubuntu-16.04.yml"
  }

Post-processor

This step does not work yet: hashicorp/packer#4140 As of packer 1.0.0, There is no support for cmd/powershell step inside post-processors

Convert the vhdx into qcow2 format

"post-processors": [
  {
    "type": "shell-local",
    "inline": ["qemu-img convert \"output-hyperv-iso\\Virtual Hard Disks\\{{user `vm_name`}}.vhdx\" -O qcow2 ubuntu-xenial.qcow2"]
  }
]
# bashrc for Git Bash on Windows
alias wbash="/c/Windows/System32/bash.exe"
convert_path() {
# repace GitBash /driveletters with WLS bash /mnt/driveletters
# note: this not works with 1 letter directory letters
params=$(echo $* | sed -e "s/\/\b\(.\)\//\/mnt\/\1\//g")
echo $params
}
ansible() {
params=$(convert_path $*)
wbash -c "ansible $params"
}
ansible-playbook() {
params=$(convert_path $*)
wbash -c "ansible-playbook $params"
}
ansible-galaxy() {
params=$(convert_path $*)
wbash -c "ansible-galaxy $params"
}
@echo off
REM "alias" for ansible-galaxy in cmd/powershell because why the hell not?
set args=%*
REM replace backslashes with slashes
call set args=%%args:\=/%%
REM fix drive letters
call set args=%%args:C:=/mnt/c%%
REM call set args=%%args:D:=/mnt/d%%
REM call set args=%%args:E:=/mnt/e%%
C:\Windows\System32\bash.exe -c 'ansible-galaxy %args%'
@echo off
REM "alias" for packer ansible provisioner running in cmd/powershell
set args=%*
REM replace backslashes with slashes
call set args=%%args:\=/%%
REM fix drive letters
call set args=%%args:C:=/mnt/c%%
REM call set args=%%args:D:=/mnt/d%%
REM call set args=%%args:E:=/mnt/e%%
C:\Windows\System32\bash.exe -c 'ansible-playbook %args%'
@echo off
REM "alias" for packer ansible provisioner running in cmd/powershell
set args=%*
REM replace backslashes with slashes
call set args=%%args:\=/%%
REM fix drive letters
call set args=%%args:C:=/mnt/c%%
REM call set args=%%args:D:=/mnt/d%%
REM call set args=%%args:E:=/mnt/e%%
C:\Windows\System32\bash.exe -c 'ansible %args%'
@davepidgeon
Copy link

davepidgeon commented May 12, 2020

This has helped me massively - thanks for sharing 👍

@coolrazor007
Copy link

coolrazor007 commented Aug 29, 2021

I am trying to get this to work, but on Packer 1.7.4 it passes an argument wrapped with single quotes. This breaks when WSL tries to hand over the %args% which is also wrapped in single quotes. Any ideas on how to escape the single quotes? I tried: call set args=%%args:'=\'%%
The error in Ansible is:
main.yml: -c: line 0: unexpected EOF while looking for matching `"'
The parameter Packer is now automatically including is this: --ssh-extra-args '-o IdentitiesOnly=yes'

@roobixx
Copy link

roobixx commented Oct 18, 2021

I am having the same issue outlined by @coolrazor007 with Packer 1.7.6

@roobixx
Copy link

roobixx commented Oct 19, 2021

@coolrazor007

After some investigating the issue was how things were being escaped. For instance double quotes were being escaped with a \ such in packer_build_name="vm" was being automatically escaped \"vm\" but that escaping \ then got clipped by the batch script to /"vm/".

Also the single quotes in the line 11 needed to be changed to double quotes

I'm sure you could reorder some of the call set lines to not need to do as much replacement and such but I wanted to leave everything intact as much as possible.

@echo off
REM "alias" for packer ansible provisioner running in cmd/powershell
set args=%*
REM replace backslashes with slashes
call set args=%%args:\=/%%
REM fix drive letters
call set args=%%args:C:=/mnt/c%%
REM call set args=%%args:D:=/mnt/d%%
REM call set args=%%args:E:=/mnt/e%%
call set args=%%args:/"=%%
call set args=%%args:"'='%%
call set args=%%args:'"='%%
call set args=%%args:"=^'%%

C:\Windows\System32\bash.exe -c "ansible-playbook %args%"

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment