summaryrefslogtreecommitdiff
path: root/lib/chef/api_client
diff options
context:
space:
mode:
authordanielsdeleo <dan@opscode.com>2012-12-18 10:47:24 -0800
committerdanielsdeleo <dan@opscode.com>2012-12-18 17:10:05 -0800
commita61c9865684466adcc9c933f05eebc1090624ea0 (patch)
tree224e1719aa7a49a2cd3e1e3c7265d204701121b5 /lib/chef/api_client
parent2de707d27251f38790a71043843749a570302aaf (diff)
downloadchef-a61c9865684466adcc9c933f05eebc1090624ea0.tar.gz
[CHEF-3689] Extract registration to a class
Diffstat (limited to 'lib/chef/api_client')
-rw-r--r--lib/chef/api_client/registration.rb110
1 files changed, 110 insertions, 0 deletions
diff --git a/lib/chef/api_client/registration.rb b/lib/chef/api_client/registration.rb
new file mode 100644
index 0000000000..d961e23ac2
--- /dev/null
+++ b/lib/chef/api_client/registration.rb
@@ -0,0 +1,110 @@
+#
+# Author:: Daniel DeLeo (<dan@opscode.com>)
+# Copyright:: Copyright (c) 2012 Opscode, Inc.
+# License:: Apache License, Version 2.0
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+require 'chef/config'
+require 'chef/rest'
+require 'chef/exceptions'
+
+class Chef
+ class ApiClient
+
+ # ==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.
+ class Registration
+ attr_reader :private_key
+ attr_reader :destination
+ attr_reader :name
+
+ def initialize(name, destination)
+ @name = name
+ @destination = destination
+ @private_key = nil
+ end
+
+ # Runs the client registration process, including creating the client on
+ # the chef-server and writing its private key to disk.
+ def run
+ assert_destination_writable!
+ retries = Config[:client_registration_retries] || 5
+ begin
+ create_or_update
+ rescue Net::HTTPFatalError => e
+ # only retry 500s
+ raise if retries <= 0 or e.response.code != "500"
+ retries -= 1
+ Chef::Log.warn("Failed to register new client, #{retries} tries remaining")
+ retry
+ end
+ write_key
+ end
+
+ def assert_destination_writable!
+ if (File.exists?(destination) && !File.writable?(destination))
+ raise Chef::Exceptions::CannotWritePrivateKey, "I cannot write your private key to #{destination} - check permissions?"
+ end
+ end
+
+ def write_key
+ ::File.open(destination, File::CREAT|File::TRUNC|File::RDWR|File::NOFOLLOW, 0600) do |f|
+ f.print(private_key)
+ end
+ rescue IOError => e
+ raise Chef::Exceptions::CannotWritePrivateKey, "Error writing private key to #{destination}: #{e}"
+ end
+
+ def create_or_update
+ create
+ rescue Net::HTTPServerException => e
+ # If create fails because the client exists, attempt to update. This
+ # requires admin privileges.
+ raise unless e.response.code == "409"
+ update
+ end
+
+ def create
+ response = http_api.post("clients", :name => name, :admin => false)
+ @private_key = response["private_key"]
+ response
+ end
+
+ def update
+ response = http_api.put("clients/#{name}", :name => name,
+ :admin => false,
+ :private_key => true)
+ if response.respond_to?(:private_key) # Chef 11
+ @private_key = response.private_key
+ else # Chef 10
+ @private_key = response["private_key"]
+ end
+ response
+ end
+
+ def http_api
+ @http_api_as_validator ||= Chef::REST.new(Chef::Config[:chef_server_url],
+ Chef::Config[:validation_client_name],
+ Chef::Config[:validation_key])
+ end
+ end
+ end
+end
+
+