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 43 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 71 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 51 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 112 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 196 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 133 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 138 def create_node! node.save end
@return [String] enviroment from the #knife_config
# File lib/chef/knife/bootstrap/client_builder.rb, line 87 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 107 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 148 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 82 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 121 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 102 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 97 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 187 def resource_exists?(relative_path) rest.get(relative_path) true rescue Net::HTTPServerException => 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 202 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 92 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 172 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