Connect to Remote Machine via WinRM (PowerShell PSSession)

Unlike SSH, connecting to a remote host with WinRM requires a little bit of a setup.
Since this is required for chef test kitchen set up, and I end up re-Googling for this every time I set up a new machine, I decided it is worth a blog post.

So there are potentially two parts to this, dependent on whether WinRM is already set up on your machine:

Connect to remote machine

First set up your credentials. Open up PowerShell and run

 $cred = Get-Credential

This will prompt you for your credentials and save them in the $cred variable. Enter the credentials you intend to use to connect to the remote machine.
Now enter PSSession using your remote host IP and the credentials you have just set up:

 Enter-PSSession 192.168.XXX.XXX -Authentication "basic" -Credential=$cred

If you get the error:

The WinRM client cannot process the request…

Continue reading on how to set up WinRM on your machine:

Set up WinRm on your machine

Open CMD as administrator
Enable WinRM

winrm quickconfig /q

To check your current WinRM configuration

winrm get winrm/config

If you get the error:

The WinRM client cannot process the request. Unencrypted traffic is currently disabled in the client configuration.

Enable unencrypted traffic in WinRM:

winrm set winrm/config/client @{AllowUnencrypted="true"}

If you get the error:

The WinRM client cannot process the request. If the authentication scheme is different from Kerberos, or if the client computer is not joined to a domain, then HTTPS transport must be used or the destination machine must be added to the TrustedHosts configuration setting.

Add the remote computer you are connecting to to Trusted hosts:

winrm set winrm/config/client @{TrustedHosts="192.168.XXX.XXX"}

If you do this fairly often and are behind a secure firewall you can save some time by adding everyone to your trusted hosts:

winrm set winrm/config/client @{TrustedHosts="*"}

Happy Remoting!

No, wait, the mandatory meme:

remote session

Azure Web App Deployment Parameters for MSBuild (TeamCity Example)

Setting up automated publish steps on CI servers often requires setting up an MSBuild step to auto-deploy your application into an Azure Website. While you usually provide a .pubxml publishing profile for that, you also need to add MSBuild parameters for the publishing to work correctly.

My example here is with TeamCity, but it would work similarly with Jenkins or TFS.

TeamCity

MSBuild parameters
 /p:Configuration=Release /p:DeployOnBuild=true 
/p:PublishProfile=MyProjectPublishProfileName /p:UserName=$MyProjectUsername 
/p:Password=XXXXX /p:AllowUntrustedCertificate=true 
/p:VisualStudioVersion=12.0 /p:_DestinationType=AzureWebSite

Don’t omit the $ in the username!

Happy Deploying!

Enable Self-Signed Certificates in Azure API Management Services

Azure API Management Services does work with self-signed certificates, however you need to enable that option first. You can only enable the self-signed certificates by using the APIM REST API (not in the portal). This is a complete example of how to make REST API call.

 

Enable APIM REST API

The first step is to enable API Management REST API
In the old Azure portal (manage.windowsazure.com) select your API Management services and click Manage
manage APIM

 

In the API Management portal go to the Security tab
Check the Enable API Management REST API checkbox
enable rest api

Generate a security token (highlighted button on the left)

Make a PUT call to APIM REST API

Call URL
https://myApimName.management.azure-api.net/backends/MyApiSuffix?api-version=2014-02-14-preview

Authorize the call by copy-pasting the access token string in its entirety into the authorization header.
Call Headers:

Authorization: SharedAccessSignature uid=XXXXXX
Content-Type: application/json

header

Call Body:

{
    "host" : "MyApiUrl.com",
    "skipCertificateChainValidation" : "true"
}

body

If you are still getting errors from the APIM, or simply want to see more information about your call, go ahead and enable trace on APIM calls (to be continued in a blog post)

A-a-and a mandatory meme πŸ™‚

self signed doge

The Simplest Example Ever: How To Create and Use LWRP in Chef

This example will walk you through creating the most basic Chef LWRP starting from scratch or, in other words, a truly light weight lightweight resource provider πŸ™‚

lightweight

I am working with a cookbook named my_cookbook, and I will define an LWRP named awesome_lwrp.
To do this, I will need two files, the Resource and the Provider. By default, the names of the Provider and the Resource files should match.
 

Create the Resource

Create a new folder resources in your cookbook directory
Add a file named awesome_lwrp.rb

Define the simplest resource ever:

actions :add, :delete
default_action :add

attribute :awesomeString, :kind_of => String, :required => true
attribute :awesomeInt, :kind_of => Integer, :required => false, :default => 3

Explanation:
awesome_lwrp supports two actions, add and delete. The default action is add.
awesome_lwrp accepts two arguments. The first one is a string, and it is required. The second one is an integer, it is optional and has a default value of 3.

 

Create the Provider

Create a new folder providers in your cookbook directory
Add a file named awesome_lwrp.rb

Defining a simple provider:

# Support β€œno-operation” mode
def whyrun_supported?
  true
end

# Should be considered a requirement for any
# lightweight resource authored against the 11.0+ versions of the chef-client
# Using this method ensures that the chef-client can notify parent lightweight resources
# after embedded resources have finished processing
use_inline_resources

# Implement action "add"
action :add do
  # Check condition
  # Use resource attribute
  if powershell_output_true?(@new_resource.awesomeInt)
    Chef::Log.debug "No need for changes!"
  else
    # Use converge_by for whyrun mode
    converge_by("Making awesome LWRP updates") do
      # Execute updates
      # Use resource attribute
      run_powershell_script(@new_resource.awesomeString)
      # Notify that a node was updated successfully (actually redundant here)
      @new_resource.updated_by_last_action(true)
      Chef::Log.debug "Awesome String was echoed"
    end
  end
end

action :delete do
  # Some code here
end

# Execute updates - this is a dummy method that simply echoes a string
def run_powershell_script(awesomeString)
  powershell_script 'Awesome Script' do
      code "echo " + awesomeString
      action :run
  end
end

# Check if updates need to be executed
def powershell_output_true?(awesomeInt)
  # A powershell command that returns false so that the update will get executed
  ps_command = "(1+1) -eq " + awesomeInt.to_s
  cmd_str = "powershell -Command " " + ps_command + " " "
  # Run powershell from cmd
  cmd = shell_out(cmd_str, { :returns => [0] })
  # Check powershell output
  if(cmd.stdout =~ /true/i)
     Chef::Log.debug "PowerShell output is true"
    return true
  else
    Chef::Log.debug "PowerShell output is false"
    return false
  end
end

What this code does:
For the sake of simplicity only the “add” action is implemented.
The “add” action checks if the updates are needed, and if the answer is yes it executes the updates and notifies the chef server that the node was updated. I am using dummy PowerShell methods simply to demonstrate the method flow.

Note that:

  • It is best practice to use use_inline_resources
  • The attributes supplied to the resource can be accessed using @new_resource.attributeName
  • It is good practice to call @new_resource.updated_by_last_action(true) if updates were executed, however it is redundant if you are using use_inline_resources and/or converge_by
  • whyrun is used in combination with converge_by statements to support a “no-operation” mode, in which chef-client is printing out what updates would be executed, without actually executing them

I am not going to go into depth on whyrun_supported and use_inline_resources. For details please check chef docs

 

Calling the new awesome LWRP

Now you can call the resource in your recipe as following:

my_cookbook_awesome_lwrp 'Awesome Resource Name' do
  action :add
  awesomeString node['my_cookbook']['awesome-string']
end

Note that:

  • The default LWRP name is the concatenation of the cookbook name with the resource/provider name using underscores.
  • Instantiated resource name (in this case ‘Awesome Resource Name’) needs to be provided to use the LWRP.
  • The required attributes are required πŸ˜‰
Appendix

In this example the LWRP is called with a node attribute. The node attribute can be defined in attributes/default.rb as following:

default['my_cookbook']['awesome-string'] = "Pumpkin Pie!"

 
* If your kitchen fails to recognize the method shell_out you need a newer version of Chef. Please specify this in your kitchen.yml

provisioner:
  name: chef_solo
  require_chef_omnibus: 12.4.1

 
That’s it! Happy lifting πŸ˜‰

Syntax Hell: Check PowerShell Command Output in Ruby (Chef)

I ran into this while creating an LWRP, and while the code below addresses a very straightforward need, the syntax is anything but straightforward, and is definitely worth documenting.

I am running a one line PowerShell command that outputs True or False, and I want my Ruby method return value to be the same as PowerShell command return value.
Reading the output from the powershell_script is not easy, so instead I am going to run my PowerShell command from the cmd and read the shell_out, and then compare the stdout of the command to “true” or “false”.
The code below is the most simplistic example:

def powershell_output_true?()
  ps_command = "(1+1) -eq 2"
  cmd_str = "powershell -Command " " + ps_command + " " "
  cmd = shell_out(cmd_str, { :returns => [0] })
  if(cmd.stdout =~ /true/i)
     Chef::Log.debug "PowerShell output is true"
    return true
  else
    Chef::Log.debug "PowerShell output is false"
    return false
  end
end

 
To compare stdout to a custom string:

def powershell_output_expected?()
  ps_command = "\"sum = {0}\" -f (1+2)"
  cmd_str = "powershell -Command " " + ps_command + " " "
  cmd = shell_out(cmd_str, { :returns => [0] })
  if(cmd.stdout =~ /sum = 3/i)
    Chef::Log.debug "PowerShell output is as expected"
    return true
  else
    Chef::Log.debug "PowerShell output is not as expected"
    return false
  end
end

The triple backslash here is to escape a quote inside of the PowerShell command. The output of the command is “sum = 3” .

Hope this saves you an hour or two of debugging from hell πŸ™‚
And one for the road:

syntax

How to pass an array Chef node attribute to powershell_script

This is a very short post on the magic of syntax in Chef + PowerShell .

My goal here is to pass an array of strings from Chef node attribute to powershell_script. The problem is that if I define a string array in ruby it fails with a syntax error in powershell. The answer on how to do it turned out to be fairly simple – if you define the node attribute to be a string using a combination of single and double quotes (see the example below) it is converted into an array in PowerShell code.

Attribute:

default['cookbook-name']['attribute-name'] = "'value1', 'value2', 'value3'"

And recipe:

powershell_script 'my script' do
  code <<-EOH
  $array = #{node['cookbook-name']['attribute-name']}
  ...
  EOH
  action :run
  guard_interpreter :powershell_script
  not_if "..."
end

 
That’s it! Happy cooking πŸ˜‰

How to Resize Vagrant Base Box VMDK Hard Disk with VirtualBox

Given: a vagrant base box with 10GB VMDK hard disk
Required: a vagrant base box with the same configuration and a 50GB hard disk

Import the .box file into VirtualBox

Add box from a local file to vagrant boxes

vagrant box add vagrantBoxName file:///C:boxesboxName.box

Notice that the file location is in URL formal
Verify that the box was added:

vagrant box list

By default, the box is created in C:Users%USERNAME%.vagrant.dboxesvagrantBoxName

Verify that the VM works:
Open VirtualBox -> File -> Import Appliance
Browse to C:Users%USERNAME%.vagrant.dboxesvagrantBoxNamevirtualbox
Select the box.ovf file
import
Import and start the machine.
If the VM runs successfully and the configuration is correct, shut the VM down. Make sure it’s in Powered Off state.

Resize the hard disk

Currently you cannot resize VMDK files with VirtualBox, but it is possible to clone VMDK to VDI and resize the VDI, and this is what we are going to do.

Open PowerShell (this will also work from cmd)
Navigate to the VirtualBox directory to be able to run VBoxManage
cd “C:Program FilesOracleVirtualBox”

By default the new VirtualBox VM is located at C:Users%USERNAME%VirtualBox VMsboxName. Let’s assume that your vmdk hard disk name is disk1.vmdk. Then the commands you need to run are the following:

Clone .vmdk to .vdi:

./VBoxManage clonehd "C:Users%USERNAME%VirtualBox VMsboxNamedisk1.vmdk" "C:Users%USERNAME%VirtualBox VMsboxNamecloned.vdi" --format vdi

Resize the .vdi 50GB (give size in MB)

./VBoxManage modifyhd "C:Users%USERNAME%VirtualBox VMsboxNamecloned.vdi" --resize 51200

Clone to a new .vmdk (to avoid file conflicts)

./VBoxManage clonehd "C:Users%USERNAME%VirtualBox VMsboxNamecloned.vdi" "C:Users%USERNAME%VirtualBox VMsboxNamedisk2.vmdk" --format vmdk
Replace the disk in VirtualBox

Open VirtualBox -> Select VM Name -> Storage -> Controller SATA -> Add Storage (Diskette with a plus sign on the bottom) -> Choose Existing Disk -> Browse and choose new VMDK
Click on the old disk, click on remove (Diskette with a minus sign on the bottom)

choose disk
Click OK
Start the VM and make sure it works correctly

Extend disk partition

On the VM, hit WinKey and type “disk management” into search
Select Create and format hard disk partitions
In the disk management tool select the disk you need to expand, right click -> Extend Volume
extend
Follow the wizard until finished.
Check that your disk has the correct size now.

Package the box with vagrant:

There are a couple of things you need to take care of prior to creating a base box. Most of them, however, should already be in place since you have started off with a configured VM. Here is the bare minimum list:

  • Note the VM’s MAC address from VirtualBox -> Select VM Name -> Settings -> Network -> Advanced
  • Make sure VirtualBox Guest Additions are installed.

For more info take a look at Vagrant Base Box

With PowerShell, navigate to the location on disk where you would like the box to be created.
Now, package the box:

vagrant package --base VirtualBoxVmName --output newBoxName.box

 
Your new base box was created!
Now I would go through the first few steps of this post to verify that the VM created from the box will work as expected.
That’s it!
Happy boxing πŸ˜‰

Jenkins Post Build Step – Execute Script

To execute a post-build script in Jenkins

Install Post Build Task Plugin
By going to Dashboard -> Manage Jenkins -> Manage Plugins -> Available -> Filter -> “Post build task”

Yes, the UI kind of sucks, anyone wants to contribute to Jenkins by improving the UX/UI design? =)

To configure the step

Go to your Jenkins job
Click Configure
Look for “Add post-build action”
Select “Post build task”
post build task

Now, the plugin looks for STRING MATCHES in the console output of the build. (I am only highlighting this because I had a typical RTFM case this morning)
So, if you want to execute the task when a specific event happens, you need it to look for that event’s output in the console log. Let’s say the output that signifies failure is this: “Build step ‘Execute Windows batch command’ marked build as failure”. You can add the substring “marked build as failure” as my Log Text, like so:
build step

You can use the AND and OR operation to perform the same script in multiple cases (such as different exceptions).

Custom Domain in WordPress on Azure Web App

Since I had to go through this process a few times lately, and it is not as straightforward as one could hope, I think the world needs this post πŸ™‚

Create the DNS records

I have tried a number of options until I was able to get both the root domain and the www subdomain verified in Azure portal.
I am using CloudFlare, and my DNS records look like this:
dns cloudflare

Add custom domain to Azure Web App

At this point if you try to access your domain you will get the following error: “Error 404 – Web app not found … The web app owner has registered a custom domain to point to the Microsoft Azure App Service, but has not yet configured Azure to recognize it”
web app not found
 
To fix this error, you will need to add your custom domain as a hostname in Azure portal.
Browse to your Web App => All settings => Custom domains and SSL => HOSTNAMES ASSIGNED TO SITE, and add both the root and the www subdomain.
portal domains
You may need to allow for some time after you have configured your DNS records. The official time frame for propagating domains is up to 24 hours, but in my experience if the DNS is set correctly it won’t take longer than 20 minutes.

Now if you browse to your domain you will see your WordPress site, yay!
However, you aren’t done yet.
If you click on one of the links on the site you will notice that WordPress still redirects you to the initial domain on someone.azurewebsites.net. To fix that you need to update the domain set in WordPress itself.
 
DO NOT update it through WordPress Dashboard => Settings => General. This does not work (at least currently) and might lock you out of the application! 😯
Instead you will need to FTP into your site and change the functions.php of your currently active theme.

FTP into the site using FileZilla

Get FTP credentials:
In the portal, browse to your Web App and click on get publish profile.
get profile

Open the publish settings file you have downloaded, and look for FTP.
Copy the publishUrl, userName and userPWD into FileZilla and click Quickconnect. (The publishUrl is the Host).
 
filezilla
* I chose FileZilla for the demonstration since it is free and easy to use. You can certainly use other applications to FTP into the site.

Update siteurl in functions.php

Browse to your /site/wwwroot/wp-content/themes/THEME_NAME, where THEME_NAME is the name of your active theme.
Find the file functions.php and copy it over to your local machine (or simply right-click and choose View/Edit to edit the file on the fly).
Add the following two lines right after the opening

<?php

tag

update_option('siteurl','http://divineops.net');
update_option('home','http://divineops.net');

 
So, in my case the file now looks like this:
functions_php

 
Upload the file back into the site using FileZilla.
* Note that your active theme might not have a functions.php file. In this case you can add one yourself. Please read this post for further details https://codex.wordpress.org/Changing_The_Site_URL
 
Your site will be down for a couple of minutes, so wait for it to come back up and sign in. Now you can browse to WordPress Dashboard => Settings => General and see if the URL settings got updated:
wordpress url
Now that your site is back up and running, you should remove the lines you added from functions.php. The WordPress manual claims it is important to clean them up πŸ˜‰

OK, we are good to go! Anyone who browses to your site will now be redirected to the siteurl you just set up as a root URL, regardless of how they got to the site in the first place. Happy browsing!