JunctionBox.ca

Branching by Abstraction 101

Committing to mainline is an important feature of CI and always keeping your mainline deployable is a requisite for Continuous Delivery and a cornerstone of DevOps. So what’s an easy way to maintain code quality and get new features in? Feature Flags and Branching by Abstraction!

So what exactly does this look like?

Let’s start with a simple function that outputs your name:

def name
	@first_name
end

Now we want to change the function but it’s going to be significant in someway, how would we achieve that while minimising the risk on the current functionality? The simplest way would be to introduce a binary variable that allows for flow control. I’m not a big fan of this option as it can lead down a difficult path for wiring in configuration files to it.

def name
	return name_flag_name2 if @enable_name2
	@name
end

def name_flag_name2
	# TBD
end

That’s a simple on/off approach for rolling out a new feature what if you want to do canary releases? Well you’ll need something that handles a little more logic:

def name
	return name_flag_name2 if @features.enabled?(:enable_name2, @user_account_type)
	@name
end

I leave the implementation details for the feature manager up to the user. Here are a few thoughts to consider during it’s implementation; How many application servers do you have? Do you want to control your features during release or live? How do you want to manage the configuration of those features? Are you interested in canary releases? How should the features be stored and how will queries to the storage medium affect performance?

Bootstrapping Windows

Finding myself back in the Windows domain I really miss package repository tools like YUM and apt-get. In what seems eons ago I used a toolset called Unattended for windows installations. It’s a little rough around the edges but it gave me some interesting ideas. I put together a quick script to download some common tools I find myself using on windows servers.

Here’s the general code cobbled together;

Const BINARY = 1
Const SAVE_CREATE_OVERWRITE = 2
Const SAVE_CREATE_NOT_EXIST = 1
Const ERR_DOWNLOAD_FILE_UNAVAILABLE = -1
Const ERR_DOWNLOAD_FILE_UNSAVABLE = -2
temp = WScript.CreateObject("Scripting.FileSystemObject").GetSpecialFolder(2).Path & "\"

Dim http, WshShell, file_stream

Set WshShell = WScript.CreateObject("WScript.Shell")



download_file "http://javadl.sun.com/webapps/download/AutoDL?BundleId=44457", "jre.exe"
WshShell.Run temp & "jre.exe /s /v ""/qn ADDLOCAL=ALL IEXPLORER=1""", 1, TRUE
' JRE


' Download a file to the temp folder and specified filename.
'
'
Function download_file(src, dest)
	' TODO: Add better error handling for http and file handles.

	Set http = CreateObject("MSXML2.ServerXMLHTTP")

	If IsNull(http) Then
		WScript.Echo "Microsoft.XmlHttp creation failed"
	End If

	http.open "GET", src, FALSE
	http.send

	Set file_stream = CreateObject("Adodb.Stream")

	file_stream.type = BINARY
	file_stream.open
	file_stream.write http.responseBody
	file_stream.saveToFile temp & dest, SAVE_CREATE_OVERWRITE 
	file_stream.close

	Set file_stream = nothing
	Set http = nothing
End Function

Initial Configuration of Puppetd on OS X

Configuring puppetd on OS X

Create the User and Group accounts;

sudo dscl . -create /Groups/puppet
sudo dscl . -create /Groups/puppet PrimaryGroupID 300

sudo dscl . -create /Users/puppet
sudo dscl . -create /Users/puppet PrimaryGroupID 300
sudo dscl . -create /Users/puppet UniqueID 300
sudo dscl . -create /Users/puppet UserShell /usr/bin/false

Create the folders

sudo mkdir /etc/puppet
sudo mkdir -p /var/puppet/log
sudo chown -R puppet:puppet /var/puppet
sudo chown -R puppet:puppet /etc/puppet

Create the config file.

sudo puppetd --genconfig > /etc/puppet/puppet.conf

Modify your /etc/hosts file with an entry for puppet (setting the server in the puppet.conf offers more flexibility should you move servers or change IP’s).

If you run into issues with your certificates;

Client

rm -rf /etc/puppet/ssl

Server

puppetca --clean CERT_ID

More Articles