]> git-server-git.apps.pok.os.sepia.ceph.com Git - ceph-cookbooks.git/commitdiff
Support client creation with pre-generated key 200/head
authorSergio de Carvalho <scarvalhojr@users.noreply.github.com>
Thu, 7 May 2015 17:47:26 +0000 (18:47 +0100)
committerSergio de Carvalho <scarvalhojr@users.noreply.github.com>
Tue, 19 May 2015 13:43:59 +0000 (14:43 +0100)
Extend the client LWRP to allow a Ceph auth entity to be created with
a given key, instead of letting ceph auth generate a random one. This
is useful when the keys are managed elsewhere and are known beforehand.

Also, change the way an entity is recreated in case of a caps mismatch.
Instead of relying on parsing an error message from auth get-or-create,
explicitly check if entity exists and matches specification.

providers/client.rb
resources/client.rb

index d2154d3868ce32c956be2c777c278a908bd8919e..21b44c4f7d82aea0cbcea4ac482aab081e669e07 100644 (file)
@@ -5,26 +5,40 @@ def whyrun_supported?
 end
 
 action :add do
-  current_resource = @current_resource
   filename = @current_resource.filename
   keyname = @current_resource.keyname
-  caps = @new_resource.caps.map { |k, v| "#{k} '#{v}'" }.join(' ')
+  as_keyring = @current_resource.as_keyring
   owner = @new_resource.owner
   group = @new_resource.group
   mode = @new_resource.mode
-  unless @current_resource.caps_match
-    converge_by("Set caps for #{@new_resource}") do
-      auth_set_key(keyname, caps)
-      current_resource.key = get_key(keyname)
 
+  if @current_resource.exists
+    if @current_resource.keys_match && @current_resource.caps_match
+      Chef::Log.info "Client #{ @new_resource } already exists and matches "\
+                     'specifications - nothing to do.'
+    else
+      converge_by("Recreating client #{ @new_resource } as existing doesn't "\
+                  'match specifications') do
+        delete_entity(keyname)
+        create_entity(keyname)
+      end
+    end
+  else
+    converge_by("Creating client #{ @new_resource }") do
+      create_entity(keyname)
     end
   end
+
+  # Obtain the randomly generated key if one wasn't provided
+  key = @new_resource.key || get_key(keyname)
+
   # update the key in the file
   file filename do
-    content file_content
+    content file_content(keyname, key, as_keyring)
     owner owner
     group group
     mode mode
+    # sensitive true if Chef::Resource::File.method_defined? :sensitive # ~FC009
   end
 
 end
@@ -33,16 +47,22 @@ def load_current_resource
   @current_resource = Chef::Resource::CephClient.new(@new_resource.name)
   @current_resource.name(@new_resource.name)
   @current_resource.as_keyring(@new_resource.as_keyring)
-  @current_resource.keyname(@new_resource.keyname || "client.#{current_resource.name}.#{node['hostname']}")
+  @current_resource.keyname(@new_resource.keyname || "client.#{@new_resource.name}.#{node['hostname']}")
   @current_resource.caps(get_caps(@current_resource.keyname))
   default_filename = "/etc/ceph/ceph.client.#{@new_resource.name}.#{node['hostname']}.#{@new_resource.as_keyring ? 'keyring' : 'secret'}"
   @current_resource.filename(@new_resource.filename || default_filename)
-  @current_resource.key = get_key(@current_resource.keyname)
-  @current_resource.caps_match = true if @current_resource.caps == @new_resource.caps
+  @current_resource.key(get_key(@current_resource.keyname))
+  @current_resource.caps_match = @current_resource.caps == @new_resource.caps
+  @current_resource.keys_match = @new_resource.key.nil? || (@current_resource.key == @new_resource.key)
+  @current_resource.exists = ! (@current_resource.key.nil? || @current_resource.key.empty?)
 end
 
-def file_content
-  @current_resource.as_keyring ? "[#{@current_resource.keyname}]\n\tkey = #{@current_resource.key}\n" : @current_resource.key
+def file_content(keyname, key, as_keyring)
+  if as_keyring
+    "[#{keyname}]\n\tkey = #{key}\n"
+  else
+    key
+  end
 end
 
 def get_key(keyname)
@@ -58,19 +78,42 @@ def get_caps(keyname)
   caps
 end
 
-def auth_set_key(keyname, caps)
-  secret = mon_secret
-  # try to add the key
-  cmd = "ceph auth get-or-create #{keyname} #{caps} --name mon. --key='#{secret}'"
-  get_or_create = Mixlib::ShellOut.new(cmd)
-  get_or_create.run_command
-  if get_or_create.stderr.scan(/EINVAL.*but cap.*does not match/)
-    Chef::Log.info('Deleting old key with incorrect caps')
-    # delete an old key if it exists and is wrong
-    Mixlib::ShellOut.new("ceph auth del #{keyname} --name mon. --key='#{secret}'").run_command
-    # try to create again
-    get_or_create = Mixlib::ShellOut.new(cmd)
-    get_or_create.run_command
+def delete_entity(keyname)
+  cmd_text = "ceph auth del #{keyname} --name mon. --key='#{mon_secret}'"
+  cmd = Mixlib::ShellOut.new(cmd_text)
+  cmd.run_command
+  cmd.error!
+  Chef::Log.debug "Client #{keyname} deleted"
+end
+
+def create_entity(keyname)
+  tmp_keyring = "#{Chef::Config[:file_cache_path]}/.#{keyname}.keyring"
+
+  if new_resource.key
+    # store key provided in a temporary keyring file
+    cmd_text = "ceph-authtool #{tmp_keyring} --create-keyring --name #{keyname} "\
+               "--add-key '#{new_resource.key}'"
+    cmd = Mixlib::ShellOut.new(cmd_text)
+    cmd.run_command
+    cmd.error!
+
+    key_option = "-i #{tmp_keyring}"
+  else
+    key_option = ''
+  end
+
+  caps = new_resource.caps.map { |k, v| "#{k} '#{v}'" }.join(' ')
+
+  cmd_text = "ceph auth #{key_option} add #{keyname} #{caps} --name mon. "\
+             "--key='#{mon_secret}'"
+  cmd = Mixlib::ShellOut.new(cmd_text)
+  cmd.run_command
+  cmd.error!
+  Chef::Log.debug "Client #{keyname} created"
+
+  # remove temporary keyring file
+  file tmp_keyring do
+    action :delete
+    # sensitive true if Chef::Resource::File.method_defined? :sensitive # ~FC009
   end
-  get_or_create.error!
 end
index 2428b34d5fb0b90b42baf4790cd1dffee2876fcf..04d1dd96a536956739c8ede23dc21e0795223627 100644 (file)
@@ -11,6 +11,9 @@ attribute :as_keyring, :kind_of => [TrueClass, FalseClass], :default => true
 # defaults to client.#{name}.#{hostname}
 attribute :keyname, :kind_of => String
 
+# The actual key (a random key will be generated if not provided)
+attribute :key, :kind_of => String, :default => nil
+
 # where the key should be saved
 # defaults to /etc/ceph/ceph.client.#{name}.#{hostname}.keyring if as_keyring
 # defaults to /etc/ceph/ceph.client.#{name}.#{hostname}.secret if not as_keyring
@@ -21,4 +24,4 @@ attribute :owner, :kind_of => String, :default => 'root'
 attribute :group, :kind_of => String, :default => 'root'
 attribute :mode, :kind_of => [Integer, String], :default => '00640'
 
-attr_accessor :key, :caps_match
+attr_accessor :exists, :caps_match, :keys_match