providers/client.rb (95 lines of code) (raw):

# # Copyright 2017, Bloomberg Finance L.P. # # 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. # use_inline_resources def whyrun_supported? true end action :add do filename = @current_resource.filename keyname = @current_resource.keyname as_keyring = @current_resource.as_keyring owner = @new_resource.owner group = @new_resource.group mode = @new_resource.mode 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(keyname, key, as_keyring) owner owner group group mode mode sensitive true if Chef::Resource::File.method_defined? :sensitive end end 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.#{@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 = @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(keyname, key, as_keyring) if as_keyring "[#{keyname}]\n\tkey = #{key}\n" else key end end def get_key(keyname) cmd = "ceph auth print_key #{keyname} --name mon. --key='#{ceph_chef_mon_secret}'" Mixlib::ShellOut.new(cmd).run_command.stdout end def get_caps(keyname) caps = {} cmd = "ceph auth get #{keyname} --name mon. --key='#{ceph_chef_mon_secret}'" output = Mixlib::ShellOut.new(cmd).run_command.stdout output.scan(/caps\s*(\S+)\s*=\s*"([^"]*)"/) { |k, v| caps[k] = v } caps end def delete_entity(keyname) cmd_text = "ceph auth del #{keyname} --name mon. --key='#{ceph_chef_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='#{ceph_chef_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 end end