Skip to end of metadata
Go to start of metadata

Knife Plugins

Opscode Knife Plugins

See Launch Cloud Instances with Knife for detail on how to launch API-driven "Cloud" servers with Opscode Knife Plugins and automatically run Chef on the launched servers.

Installing Plugins

With Chef 0.10, knife will load commands from the following locations:

  • The core set of knife commands shipped with Chef
  • Commands in your home chef directory: ~/.chef/plugins/knife/
  • Commands in a .chef/plugins/knife/ directory in your cookbook repo
  • Commands located in a chef/knife/ directory in a Ruby Gem you have installed.

This allows you to conveniently keep a set of knife plugins that you reuse across projects in your home directory, share plugins with your team by including them in your cookbook repo, and share plugins with the whole Chef community by distributing them as Ruby gems.

To install a knife plugin from a file, such as a gist on github or email attachment, simply copy the file to your ~/.chef/plugins/knife/ directory. If you share a chef repo with your team and would like to share the plugin, copy the file to CHEF_REPO/.chef/plugins/knife/.

You can name the file anything you'd like as long as it's in this directory and has a .rb extension. You can also have multiple classes in one plugin file.

To use a plugin distributed as a rubygem, just install the gem.

Creating Plugins

Knife commands are Ruby classes that inherit from the Chef::Knife class. Knife will load your command regardless of how it is namespaced, so it is recommended that you put your commands in your own namespace. Knife commands are run by calling the `#run` method on an instance of your command class. For example, here is a "hello, world" knife command:



Chef Community Plugins

Review (or contribute to) a collection of Community Plugins Found In The Wild.

Knife, Chef, and Ohai plugins are available.


Notifying and Logging Resources with Knife Plugins

Nuclear Rooster did a nice blog post on using Chef's flexible reporting handlers and knife plugins for logging node updates, for easy debugging.


You should now be able to run this command using `knife hello world`. If you wanted the command to be `knife helloworld` instead, you would want to use `class Helloworld` with just the first letter capitalized.

You can also "override" current knife subcommands by using the class as the name of the subcommand, for example you could override the current functions of knife cookbook upload by using class CookbookUpload < Chef::Knife.

Command Line Options And Banners

If you run knife --help after creating the hello world plugin, you'll see this usage message:

    ** HELLO COMMANDS **
    Usage: /Users/ddeleo/opscode/chef/chef/bin/knife (options)

This isn't very helpful. Let's add a usage banner to match the other knife commands. You can add a banner by calling the banner method in the class body of your knife command class, like this:

Now the help for this command will look like this:

    ** HELLO COMMANDS **
    knife hello world

Command line options are added to your command using the Mixlib::CLI library. Let's add a flag to give our plugin more emotion. As with the banner, we define new command line options by calling the `option` method inside the class body, like this:

If we look at the help for our command, by running knife hello world --help, we can see that this option was added to the list:

When knife runs our command, it will parse the options from the command line and make the settings available to us as a Hash that we can access using the config method. We can update the run method of our class to change its behavior based on the config flag like this:

You can now run knife hello world --omg and you should see 'OMG HELLO WORLD!!!1!!11' in the output.

Command Line Arguments

Knife commands also take command line arguments that are not specified via an option flag (for example, knife node show NODE). You don't need to add any code to your knife command class to configure it to accept command line arguments; arguments are automatically made available via the name_args method. To illustrate, lets make our hello world command say hello to anyone:

Now that our command requires additional user input, we need to check the number of arguments and fail if the input doesn't make sense. Here we used the show_usage method to display the correct usage before exiting. Notice also that we updated the banner with the new usage for the command. With this update to our command, we have the following behaviors:

    shell > knife hello world
    You need to say hello to someone!
    USAGE: knife hello world WHO
      # options snipped...

    shell > knife hello world chefs
    Hello, Chefs!

    shell > knife hello world chefs --omg
    OMG HELLO CHEFS!!!1!!11

User Interaction

The ui object provides methods for user interaction that ensure a consistent user experience across knife plugins. Use these methods in favor of manually handling user interaction whenever possible. The following table summarizes the most useful methods:

Method Description
ui.msg(message) Presents a message to the user
ui.warn(message) Presents a warning to the user.
ui.error(message) Presents an error to the user.
ui.fatal(message) Presents a fatal error to the user.
ui.output(data) Present a data structure to the user. This function will respect the output the user requested with the -F command-line option. The generic presenter used by default is suitable for most data that will be passed to it in a knife plugin; however, a custom presenter can be provided using ui.use_presenter
ui.ask_question(question, opts={}) Asks the user the question contained in the string question. If :default => default_value is passed as the second argument, default_value will be used if the user does not provide an answer. This respects Knife's --default command line option.
ui.confirm(question) Ask a Y/N question. Immediately exit with status code 3 if user responds with N.
ui.highline Provides direct access to the HighLine object used by many ui methods. See http://highline.rubyforge.org/doc/

for more information.

Using these classes we can improve the error messaging in our example:

This ensures that our fatal error is shown in the same way as all other fatal errors in knife.

Handling Exceptions

Exceptions can be handled within your Knife plugin just as they can be handled in any Ruby program. However, in many cases the exception handling that Knife provides will be enough and ensure that your plugin's exception handling is consistent with the rest of Knife.

Handling Dependencies

You can declare all of your dependencies at the top of the file, but this will make knife load slower for all commands. It's recommended that you use knife's lazy loader within the plugin for any dependencies, so they are only used when you use the plugin command.

You can do this by adding this command below the `class` command for each plugin:

This would use the chef/server/query library, only whenever the `knife hello world` command is used.

Interacting With the Chef API using shef's DSL

Our example knife command is friendly, but it isn't very useful. In order to write useful knife commands, you will most likely want to interact with the Chef Server API in some way. There are two ways to do this. One way is to extend your knife command with shef's DSL for the API. This is an attractive way to go if you are looking to extend any existing `knife exec` scripts you already have. To do this, just require chef/shef/ext at the top of your file and then activate the Shef DSL by calling Shef::Extensions.extend_context_object(self) inside your run method. For example, we could write a knife command to search nodes like this:

You can also interact with the Chef API by using the model classes directly. Consult the chef source code and existing knife commands for examples.

Using Search

You can also use search within a plugin, to return information about your infrastructure and run knife commands. To do this you will need to add these lines to the top, so Ruby knows it'll need additional libraries for search:

Then you will want to create a Chef::Search::Query object and assign it to a variable:

Afterwards you can use the search method on this object to search, in this example it is searching for nodes with the webserver role and then prints the name of each of the nodes it finds:

You can also then use this to edit nodes, in this example it searches for any nodes with the webserver role and changes the runlist to a role named apache2:

This will overwrite any existing data on the attribute you edit. It's also possible to specify multiple items to add to the run_list:

You can also use the arguments you've sent with the plugin command to search. For instance in this example, if you used the command "knife envchange "web*" it would search for any nodes in roles beginning with "web" and change their environment to "web":

Using Plugins within Other Plugins

You can access the functionality of other knife plugins from within your own plugin. For instance, suppose that you write a plugin that needs to run a custom bootstrap command on a node. Rather than executing a knife command using the ` (backtick) operator, you can directly run the plugin from inside your own plugin. To do this, you need to do three things:

  1. require the necessary files to use the plugin's classes. The necessary files will change for each plugin. However, in most cases the library you want to include is in the form of chef/knife/name_of_command.
  2. Create a new object of the Class of the plugin you want to use.
  3. Pass any arguments or options to the object. You do this by altering the object's config and name_arg variables.
  4. Call the object's run method.

Existing Plugins

See Community Plugins for the Opscode Knife Plugins, in addition to plugins that have been developed and shared by the Chef Community. See Launch Cloud Instances with Knife for information on use of the Opscode Knife Plugins for launching cloud servers, including configuration and sub-command options.

Knife and Chef plugins can be distributed as gems. So an alternate way to find them is to just do a quick gem search.







Managing Roles With Knife


Community Plugins



Labels:
None
Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.