Hi there, Chef noob here. I’m looking into using Chef to deploy our builds to Chef node servers (Windows Server 2012 machines). I have a cookbook called copy_builds that goes out to a central repository and selects the build we want to deploy and copies it out to the node server. The recipe I have contains basic and generic steps that perform the copy steps, and this recipe could be used for all builds we want to deploy except for one thing: the build name.
Here is an example of the recipe:
powershell_script 'Copy build files' do
code '
$Project = "Dev3_SomeCoolBuild"
net use "\\\\server\\build_share\\drop\\$Project"
$BuildNum = GC "\\\\server\\build_share\\drop\\$Project\\buildlabel.txt"
robocopy \\\\server\\build_share\\drop\\$Project\\webbin W:\\binroot\\$BuildNum'
end
As you can see, the variable $Project contains the name of the build in this recipe. If we have 100 different builds, all with different names, then what is the best way to handle this without creating 100 different recipes for my copy_builds cookbook?
BTW: this is how I’m currently calling Chef to deploy:
knife node run_list set $Node "recipe[copy_builds::$ProjectName],recipe[install_build]"
This command is in a PowerShell script and contains the $Project name info within it’s own $ProjectName variable. In this case $ProjectName contains the value of ‘Dev3_SomeCoolBuild’, to reference the recipe Dev3_SomeCoolBuild.rb.
What I’d like to do is have just one default recipe under copy_builds cookbook, and pass in the build name. Is this possible? And what is the best way to do it? I’ve read about data bags and attributes, but not sure if they would work for what I want.
It sounds like you should convert that to a provider, and then have a recipe loop over attributes or some other logic to call multiple instances of that provider.
A provider is a piece of Ruby code that implements a resource. In addition to the ones that come with Chef (such as File, Directory, Service, …) you can define your own.
Basically, instead of using a recipe what you are planning to do, you would create your own custom resource.
Providers are written in pure Ruby, rather than the Chef DSL. The advantage is that resources you can use the same resource multiple times in a recipe, each time with different attributes.
I ended up using attributes here. My script writes to the attributes file with the build name and uploads it to Chef to use in the deployment. I get the build name with a call to the attributes file from my recipe:
"#{node['copy_builds']['build']}"
The question I have now is, what if two build machines are attempting to write to the attributes file and upload to Chef at the same time. Will this cause any type of file collision?
Cookbook create/update are atomic-ish, in that you do all the file uploads and only once the files are available can you insert the new cookbook data (with references to the files) into the database. Files are stored by a hash of the content, so there should not be conflicting writes.
Hi kswem. I can see that your post was a number of years ago but I'm new to Chef like you were and I'm now working on a project which sounds similar to what you did. I'm also using a PowerShell script to call chef-run where I have the cookbookname::recipename_version. Like you, I don't want to have a ton of different recipes for each version I need to install. Can you share with me how you updated your attributes file and then how you used that attribute value to call the correct recipe?