From 38cbfde68bd287e07e7a4dde9756f311537c4341 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81cs=20S=C3=A1ndor?= Date: Mon, 5 Oct 2015 07:18:45 +0200 Subject: [PATCH 1/3] Add RBD LWRP. --- .kitchen.yml | 1 + README.md | 16 ++ providers/rbd.rb | 158 ++++++++++++++++++ recipes/rbd_images.rb | 25 +++ resources/rbd.rb | 24 +++ .../ceph_test/attributes/ceph_rbd.rb | 1 + test/cookbooks/ceph_test/recipes/rbd.rb | 35 ++++ test/integration/aio/bats/ceph_rbd.bats | 11 ++ 8 files changed, 271 insertions(+) create mode 100644 providers/rbd.rb create mode 100644 recipes/rbd_images.rb create mode 100644 resources/rbd.rb create mode 100644 test/cookbooks/ceph_test/attributes/ceph_rbd.rb create mode 100644 test/cookbooks/ceph_test/recipes/rbd.rb create mode 100644 test/integration/aio/bats/ceph_rbd.bats diff --git a/.kitchen.yml b/.kitchen.yml index ae7e508..2e78206 100644 --- a/.kitchen.yml +++ b/.kitchen.yml @@ -65,3 +65,4 @@ suites: run_list: - recipe[ceph::all_in_one] - recipe[ceph_test::cephfs] + - recipe[ceph_test::rbd] \ No newline at end of file diff --git a/README.md b/README.md index f7a6e7c..5d9bc52 100644 --- a/README.md +++ b/README.md @@ -199,6 +199,22 @@ It assumes that connectivity to the cluster is setup and that admin credentials - :create_options - arguments for pool creation (optional) - :force - force the deletion of an exiting pool along with any data that is stored in it +### ceph\_rbd (Rados Block Device) + +The ceph\_rbd LWRP provides an easy way to create, delete, attach and detach rados block devices. + +#### Actions + +- :crete - creates an rbd with the given parameters +- :delete - deletes an rbd +- :attach - attach an existing rbd +- :detach - detach rbd + +#### Parameters + +- :name - the name of the new rbd +- :size - the size of the new rbd + ## DEVELOPING ### Style Guide diff --git a/providers/rbd.rb b/providers/rbd.rb new file mode 100644 index 0000000..1d4e049 --- /dev/null +++ b/providers/rbd.rb @@ -0,0 +1,158 @@ +# +# Cookbook Name:: ceph +# Provider:: rbd +# +# Authors:: Sandor Acs , Krisztian Gacsal +# + +def whyrun_supported? + true +end + +use_inline_resources + +action :attach do + if @current_resource.attached + Chef::Log.info "#{@new_resource} already attached - nothing to do." + else + converge_by("Attach RBD: #{@new_resource.name}") do + create_client + attach_rbd_image(@new_resource.pool, @new_resource.name) + end + end +end + +action :detach do + if ! @current_resource.attached + Chef::Log.info "#{@new_resource} does not attached - nothing to do." + else + converge_by("Detach RBD: #{@new_resource.name}") do + detach_rbd_image(@new_resource.pool, @new_resource.name) + end + end +end + +action :create do + if @current_resource.exists + Chef::Log.info "#{@new_resource} already created - nothing to do." + else + converge_by("Create RBD: #{@new_resource.name}") do + create_client + create_rbd_image(@new_resource.pool, @new_resource.name, @new_resource.size) + end + end +end + +action :delete do + if ! @current_resource.exists + Chef::Log.info "#{@new_resource} does not exist - nothing to do." + else + converge_by("Delete RBD: #{@new_resource.name}") do + delete_rbd_image(@new_resource.pool, @new_resource.name) + end + end +end + +def load_current_resource + @current_resource = Chef::Resource::CephRbd.new(@new_resource.name) + @current_resource.name(@new_resource.name) + @current_resource.pool(@new_resource.pool) + @current_resource.size(@new_resource.size) + @current_resource.exists = rbd_exists?(@current_resource.pool, @current_resource.name) + @current_resource.attached = rbd_attached?(@current_resource.pool, @current_resource.name) +end + +def rbd_exists?(pool, image) + cmd = Mixlib::ShellOut.new("rbd info #{pool}/#{image}") + cmd.run_command + cmd.error! + Chef::Log.debug "RBD exists: #{cmd.stdout}" + true +rescue + Chef::Log.debug "RBD doesn't seem to exist: #{cmd.stderr}" + false +end + +def rbd_attached?(pool, image) + id = "rbd.#{node['hostname']}" + keyring = "/etc/ceph/ceph.client.#{id}.secret" + + cmd = Mixlib::ShellOut.new("rbd showmapped --id #{id} --keyfile #{keyring}|grep '#{pool} #{image}'") + cmd.run_command + cmd.error! + Chef::Log.debug "RBD attached: #{cmd.stdout}" + true +rescue + Chef::Log.debug "RBD doesn't seem to exist: #{cmd.stderr}" + false +end + +def create_client + id = "rbd.#{node['hostname']}" + filename = "/etc/ceph/ceph.client.#{id}.secret" + + name = 'rbd' + ceph_client name do + filename filename + caps('mon' => 'allow r', 'osd' => 'allow rw') + as_keyring false + end +end + +def attach_rbd_image(pool, image) + id = "rbd.#{node['hostname']}" + keyring = "/etc/ceph/ceph.client.#{id}.secret" + + ruby_block 'Add RBD to rbdmap' do + block do + rc = Chef::Util::FileEdit.new('/etc/ceph/rbdmap') + rc.insert_line_if_no_match(%r{#{pool}\/#{image}\tid=#{id},keyring=#{keyring}}, "%r{#{pool}/#{image}\tid=#{id},keyring=#{keyring}}") + rc.write_file + end + only_if { rbd_exists?(pool, image) } + end + + execute 'attach_rbd' do + command "rbd map #{pool}/#{image}" + only_if { rbd_exists?(pool, image) } + end +end + +def detach_rbd_image(pool, image) + id = "rbd.#{node['hostname']}" + keyring = "/etc/ceph/ceph.client.#{id}.secret" + + execute 'detach_rbd' do + command "rbd unmap /dev/rbd/#{pool}/#{image} --id #{id} --keyfile #{keyring}" + end + + ruby_block 'Remove RBD from rbdmap' do + block do + rc = Chef::Util::FileEdit.new('/etc/ceph/rbdmap') + rc.search_file_delete_line(%r{#{pool}\/#{image}\tid=#{id},keyring=#{keyring}}) + rc.write_file + end + end +end + +def create_rbd_image(pool, image, size) + id = "rbd.#{node['hostname']}" + keyring = "/etc/ceph/ceph.client.#{id}.secret" + + cmd_text = "rbd create #{image} --size #{size} --pool #{pool} --id #{id} --keyfile #{keyring}" + cmd = Mixlib::ShellOut.new(cmd_text) + cmd.run_command + cmd.error! + Chef::Log.debug "RBD image created: #{cmd.stdout}" +end + +def delete_rbd_image(pool, image) + id = "rbd.#{node['hostname']}" + keyring = "/etc/ceph/ceph.client.#{id}.secret" + + cmd_text = "rbd rm #{image} --pool #{pool} --id #{id} --keyfile #{keyring}" + cmd = Mixlib::ShellOut.new(cmd_text) + cmd.run_command + cmd.error! + Chef::Log.debug "RBD image deleted: #{cmd.stdout}" +end diff --git a/recipes/rbd_images.rb b/recipes/rbd_images.rb new file mode 100644 index 0000000..ab55fcc --- /dev/null +++ b/recipes/rbd_images.rb @@ -0,0 +1,25 @@ +# +# Cookbook Name:: ceph +# Provider:: rbd +# +# Authors:: Sandor Acs , Krisztian Gacsal +# + +id = "rbd.#{node['hostname']}" +filename = "/etc/ceph/ceph.client.#{id}.secret" + +ceph_client 'rbd' do + filename filename + caps('mon' => 'allow r', 'osd' => 'allow rw') + as_keyring false +end + +if node['ceph']['user_rbd_images'] + node['ceph']['user_rbd_images'].each do |image| + # Create user-defined images + ceph_rbd image['name'] do + size image['size'] + action :create + end + end +end diff --git a/resources/rbd.rb b/resources/rbd.rb new file mode 100644 index 0000000..02975d3 --- /dev/null +++ b/resources/rbd.rb @@ -0,0 +1,24 @@ +# +# Cookbook Name:: ceph +# Provider:: rbd +# +# Authors:: Sandor Acs , Krisztian Gacsal +# +actions :attach, :detach, :create, :delete +default_action :attach + +attribute :name, :name_attribute => true, :kind_of => String, :required => true + +# Name of the pool that stores the image +attribute :pool, :kind_of => String, :default => 'rbd' + +# Size of the image +attribute :size, :kind_of => [Integer, String], :default => '1024' + +# Client ID +attribute :id, :kind_of => String, :required => true + +# Client keyring +attribute :keyring, :kind_of => String, :required => true + +attr_accessor :exists, :attached diff --git a/test/cookbooks/ceph_test/attributes/ceph_rbd.rb b/test/cookbooks/ceph_test/attributes/ceph_rbd.rb new file mode 100644 index 0000000..a7ba12e --- /dev/null +++ b/test/cookbooks/ceph_test/attributes/ceph_rbd.rb @@ -0,0 +1 @@ +default['ceph']['user_rbd_images'] = [{ 'name' => 'rbd_test', 'size' => '128' }] diff --git a/test/cookbooks/ceph_test/recipes/rbd.rb b/test/cookbooks/ceph_test/recipes/rbd.rb new file mode 100644 index 0000000..d36ae91 --- /dev/null +++ b/test/cookbooks/ceph_test/recipes/rbd.rb @@ -0,0 +1,35 @@ +# +# Cookbook Name:: ceph +# Provider:: rbd +# +# Authors:: Sandor Acs , Krisztian Gacsal +# + +execute 'start rbd kernel module' do + command 'modprobe rbd' + user 'root' + group 'root' +end + +include_recipe 'ceph::rbd_images' + +ceph_rbd 'rbd_test' do + action :attach +end + +ceph_rbd 'full_test' do + action :create + size '128' +end + +ceph_rbd 'full_test' do + action :attach +end + +ceph_rbd 'full_test' do + action :detach +end + +ceph_rbd 'full_test' do + action :delete +end diff --git a/test/integration/aio/bats/ceph_rbd.bats b/test/integration/aio/bats/ceph_rbd.bats new file mode 100644 index 0000000..41374c4 --- /dev/null +++ b/test/integration/aio/bats/ceph_rbd.bats @@ -0,0 +1,11 @@ +@test "test rbd is created" { + rbd info rbd/rbd_test +} + +@test "test rbd is in rbdmap" { + grep rbd_test /etc/ceph/rbdmap +} + +@test "test rbd is attached" { + rbd showmapped|grep 'rbd rbd_test' +} From 97a02bb3fb34ba9cfb3e5cf9cd04731ffc2062b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81cs=20S=C3=A1ndor?= Date: Mon, 19 Oct 2015 16:18:05 +0200 Subject: [PATCH 2/3] RBD LWRP should not create client credentials. --- providers/rbd.rb | 71 ++++++++----------------- recipes/rbd_images.rb | 5 +- test/cookbooks/ceph_test/recipes/rbd.rb | 15 +++++- test/integration/aio/bats/ceph_rbd.bats | 4 +- 4 files changed, 41 insertions(+), 54 deletions(-) diff --git a/providers/rbd.rb b/providers/rbd.rb index 1d4e049..0469f7d 100644 --- a/providers/rbd.rb +++ b/providers/rbd.rb @@ -16,8 +16,7 @@ def whyrun_supported? Chef::Log.info "#{@new_resource} already attached - nothing to do." else converge_by("Attach RBD: #{@new_resource.name}") do - create_client - attach_rbd_image(@new_resource.pool, @new_resource.name) + attach_rbd_image(@new_resource.pool, @new_resource.name, @new_resource.id, @new_resource.keyring) end end end @@ -27,7 +26,7 @@ def whyrun_supported? Chef::Log.info "#{@new_resource} does not attached - nothing to do." else converge_by("Detach RBD: #{@new_resource.name}") do - detach_rbd_image(@new_resource.pool, @new_resource.name) + detach_rbd_image(@new_resource.pool, @new_resource.name, @new_resource.id, @new_resource.keyring) end end end @@ -37,8 +36,7 @@ def whyrun_supported? Chef::Log.info "#{@new_resource} already created - nothing to do." else converge_by("Create RBD: #{@new_resource.name}") do - create_client - create_rbd_image(@new_resource.pool, @new_resource.name, @new_resource.size) + create_rbd_image(@new_resource.pool, @new_resource.name, @new_resource.size, @new_resource.id, @new_resource.keyring) end end end @@ -48,7 +46,7 @@ def whyrun_supported? Chef::Log.info "#{@new_resource} does not exist - nothing to do." else converge_by("Delete RBD: #{@new_resource.name}") do - delete_rbd_image(@new_resource.pool, @new_resource.name) + delete_rbd_image(@new_resource.pool, @new_resource.name, @new_resource.id, @new_resource.keyring) end end end @@ -57,13 +55,15 @@ def load_current_resource @current_resource = Chef::Resource::CephRbd.new(@new_resource.name) @current_resource.name(@new_resource.name) @current_resource.pool(@new_resource.pool) + @current_resource.id(@new_resource.id) + @current_resource.keyring(@new_resource.keyring) @current_resource.size(@new_resource.size) - @current_resource.exists = rbd_exists?(@current_resource.pool, @current_resource.name) - @current_resource.attached = rbd_attached?(@current_resource.pool, @current_resource.name) + @current_resource.exists = rbd_exists?(@current_resource.pool, @current_resource.name, @current_resource.id, @current_resource.keyring) + @current_resource.attached = rbd_attached?(@current_resource.pool, @current_resource.name, @current_resource.id, @current_resource.keyring) end -def rbd_exists?(pool, image) - cmd = Mixlib::ShellOut.new("rbd info #{pool}/#{image}") +def rbd_exists?(pool, image, id, keyring) + cmd = Mixlib::ShellOut.new("rbd info #{pool}/#{image} --id #{id} --keyring=#{keyring}") cmd.run_command cmd.error! Chef::Log.debug "RBD exists: #{cmd.stdout}" @@ -73,11 +73,8 @@ def rbd_exists?(pool, image) false end -def rbd_attached?(pool, image) - id = "rbd.#{node['hostname']}" - keyring = "/etc/ceph/ceph.client.#{id}.secret" - - cmd = Mixlib::ShellOut.new("rbd showmapped --id #{id} --keyfile #{keyring}|grep '#{pool} #{image}'") +def rbd_attached?(pool, image, id, keyring) + cmd = Mixlib::ShellOut.new("rbd showmapped --id #{id} --keyring=#{keyring}|grep '#{pool} #{image}'") cmd.run_command cmd.error! Chef::Log.debug "RBD attached: #{cmd.stdout}" @@ -87,43 +84,25 @@ def rbd_attached?(pool, image) false end -def create_client - id = "rbd.#{node['hostname']}" - filename = "/etc/ceph/ceph.client.#{id}.secret" - - name = 'rbd' - ceph_client name do - filename filename - caps('mon' => 'allow r', 'osd' => 'allow rw') - as_keyring false - end -end - -def attach_rbd_image(pool, image) - id = "rbd.#{node['hostname']}" - keyring = "/etc/ceph/ceph.client.#{id}.secret" - +def attach_rbd_image(pool, image, id, keyring) ruby_block 'Add RBD to rbdmap' do block do rc = Chef::Util::FileEdit.new('/etc/ceph/rbdmap') rc.insert_line_if_no_match(%r{#{pool}\/#{image}\tid=#{id},keyring=#{keyring}}, "%r{#{pool}/#{image}\tid=#{id},keyring=#{keyring}}") rc.write_file end - only_if { rbd_exists?(pool, image) } + only_if { rbd_exists?(pool, image, id, keyring) } end execute 'attach_rbd' do - command "rbd map #{pool}/#{image}" - only_if { rbd_exists?(pool, image) } + command "rbd map #{pool}/#{image} --id #{id} --keyring #{keyring}" + only_if { rbd_exists?(pool, image, id, keyring) } end end -def detach_rbd_image(pool, image) - id = "rbd.#{node['hostname']}" - keyring = "/etc/ceph/ceph.client.#{id}.secret" - +def detach_rbd_image(pool, image, id, keyring) execute 'detach_rbd' do - command "rbd unmap /dev/rbd/#{pool}/#{image} --id #{id} --keyfile #{keyring}" + command "rbd unmap /dev/rbd/#{pool}/#{image} --id #{id} --keyring=#{keyring}" end ruby_block 'Remove RBD from rbdmap' do @@ -135,22 +114,16 @@ def detach_rbd_image(pool, image) end end -def create_rbd_image(pool, image, size) - id = "rbd.#{node['hostname']}" - keyring = "/etc/ceph/ceph.client.#{id}.secret" - - cmd_text = "rbd create #{image} --size #{size} --pool #{pool} --id #{id} --keyfile #{keyring}" +def create_rbd_image(pool, image, size, id, keyring) + cmd_text = "rbd create #{image} --size #{size} --pool #{pool} --id #{id} --keyring=#{keyring}" cmd = Mixlib::ShellOut.new(cmd_text) cmd.run_command cmd.error! Chef::Log.debug "RBD image created: #{cmd.stdout}" end -def delete_rbd_image(pool, image) - id = "rbd.#{node['hostname']}" - keyring = "/etc/ceph/ceph.client.#{id}.secret" - - cmd_text = "rbd rm #{image} --pool #{pool} --id #{id} --keyfile #{keyring}" +def delete_rbd_image(pool, image, id, keyring) + cmd_text = "rbd rm #{image} --pool #{pool} --id #{id} --keyring=#{keyring}" cmd = Mixlib::ShellOut.new(cmd_text) cmd.run_command cmd.error! diff --git a/recipes/rbd_images.rb b/recipes/rbd_images.rb index ab55fcc..a9fd233 100644 --- a/recipes/rbd_images.rb +++ b/recipes/rbd_images.rb @@ -10,8 +10,7 @@ ceph_client 'rbd' do filename filename - caps('mon' => 'allow r', 'osd' => 'allow rw') - as_keyring false + caps('mon' => 'allow r', 'osd' => 'allow * pool=rbd') end if node['ceph']['user_rbd_images'] @@ -19,6 +18,8 @@ # Create user-defined images ceph_rbd image['name'] do size image['size'] + id id + keyring filename action :create end end diff --git a/test/cookbooks/ceph_test/recipes/rbd.rb b/test/cookbooks/ceph_test/recipes/rbd.rb index d36ae91..765382c 100644 --- a/test/cookbooks/ceph_test/recipes/rbd.rb +++ b/test/cookbooks/ceph_test/recipes/rbd.rb @@ -13,23 +13,36 @@ include_recipe 'ceph::rbd_images' +id = "rbd.#{node['hostname']}" +filename = "/etc/ceph/ceph.client.#{id}.secret" + ceph_rbd 'rbd_test' do + id id + keyring filename action :attach end ceph_rbd 'full_test' do - action :create size '128' + id id + keyring filename + action :create end ceph_rbd 'full_test' do + id id + keyring filename action :attach end ceph_rbd 'full_test' do + id id + keyring filename action :detach end ceph_rbd 'full_test' do + id id + keyring filename action :delete end diff --git a/test/integration/aio/bats/ceph_rbd.bats b/test/integration/aio/bats/ceph_rbd.bats index 41374c4..418b881 100644 --- a/test/integration/aio/bats/ceph_rbd.bats +++ b/test/integration/aio/bats/ceph_rbd.bats @@ -1,5 +1,5 @@ @test "test rbd is created" { - rbd info rbd/rbd_test + rbd info rbd/rbd_test --id=rbd.vagrant --keyring=/etc/ceph/ceph.client.rbd.vagrant.secret } @test "test rbd is in rbdmap" { @@ -7,5 +7,5 @@ } @test "test rbd is attached" { - rbd showmapped|grep 'rbd rbd_test' + rbd showmapped --id=rbd.vagrant --keyring=/etc/ceph/ceph.client.rbd.vagrant.secret |grep 'rbd rbd_test' } From 98efe898d75323809a616d43ff17565c30ac2d9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81cs=20S=C3=A1ndor?= Date: Mon, 19 Oct 2015 17:03:16 +0200 Subject: [PATCH 3/3] Fix RBD LWRP section in readme file. --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 5d9bc52..37558f6 100644 --- a/README.md +++ b/README.md @@ -214,6 +214,8 @@ The ceph\_rbd LWRP provides an easy way to create, delete, attach and detach rad - :name - the name of the new rbd - :size - the size of the new rbd +- :id - the id of the client (e.g admin) +- :keyring - the path of the keyring file (e.g /etc/ceph/ceph.client.admin.keyring) ## DEVELOPING