Assuming that we have a bigger Microsoft .NET project that has a structure like this:

  -- SubProject1
  -- SubProject1\SubProject1.sln
  -- SubProject1.Tests
  -- SubProject1.Tests\SubProject1.Tests.csproj
  -- SubProject2
  -- SubProject2\SubProject1.sln
  -- SubProject2.Tests
  -- SubProject2.Tests\SubProject2.Tests.csproj
  -- SubProject3
  -- SubProject3\SubProject1.sln
  -- SubProject3.Tests
  -- SubProject3.Tests\SubProject2.Tests.csproj

we can build it at once using MSBuild. Lets create a builder.proj file

<?xml version="1.0" encoding="utf-8"?>
<Project xmlns="" >
	<Solution Include="**\*.sln" />
	<TestAssemblies Include="**\**\bin\**\*Tests.dll"/>
<Target Name="Build">
  <MSBuild Projects="@(Solution)" Targets="Build"/>
<Target Name="Test">
  <Exec Condition=" '@(TestAssemblies)' != ''"
          Command="Mstest.exe /resultsfile:results.trx @(TestAssemblies ->'/testcontainer:"%(RecursiveDir)%(Filename)%(Extension)"', ' ')"
          ContinueOnError="true" IgnoreExitCode="true" />

and then we can execute

msbuild /t:Build builder.proj -- building the project
msuilbd /t:Test builder.proj -- running all tests


Sometime we face the situation that we need to copy the deployment results (or Artifacts) to some central repository where all deployments are stored. This is not a problem for Linux-to-Linux copy as we can use SCP, RSYNC or any other task. What if the target is a Windows machine though and if we want to customize the directory naming to be dependent on e.g. version of the product hidden in the exe file? PowerShell to the rescue! We need two pieces:

We need a Bamboo Remote Agent that is running on a Windows box - this will be doing the deployment itself and executing the PowerShell script.

A powershell script Task (normal Script task with the Powershell type selected) and a script that will do the actual copy

$VERSION=(dir Setup.Full.exe).VersionInfo.ProductVersion
Write-Host &quot;Saving artifacts to $DIR&quot;
New-Item -itemtype directory $DIR
Copy-Item * $DIR

What this script does is:

It sets current date to $TODAY variable It takes setup.full.exe and pulls out version information from inside It create a new directory in $DIR path Copies all files from the current deployment bamboo agent directory to the target $DIR

There is no template for Debian Wheezy while creating new VMs in XenServer. However, it is easy to clone it from the 6.0 version. Firstly we clone the template, then we change the parameters to use Wheezy.

# xe vm-clone uuid=`xe template-list name-label="Debian Squeeze 6.0 (64-bit)" --minimal` new-name-label="Debian Wheezy 7.0 (64-bit)"
# xe template-param-set other-config:default_template=true other-config:debian-release=wheezy uuid=`xe template-list name-label="Debian Wheezy 7.0 (64-bit)" --minimal`

If you ever try to talk from a script with Web Service that via WSDL definition, you may end up with a script like this:

use SOAP::Lite +trace => 'debug';
#use SOAP::Lite;
use Data::Dumper;
use strict;
use warnings;
my $serviceWsdl = 'http://server/service?wsdl';
my $soap = SOAP::Lite
my $result = $soap->serviceMethod();
unless ($result->fault) {
	print $result->result();
} else {
	print join ', ',

This will work with some web services, but with others it will not, especially when the method invoked on the service is parameter-less. The resulted XML code will show xsi:nil=”true” in the method invocation, what will effectively break the query. To overcome this, I just switched to Python and came up with this simple script:

from suds.client import Client
client = Client('http://server/service?wsdl')
print client.service.serviceMethod()

Puppet is great for centralised management of SSH keys on Linux boxes. The SSH module described in the project pages does its job really well for creating a new key pair and distributing it for clients (using the keys) and servers (authorized_keys file management).

The key generation mechanism provides several options to set up how the keys should be generated. One of them, is the maxdays options, defining how long the keys are valid. Because of that, I needed some mechanism to notify the users when their key has changed and they need to fetch new one. Normally, ssh::auth::server can be used for private key distribution, sometimes however this is not possible and that’s why this need floated.

To solve that, I thought that the simplest way will be to send an email that is set in the account properties. Basically the most crucial code needed is this one:

exec { "Create key $title: $keytype, $length bits":
      command => "ssh-keygen -t ${keytype} -b ${length} -f ${keyfile} -C \"${keytype} ${length}\" -N \"\"",
      user    => "puppet",
      group   => "puppet",
      creates => $keyfile,
      require => File[$keydir],
      before  => [File[$keyfile, "${keyfile}.pub"],Exec["Notify user ${email}"]]
    exec { "Notify user ${email}":
        command => "cat ${keyfile} | mail -s 'New SSH key notification' ${email}",
        subscribe => Exec["Create key $title: $keytype, $length bits"],
        refreshonly => true

The command for user notification is in the exec clause and it is using a simple mail command.

The full diff of modules/ssh/manifests/auth.pp is below:

Index: modules/ssh/manifests/auth.pp
--- modules/ssh/manifests/auth.pp
+++ modules/ssh/manifests/auth.pp
@@ -22,7 +22,7 @@
 # is done in the private definitions called by the virtual resources:
 # ssh_auth_key_{master,server,client}.                                
-define key ($ensure = "present", $filename = "", $force = false, $group = "puppet", $home = "", $keytype = "rsa", $length = 2048, $maxdays = "", $mindate = "", $options = "", $user = "") {
+define key ($ensure = "present", $filename = "", $force = false, $group = "puppet", $home = "", $keytype = "rsa", $length = 2048, $maxdays = "", $mindate = "", $options = "", $user = "", $email="") {                                                                                                                                                    
   ssh_auth_key_namecheck { "${title}-title": parm => "title", value => $title }
@@ -44,6 +44,7 @@
     length  => $_length,
     maxdays => $maxdays,
     mindate => $mindate,
+    email   => $email
   @ssh_auth_key_client { $title:
     ensure   => $ensure,
@@ -144,7 +145,7 @@
 # This definition is private, i.e. it is not intended to be called directly by users.
 # ssh::auth::key calls it to create virtual keys, which are realized in ssh::auth::keymaster.
-define ssh_auth_key_master ($ensure, $force, $keytype, $length, $maxdays, $mindate) {
+define ssh_auth_key_master ($ensure, $force, $keytype, $length, $maxdays, $mindate, $email) {
   Exec { path => "/usr/bin:/usr/sbin:/bin:/sbin" }
   File {
@@ -212,8 +213,14 @@
       group   => "puppet",
       creates => $keyfile,
       require => File[$keydir],
-      before  => File[$keyfile, "${keyfile}.pub"],
-    }
+      before  => [File[$keyfile, "${keyfile}.pub"],Exec["Notify user ${email}"]]
+    }
+    exec { "Notify user ${email}":
+       command => "echo 'A new SSH key for you has just been generated. Please fetch it from the server.' | mail -s 'New SSH key notification' ${email}",
+       subscribe => Exec["Create key $title: $keytype, $length bits"],
+       refreshonly => true
+    }
   } # if $ensure  == "present"