Sunday, October 18, 2015

Windows Nano with vagrant, virtualbox, and powershell

I'm attracted by the vision of immutable infrastructure and phoenix servers. Interactively logging into a server and working on it seems rather non-repeatable, and a source of potential errors. I'm not very far along the journey, but I am moving forward slowly.

Prompted by Matt Callanan's presentation of Expedia's "primer" platform, and Hashicorp's recent release of otto, I wanted to make some more progress. Reading about Microsoft's Nano Server (also this and this) was the trigger.

On my Windows 7 home PC, I've already played with vagrant before using virtualbox, so it was easy to find Matt Wrock's box to try. I thought I'd jot down a few of the obstacles I came across, in case it helps someone (perhaps me) in the future.

As a preface, I recommend installing chocolatey and then patheditor.

Install Vagrant and Virtualbox

Download and install the Vagrant msi package. I have version 1.7.4. Add the bin directory to your path. For me, it was C:\HashiCorp\Vagrant\bin

Download and install the Virtualbox installer. I have version 5.0.6. Add the directory containing VBoxManage.exe to your path. For me it was C:\Program Files\Oracle\VirtualBox

Clear Virtualbox Network Adapters

If you have already been using Virtualbox, it may be best to remove any network adapters that have been created. It took me several steps to get this right. There must be a nice command line way to do this, but I have resorted to the GUI. Start Virtualbox, and in File > Preferences, choose the Network entry in the list on the left. In the Host-only Networks tab (perhaps the NAT networks tab too), select any network, and click on the "-" button on the right.
If it seems that nothing is happening, check the task bar to see if there's a UAC shield requesting permission for Virtualbox to modify the system. That will happen for each network adapter you need to delete, and also again when the VM first starts.

Set up directory

Make yourself a fresh directory somewhere to do this test, and then open a cmd prompt to that directory. To set up the Vagrantfile, type
vagrant init mwrock/WindowsNano
And then start downloading the box file (only 327MB for a windows distribution!) if you don't already have it, and then building and booting the VM, type.
vagrant up --provider virtualbox
This will probably take several minutes. For me, the script finishes with a window containing the VM, and the cmd window showing a multiline error starting with "An error occurred executing a remote WinRM command." 

> vagrant up
Bringing machine 'default' up with 'virtualbox' provider...
==> default: Importing base box 'mwrock/windowsNano'...
==> default: Matching MAC address for NAT networking...
==> default: Checking if box 'mwrock/windowsNano' is up to date...
==> default: Setting the name of the VM: vagrant_default_1445065064697_71724
==> default: Clearing any previously set forwarded ports...
==> default: Clearing any previously set network interfaces...
==> default: Preparing network interfaces based on configuration...
    default: Adapter 1: nat
    default: Adapter 2: hostonly
==> default: Forwarding ports...
    default: 5985 => 55985 (adapter 1)
    default: 5986 => 55986 (adapter 1)
==> default: Running 'pre-boot' VM customizations...
==> default: Booting VM...
==> default: Waiting for machine to boot. This may take a few minutes...
    default: WinRM address: 127.0.0.1:55985
    default: WinRM username: vagrant
    default: WinRM transport: plaintext
An error occurred executing a remote WinRM command.

Shell: powershell
Command: hostname
if ($?) { exit 0 } else { if($LASTEXITCODE) { exit $LASTEXITCODE } else { exit 1 } }
Message: [WSMAN ERROR CODE: 2150859072]: The WinRS client cannot process the request. The server cannot set Code Page. You may want to use the CHCP command to change the client Code Page to 437 and receive the results in English.

This error can be ignored: it's a known issue for this box. On my PC, it isn't important to use the "--provider virtualbox" arguments, but it may be for you.

If you can't resist logging into the shiny new VM, type the username "vagrant", press tab twice to skip over the domain line, and type the password "vagrant", and press enter. You will see details of network adapters and address.

This is the extent of the user interface available with Nano Server. The only options available are to shutdown or reboot.

The network interface that this VM has is a NAT type, with two ports (5985, 5986) routed to the host. I wanted to have a "hostonly" network so that I could (eventually) interact with a variety of applications on the server.

Add hostonly network 

Getting a workable hostonly network was the part that took me the most work. Assuming that your priority is to get it working quickly, rather than see how little I know about virtualbox and vagrant, I won't describe my failed attempts. There may be better ways, but this one worked for me.

First step is to remove the last VM and ensure there are no hostonly interfaces lying around. Shutdown the virtual machine with ctrl-F12 enter. In the Virtualbox management GUI, right click on the vagrant_default machine in the column, and choose Remove... and Delete all files.

In File > Preferences, choose Networks and if there are any host-only adapters, remove them (again noting that this may require UAC permission).

With a text editor, edit the file Vagrantfile that was created in your directory. I found a section at lines 27-29 that looked like this
  # Create a private network, which allows host-only access to the machine
  # using a specific IP.                
  # config.vm.network "private_network", ip: "192.168.33.10"
Add a line below this one saying:
config.vm.network "private_network", type: "dhcp"
Save and close the editor, and then in your command window, type again:
vagrant up 
You may need to approve one or two UAC permission requests. This time, when the machine starts up and you login with vagrant/vagrant (no domain, again), you may see something like this.

At this point, you may look at your (host) computer's network adapters control panel, and see that there's one called "VirtualBox Host-Only Network". When I double click on it, choose Properties, and then double click on Internet Protocol v4, I see that the adapter address is 192.168.33.1. This initially seemed disappointing, since the VM address of 172.28.128.3 is not in the right subnet. Indeed, trying to ping 172.28.128.3 doesn't work.

But, in the Virtualbox manager GUI, look at the network adapter properties: File > Preferences, select Networks, then the Host-Only tab, select "VirtualBox Host-Only Network", and then click on the screwdriver icon. It shows me that the adapter's IP address is 172.28.128.1, which is in the same subnet as the machine. Out of interest, the next tab (DHCP server) shows that the VM has been given the first available address from the range indicated.

So why doesn't the ping work? I don't know. Maybe ping isn't enabled on the Nano box, or maybe there's a firewall. Perhaps I'll find out one day.

Connect Powershell to new VM

Start an elevated powershell. I do this by right-clicking on a CMD icon and choosing "Run as administrator", and then typing powershell.

To start working with the new VM, it's necessary to add it to your host computer's list of trusted hosts. To see if there are any there already, type
get-item wsman:\localhost\client\trustedhosts
If there are none, then you can add the new VM with
set-item wsman:\localhost\Client\TrustedHosts -value 172.28.128.3
If you already have some trusted hosts, and need to append this one to the list, the details here should help. The entries stored here will persist across reboots of your host computer, so you may not need to repeat this step.

The following commands (taken from Channel 9) don't need to be in an elevated shell, but perhaps it's easier to keep using the one you have. These two commands will set useful variables:
$ip = "172.28.128.3

$s = New-PSSession -ComputerName $ip -Credential $ip\vagrant
You'll be asked for the password in a separate dialog box. You know it's "vagrant". Then you can start working on your new VM with:
Enter-PSSession -Session $s
At last! You are now connected to the new machine, and you can use a variety of powershell (or cmd) commands to navigate around.

At this point, I recommend watching Rickster's 4-minute video to learn about copying files to and from the VM, and even editing and debugging scripts. It's on MSDN Channel 9. I discovered that I had to upgrade to Powershell version 5. The first download link I found (KB2908075) contained outdated certificates, but this one (KB3066439) seems ok.

Thanks to those whose work helped me get this far. If anything here didn't work for you, please leave a comment in case it helps others.