class Chef::Knife::Bootstrap::ClientBuilder
Attributes
@return [Hash] chef config object
@return [Chef::ApiClient] client saved on run
@return [Hash] knife merged config, typically @config
@return [Chef::Knife::UI] ui object for output
Public Class Methods
@param knife_config
[Hash] Hash of knife config settings @param chef_config
[Hash] Hash of chef config settings @param ui [Chef::Knife::UI] UI
object for output
# File lib/chef/knife/bootstrap/client_builder.rb, line 42 def initialize(knife_config: {}, chef_config: {}, ui: nil) @knife_config = knife_config @chef_config = chef_config @ui = ui end
Public Instance Methods
Tempfile to use to write newly created client credentials to.
This method is public so that the knife bootstrapper can read then and pass the value into the handler for chef vault which needs the client cert we create here.
We hang onto the tmpdir as an ivar as well so that it will not get GC'd and removed
@return [String] path to the generated client.pem
# File lib/chef/knife/bootstrap/client_builder.rb, line 70 def client_path @client_path ||= begin @tmpdir = Dir.mktmpdir File.join(@tmpdir, "#{node_name}.pem") end end
Main entry. Prompt the user to clean up any old client or node objects. Then create the new client, then create the new node.
# File lib/chef/knife/bootstrap/client_builder.rb, line 50 def run sanity_check ui.info("Creating new client for #{node_name}") @client = create_client! ui.info("Creating new node for #{node_name}") create_node! end
Private Instance Methods
@return [String] chef server url from the Chef::Config
# File lib/chef/knife/bootstrap/client_builder.rb, line 111 def chef_server_url chef_config[:chef_server_url] end
@return [Chef::ServerAPI] REST client using the client credentials
# File lib/chef/knife/bootstrap/client_builder.rb, line 195 def client_rest @client_rest ||= Chef::ServerAPI.new(chef_server_url, client_name: node_name, signing_key_filename: client_path) end
Create the client object and save it to the Chef
API
# File lib/chef/knife/bootstrap/client_builder.rb, line 132 def create_client! Chef::ApiClient::Registration.new(node_name, client_path, http_api: rest).run end
Create the node object (via the lazy accessor) and save it to the Chef
API
# File lib/chef/knife/bootstrap/client_builder.rb, line 137 def create_node! node.save end
@return [String] enviroment from the knife_config
# File lib/chef/knife/bootstrap/client_builder.rb, line 86 def environment knife_config[:environment] end
@return [Hash,Array] Object
representation of json first-boot attributes from the knife_config
# File lib/chef/knife/bootstrap/client_builder.rb, line 106 def first_boot_attributes knife_config[:first_boot_attributes] end
Create a new Chef::Node
. Supports creating the node with its name, run_list
, attributes and environment. This injects a rest object into the Chef::Node
which uses the client key for authentication so that the client creates the node and therefore we get the acls setup correctly.
@return [Chef::Node] new chef node to create
# File lib/chef/knife/bootstrap/client_builder.rb, line 147 def node @node ||= begin node = Chef::Node.new(chef_server_rest: client_rest) node.name(node_name) node.run_list(normalized_run_list) node.normal_attrs = first_boot_attributes if first_boot_attributes node.environment(environment) if environment node.policy_name = policy_name if policy_name node.policy_group = policy_group if policy_group (knife_config[:tags] || []).each do |tag| node.tags << tag end node end end
@return [String] node name from the knife_config
# File lib/chef/knife/bootstrap/client_builder.rb, line 81 def node_name knife_config[:chef_node_name] end
Accesses the run_list
and coerces it into an Array, changing nils into the empty Array, and splitting strings representations of run_lists into Arrays.
@return [Array] run_list
coerced into an array
# File lib/chef/knife/bootstrap/client_builder.rb, line 120 def normalized_run_list case run_list when nil [] when String run_list.split(/\s*,\s*/) when Array run_list end end
@return [String] policy_group
from the knife_config
# File lib/chef/knife/bootstrap/client_builder.rb, line 101 def policy_group knife_config[:policy_group] end
@return [String] policy_name
from the knife_config
# File lib/chef/knife/bootstrap/client_builder.rb, line 96 def policy_name knife_config[:policy_name] end
Check if an relative path exists on the chef server
@param relative_path [String] URI path relative to the chef organization @return [Boolean] if the relative path exists or returns a 404
# File lib/chef/knife/bootstrap/client_builder.rb, line 186 def resource_exists?(relative_path) rest.get(relative_path) true rescue Net::HTTPClientException => e raise unless e.response.code == "404" false end
@return [Chef::ServerAPI] REST client using the cli user's knife credentials this uses the users's credentials
# File lib/chef/knife/bootstrap/client_builder.rb, line 201 def rest @rest ||= Chef::ServerAPI.new(chef_server_url) end
@return [String] run_list
from the knife_config
# File lib/chef/knife/bootstrap/client_builder.rb, line 91 def run_list knife_config[:run_list] end
Check for the existence of a node and/or client already on the server. If the node already exists, we must delete it in order to proceed so that we can create a new node object with the permissions of the new client. There is a use case for creating a new client and wiring it up to a precreated node object, but we do currently support that.
We prompt the user about what to do and will fail hard if we do not get confirmation to delete any prior node/client objects.
# File lib/chef/knife/bootstrap/client_builder.rb, line 171 def sanity_check if resource_exists?("nodes/#{node_name}") ui.confirm("Node #{node_name} exists, overwrite it") rest.delete("nodes/#{node_name}") end if resource_exists?("clients/#{node_name}") ui.confirm("Client #{node_name} exists, overwrite it") rest.delete("clients/#{node_name}") end end