NAME
pantry - Manage resources for chef-solo
VERSION
version 0.012
SYNOPSIS
$ mkdir my-project
$ cd my-project
$ pantry init
$ pantry create node foo.example.com
$ pantry list nodes
$ pantry apply node foo.example.com --recipe nginx
$ pantry apply node foo.example.com --default nginx.port=80
$ pantry sync node foo.example.com
DESCRIPTION
pantry
is a utility to make it easier to manage a collection of computers with the configuration management tool Chef Solo http://wiki.opscode.com/display/chef/Chef+Solo
USAGE
Arguments to the pantry
command line tool follow a regular structure:
$ pantry VERB [[NOUN] [ARGUMENTS...]]
See the following sections for details and examples by topic.
Pantry setup and introspection
init
$ pantry init
This initializes a pantry in the current directory. Currently, it just creates some directories for use storing cookbooks, node data, data bags, etc.
list
$ pantry list nodes
$ pantry list roles
$ pantry list environments
$ pantry list cookbooks
$ pantry list bags
Prints to STDOUT a list of items of a particular type managed within the pantry.
Managing nodes
In this section, when a node NAME is required, the name is expected to be a valid DNS name or IP address. The name will be converted to lowercase for consistency. When referring to an existing node, you may often abbreviate it to a unique prefix, e.g. "foo" for "foo.example.com".
Also, whenever a command takes a single 'node NAME' target, you may give a single dash ('-') as the NAME and the command will be run against a list of nodes read from STDIN.
You can combine this with the pantry list
command to do batch operations. For example, to sync all nodes:
$ pantry list nodes | pantry sync node -
Pantry supports grouping nodes into arbitrarily named environments, such as "test", "staging" or "production". The node commands "create" and "list" can be given an environment selector with the --env ENV_NAME
or -E ENV_NAME
options and all operations will be happen in the context of that environment.
This works with "list" and input from STDIN for a handy way to sync all nodes in an environment:
$ pantry list nodes -E staging | pantry sync node -
See ""Managing Environments" for more.
create
$ pantry create node NAME
Creates a node configuration file for the given NAME
.
rename
$ pantry rename node NAME DESTINATION
Renames a node to a new name. The old node data file is renamed. The NAME
must exist.
delete
$ pantry delete node NAME
Deletes a node. The NAME
must exist. Unless the --force
or -f
options are given, the user will be prompted to confirm deletion.
show
$ pantry show node NAME
Prints to STDOUT the JSON data for the given NAME
.
apply
$ pantry apply node NAME --recipe nginx --role mail --default nginx.port=80
Applies recipes, roles or attributes to the given NAME
.
To apply a role to the node's run_list
, specify --role role
or -R role
. May be specified multiple times to apply more than one role. Roles will be appended to the run_list
before after any existing entries but before any recipes specified in the same command.
To apply a recipe to the node's run_list
, specify --recipe RECIPE
or -r RECIPE
. May be specified multiple times to apply more than one recipe.
To apply an attribute to the node, specify --default KEY=VALUE
or -d KEY=VALUE
. If the KEY
has components separated by periods (.
), they will be interpreted as subkeys of a multi-level hash. For example:
$ pantry apply node NAME -d nginx.port=80
will be added to the node's data structure like this:
{
... # other node data
nginx => {
port => 80
}
}
If the VALUE
contains commas, the value will be split and serialized as an array data structure. For example:
$ pantry apply node NAME -d nginx.port=80,8080
will be added to the node's data structure like this:
{
... # other node data
nginx => {
port => [80, 8080]
}
}
Both KEY
and VALUE
support periods and commas (respectively) to be escaped by a backslash.
If a VALUE
is a literal string containing 'true' or 'false', it will be replaced in the configuration data with actual JSON boolean values.
N.B. While the term --default
is used for command line consistency, attributes set on nodes actually have what Chef terms "normal" precedence.
strip
$ pantry strip node NAME --recipe nginx --role mail --default nginx.port
Strips recipes, roles or attributes from the given NAME
.
To strip a role to the node's run_list
, specify --role role
or -R role
. May be specified multiple times to strip more than one role.
To strip a recipe to the node's run_list
, specify --recipe RECIPE
or -r RECIPE
. May be specified multiple times to strip more than one recipe.
To strip an attribute from the node, specify --default KEY
or -d KEY
. The KEY
parameter is interpreted and may be escaped just like in apply
, above.
sync
$ pantry sync node NAME
Copies cookbooks and configuration data to the NAME
node and invokes chef-solo
via ssh
to start a configuration run. After configuration, the latest run-report for the node is updated in the 'reports' directory of the pantry.
If the --reboot
option is given, each node will be rebooted after the synchronization run. This will only work on Unix hosts that can use the shutdown
command.
edit
$ pantry edit node NAME
Invokes the editor given by the environment variable EDITOR
on the configuration file for the name
node.
The resulting file must be valid JSON in a form acceptable to Chef. Generally, you should use the apply
or strip
commands instead of editing the node file directly.
Managing roles
In this section, when a role NAME is required, any name without whitespace is acceptable. The name will be converted to lowercase for consistency. When referring to an existing role, you may often abbreviate it to a unique prefix, e.g. "web" for "webserver".
Also, whenever a command takes a single 'role NAME' target, you may give a single dash ('-') as the NAME and the command will be run against a list of roles read from STDIN.
You can combine this with the pantry list
command to do batch operations. For example, to add a recipe to all roles:
$ pantry list roles | pantry apply role - --recipe ntp
create, rename, delete, show and edit
These commands work the same as they do for nodes. The difference is that you must specify the 'role' type:
$ pantry create role web
$ pantry show role web
apply and strip
The apply
and strip
commands have slight differences, as roles have two kinds of attributes, "default attributes" (--default
or -d
) and "override attributes" (--override
), with slightly different precedence.
$ pantry apply role NAME -d nginx.user=nobody --override nginx.port=80
$ pantry strip role NAME -d nginx.user --override nginx.port
The --recipe
(-r
) and --role
(-R
) arguments work the same as for nodes. Note that roles can have other roles in their run_list
.
When Chef merges attribute, the role default attribute has the lower precedence than node attributes. Override attributes have higher precedence than node attributes. Yes, this is a gross simplification of how Chef does it. See Chef docs for more: http://wiki.opscode.com/display/chef/Attributes
Roles have two kinds of run lists: default and environment-specific. The default run list applies whenever there is no environment-specific run list for the active environment for a node. You can apply/strip environment-specific run list entries with the -E ENV_NAME
option, or omit it to apply/strip from the default list.
$ pantry apply role web -r nginx
$ pantry apply role web -r ufw -E production
Managing data bags
In this section, when a bag NAME is required, any name without whitespace is acceptable. The name will be converted to lowercase for consistency. When referring to an existing bag, you may often abbreviate it to a unique prefix, e.g. "users/d" for "users/dagolden".
Note that data bags may exist at the "top" level or within subdirectories and so either of these forms are acceptable as bag names:
top_level_bag
bag_name/item_name
Also, whenever a command takes a single 'bag NAME' target, you may give a single dash ('-') as the NAME and the command will be run against a list of bags read from STDIN.
You can combine this with the pantry list
command to do batch operations.
$ pantry list bags | grep users | pantry apply bag - -d remove=true
create, rename, delete, show and edit
These commands work the same as they do for nodes. The difference is that you must specify the 'bag' type:
$ pantry create bag users/dagolden
$ pantry show bag users/dagolden
apply and strip
The apply
and strip
commands have slight differences, as bags don't have attributes in the way that nodes or roles do. The "default" flags are used and just set fields in the top level of the bag. (Don't set "id" or bad things might happen.)
$ pantry apply bag NAME -d key=value
$ pantry strip bag NAME -d key
Managing environments
In this section, when a environment NAME is required, any name without whitespace is acceptable. The name will be converted to lowercase for consistency. When referring to an existing role, you may often abbreviate it to a unique prefix, e.g. "prod" for "production".
Also, whenever a command takes a single 'environment NAME' target, you may give a single dash ('-') as the NAME and the command will be run against a list of roles read from STDIN.
You can combine this with the pantry list
command to do batch operations. For example, to add a default to all environments:
$ pantry list environments | pantry apply environment - -d nginx.port=8080
Environments are different than nodes and roles because there are really three ways to work with an environment. When you create an environment, an environment data file is created to hold attributes. When you create a node, it gets assigned to an environment (the "_default" environment is used if you don't specify one). However, you can create a node in an environment even if you don't create the environment data file first. Finally, roles can have environment-specific run lists.
Here's a summary of those distinctions:
When you want to affect environment data files, you'll use pantry VERB environment ...
commands, like this:
$ pantry show environment staging
When you want to set an environment for node and role actions, you'll use the --env
or -E
selector option
$ pantry create node foo.example.com -E test
$ pantry apply role web -r ufw -E production
create, rename, delete, show and edit
These commands work the same as they do for nodes and roles. The difference is that you must specify the 'environment' type:
$ pantry create environment staging
$ pantry show environment staging
apply and strip
The apply
and strip
commands work like roles, except that environments don't have run lists.
$ pantry apply environment NAME -d nginx.user=nobody --override nginx.port=80
$ pantry strip environment NAME -d nginx.user --override nginx.port
If you want to have different run lists in different environments, you have to do that via roles, with environment-specific run lists:
# turn on firewall in production
$ pantry apply role web -r ufw -E production
An environment-specific run list replaces the default run list if the role is applied to a node in the specified environment.
Chef Solo does not yet have support for merging environment attributes the way Chef Client does. Therefore, during sync, Pantry will do its own merge with node attributes to provide a reasonable emulation. The precedence is slightly different, but if you have overlapping environment, role and node attributes and the order is really important to you, you're probably over-complicating things. See Chef docs for more: http://wiki.opscode.com/display/chef/Attributes
Managing cookbooks
Pantry does very little to manage cookbooks -- this is left up to you and you are free to do whatever you like in the cookbooks
directory.
As a convenience, however, Pantry may be used to create an empty boilerplate cookbook for you to customize:
$ pantry create cookbook my-cookbook
Getting help
commands
$ pantry commands
This gives a list of all pantry commands with a short description of each.
help
$ pantry help COMMAND
This gives some detailed help for a command, including the options and arguments that may be used.
AUTHENTICATION
pantry
relies on OpenSSH for secure communications with managed nodes, but does not manage keys itself. Instead, it expects the user to manage keys using standard OpenSSH configuration and tools.
The user should specify SSH private keys to use in the ssh config file. One approach would be to use the IdentityFile
with a host-name wildcard:
IdentityFile ~/.ssh/identities/id_dsa_%h
This would allow a directory of host-specific identities (which could all be symlinks to a master key). Another alternative might be to create a master key for each environment:
IdentityFile ~/.ssh/id_dsa_dev
IdentityFile ~/.ssh/id_dsa_test
IdentityFile ~/.ssh/id_dsa_prod
pantry
also assumes that the user will unlock keys using ssh-agent
. For example, assuming that ssh-agent has not already been invoked by a graphical shell session, it can be started with a subshell of a terminal:
$ ssh-agent $SHELL
Then private keys can be unlocked in advance of running pantry
using ssh-add
:
$ ssh-add ~/.ssh/id_dsa_test
$ pantry ...
See the documentation for ssh-add
for control over how long keys stay unlocked.
ROADMAP
In the future, I hope to extend pantry to support some or all of the following:
tagging nodes
searching nodes based on configuration
encrypted data bags (or equivalent functionality)
cookbook download from Opscode community repository
bootstrapping Chef over ssh
If you are interested in contributing features or bug fixes, please let me know!
SEE ALSO
Inspiration for this tool came from similar chef-solo management tools. In addition to being implemented in different languages, each approaches the problem in slightly different ways, neither of which fit my priorities. Nevertheless, if you use chef-solo, you might consider them as well:
littlechef http://github.com/tobami/littlechef (Python)
pocketknife http://github.com/igal/pocketknife (Ruby)
knife-solo https://github.com/matschaffer/knife-solo (Ruby)
AUTHOR
David Golden <dagolden@cpan.org>
COPYRIGHT AND LICENSE
This software is Copyright (c) 2011 by David Golden.
This is free software, licensed under:
The Apache License, Version 2.0, January 2004