Is there a way to pass parameters at run time in Chef?
I wanted to pass some attributes to chef-client
at runtime. Is there a way to do the same?
I was looking into chef-client -j
option, but to my knowledge it can be used to specify run_list. Can I pass some attributes in it? If yes, how?
Yes, you can use the -j
json file option to populate node attributes.
{
"my_attribute": "I like attributes!"
}
This will make an attribute named my_attribute
available in your cookbooks. For example,
Chef::Log.info(node['my_attribute'])
Or,
if node['my_attribute'] =~ /like/
package "foo-likes-attributes" do
action :install
end
end
Setting an initial run_list is the most common use of the json attributes file for Chef Client. If you're using Chef Client + Chef Server, though, you can simply modify the node object on the server either through the webui (Open Source Chef Server) or management console (Opscode Hosted/Private Chef), or through knife node edit
if you're using the command-line tool, knife.
Note that using the JSON file is like modifying the node object on the server, the attributes set here "normal" priority like when they are used in a recipe, and these attribute values will be saved to the Node object on the server at the end of a successful run.
- Normal attributes applied on a node directly in a recipe (from the documentation)
The ideal way to use attributes is to write them into your cookbook or into a data bag. Here are the file locations for either:
Chef Repo Directory Layout
|- chef-repo
|---- cookbooks
|------- attributes
|---------- default.rb
|------- recipes
|---------- default.rb
|---- data_bags
|------- users
|---------- john.json
|---------- susan.json
|------- databases
|----------- master.json
|----------- slave.json
You can store data in your data bag files in basic JSON format ( knife create data_bag users
).
Create user data bag for john:
$ knife data bag create users john
{
"id" : "john"
"age" : "27"
"height" : "60in"
}
Using Data Bags
If you choose to use data bags (I recommend them if you have a lot of different users or database servers (in this context)), you can view more information at https://docs.getchef.com/dsl_recipe_method_data_bag.html. Additionally, it's easier to create a users
directory in your data_bags directory, and create the user .json files in there (~/chef-repo/data_bags/users/john.json) with the content above, then upload the data bag to the chef server: knife data bag from file users /path/to/data_bags/users/john.json
Using Attributes
You can also store the data in your attributes file:
attributes file
$ vi ~/chef-repo/cookbooks/my-cookbook-name/attributes/default.rb
default['my-cookbook-name']['user-1'] = "John"
default['my-cookbook-name']['user-1']['age'] = "27"
default['my-cookbook-name']['user-1']['height'] = "60in"
cookbook recipe
$ vi ~/chef-repo/cookbooks/my-cookbook-name/default.rb
template "/root/user-list" do
action :create
source "user-list.erb"
end
user-list.erb
$ vi ~/chef-repo/cookbooks/my-cookbook-name/templates/default/user-list.erb
<html>
<head>
<title>My User List</title>
</head>
<body>
<h1>User List</h1>
User 1: <%= node['my-cookbook-name']['user-1'] %>
User Age: <%= node['my-cookbook-name']['user-1']['age'] %>
User Height: <%= node['my-cookbook-name']['user-1']['height'] %>
</body>
</html>
you can do it on the command line, but - especially in a knife run - it'll start to look reeeally ooky:
chef-client \
-o vmware-tools \
--force-formatter \
-j '<(echo {\"vmware-tools\":{\"style\":\"rpm\"}})'
But here we're leveraging -j and a <(notation)
to create the JSON file on the fly, as artefacts tossed in via knife (or ssh-i, here). If you must do it, the risk is the conflicting delimiters will drive you insane at about the time you get it to work.