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 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(config: {}, knife_config: nil, chef_config: {}, ui: nil) @config = config unless knife_config.nil? @config = knife_config Chef.deprecated(:knife_bootstrap_apis, "The knife_config option to the Bootstrap::ClientBuilder object is deprecated and has been renamed to just 'config'") end @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 74 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 54 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 115 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 200 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 136 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 141 def create_node! node.save end
@return [String] environment from the config
# File lib/chef/knife/bootstrap/client_builder.rb, line 90 def environment config[:environment] end
@return [Hash,Array] Object representation of json first-boot attributes from the config
# File lib/chef/knife/bootstrap/client_builder.rb, line 110 def first_boot_attributes 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 151 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 (config[:tags] || []).each do |tag| node.tags << tag end node end end
@return [String] node name from the config
# File lib/chef/knife/bootstrap/client_builder.rb, line 85 def node_name 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 124 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 config
# File lib/chef/knife/bootstrap/client_builder.rb, line 105 def policy_group config[:policy_group] end
@return [String] policy_name
from the config
# File lib/chef/knife/bootstrap/client_builder.rb, line 100 def policy_name 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 190 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 206 def rest @rest ||= Chef::ServerAPI.new(chef_server_url) end
@return [String] run_list
from the config
# File lib/chef/knife/bootstrap/client_builder.rb, line 95 def run_list 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 175 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