Skip to content

Instantly share code, notes, and snippets.

@jkeiser
Created October 23, 2013 04:40
Show Gist options
  • Save jkeiser/7112700 to your computer and use it in GitHub Desktop.
Save jkeiser/7112700 to your computer and use it in GitHub Desktop.
Fun With Chef On Windows

Setting up with Chef, Windows Version

I decided I'd do some work on Windows today, and noticed a lot of my software was out of date, and there were new dev tools that I want to install. I am tired of installing this shit over and over again every time I have a new computer or wipe the OS. Thankfully, that's what Chef is for! So time for an experiment. Now that chef-client -z is out in Chef 11.8 (yay!) it's time to take the leap and start using Chef to set up my Windows 7 workstation. My goal is modest(ish):

  • Update HipChat (I want to use the new Windows msi instead of the Adobe Air version)
  • Update Sublime Text 3 (don't need to first-install it yet)
  • Use the development console tools outlined here

The stretch:

  • Install Ghost on my website (which only supports ftp), in order to post the very blog you are reading right now. Funny how that's the stretch, eh?

Step 1: Install the Client

I want to use Chef, so I type "windows install chef" into Google. This takes me to [http://www.opscode.com/chef/install/](the Chef install page).

Oops, problem #1. What do I click? It hasn't filled in Windows (and honestly it should ...), and when I click "Windows" there is no entry for Windows 7. My answer: go ask Adam Edwards. He tells me I want Windows Server 2008r2 (and he tells me that all our Windows packages are the same anyway :). Once I know this, there's still a LOT of clicking here. This is a completely unnecessary barrier. CHEF-4665 filed.

Plus, I can't get the RC from this page, which I need (but a normal first-time user won't). Well ... screw all this for now. Chalking up this step as a failure. I already have ruby and git. So I go git clone chef and rake install from there, omnibus-free. Doing it the wrong way, and on to using Chef!

Step 2: HipChat

First let's do hipchat. What I want is to make a recipe that will download the latest hipchat (http://downloads.hipchat.com/windows/hipchat.msi) and install if it's different. Bonus points for not re-downloading the msi every time it runs. So first I create the chef repository--the directory where I will be placing all my cookbooks and such:

mkdir workstation_setup
cd workstation_setup

Now, I don't know how to install an MSI using Chef, so I search for "chef windows package" and learn that the windows_package resource is what I need. This is part of the windows cookbook from the community, so I decided to install that. knife cookbook site install is how you are supposed to do it, but I encountered CHEF-4666, CHEF-4668, CHEF-4669, CHEF-2629 and CHEF-4667. knife cookbook site download is what I eventually used. Good thing I already had tar on my system:

mkdir cookbooks
cd cookbooks
knife cookbook site download -z windows
tar xzvf windows-1.11.0.tar.gz
del windows-1.11.0.tar.gz

Now it's time to make the recipe! I made these files:

cookbooks\hipchat\metadata.rb

depends 'windows'

cookbooks\hipchat\recipes\default.rb

windows_package 'HipChat' do
  source 'http://downloads.hipchat.com/windows/hipchat.msi'
end

Time to see if it works! Let's run chef-client -z with "hipchat" as the run list.

C:\Users\jkeiser\workstation_setup>chef-client -z -o hipchat
[2013-10-22T18:26:08-07:00] WARN: No config file found or specified on command line, using command line options.
Starting Chef Client, version 11.10.0.alpha.0
[2013-10-22T18:26:52-07:00] WARN: Run List override has been provided.
[2013-10-22T18:26:52-07:00] WARN: Original Run List: []
[2013-10-22T18:26:52-07:00] WARN: Overridden Run List: [recipe[hipchat]]
[2013-10-22T18:26:52-07:00] WARN: chef-client doesn't have administrator privileges on node jkeiser-PC. This might cause
 unexpected resource failures.
resolving cookbooks for run list: ["hipchat"]

================================================================================
Error Resolving Cookbooks for Run List:
================================================================================

Missing Cookbooks:
------------------
Unsolvable versions!

Expanded Run List:
------------------
* hipchat

[2013-10-22T18:26:52-07:00] ERROR: Running exception handlers
[2013-10-22T18:26:52-07:00] ERROR: Exception handlers complete
[2013-10-22T18:26:52-07:00] FATAL: Stacktrace dumped to C:/Users/jkeiser/.chef/local-mode-cache/cache/chef-stacktrace.ou
t
Chef Client failed. 0 resources updated
[2013-10-22T18:26:52-07:00] FATAL: Net::HTTPServerException: 412 "Precondition Failed"

NOPE. We're missing a dependency. Which one?

C:\Users\jkeiser\workstation_setup>knife deps -z /cookbooks/hipchat
WARNING: No knife configuration file found
ERROR: cookbooks/chef_handler: No such file or directory
cookbooks/chef_handler
cookbooks/windows
cookbooks/hipchat

We're missing chef_handler. OK, that's cool. We'll install it.

cd cookbooks
knife cookbook site download -z chef_handler
tar xzvf chef_handler-1.1.4.tar.gz
del chef_handler-1.1.4.tar.gz

Step 2 ... again ... Install HipChat!

NOW we can go. But it doesn't do what we want:

C:\Users\jkeiser\workstation_setup>chef-client -z -o hipchat
[2013-10-22T19:56:21-07:00] WARN: No config file found or specified on command line, using command line options.
Starting Chef Client, version 11.10.0.alpha.0
[2013-10-22T19:56:31-07:00] WARN: Run List override has been provided.
[2013-10-22T19:56:31-07:00] WARN: Original Run List: [recipe[hipchat]]
[2013-10-22T19:56:31-07:00] WARN: Overridden Run List: [recipe[hipchat]]
[2013-10-22T19:56:31-07:00] WARN: chef-client doesn't have administrator privileges on node jkeiser-PC. This might cause
 unexpected resource failures.
resolving cookbooks for run list: ["hipchat"]
Synchronizing Cookbooks:
  - hipchat
  - windows
  - chef_handler
Compiling Cookbooks...
Converging 1 resources
Recipe: hipchat::default
  * windows_package[HipChat] action install (up to date)
Chef Client finished, 0 resources updated

... up to date? You didn't even try to download anything. Shame! It turns out the reason for this is that the :install action (the default for windows_package) doesn't try to upgrade the package by default; since I have a really old version installed already, we do nothing. We want action :upgrade in the resource, which is how you would do it with a normal package. Sadly, this is unsupported in windows_package.

This could be a long night.

But we'll persevere. install WILL upgrade HipChat if you specify the exact version you are migrating to. Lo and behold, does a redirect which tells us the version. Here's what the recipe looks like now:

bare_msi_url = 'http://downloads.hipchat.com/windows/hipchat.msi'
redirected_to = Net::HTTP.get_response(URI(bare_msi_url))['location']
if redirected_to =~ /^\/windows\/HipChat-([0-9.]+)-win32.msi$/
  hipchat_version = $1
else
  raise "#{bare_msi_url} redirected to #{redirected_to}; expected it to look like /windows/HipChat-VERSION-win32.msi."
end

# /windows/HipChat-1.99.894-win32.msi
windows_package 'HipChat' do
  source "http://downloads.hipchat.com#{redirected_to}"
  version hipchat_version
  action :install
end

Step 2! Third time's the charm? Install HipChat!

Here we go!


C:\Users\jkeiser\workstation_setup>chef-client -z -o hipchat
[2013-10-22T21:07:42-07:00] WARN: No config file found or specified on command line, using command line options.
Starting Chef Client, version 11.10.0.alpha.0
[2013-10-22T21:07:52-07:00] WARN: Run List override has been provided.
[2013-10-22T21:07:52-07:00] WARN: Original Run List: [recipe[hipchat]]
[2013-10-22T21:07:52-07:00] WARN: Overridden Run List: [recipe[hipchat]]
[2013-10-22T21:07:52-07:00] WARN: chef-client doesn't have administrator privileges on node jkeiser-PC. This might cause unexpected resource failures.
resolving cookbooks for run list: ["hipchat"]
Synchronizing Cookbooks:
  - hipchat
  - windows
  - chef_handler
Compiling Cookbooks...
Converging 1 resources
Recipe: hipchat::default
  * windows_package[HipChat] action installRecipe: <Dynamically Defined Resource>
  * remote_file[C:/Users/jkeiser\.chef\local-mode-cache\cache/HipChat-1.99.894-win32.msi] action create
    - create new file C:/Users/jkeiser\.chef\local-mode-cache\cache/HipChat-1.99.894-win32.msi
================================================================================
Error executing action `create` on resource 'remote_file[C:/Users/jkeiser\.chef\local-mode-cache\cache/HipChat-1.99.894-win32.msi]'
================================================================================

Chef::Exceptions::WindowsNotAdmin
---------------------------------
can not get the security information for 'C:/Users/jkeiser/.chef/local-mode-cache/cache/HipChat-1.99.894-win32.msi' due to missing Administrator privilages.

Compiled Resource:
------------------
# Declared in

remote_file("C:/Users/jkeiser\.chef\local-mode-cache\cache/HipChat-1.99.894-win32.msi") do
  provider Chef::Provider::RemoteFile
  action "create"
  retries 0
  retry_delay 2
  path "C:/Users/jkeiser\\.chef\\local-mode-cache\\cache/HipChat-1.99.894-win32.msi"
  atomic_update true
  source ["http://downloads.hipchat.com/windows/HipChat-1.99.894-win32.msi"]
  use_etag true
  use_last_modified true
end

Missing Windows Admin Privileges
--------------------------------
chef-client doesn't have administrator privileges. This can be a possible reason for the resource failure.

We'll overlook "privilages," which everyone misspells, causing me no end of headache. There's nothing for it.

But it didn't work. Given that normal users can install packages in windows, I wouldn't have expected such a unilateral failure. And why do we care about the SACL on this file? Why can't it gray out the screen like an installer does and ask for an escalation in privilege?

Ah well. We'll give it what it wants.

Step 2, once more with feeling! Install HipChat

OK, we're in an admin command prompt now. Let's give it a whirl:

C:\Users\jkeiser\workstation_setup>chef-client -z -o hipchat
[2013-10-22T21:19:08-07:00] WARN: No config file found or specified on command line, using command line options.
Starting Chef Client, version 11.10.0.alpha.0
[2013-10-22T21:19:18-07:00] WARN: Run List override has been provided.
[2013-10-22T21:19:18-07:00] WARN: Original Run List: [recipe[hipchat]]
[2013-10-22T21:19:18-07:00] WARN: Overridden Run List: [recipe[hipchat]]
resolving cookbooks for run list: ["hipchat"]
Synchronizing Cookbooks:
  - hipchat
  - windows
  - chef_handler
Compiling Cookbooks...
Converging 1 resources
Recipe: hipchat::default
  * windows_package[HipChat] action installRecipe: <Dynamically Defined Resource>
  * remote_file[C:/Users/jkeiser\.chef\local-mode-cache\cache/HipChat-1.99.894-win32.msi] action create
    - update content in file C:/Users/jkeiser\.chef\local-mode-cache\cache/HipChat-1.99.894-win32.msi from e3b0c4 to ba5
9f5
        (file sizes exceed 10000000 bytes, diff output suppressed)

Chef Client finished, 2 resources updated

IT WORKED! Now our job is done.

Step 3: Looking A Gift Horse In The Mouth

Chef being convergent, we want to make sure that if we RE-run the recipe, Chef doesn't try to re-download and re-install it. So let's do that, ya?

C:\Users\jkeiser\workstation_setup>chef-client -z -o hipchat
[2013-10-22T21:23:50-07:00] WARN: No config file found or specified on command line, using command line options.
Starting Chef Client, version 11.10.0.alpha.0
[2013-10-22T21:23:59-07:00] WARN: Run List override has been provided.
[2013-10-22T21:23:59-07:00] WARN: Original Run List: [recipe[hipchat]]
[2013-10-22T21:23:59-07:00] WARN: Overridden Run List: [recipe[hipchat]]
resolving cookbooks for run list: ["hipchat"]
Synchronizing Cookbooks:
  - hipchat
  - windows
  - chef_handler
Compiling Cookbooks...
Converging 1 resources
Recipe: hipchat::default
  * windows_package[HipChat] action installRecipe: <Dynamically Defined Resource>
  * remote_file[C:/Users/jkeiser\.chef\local-mode-cache\cache/HipChat-1.99.894-win32.msi] action create
================================================================================
Error executing action `create` on resource 'remote_file[C:/Users/jkeiser\.chef\local-mode-cache\cache/HipChat-1.99.894-win32.msi]'
================================================================================

NoMethodError
-------------
undefined method `path' for nil:NilClass

Compiled Resource:
------------------
# Declared in

remote_file("C:/Users/jkeiser\.chef\local-mode-cache\cache/HipChat-1.99.894-win32.msi") do
  provider Chef::Provider::RemoteFile
  action "create"
  retries 0
  retry_delay 2
  path "C:/Users/jkeiser\\.chef\\local-mode-cache\\cache/HipChat-1.99.894-win32.msi"
  atomic_update true
  source ["http://downloads.hipchat.com/windows/HipChat-1.99.894-win32.msi"]
  use_etag true
  use_last_modified true
end

================================================================================
Error executing action `install` on resource 'windows_package[HipChat]'
================================================================================

NoMethodError
-------------
remote_file[C:/Users/jkeiser\.chef\local-mode-cache\cache/HipChat-1.99.894-win32.msi] (dynamically defined) had an error: NoMethodError: undefined method `path' for nil:NilClass

Resource Declaration:
---------------------
# In C:/Users/jkeiser/.chef/local-mode-cache/cache/cookbooks/hipchat/recipes/default.rb

 10: windows_package 'HipChat' do
 11:   source "http://downloads.hipchat.com#{redirected_to}"
 12:   version hipchat_version
 13:   action :install
 14: end

Compiled Resource:
------------------
# Declared in C:/Users/jkeiser/.chef/local-mode-cache/cache/cookbooks/hipchat/recipes/default.rb:10:in `from_file'

windows_package("HipChat") do
  action [:install]
  retries 0
  retry_delay 2
  cookbook_name "hipchat"
  recipe_name "default"
  source "http://downloads.hipchat.com/windows/HipChat-1.99.894-win32.msi"
  version "1.99.894"
  package_name "HipChat"
end

[2013-10-22T21:24:01-07:00] ERROR: Running exception handlers
[2013-10-22T21:24:01-07:00] ERROR: Exception handlers complete
[2013-10-22T21:24:01-07:00] FATAL: Stacktrace dumped to C:/Users/jkeiser/.chef/local-mode-cache/cache/chef-stacktrace.out
Chef Client failed. 0 resources updated
[2013-10-22T21:24:01-07:00] FATAL: NoMethodError: windows_package[HipChat] (hipchat::default line 10) had an error: NoMethodError: remote_file[C:/Users/jkeiser\.chef\local-mode-cache\cache/HipChat-1.99.894-win32.msi] (dynamically defined) had an error: NoMethodError: undefined method `path' for nil:NilClass

I knew I should have left well enough alone.

First question: why did it try to install again? Answer: there are two hipchats in my Add/Remove Programs. I don't know why or how that is, but it could have to do with the leap from Adobe Air to an msi. I'll leave that until a new version comes out (Thursday) and see what happens then.

Second question: whence the crash? It appears this is happening because tempfile is nil when it's passed here. I know Chef::HTTP::Simple is a new thing in Chef 11.8, so we may have found an actual bug. Not sure the source, but this is reproducible.

The stacktrace:

Generated at 2013-10-22 21:24:01 -0700
NoMethodError: windows_package[HipChat] (hipchat::default line 10) had an error: NoMethodError: remote_file[C:/Users/jkeiser\.chef\local-mode-cache\cache/HipChat-1.99.894-win32.msi] (dynamically defined) had an error: NoMethodError: undefined method `path' for nil:NilClass
C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.10.0.alpha.0/lib/chef/provider/remote_file/http.rb:78:in `update_cache_control_data'
C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.10.0.alpha.0/lib/chef/provider/remote_file/http.rb:63:in `fetch'
C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.10.0.alpha.0/lib/chef/provider/remote_file/content.rb:65:in `grab_file_from_uri'
C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.10.0.alpha.0/lib/chef/provider/remote_file/content.rb:50:in `try_multiple_sources'
C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.10.0.alpha.0/lib/chef/provider/remote_file/content.rb:39:in `file_for_provider'
C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.10.0.alpha.0/lib/chef/file_content_management/content_base.rb:40:in `tempfile'
C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.10.0.alpha.0/lib/chef/provider/file.rb:386:in `tempfile'
C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.10.0.alpha.0/lib/chef/provider/file.rb:338:in `do_contents_changes'
C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.10.0.alpha.0/lib/chef/provider/file.rb:120:in `action_create'
C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.10.0.alpha.0/lib/chef/provider.rb:114:in `run_action'
C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.10.0.alpha.0/lib/chef/resource.rb:625:in `run_action'
C:/Users/jkeiser/.chef/local-mode-cache/cache/cookbooks/windows/libraries/helper.rb:76:in `cached_file'
C:/Users/jkeiser/.chef/local-mode-cache/cache/cookbooks/windows/providers/package.rb:228:in `installer_type'
C:/Users/jkeiser/.chef/local-mode-cache/cache/cookbooks/windows/providers/package.rb:120:in `install_package'
C:/Users/jkeiser/.chef/local-mode-cache/cache/cookbooks/windows/providers/package.rb:46:in `block in class_from_file'
C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.10.0.alpha.0/lib/chef/provider/lwrp_base.rb:138:in `instance_eval'
C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.10.0.alpha.0/lib/chef/provider/lwrp_base.rb:138:in `block in action'
C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.10.0.alpha.0/lib/chef/provider.rb:118:in `run_action'
C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.10.0.alpha.0/lib/chef/resource.rb:625:in `run_action'
C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.10.0.alpha.0/lib/chef/runner.rb:49:in `run_action'
C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.10.0.alpha.0/lib/chef/runner.rb:81:in `block (2 levels) in converge'
C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.10.0.alpha.0/lib/chef/runner.rb:81:in `each'
C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.10.0.alpha.0/lib/chef/runner.rb:81:in `block in converge'
C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.10.0.alpha.0/lib/chef/resource_collection.rb:98:in `block in execute_each_resource'
C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.10.0.alpha.0/lib/chef/resource_collection/stepable_iterator.rb:116:in `call'
C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.10.0.alpha.0/lib/chef/resource_collection/stepable_iterator.rb:116:in `call_iterator_block'
C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.10.0.alpha.0/lib/chef/resource_collection/stepable_iterator.rb:85:in `step'
C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.10.0.alpha.0/lib/chef/resource_collection/stepable_iterator.rb:104:in `iterate'
C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.10.0.alpha.0/lib/chef/resource_collection/stepable_iterator.rb:55:in `each_with_index'
C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.10.0.alpha.0/lib/chef/resource_collection.rb:96:in `execute_each_resource'
C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.10.0.alpha.0/lib/chef/runner.rb:80:in `converge'
C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.10.0.alpha.0/lib/chef/client.rb:433:in `converge'
C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.10.0.alpha.0/lib/chef/client.rb:500:in `do_run'
C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.10.0.alpha.0/lib/chef/client.rb:213:in `run'
C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.10.0.alpha.0/lib/chef/application.rb:208:in `run_chef_client'
C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.10.0.alpha.0/lib/chef/application/client.rb:312:in `block in run_application'
C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.10.0.alpha.0/lib/chef/application/client.rb:304:in `loop'
C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.10.0.alpha.0/lib/chef/application/client.rb:304:in `run_application'
C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.10.0.alpha.0/lib/chef/application.rb:66:in `run'
C:/opscode/chef/embedded/lib/ruby/gems/1.9.1/gems/chef-11.10.0.alpha.0/bin/chef-client:26:in `<top (required)>'
C:/opscode/chef/bin/chef-client:23:in `load'
C:/opscode/chef/bin/chef-client:23:in `<main>'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment