Nov 11, 2014

The 5-minute guide to getting Vagrant up and running (Windows .box edition)

This blog post came about because I had an emergency need a fresh Windows box on the Macbook I'm using. took me a few seconds to get up and running, so why 5 min? Because I already had vagrant installed and .box file available.

It will really take you about 35 seconds to get up and running, but you still need to download and install some stuff.

Minute 1 - Download and install Vagrant

Minute 2 - Download and Install Virtual Box

Minute 3-4 - Download a Windows .box file

We're going to use Windows 7 Enterprise x86 - others are available here:

  • Open Command line
  • Execute: vagrant box add alex_rocks

Minute 5 - Get vagrant box up and running

This is the only step I had to do to get up and running
  • Open command line and create a new folder (example - C:\vagrant_test)
  • Go to that folder and type vagrant init
  • Edit the Vagrantfile and paste the following gist into it:
  • Save, Exit
  • execute: Vagrant up

Minute 6 - Do whatever you need to do with the Windows you now have. 

...what's a blog post with no pictures?

Nov 10, 2014

Maintaining access to PC while away from home (plus nuclear backup option)

This is fairly straight forward and takes roughly 30 to 45 minutes to configure. If you hadn't done it before, I'd say it'll take about 2 hours.

You are going to Abu Dhabi, but you still want to access your home (windows) PC.


a) Create backup user (just in case)
b) Enable remote desktop (RDP).
c) Install and configure DNS client to have a stable 'dial-home' address.
d) Configure WOL (wake on LAN) on PC.
e) Configure router to allow remote connections and WOL
f) Configure Scheduled task
g) Configure Power Management
h) Test (also make sure you have whatever notes you need).
z) Plan Z

A) Create backup user

Right click on My Computer, select manage, select users.
There will be a link somewhere to create a user, or just click on a blank space below existing users.
Select New user.
Enter username - something not super obvious like "backup". Instead, make it 'remote' or 'alex2'
Give it a password, check box for 'password never expires', check box for 'user cant change password'. Go to groups, and add 'administrator' group to the list. Click OK.
If you are prompted to enable Firewall rules to allow remote user, click 'yes'
If your antivirus says something, read it, and select whatever options would allow connections.

B) Enable remote desktop (RDP)

Right click on My Computer, select properties, select remote tab, check the box to enable remote access.
Click users button, and add the 'remote' user you created in Step A.

C) Install and configure DNS client to have a stable 'dial-home' address.

Since your ISP can change your IP address (and will change it almost daily) you need a way to find your computer. This is why we install DNS client. It will update your IP every time your computer starts, and map it to a public DNS address which you will use from Zimbabwe or wherever.

My all time favorite app 'DynDNS' is now a paid app, so it instantly seised to be my favorite app.
I've tried and it seems to work really well. It also allows you google signin, which is nice /borat.

Install - go to, sing in, and install the client.
Pick a name and enter it in a white box next to "domains". This will be the consistent 'stable' DNS name that you will use to connect to your home PC.
Now, go ahead and start the DuckDNS if it's not already started. It will show up in your task bar (bottom right).
Right click on it, and pick settings.
Enter the DNS name and token 
- DNS you chose (may be the whole name, I am writing this from memory) - 
- Token is available on the top of the webpage after you login.
Make sure you can click OK and things are green, and update works.

Testing via ping wont work, DuckDNS guys protect you from discovery, which is also very nice /borat. 

D) Configure WOL (wake on LAN) on PC and Wake on Timer.

Probably your PC is not configured for Wake on LAN. Most are not.
You will also enable a 'backup' plan to make sure your PC is awake during certain hours.
You will have to reboot the PC, go into BIOS, enable it and save the change.

WOL settings
Reboot PC.
Press DEL key or F2 or F10 like 7000 times. Start mashing the button as soon as you hear a *beep*.
Once inside look either in Power Settings or Network, or Advanced for "WOL" or "Wake-on-Lan" or "Magic packet".
Enable it.
If you have an option for password, enable it as well, and set some easy password, like 'sparky'.
Write the password down.

Setting Wake on Timer
While looking for WOL you may have seen 'Alarm' or 'Timer' or 'Wake on Event' or 'Schedule' or 'Wake on Schedule' or any other permutation of words indication that something will happen at a particular point in time or on event.

Once you find it - Probably under Power Management (might be under advanced).
Set the Wake up timer to around 8am of the timezone where you'll be at.

E) Configure router to allow remote connections and WOL 

Once Windows boots back up. Go to your router config page.
If you hadn't changed any of the default settings on your router, you most likely have a sticker with all of the info on the back of the router. If you have changed defaults, you probably know what you're doing.

Create 2 rules - one for RDP, another for WOL

Go to config page - or something like that
Go to port forwarding page, or Advanced section and then port forwarding.
You should see a button to create a new rule.
Create a rule -
- Name it something descriptive like 'home pc RDP'.
- under trigger or incoming port (usually this is either on the left side or on top of the new rule box) enter some random 5 digit number below 65000. (example 49381 - write it down)
-- we pick a random incoming port instead of mapping 3389 to 3389 to create a tiny bit of security against random port scans. Call it security through obscurity. Every little bit helps.
- for destination port enter 3389
- for destination pc you may either have a drop-down or a list of computers. Best way is to pick a MAC address if you have it. Otherwise Pick a name. If neither of these is available, pick an IP.
-- IP is generally a bad idea, because your router can reassign IP address to your PC if you lose power or if it decides it's a good idea. If you are feeling comfortable in this arena, dig through the settings and see if you can assign a static IP to your computer somewhere to keep this from happening.
Click Save.

Your router *may* have a specific setting for WOL but I rarely seen this. If it does, enable it, and you're golden.
Using the steps above, you will create 2 additional rules for WOL  - one for port 7, another for port 9.
I think there is a much lesser need to remap ports here, but you still can.

Click add rule
Name - WOL_7
Source port - 7 (or whatever 5 digit number below 65000 - make sure to write it down)
Destination port 7
Destination PC - Your PC by MAC / Name / IP

Click add rule
Name - WOL_9
Source port - 9 (or whatever 5 digit number below 65000 - make sure to write it down)
Destination port 9
Destination PC - Your PC by MAC / Name / IP

F) Configure Scheduled task

In 'Wake on Timer' section we set our PC to wake up at 8am every day.
Now we don't want the PC to run non-stop all day, but we also don't want it to go to sleep, because I've seen WOL fail if PC is sleeping. So instead, we are going to shut it down after 2 hours.

Click Start, type task, count to 3, and you will see 'Scheduled Task' appear.
Select it
Select tasks from the left side
Select 'new task'
Name it something descriptive like - Shut down PC after 2 hours of being awake.
Under Triggers tab, click 'add' or 'new' specify the time 2 hours after you've set it to automatically wake up.
Under Actions tab, click add.
- command will be 'cmd' (no quotes)
- switches will be '/c shutdown /s /t 30 /f' (no quotes)
-- cmd will open command prompt. /c will close it after command executed. /s is to shutdown /t 30 is to wait 30 seconds - if you're logged in, you'll get a warning and a chance to abort it. /f is to force - in case some app is stuck.
Under Advanced
- specify options to run the task if scheduled time was missed.
- specify to kill task if ran for more than 2 hours
- specify other options if may find relevant
- click check box to run using higher privileges.
When you press OK enter your password.

G) Configure Power Management

Press Start
Type power, count to 3, you will see "power management" appear towards the top of the list.
At the main menu, specify turn off monitors after 1 minute - you wont need them since you're connecting remote.
Under sleep specify never - you'll be turning PC off after 2 hours via task above
Under hibernate specify never - same reason as above
Click Advanced
Select 'performance plan'
Click OK till you exit

H) Test it.

Remote login and DNS
You can test it from the same PC, or if you have another one, test it from there.
**If you're testing from the computer you're connecting to, you wont be able to actually login, but if you get the login box, you're in a good place.

Open command prompt - Start+R, type CMD, press enter
type mstsc /
-- mstsc is a program for remote desktop
-- /v is a switch for address
-- : is the DNS name you chose yourself
-- RDPportNumber is the port in your router that will forward to 3389
-- example command :    mstsc /

you should get a login box.
-- If you get login box 99% of the stuff you configured is working.
You will see username and password and under domain you will have a name of the box you're presently on, not the name of the box you're connecting to.
Enter username as <computer name you're connecting to>\username
-- example: ALEX-PC\Alex2
Enter password
Press OK

Testing WOL

Turn computer OFF.
On another computer or cellphone, go to 
-- I've used it for years, but I dont actually know anything about them, or if it still works today
Enter necessary info
-- At this point you will realize you dont have a MAC address because I never told you to write it down.
-- Obtain and write down your MAC address

IP or Hostname -
-- example -
MAC will be your MAC 
-- example - 01-23-45-67-89-ab
Password / schedule / zone are optional
Press "Wake up my pc!" button

Count to 3 or maybe 42
Your PC should turn on.

Testing Wake on Schedule

You can either wait until the scheduled time and see if PC turns on
You can go back into the BIOS and change the wake up timer to around 2 minutes in the future.
Turn off PC
Count to 120
PC should turn on
Go into BIOS and Change the timer back to Zimbabwe 8am

Testing Scheduled task

Go to Windows
Right click on your task
Click Run
Count to 30
PC should turn off

Obligatory funny -

Plan Z

This is my new favorite recommendation because it works, but it's definitely the heavy handed approach.
- Make an account at (hosted chef - main url here
- Download and Install chef-client. Make sure to check the service check-box. 
-- Get files from (main url - )
- Connect (chef term is bootstrap) your home PC to your hosted Chef account.
-- This is probably the most 'complicated' step in the whole process. Best and simplest way is to head over to instead of me retyping same same stuff here.

Plan Z in action:
Once your PC is connected to Chef server, you will be able to add items to be executed on your PC from anywhere on the planet without actually ever having to connect to your PC. If your router changes, your PC gets stolen. As long as it's working and has access to internet, you can execute commands on it.

Sep 22, 2014

Working with Chef and Vagrant while on VPN

I've been beating my head against every object in my living room for the last 2 hours.

Last time this happened it turned out that the VPN I was on was blocking all 10.* addresses - in case you didnt realize, Vagrant assigns 10.* address by default. So simply changing the network IP address in Vagrantfile solved the problem.

Solution to internal network blocking 10.* addresses: :public_network, ip: ""

Well, something happened and everything stopped working again (I am a consultant for a company, so perhaps something got locked down just for contingent staff, because all of the FTEs can work just fine with default config).

Solution is to allow VPN passthrough in Vagrantfile:
... :private_network, ip: ""
config.vm.provider :virtualbox do |p|
    p.gui = true
    p.customize ["modifyvm", :id, "--memory", "1500", "--clipboard", "bidirectional", "--natdnshostresolver1", "on"]

* shamelessly stolen from a random (but very useful) site I found after banging my head against a keyboard failed to produce the desired outcome. (source: (I even kept the pretty code background)).

Random yet very accurate and completely unrelated funny

Aug 12, 2014

STIG, Windows2012, ACL, ACE, Registry, and aneurism

It's a very rewarding feeling, when after hours of research, google, and beating your head against the table, you finally come up with an answer. But I can't help feeling that 3 lines of code for 10 hours of research somehow diminish the sense of accomplishment. Not to say that I want 300 lines, but you know...

STIG and CIS benchmark documentation are as useful as they are impractical in the modern age. It's pages upon pages of useless manual steps. It's 2014.  TWENTY FOURTEEN!!  Unless you manage 4 systems that you NEVER rebuild, no one in their right mind is going to do this nonsense manually.

Example of nonsense:
Configure the policy value for Computer Configuration -> Windows Settings -> Security Settings -> Advanced Audit Policy Configuration -> System Audit Policies -> Global Object Access Auditing -> "File system" with the following: Select All Items.

The challenge at hand was automating implementation and validation of STIG V-1080:

Use the AuditPol tool to review the current configuration.Open a Command Prompt with elevated privileges ("Run as Administrator").  Enter "Auditpol /resourceSACL /type:File /view". ("File" in the /type parameter is case sensitive). The following results should be displayed:

Entry: 1
Resource Type: 

The command was successfully executed.

Apparently it's not at all easy to apply Auditing rules to registry via CMD or Powershell.
Microsoft documentation leaves a lot to your imagination.

And as always, the answer was a mixture of Stackoverflow and blogs:

Step 1. Set the Audit rules manually.
Step 2. Get the SDDL from registry
$acl = get-acl hklm:\software
Step 3. Apply SDDL via automation

$acl  = get-acl HKLM:\SOFTWARE
set-acl -Path HKLM:\\SOFTWARE -AclObject $acl

Step 4. Write Chef recipe and Serverspec integration test
Step 5. Realize that for some reason (either too much coffee or not enough) I confused two STIG rules and spent a mile walking in a direction of applying Auditing to HKLM:\Software instead of C:\ (Easy mistake to make I suppose)
Step 6. Change the script to actually apply auditing to all Drives instead.

Step 7. Make Chef recipe
Step 8. Make integration test via Serverspec

Useful links (in order of usefulness):


Jul 15, 2014

RHEL from a Windows guy

As ironic as it sounds, it wasnt until just a few months ago that I finally learned what RHEL stood for. That's 1994 - 2014. Nearly 20 years of blissful ignorance..

Now, I have a task to test a set of Chef recipes on RHEL 6.5 ... in Japanese.

So... questions are - 
1) How do I install RHEL?
2) How do I get it into Japanese?

... this is going to be as much of a brain dump, as a manual for myself to retrace my steps so that I can write a Chef cookbook automate everything when the time comes..

For the record - My workstation is a mac running OSX 10.9.4

1 - Getting RHEL box up.

Apparently you need some special license which you have to pay for. And I know nothing about it... nor does it have anything to do with what i'm trying to do. So to get some lift, I went with AWS.

Login, EC2 -> New server -> RHEL 6.5 -> Micro. Alternatively, you could spin up a CentOS box from which will be *almost* the exact same thing, but not really. So to avoid duplication I wanted actual RHEL. Also, you can use knife-ec2.

Even that has a tiny yak that one must shave.
  a) create an AWS key (aka AIM)
  b) save it locally
  c) fail to SSH using the key
  d) Google to find out that you need to change permissions on the key
  e) CHMOD the pem key 
  f) ssh success

Ok. I'm in, now to validate if my RHEL is the actual version I need it to be.
   a) attempt a few obvious commands.
   b) fail
   c) google (
   d) lsb_release -i -r
   e) above fails on some boxes, one alternative is to cat /etc/redhat-release

2 - How do I get it into Japanese

a) google...official documentation
b) read -

Per kickstart docs, installation doesn't support Japanese / Chinese / few other languages, and defaults to English, which is great. One less test case to worry about and theoretically I won't have to deal with Kickstart since all configs can be done post OS.

On a related note, it sounds like there are 4 language settings:
* keyboard
* UI
* shell
* runtime  
btw - example kickstart files can be found here -

c) fail.. system-config-language does not exist
..) google...
..) sudo yum install system-config-language
So.. i have no idea what the root password is, and I don't feel like resetting it or using EC2 UI again..
..) sudo su - 
..) system-config-language
..) scroll down..... tab tab.. ok!
..) Everything's still in English. now what? 

Turns out that by default, many linux distros will take on the locale of the system initiating the SSH connection. So there are a couple of other configuration steps needed to be done:

So in Summary:

  • lsb_release -i -r   or    cat /etc/redhat-release
  • sudo su -
  • yum install system-config-keyboard
  • yum install system-config-language
  • system-config-keyboard (should obviously be done first, otherwise the language selection is in Japanese.)
  • system-config-language
  • modify "keytable" value in  keyboard setting file /etc/sysconfig/keyboard (set it to jp106)

Keyboard maps available maps here -- /lib/kbd/keymaps/i386/qwerty/

Good discussion on the topic:
Finally found something very useful...confirming my suspicions that changes were only temporary unless some file was actually modified to set them in stone:

-------------random unarranged stuff below this line -----------

3 - other stuff

bootstrapping AWS box is a little bit tricker now than it was a few months ago
gotta use the pem key, so you can literally grab the -i switch from SSH command and dump it into knife bootstrap

knife bootstrap 54.208.333.333 -x ec2-user -i ../../Projects/Amazon/alex.pem --sudo

Jun 24, 2014

Git aliases for my Powershell friends

For my windows friends.

In retrospect, I realized that OSX gives you some niftly little shortcuts that I pretty much take for granted. A list of Git Aliases that comes with Dotfiles is something I took for granted. It sure would be nice to have had these a year ago. Here it is for all of my Powershell Friends:

just ctrl+h alias to new-alias and dump it somewhere in your powershell's $profile

alias g=git
alias gCa='git add $(gCl)'
alias gCe='git mergetool $(gCl)'
alias gCl='git status | sed -n "s/^.*both [a-z]*ed: *//p"'
alias gCo='git checkout --ours --'
alias gCt='git checkout --theirs --'
alias gR='git remote'
alias gRa='git remote add'
alias gRb=git-hub-browse
alias gRl='git remote --verbose'
alias gRm='git remote rename'
alias gRp='git remote prune'
alias gRs='git remote show'
alias gRu='git remote update'
alias gRx='git remote rm'
alias gS='git submodule'
alias gSI='git submodule update --init --recursive'
alias gSa='git submodule add'
alias gSf='git submodule foreach'
alias gSi='git submodule init'
alias gSl='git submodule status'
alias gSm=git-submodule-move
alias gSs='git submodule sync'
alias gSu='git submodule foreach git pull origin master'
alias gSx=git-submodule-remove
alias ga='git add -A'
alias gam='git amend --reset-author'
alias gb='git b'
alias gbL='git branch -av'
alias gbM='git branch -M'
alias gbS='git show-branch -a'
alias gbX='git branch -D'
alias gbb='git bisect bad'
alias gbc='git checkout -b'
alias gbd='git b -D -w'
alias gbg='git bisect good'
alias gbi='git rebase --interactive'
alias gbl='git branch -v'
alias gbm='git branch -m'
alias gbs='git show-branch'
alias gbx='git branch -d'
alias gc='git commit --verbose'
alias gcF='git commit --verbose --amend'
alias gcO='git checkout --patch'
alias gcP='git cherry-pick --no-commit'
alias gcR='git reset "HEAD^"'
alias gca='git commit --verbose --all'
alias gcf='git commit --amend --reuse-message HEAD'
alias gci='git ci'
alias gcim='git ci -m'
alias gcl=git-commit-lost
alias gcln='git clean'
alias gclndf='git clean -df'
alias gclndfx='git clean -dfx'
alias gcm='git ci -m'
alias gco='git co'
alias gcp='git cp'
alias gcr='git revert'
alias gcs='git show'
alias gd='git diff'
alias gdc='git diff --cached -w'
alias gdi='git status --porcelain --short --ignored | sed -n "s/^!! //p"'
alias gdk='git ls-files --killed'
alias gdm='git ls-files --modified'
alias gdu='git ls-files --other --exclude-standard'
alias gdx='git ls-files --deleted'
alias gf='git fetch'
alias gfc='git clone'
alias gfch='git fetch'
alias gfm='git pull'
alias gfr='git pull --rebase'
alias gg='git grep'
alias ggL='git grep --files-without-matches'
alias ggi='git grep --ignore-case'
alias ggl='git grep --files-with-matches'
alias ggrc='git rebase --continue'
alias ggv='git grep --invert-match'
alias ggw='git grep --word-regexp'
alias gi='vim .gitignore'
alias giA='git add --patch'
alias giD='git diff --no-ext-diff --cached --word-diff'
alias giR='git reset --patch'
alias giX='git rm -rf --cached'
alias gia='git add'
alias gid='git diff --no-ext-diff --cached'
alias gir='git reset'
alias git='noglob git'
alias giu='git add --update'
alias gix='git rm -r --cached'
alias gl='git l'
alias glb='git log --topo-order --pretty=format:${_git_log_brief_format}'
alias glc='git shortlog --summary --numbered'
alias gld='git log --topo-order --stat --patch --full-diff --pretty=format:${_git_log_medium_format}'
alias glg='git l'
alias glo='git log --topo-order --pretty=format:${_git_log_oneline_format}'
alias glog='git l'
alias gls='git log --topo-order --stat --pretty=format:${_git_log_medium_format}'
alias gm='git merge'
alias gmC='git merge --no-commit'
alias gmF='git merge --no-ff'
alias gma='git merge --abort'
alias gms='git merge --squash'
alias gmt='git mergetool'
alias gnb='git nb'
alias gp='git push'
alias gpA='git push --all && git push --tags'
alias gpa='git push --all'
alias gpc='git push --set-upstream origin "$(git-branch-current 2> /dev/null)"'
alias gpf='git push --force'
alias gpl='git pull'
alias gplr='git pull --rebase'
alias gpp='git pull origin "$(git-branch-current 2> /dev/null)" && git push origin "$(git-branch-current 2> /dev/null)"'
alias gps='git push'
alias gpsh='git push'
alias gpt='git push --tags'
alias gr='git rebase'
alias gra='git rebase --abort'
alias grad='git remote add'
alias grc='git rebase --continue'
alias gri='git rebase --interactive'
alias grr='git remote rm'
alias grs='git reset'
alias grsh='git reset --hard'
alias grv='git remote -v'
alias gs='git status'
alias gsL=git-stash-dropped
alias gsS='git stash save --patch --no-keep-index'
alias gsX=git-stash-clear-interactive
alias gsa='git stash apply'
alias gsd='git stash show --patch --stat'
alias gsh='git show'
alias gshow='git show'
alias gshw='git show'
alias gsl='git stash list'
alias gsm='git submodule'
alias gsmi='git submodule init'
alias gsmu='git submodule update'
alias gsp='git stash pop'
alias gsr=git-stash-recover
alias gss='git stash save --include-untracked'
alias gst='git stash'
alias gstsh='git stash'
alias gsw='git stash save --include-untracked --keep-index'
alias gsx='git stash drop'
alias gt='git t'
alias gunc='git uncommit'
alias guns='git unstage'
alias gwC='git clean -f'
alias gwD='git diff --no-ext-diff --word-diff'
alias gwR='git reset --hard'
alias gwS='git status --ignore-submodules=${_git_status_ignore_submodules}'
alias gwX='git rm -rf'
alias gwc='git clean -n'
alias gwd='git diff --no-ext-diff'
alias gwr='git reset --soft'
alias gws='git status --ignore-submodules=${_git_status_ignore_submodules} --short'
alias gwx='git rm -r'
    && print .bundle       >>! .gitignore \
    && print vendor/assets >>! .gitignore \
    && print vendor/bundle >>! .gitignore \
    && print vendor/cache  >>! .gitignore'
alias spb='git checkout -b `sp | tail -2 | grep ''#'' | sed ''s/^ //'' | sed ''s/[^A-Za-z0-9 ]//g'' | sed ''s/ /-/g'' | cut -d- -f1,2,3,4,5`'

Learning GIT

Step 1. Use it
Step 2. Use it

Other resources to supplement step 1 and 2:

Jun 16, 2014

How to do conditional include_recipe (how to use guards with include_recipe)

Lets say you want to include a recipe based on some state of the server. Obviously this is a server you inherited from some team, and rebuilding it is just not an option because server provisioning takes 2 weeks (or two months).

include_recipe "foo::bar" do not_if { ::File.exists?("/etc/foo/bar") } end
/\ That simple does't work, although it'd be awesome if it did (seems like a consistency thing to me). Reason for that is include_recipe is a method and not a resource. Which means it's evaluated at the compilation phase, and not at execution (which makes sense from building the resource collection perspective)
So, if you do want a conditional include_recipe, you want to do something like this instead:
some_variable = {some logic to check for some state on a system} 
include_recide 'foo::bar' unless some_variable
Situation where this becomes super useful for example, is on windows, for chef runs which need to reboot a server and go on:
include_recipe 'cookbook::recipe' unless reboot_pending? 
Great link:


Jun 12, 2014

mini post - Chef (Opscode) - Simplifying Unit Testing

Saw something cool today in regards to unit testing.

Chefspec runs the first portion of your Chef run, the complication phase, but not the execution phase.

Next, it tests the resulting objects against the set of objects you defined in your unit tests. If they match, you pass. The key here is that you have all of the recipe stuff accessible to you from inside your unit tests, so you can use it to simplify your life. (where applicable, last thing you want is a set of tests that never fails)

For example, in situations where I build a string and some of the attributes are from upstream cookbooks - DNS server, Bill Gates favorite color, population of Ukraine...

So, with an attribute driven cookbook, a traditional unit test looks something like this:

default['download_dir'] = '/var/windows/rocks'

directory node['download_dir'] do
  owner "root"
  group "root"
  mode 0755
  action :create
  recursive true
Unit test (traditional):
it 'create directory' do
    expect(chef_run).to create_directory('/var/windows/rocks')
Unit test (simplified):
it 'create directory' do
    expect(chef_run).to create_directory(chef_run.node['download_dir'])

Now if you modify the attribute your unit test will still pass. Whether you want it or not is a whole different story, but so far it's been working much better than placing an exact string in the unit test.

mini post - Chef (Opscode) best practices series - Unit testing and TDD

The argument of TDD is great and all, but I do not think it's directly applicable to Chef.

Here is the idea - Chef offers a lot of resources, and a lot of ways to skin the cat/dog/lizard/etc.. So you simply can't write unit tests first, because you don't actually know which resources you're going to use to skin said animal.

What you CAN do, is write integration tests first. Because you DO know the ultimate outcome of your cookbook. And you can write Stubs for your unit tests ahead of time, if that makes you feel good.

Lets say you want to write a WSUS cookbook. The goal of the cookbook is to install WSUS role on your server. So your TDD (test driven development) for installing WSUS server would look something like this:
/> knife kitchen create wsus (or knife cookbook create wsus)
Your unit test would look very generic:

it 'installs some prerequisite that came with windows' do
it 'downloads some prereq that didnt come with windows' do
it 'installs the downloaded prereq' do
Your integration tests on the other hand, would look very specific - Because you know ahead of time what constitutes a functional WSUS server.

 describe package('wsus') do
   it { should be_installed }
describe service('wsus') do
  it { should be_enabled   }
  it { should be_running   }
describe port(3859) do
  it { should be_listening }
IMHO, that's the best you can do when it comes to TDD with Chef. If you start with unit tests you're forcing yourself down the path of constantly re-writing your tests... over and over and over...

Here is an image of DNA relication.

May 20, 2014

Net user hidden switch

Holy moly... if only all of the internet problems were this easy to solve.

After creating and nuking 3 AWS boxes I finally broke down and regenerated the private cert. (I lost .pem file to interactively login a long time ago. Knife EC2 server create ftw!!)

Login and run my user_data script manually and get greeted with this 14 year old annoyance. Who in their right mind still runs win2k? Is it even supported?? Well, sadly we all know the answer to that question.

The password entered is longer than 14 characters.  Computers with Windows prior to Windows 2000 will not be able to use his account. Do you want to continue this operation? (Y/N) [Y]:
I nuked three boxes to find out my password was too long...

Combining last few drops of coffee with curiosity I ran the below command which to my complete and utter amazement succeeded. Half a google search later I find that this is a hidden switch in NET command... and now you know too

net user /add $user $password /yes
fyi: both /y and /yes work, and no matter how many times you type net help you wont get the answer you're looking for.

btw, here is the user data scrip:
<powershell>  #;
  "[System Access]" | out-file c:\delete.cfg;  "PasswordComplexity = 0" | out-file c:\delete.cfg -append;  "[Version]"  | out-file c:\delete.cfg -append;  'signature="$CHICAGO$"'  | out-file c:\delete.cfg -append;    secedit /configure /db C:\Windows\security\new.sdb /cfg c:\delete.cfg /areas SECURITYPOLICY;    $user="UsernameGoesHere";  $password = "UserPasswordGoestHere";  net user /add $user $password;  net localgroup Administrators /add $user;    winrm quickconfig -q;  Enable-PSRemoting -force;  winrm set winrm/config/winrs '@{MaxMemoryPerShellMB="300"}';  winrm set winrm/config '@{MaxTimeoutms="1800000"}';  winrm set winrm/config/service '@{AllowUnencrypted="true"}';  winrm set winrm/config/service/auth '@{Basic="true"}';  winrm set winrm/config/service/auth '@{CredSSP="true"}';    netsh advfirewall firewall set rule name="Windows Remote Management (HTTP-In)" profile=public protocol=tcp localport=5985 new remoteip=any;</powershell>

Here is a random bit of awesomeness

May 9, 2014

Finding illegal characters somewhere in your chef cookbook / code

Use case:
I cant upload a cookbook / run powershell script / render web.config because something somewhere throws up on an illegal character.

One route to fix it, is to look at most critical files - web.config, json.config, README.MD and hope that the error is somewhere in there.

Well, that's one approach. About a year ago I would fire up notepad++ or BeyondCompare and look for iffy characters. It works, but it's stupid slow.

In case of Chef, the whole cookbook is processed, so theoretically the error could be anywhere. So, going through it one file at a time is just not practical. On top of that, I advocate automation, so... automation it is:

I've been learning OSX so I actually dont know the equivalent for windows, but since you dont have grep anyway, install the version that comes with -P and all is good.

brew install pcre
CD to the folder where you're breaking
pcregrep --color='auto'  -r -n "[^\x00-\x7F]" .
pcregrep --color='auto'  -r -n "[\x80-\xFF]" .

-r                              is for recursive
--exclude-dir .git      is to exclude .git from your search. You'll get a ton of hits here otherwise (not used in example above)
-n                             is to specify ascii range. Both work.


Way to test:  Grab a broken Repo and run the command to make sure you get expected broken file
Fix is here (, so we're going to grab a pre fix commit

git clone
git checkout 5e1a812a38c19a45b774862345f552c41836606f
pcregrep --color='auto'  -r -n "[\x80-\xFF]" .


Apr 18, 2014

Post conference Rage blog - ChefConf

Having spent a week hanging out with the most genius people I've ever met, have really changed the way I look at user experience of the technology around us.

The third place goes to: Volvo
This example came from the CEO of the company during his keynote speech:
Volvo has a yearly GPS update package, which consists of 6 DVD disks, which have to be fed into the car over the course of 6 hours. AND!!! the car has to be running the whole time. Holy fucking shit, no way would a $60k+ car make you do that.

Sloppy seconds goes to: Hyatt
Preface: Hyatt has this pretty elevator system with dual factor authentication which doubles as first firewall in their customer defense system: after 7pm, you have to scan your card, AND the elevator takes you to your floor only. Neat, but mildly annoying, because card slots are small and very annoying to a drunk guy. Strike one.

That's minor though. The major flaw is that after the doors close, no new input can be added to the system. So, you're stuck riding in elevator till it stops.

And the first place goes to a Dealership:
Younker Nissan
3401 East Valley Rd
Renton, WA  98057

All of their emails come from: System Administrator

... maybe not so much of user experience on that last one, but it definitely inspired this whole post. ...and now off to find a relevant XKCD post.

How about: What is Heartbleed in pictures

Feb 15, 2014

Automating WSUS 3.0 server with Powershell on Win 2k8r2

It was supposed to be easy... EASY!!!!

...this ended up being the first line that actually did anything relevant... obviously not fucking easy.

So this project started as usual, with a false hopes and unkept promises
PS C:\chef> Add-WindowsFeature OOB-WSUS
WARNING: Installation of 'Windows Server Update Services' is not supported on the command line. Skipping...

Oh Come on!!!!

So Step 1 - Install Pre - Reqs
"web-server", "Web-Asp-Net", "Web-Windows-Auth", "Web-Metabase", "File-Services" | foreach {if (!(Get-WindowsFeature $_)){add-windowsfeature $_}}

Step 2 - download / contribute to my Chef cookbook which will do it all for you

The thing you probably really care about the most is here: 

Feb 10, 2014

Chef and Ruby and Gems and Windows

One of the many things in Chef ecosystem is Gems. Think of Gems as DLLs. They have versions, dependencies, and while MSFT figured this dependency hell years ago, Gems do not have that luxury.

One of the minuses is that when you install a gem, it pulls down depends, when you uninstall a gem, depends stay behind.

A - clean up unused gems
gem cleanup
B - nuke everything and start for scratch.
gem list | cut -d" " -f1 | xargs gem uninstall -aIx

C - read about bundler and track your depends in a gemfile. Each cookbook has its own gemfile. You always update your gemfile and never install gems manually

D - when your gems start complaining about missing dependencies see B

A good read:

Feb 6, 2014

Chef - Packer and generating images from custom ISO

If you want to develop quicker, you cant sit around waiting for your operations team to give you a server. .. and then give you another server when you destroyed it 20 minutes later. That's where you download VirtualBox, get Packer, Vagrant and go nuts.

The point of this post is to talk about packer templates you can get from GitHub. (templates have been moved into another project, but you can still get all of them for basic packer consumption from a dev branch of the same repo. Or just roll back master branch a couple of commits):

If you want to use a ISO other than the one in a template, you'll need to specify a couple of parameters for packer, and get the SHA1 of the ISO you're using.

If you have OpenSSL, SHA1 is super easy: 
openssl sha1 c:\Images\raw\7601.17514.101119-1850_x64fre_server_eva
Alternatively, you can get this tool from the mothership:

packer build -only=virtualbox-iso -var 'iso_url=C:\Images\raw\7601.17514.101119-1850_x64fre_server_eval_en-us-GRMSXEVAL_EN_DVD.iso' -var 'iso_checksum=beed231a34e90e1dd9a04b3afabec31d62ce3889' win2008r2-enterprise.json

That's it. 5 minutes later you will have a brand spanking new virtual box for continuous destruction.

/ The best way to learn Chef is to use \
\ Chef. --Me                           /
       `.  ,.'        
        :o o:   O   
       _`~^~'_  |    
     /'   ^   `=)
   .'  _______ '~|
   `(<=|     |= /'
       |     |
 ~~~~~~ ===== ~~~~~~~~

/ Actually, my goal is to have a sandwich \
\ named after me.                         /
       `.  ,.'        
        :o o:   O   
       _`~^~'_  |    
     /'   ^   `=)
   .'  _______ '~|
   `(<=|     |= /'
       |     |
 ~~~~~~ ===== ~~~~~~~~

Jan 27, 2014

Fixing AWS after upgrading to Powershell 4.0

I just got done scratching my head... After all, it's a PC, not an iPhone. I didnt think Amazon had a way to uninstall cmd-lets off my box remotely... or DID THEY!?

Well, no, they didnt. But apparently upgrading to powershell 4.0 does nuke all of the user modules, which sucks.

So. Step 1. Re-Install amazon modules (I just installed everything)  

Step 2.
Open new Powershell window and run:
Get-Module -ListAvailable
Step 3.

Step 4. - Setup your private keys again. Oddly enough that part actually still works. So, hitting the ec2 commands works right after reinstalling cmdlets.
(Get-EC2ImageByName WINDOWS_2008_BASE).imageid 

Step 5. If your creds were not carried over, or you never configured them, take a look at my earlier post 

You done

Jan 15, 2014

How to use same set of cookbooks with multiple Chef Servers

Simple answer is GIT. Well... probably the simple answer is to have multiple folders, each with corresponding .PEM files and configs, but then each knife.rb will have things like ../../cookbooks ../../.. and that's just too ghetto.

I assume by now you have GIT installed. If not, go install it -
As a side benefit now you can do knife cookbook site install (instead of download)

Now you have a set of cookbooks - lets say your working directory is <somedir> and it has a few sub folders:
.kitchen (maybe, maybe not)
spec (maybe?, maybe not yet)
And you want to share them between two different Orgs - lets say, chef server, and a private Server behind 13 firewalls and 14 VPNs..

Easy. Add your configs under source control, and setup two branches. One for each Chef server you'll be dealing with. Then you'll just check out the branch corresponding to the server config you want to use.

* Test that your current server works (knife cookbook show or knife client list)
* Go to .chef folder, or wherever your knife.rb and various settings live.
git init (initialize bare git repo)
git add . (add all files to repo)
git commit -m 'bla' (commit files to git repo)
You just placed your configs under version control in 'master' branch. YAY (*think of Dallas cheer leaders*)

Now, we will clone the master branch and configure .PEM keys and URL for the other server

git checkout -b local master (you just cloned master into local - good idea to have this as a backup of master)git checkout -b russia master (you just cloned master into russia)git checkout russia (switch to working on a specific branch)Add new .PEM files (your validator/pem may have different names.)Make changes to knife.rb (URL and if needed, file names. The rest should stay the same)Connect to the VPN's and/or whatever else. Test the new connections. (knife cookbook show)git add .git commit -m 'bbbla'

now any time you want to change which server you're working with just do git checkout local or git checkout russia.