summaryrefslogtreecommitdiff
path: root/knife/docs/dev/README.md
blob: 76cab6a7be0f741f869fc7bb190f42baff464a3f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# Developer's Guide to Knife

## Overview

knife is a command-line tool that provides an interface between a local Chef repository and the Chef Infra Server. Read more about knife [here](https://docs.chef.io/workstation/knife/).

## Development setup

To setup knife for development-
1. Fork and clone the [chef repository](https://github.com/chef/chef) in GitHub.
1. Ensure you have Ruby 3.x installed on your system. You will additionally need tools such as `make` and `gcc`. These are usually already present on most Linux distributions or on your macOS.
1. Navigate to chef/knife and run `bundle install`.
1. You can run knife commands in this setup by executing `bundle exec knife <subcommand> <argument> <options>`.
1. Refer to the article [Setting up Knife](https://docs.chef.io/workstation/knife_setup/) for help with necessary configuration.
1. byebug or your preferred Ruby debugger can be used to step through the execution flow.

## Execution Flow

The execution starts by instantiating the `Chef::Application::Knife` class with its `run` instance method being invoked. Ref [knife/bin/knife](https://github.com/chef/chef/blob/main/knife/bin/knife). The `Chef::Application` class helps work with CLI command options through the `Mixlib::CLI` module. This `run` instance method in turn invokes the `Chef::Knife`'s `run` class method. `Chef::Knife` acts as the base class for some of the classes associated with knife subcommands such as `Chef::Knife::NodeCreate`, `Chef::Knife::SupermarketList`, `Chef::Knife::Bootstrap`, etc. The role of `Chef::Knife` is summarized here:

- Identify the subcommand supplied.
- Merge subcommand specific CLI options, if any.
- Load dependencies to help subclass perform subcommand action.
- Instantiate the associated subclass.
- Set up a local-mode Chef server if chef-zero is configured.
- Run the subcommand action.

With this design, most classes associated with subcommands only need to implement the `run` instance method, while the setup and context is broadly taken care of by `Chef::Knife`. The `Chef::Knife::Bootstrap` class is somewhat of an exception here, as its functionality requires a rather elaborate set of methods and additional classes. That said, not all classes associated with subcommands directly inherit `Chef::Knife`. These inherit the `Chef::ChefFS::Knife` class of the `Chef::ChefFS` module. `Chef::ChefFS::Knife` happens to be a subclass of `Chef::Knife` to avoid redundancy. `Chef::ChefFS` [module](https://www.rubydoc.info/gems/chef/Chef/ChefFS) encapsulates classes and modules that help map the Chef server objects to the local chef repository using a file/directory analogy. It also employs a parallel thread utility to speed up command execution. Examples of such Knife classes are `Chef::Knife::Upload`, `Chef::Knife::Diff` & `Chef::Knife::List`.

## Knife Bootstrap

As `bootstrap` is a remote/distributed operation, there are several phases to it:
- Set up knife plugin, if needed.
- Validate if the specified protocol to connect to client node is supported.
- Validate if the transport and policy options are correct.
- Establish connection with the server where chef client is to be deployed. The connection is identified by a `Chef::Knife::Bootstrap::TrainConnector` instance.
- Define the `Chef::Node` instance that represents the server & update this object in Chef server. The class `Chef::Knife::Bootstrap::ClientBuilder` encapsulates this functionality.
- Update the Chef vault item(s) so the new node has access to those. The class `Chef::Knife::Bootstrap::ChefVaultHandler` encapsulates this functionality.
- Prepare the `bootstrap.bat` or `bootstrap.sh` script based on the bootstrap template.
- Copy and execute the bootstrap script on the remote server.

## Knife Plugins

The choice of mapping subcommand action to `Chef::Knife` subclass makes it easy to author knife custom plugins. These can help with extending knife capabilities for specific cloud platforms or customize knife behavior for a subset of subcommands. Follow the instructions [here](https://docs.chef.io/workstation/plugin_knife_custom/) to develop your own knife plugin. Detailed documentation on writing knife cloud plugins is available [here](https://github.com/chef/knife-cloud/blob/main/README.md).