Class: Chef::ApiClient::Registration
- Inherits:
-
Object
- Object
- Chef::ApiClient::Registration
- Defined in:
- lib/chef/api_client/registration.rb
Overview
Chef::ApiClient::Registration
Manages the process of creating or updating a Chef::ApiClient on the server and writing the resulting private key to disk. Registration uses the validator credentials for its API calls. This allows it to bootstrap a new client/node identity by borrowing the validator client identity when creating a new client.
Instance Attribute Summary collapse
-
#destination ⇒ Object
readonly
Returns the value of attribute destination.
-
#name ⇒ Object
readonly
Returns the value of attribute name.
Instance Method Summary collapse
- #api_client(response) ⇒ Object
- #api_client_key(response, key_name) ⇒ Object
- #assert_destination_writable! ⇒ Object
- #create ⇒ Object
- #create_or_update ⇒ Object
- #file_flags ⇒ Object
- #generated_private_key ⇒ Object
- #generated_public_key ⇒ Object
- #http_api ⇒ Object
-
#initialize(name, destination, http_api: nil) ⇒ Registration
constructor
A new instance of Registration.
- #post_data ⇒ Object
- #private_key ⇒ Object
- #put_data ⇒ Object
-
#run ⇒ Object
Runs the client registration process, including creating the client on the chef-server and writing its private key to disk.
-
#self_generate_keys? ⇒ Boolean
Whether or not to generate keys locally and post the public key to the server.
- #update ⇒ Object
- #write_key ⇒ Object
Constructor Details
permalink #initialize(name, destination, http_api: nil) ⇒ Registration
Returns a new instance of Registration.
37 38 39 40 41 42 |
# File 'lib/chef/api_client/registration.rb', line 37 def initialize(name, destination, http_api: nil) @name = name @destination = destination @http_api = http_api @server_generated_private_key = nil end |
Instance Attribute Details
permalink #destination ⇒ Object (readonly)
Returns the value of attribute destination.
34 35 36 |
# File 'lib/chef/api_client/registration.rb', line 34 def destination @destination end |
permalink #name ⇒ Object (readonly)
Returns the value of attribute name.
35 36 37 |
# File 'lib/chef/api_client/registration.rb', line 35 def name @name end |
Instance Method Details
permalink #api_client(response) ⇒ Object
[View source]
121 122 123 124 125 126 127 128 129 |
# File 'lib/chef/api_client/registration.rb', line 121 def api_client(response) return response if response.is_a?(Chef::ApiClient) client = Chef::ApiClient.new client.name(name) client.public_key(api_client_key(response, "public_key")) client.private_key(api_client_key(response, "private_key")) client end |
permalink #api_client_key(response, key_name) ⇒ Object
[View source]
131 132 133 134 135 136 137 138 139 140 141 |
# File 'lib/chef/api_client/registration.rb', line 131 def api_client_key(response, key_name) if response[key_name] if response[key_name].respond_to?(:to_pem) response[key_name].to_pem else response[key_name] end elsif response["chef_key"] response["chef_key"][key_name] end end |
permalink #assert_destination_writable! ⇒ Object
[View source]
73 74 75 76 77 78 79 80 81 82 83 84 85 |
# File 'lib/chef/api_client/registration.rb', line 73 def assert_destination_writable! abs_path = File.(destination) unless File.exist?(File.dirname(abs_path)) begin FileUtils.mkdir_p(File.dirname(abs_path)) rescue Errno::EACCES raise Chef::Exceptions::CannotWritePrivateKey, "I can't create the configuration directory at #{File.dirname(abs_path)} - check permissions?" end end if (File.exist?(abs_path) && !File.writable?(abs_path)) || !File.writable?(File.dirname(abs_path)) raise Chef::Exceptions::CannotWritePrivateKey, "I can't write your private key to #{abs_path} - check permissions?" end end |
permalink #create ⇒ Object
[View source]
105 106 107 108 109 |
# File 'lib/chef/api_client/registration.rb', line 105 def create response = http_api.post("clients", post_data) @server_generated_private_key = response["private_key"] response end |
permalink #create_or_update ⇒ Object
[View source]
95 96 97 98 99 100 101 102 103 |
# File 'lib/chef/api_client/registration.rb', line 95 def create_or_update create rescue Net::HTTPClientException => e # If create fails because the client exists, attempt to update. This # requires admin privileges. raise unless e.response.code == "409" update end |
permalink #file_flags ⇒ Object
[View source]
191 192 193 194 195 196 197 198 |
# File 'lib/chef/api_client/registration.rb', line 191 def file_flags base_flags = File::CREAT | File::TRUNC | File::RDWR # Windows doesn't have symlinks, so it doesn't have NOFOLLOW if defined?(File::NOFOLLOW) && !Chef::Config[:follow_client_key_symlink] base_flags |= File::NOFOLLOW end base_flags end |
permalink #generated_private_key ⇒ Object
[View source]
183 184 185 |
# File 'lib/chef/api_client/registration.rb', line 183 def generated_private_key @generated_key ||= OpenSSL::PKey::RSA.generate(2048) end |
permalink #generated_public_key ⇒ Object
[View source]
187 188 189 |
# File 'lib/chef/api_client/registration.rb', line 187 def generated_public_key generated_private_key.public_key.to_pem end |
permalink #http_api ⇒ Object
[View source]
159 160 161 162 163 164 165 166 |
# File 'lib/chef/api_client/registration.rb', line 159 def http_api @http_api ||= Chef::ServerAPI.new(Chef::Config[:chef_server_url], { api_version: "0", client_name: Chef::Config[:validation_client_name], signing_key_filename: Chef::Config[:validation_key], }) end |
permalink #post_data ⇒ Object
[View source]
153 154 155 156 157 |
# File 'lib/chef/api_client/registration.rb', line 153 def post_data post_data = { name: name, admin: false } post_data[:public_key] = generated_public_key if self_generate_keys? post_data end |
permalink #private_key ⇒ Object
[View source]
175 176 177 178 179 180 181 |
# File 'lib/chef/api_client/registration.rb', line 175 def private_key if self_generate_keys? generated_private_key.to_pem else @server_generated_private_key end end |
permalink #put_data ⇒ Object
[View source]
143 144 145 146 147 148 149 150 151 |
# File 'lib/chef/api_client/registration.rb', line 143 def put_data base_put_data = { name: name, admin: false } if self_generate_keys? base_put_data[:public_key] = generated_public_key else base_put_data[:private_key] = true end base_put_data end |
permalink #run ⇒ Object
Runs the client registration process, including creating the client on the chef-server and writing its private key to disk. – If client creation fails with a 5xx, it is retried up to 5 times. These retries are on top of the retries with randomized exponential backoff built in to Chef::ServerAPI. The retries here are a workaround for failures caused by resource contention in Hosted Chef when creating a very large number of clients simultaneously, (e.g., spinning up 100s of ec2 nodes at once). Future improvements to the affected component should make these retries unnecessary.
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
# File 'lib/chef/api_client/registration.rb', line 54 def run assert_destination_writable! retries = Config[:client_registration_retries] || 5 client = nil begin client = api_client(create_or_update) rescue Net::HTTPFatalError => e # HTTPFatalError implies 5xx. raise if retries <= 0 retries -= 1 Chef::Log.warn("Failed to register new client, #{retries} tries remaining") Chef::Log.warn("Response: HTTP #{e.response.code} - #{e}") retry end write_key client end |
permalink #self_generate_keys? ⇒ Boolean
Whether or not to generate keys locally and post the public key to the server. Delegates to ‘Chef::Config.local_key_generation`. Servers before 11.0 do not support this feature.
171 172 173 |
# File 'lib/chef/api_client/registration.rb', line 171 def self_generate_keys? Chef::Config.local_key_generation end |
permalink #update ⇒ Object
[View source]
111 112 113 114 115 116 117 118 119 |
# File 'lib/chef/api_client/registration.rb', line 111 def update response = http_api.put("clients/#{name}", put_data) if response.respond_to?(:private_key) # Chef 11 @server_generated_private_key = response.private_key else # Chef 10 @server_generated_private_key = response["private_key"] end response end |
permalink #write_key ⇒ Object
[View source]
87 88 89 90 91 92 93 |
# File 'lib/chef/api_client/registration.rb', line 87 def write_key ::File.open(destination, file_flags, 0600) do |f| f.print(private_key) end rescue IOError => e raise Chef::Exceptions::CannotWritePrivateKey, "Error writing private key to #{destination}: #{e}" end |