diff --git a/README.md b/README.md index 7bae1fea..4ffbc50f 100644 --- a/README.md +++ b/README.md @@ -131,22 +131,14 @@ cinder::backend::rbd {'rbd-images': rbd_user => 'images', } -# Cinder::Type requires keystone credentials -Cinder::Type { - os_password => 'admin', - os_tenant_name => 'admin', - os_username => 'admin', - os_auth_url => 'http://127.0.0.1:5000/v2.0/', +cinder_type {'iscsi': + ensure => present, + properties => ['volume_backend_name=iscsi,iscsi1,iscsi2'], } -cinder::type {'iscsi': - set_key => 'volume_backend_name', - set_value => ['iscsi1', 'iscsi2', 'iscsi'] -} - -cinder::type {'rbd': - set_key => 'volume_backend_name', - set_value => 'rbd-images', +cinder_type {'rbd-images': + ensure => present, + properties => ['volume_backend_name=rbd-images'], } class { 'cinder::backends': @@ -157,13 +149,14 @@ class { 'cinder::backends': Note: that the name passed to any backend resource must be unique accross all backends otherwise a duplicate resource will be defined. -** Using type and type_set ** +** Using cinder_type ** Cinder allows for the usage of type to set extended information that can be -used for various reasons. We have resource provider for ``type`` and -``type_set`` Since types are rarely defined with out also setting attributes -with it, the resource for ``type`` can also call ``type_set`` if you pass -``set_key`` and ``set_value`` +used for various reasons. We have resource provider for ``cinder_type`` +and if you want create some cinder type, you should set ensure to absent. +Properties field is optional and should be an array. All items of array +should match pattern key=value1[,value2 ...]. In case when you want to +delete some type - set ensure to absent. Implementation diff --git a/lib/puppet/provider/cinder.rb b/lib/puppet/provider/cinder.rb new file mode 100644 index 00000000..829a3353 --- /dev/null +++ b/lib/puppet/provider/cinder.rb @@ -0,0 +1,76 @@ +require 'puppet/util/inifile' +require 'puppet/provider/openstack' +require 'puppet/provider/openstack/auth' +require 'puppet/provider/openstack/credentials' + +class Puppet::Provider::Cinder < Puppet::Provider::Openstack + + extend Puppet::Provider::Openstack::Auth + + def self.conf_filename + '/etc/cinder/cinder.conf' + end + + def self.cinder_conf + return @cinder_conf if @cinder_conf + @cinder_conf = Puppet::Util::IniConfig::File.new + @cinder_conf.read(conf_filename) + @cinder_conf + end + + def self.request(service, action, properties=nil) + begin + super + rescue Puppet::Error::OpenstackAuthInputError, Puppet::Error::OpenstackUnauthorizedError => error + cinder_request(service, action, error, properties) + end + end + + def self.cinder_request(service, action, error, properties=nil) + properties ||= [] + @credentials.username = cinder_credentials['admin_user'] + @credentials.password = cinder_credentials['admin_password'] + @credentials.project_name = cinder_credentials['admin_tenant_name'] + @credentials.auth_url = auth_endpoint + raise error unless @credentials.set? + Puppet::Provider::Openstack.request(service, action, properties, @credentials) + end + + def self.cinder_credentials + @cinder_credentials ||= get_cinder_credentials + end + + def cinder_credentials + self.class.cinder_credentials + end + + def self.get_cinder_credentials + auth_keys = ['auth_uri', 'admin_tenant_name', 'admin_user', + 'admin_password'] + conf = cinder_conf + if conf and conf['keystone_authtoken'] and + auth_keys.all?{|k| !conf['keystone_authtoken'][k].nil?} + creds = Hash[ auth_keys.map \ + { |k| [k, conf['keystone_authtoken'][k].strip] } ] + return creds + else + raise(Puppet::Error, "File: #{conf_filename} does not contain all " + + "required sections. Cinder types will not work if cinder is not " + + "correctly configured.") + end + end + + def self.get_auth_endpoint + q = cinder_credentials + "#{q['auth_uri']}" + end + + def self.auth_endpoint + @auth_endpoint ||= get_auth_endpoint + end + + def self.reset + @cinder_conf = nil + @cinder_credentials = nil + end +end diff --git a/lib/puppet/provider/cinder_type/openstack.rb b/lib/puppet/provider/cinder_type/openstack.rb new file mode 100644 index 00000000..85940360 --- /dev/null +++ b/lib/puppet/provider/cinder_type/openstack.rb @@ -0,0 +1,70 @@ +require 'puppet/provider/cinder' + +Puppet::Type.type(:cinder_type).provide( + :openstack, + :parent => Puppet::Provider::Cinder +) do + + desc 'Provider for cinder types.' + + @credentials = Puppet::Provider::Openstack::CredentialsV2_0.new + + mk_resource_methods + + def create + properties = [] + resource[:properties].each do |item| + properties << '--property' << item + end + properties << name + self.class.request('volume type', 'create', properties) + @property_hash[:ensure] = :present + @property_hash[:properties] = resource[:properties] + @property_hash[:name] = name + end + + def destroy + self.class.request('volume type', 'delete', name) + @property_hash.clear + end + + def exists? + @property_hash[:ensure] == :present + end + + def properties=(value) + properties = [] + (value - @property_hash[:properties]).each do |item| + properties << '--property' << item + end + unless properties.empty? + self.class.request('volume type', 'set', [properties, name]) + @property_hash[:properties] = value + end + end + + def self.instances + list = request('volume type', 'list', '--long') + list.collect do |type| + new({ + :name => type[:name], + :ensure => :present, + :id => type[:id], + :properties => string2array(type[:properties]) + }) + end + end + + def self.prefetch(resources) + types = instances + resources.keys.each do |name| + if provider = types.find{ |type| type.name == name } + resources[name].provider = provider + end + end + end + + def self.string2array(input) + return input.delete("'").split(/,\s/) + end +end diff --git a/lib/puppet/type/cinder_type.rb b/lib/puppet/type/cinder_type.rb new file mode 100644 index 00000000..8976f9ee --- /dev/null +++ b/lib/puppet/type/cinder_type.rb @@ -0,0 +1,26 @@ +Puppet::Type.newtype(:cinder_type) do + + desc 'Type for managing cinder types.' + + ensurable + + newparam(:name, :namevar => true) do + newvalues(/\S+/) + end + + newproperty(:properties, :array_matching => :all) do + desc 'The properties of the cinder type. Should be an array, all items should match pattern ' + def insync?(is) + return false unless is.is_a? Array + is.sort == should.sort + end + validate do |value| + raise ArgumentError, "Properties doesn't match" unless value.match(/^\s*[^=\s]+=[^=\s]+$/) + end + end + + autorequire(:service) do + 'cinder-api' + end + +end diff --git a/manifests/keystone/auth.pp b/manifests/keystone/auth.pp index 9dab6e4f..81b6a354 100644 --- a/manifests/keystone/auth.pp +++ b/manifests/keystone/auth.pp @@ -181,7 +181,7 @@ class cinder::keystone::auth ( if $configure_user_role { Keystone_user_role["${auth_name}@${tenant}"] ~> Service <| name == 'cinder-api' |> - Keystone_user_role["${auth_name}@${tenant}"] -> Cinder::Type <| |> + Keystone_user_role["${auth_name}@${tenant}"] -> Cinder_type <| |> } } diff --git a/manifests/type.pp b/manifests/type.pp index 42d79346..e94a84e6 100644 --- a/manifests/type.pp +++ b/manifests/type.pp @@ -1,6 +1,7 @@ # == Define: cinder::type # # Creates cinder type and assigns backends. +# Deprecated class. # # === Parameters # @@ -17,73 +18,55 @@ # passed to type_set # Defaults to 'undef'. # +# === DEPRECATED PARAMETERS +# # [*os_tenant_name*] # (Optional) The keystone tenant name. -# Defaults to 'admin'. +# Defaults to undef. # # [*os_username*] # (Optional) The keystone user name. -# Defaults to 'admin. +# Defaults to undef. # # [*os_auth_url*] # (Optional) The keystone auth url. -# Defaults to 'http://127.0.0.1:5000/v2.0/'. +# Defaults to undef. # # [*os_region_name*] # (Optional) The keystone region name. -# Default is unset. +# Default is undef. # # Author: Andrew Woodward # define cinder::type ( - $os_password, $set_key = undef, $set_value = undef, - $os_tenant_name = 'admin', - $os_username = 'admin', - $os_auth_url = 'http://127.0.0.1:5000/v2.0/', + # DEPRECATED PARAMETERS + $os_password = undef, + $os_tenant_name = undef, + $os_username = undef, + $os_auth_url = undef, $os_region_name = undef, ) { - $volume_name = $name - -# TODO: (xarses) This should be moved to a ruby provider so that among other -# reasons, the credential discovery magic can occur like in neutron. - - $cinder_env = [ - "OS_TENANT_NAME=${os_tenant_name}", - "OS_USERNAME=${os_username}", - "OS_PASSWORD=${os_password}", - "OS_AUTH_URL=${os_auth_url}", - ] - - if $os_region_name { - $region_env = ["OS_REGION_NAME=${os_region_name}"] - } - else { - $region_env = [] - } - - exec {"cinder type-create ${volume_name}": - command => "cinder type-create ${volume_name}", - unless => "cinder type-list | grep -qP '\\s${volume_name}\\s'", - environment => concat($cinder_env, $region_env), - require => Package['python-cinderclient'], - path => ['/usr/bin', '/bin'], - tries => '2', - try_sleep => '5', + if $os_password or $os_region_name or $os_tenant_name or $os_username or $os_auth_url { + warning('Parameters $os_password/$os_region_name/$os_tenant_name/$os_username/$os_auth_url are not longer required') + warning('Auth creds will be used from env or /root/openrc file or cinder.conf') } if ($set_value and $set_key) { - Exec["cinder type-create ${volume_name}"] -> - cinder::type_set { $set_value: - type => $volume_name, - key => $set_key, - os_password => $os_password, - os_tenant_name => $os_tenant_name, - os_username => $os_username, - os_auth_url => $os_auth_url, - os_region_name => $os_region_name, + if is_array($set_value) { + $value = join($set_value, ',') + } else { + $value = $set_value + } + cinder_type { $name: + ensure => present, + properties => ["${set_key}=${value}"], + } + } else { + cinder_type { $name: + ensure => present, } } } diff --git a/manifests/type_set.pp b/manifests/type_set.pp index ddf3373f..696a2019 100644 --- a/manifests/type_set.pp +++ b/manifests/type_set.pp @@ -1,12 +1,10 @@ # ==Define: cinder::type_set # # Assigns keys after the volume type is set. +# Deprecated class. # # === Parameters # -# [*os_password*] -# (required) The keystone tenant:username password. -# # [*type*] # (required) Accepts single name of type to set. # @@ -16,54 +14,45 @@ # [*value*] # the value that we are setting. Defaults to content of namevar. # +# === Deprecated parameters +# +# [*os_password*] +# (optional) DEPRECATED: The keystone tenant:username password. +# Defaults to undef. +# # [*os_tenant_name*] -# (optional) The keystone tenant name. Defaults to 'admin'. +# (optional) DEPRECATED: The keystone tenant name. Defaults to undef. # # [*os_username*] -# (optional) The keystone user name. Defaults to 'admin. +# (optional) DEPRECATED: The keystone user name. Defaults to undef. # # [*os_auth_url*] -# (optional) The keystone auth url. Defaults to 'http://127.0.0.1:5000/v2.0/'. +# (optional) DEPRECATED: The keystone auth url. Defaults to undef. # # [*os_region_name*] -# (optional) The keystone region name. Default is unset. +# (optional) DEPRECATED: The keystone region name. Default is undef. # # Author: Andrew Woodward - - +# define cinder::type_set ( $type, $key, - $os_password, - $os_tenant_name = 'admin', - $os_username = 'admin', - $os_auth_url = 'http://127.0.0.1:5000/v2.0/', - $os_region_name = undef, $value = $name, + # DEPRECATED PARAMETERS + $os_password = undef, + $os_tenant_name = undef, + $os_username = undef, + $os_auth_url = undef, + $os_region_name = undef, ) { -# TODO: (xarses) This should be moved to a ruby provider so that among other -# reasons, the credential discovery magic can occur like in neutron. - - $cinder_env = [ - "OS_TENANT_NAME=${os_tenant_name}", - "OS_USERNAME=${os_username}", - "OS_PASSWORD=${os_password}", - "OS_AUTH_URL=${os_auth_url}", - ] - - if $os_region_name { - $region_env = ["OS_REGION_NAME=${os_region_name}"] - } - else { - $region_env = [] + if $os_password or $os_region_name or $os_tenant_name or $os_username or $os_auth_url { + warning('Parameters $os_password/$os_region_name/$os_tenant_name/$os_username/$os_auth_url are not longer required.') + warning('Auth creds will be used from env or /root/openrc file or cinder.conf') } - exec {"cinder type-key ${type} set ${key}=${value}": - path => ['/usr/bin', '/bin'], - command => "cinder type-key ${type} set ${key}=${value}", - unless => "cinder extra-specs-list | grep -Eq '\\b${type}\\b.*\\b${key}\\b.*\\b${value}\\b'", - environment => concat($cinder_env, $region_env), - require => Package['python-cinderclient'] + cinder_type { $type: + ensure => present, + properties => ["${key}=${value}"], } } diff --git a/manifests/vmware.pp b/manifests/vmware.pp index f05e9c0b..39ce6dd6 100644 --- a/manifests/vmware.pp +++ b/manifests/vmware.pp @@ -1,56 +1,59 @@ -# == Define: cinder::vmware +# == Class: cinder::vmware # # Creates vmdk specific disk file type & clone type. # # === Parameters # # [*os_password*] -# (Required) The keystone tenant:username password. +# DEPRECATED. The keystone tenant:username password. +# Defaults to undef. # # [*os_tenant_name*] -# (Optional) The keystone tenant name. -# Defaults to 'admin'. +# DEPRECATED. The keystone tenant name. +# Defaults to undef. # # [*os_username*] -# (Optional) The keystone user name. -# Defaults to 'admin. +# DEPRECATED. The keystone user name. +# Defaults to undef. # # [*os_auth_url*] -# (Optional) The keystone auth url. -# Defaults to 'http://127.0.0.1:5000/v2.0/'. +# DEPRECATED. The keystone auth url. +# Defaults to undef. # class cinder::vmware ( - $os_password, - $os_tenant_name = 'admin', - $os_username = 'admin', - $os_auth_url = 'http://127.0.0.1:5000/v2.0/' - ) { + $os_password = undef, + $os_tenant_name = undef, + $os_username = undef, + $os_auth_url = undef +) { - Cinder::Type { - os_password => $os_password, - os_tenant_name => $os_tenant_name, - os_username => $os_username, - os_auth_url => $os_auth_url + if $os_password or $os_tenant_name or $os_username or $os_auth_url { + warning('Parameters $os_password/$os_tenant_name/$os_username/$os_auth_url are not longer required.') + warning('Auth creds will be used from env or /root/openrc file or cinder.conf') } - cinder::type {'vmware-thin': - set_value => 'thin', - set_key => 'vmware:vmdk_type' + cinder_type { 'vmware-thin': + ensure => present, + properties => ['vmware:vmdk_type=thin'] } - cinder::type {'vmware-thick': - set_value => 'thick', - set_key => 'vmware:vmdk_type' + + cinder_type { 'vmware-thick': + ensure => present, + properties => ['vmware:vmdk_type=thick'] } - cinder::type {'vmware-eagerZeroedThick': - set_value => 'eagerZeroedThick', - set_key => 'vmware:vmdk_type' + + cinder_type { 'vmware-eagerZeroedThick': + ensure => present, + properties => ['vmware:vmdk_type=eagerZeroedThick'] } - cinder::type {'vmware-full': - set_value => 'full', - set_key => 'vmware:clone_type' + + cinder_type { 'vmware-full': + ensure => present, + properties => ['vmware:clone_type=full'] } - cinder::type {'vmware-linked': - set_value => 'linked', - set_key => 'vmware:clone_type' + + cinder_type { 'vmware-linked': + ensure => present, + properties => ['vmware:clone_type=linked'] } } diff --git a/spec/classes/cinder_vmware_spec.rb b/spec/classes/cinder_vmware_spec.rb index 96786d40..99e5ff51 100644 --- a/spec/classes/cinder_vmware_spec.rb +++ b/spec/classes/cinder_vmware_spec.rb @@ -2,34 +2,27 @@ require 'spec_helper' describe 'cinder::vmware' do - let :params do - {:os_password => 'asdf', - :os_tenant_name => 'admin', - :os_username => 'admin', - :os_auth_url => 'http://127.127.127.1:5000/v2.0/'} - end - describe 'with defaults' do it 'should create vmware special types' do - is_expected.to contain_cinder__type('vmware-thin').with( - :set_key => 'vmware:vmdk_type', - :set_value => 'thin') + is_expected.to contain_cinder_type('vmware-thin').with( + :ensure => :present, + :properties => ['vmware:vmdk_type=thin']) - is_expected.to contain_cinder__type('vmware-thick').with( - :set_key => 'vmware:vmdk_type', - :set_value => 'thick') + is_expected.to contain_cinder_type('vmware-thick').with( + :ensure => :present, + :properties => ['vmware:vmdk_type=thick']) - is_expected.to contain_cinder__type('vmware-eagerZeroedThick').with( - :set_key => 'vmware:vmdk_type', - :set_value => 'eagerZeroedThick') + is_expected.to contain_cinder_type('vmware-eagerZeroedThick').with( + :ensure => :present, + :properties => ['vmware:vmdk_type=eagerZeroedThick']) - is_expected.to contain_cinder__type('vmware-full').with( - :set_key => 'vmware:clone_type', - :set_value => 'full') + is_expected.to contain_cinder_type('vmware-full').with( + :ensure => :present, + :properties => ['vmware:clone_type=full']) - is_expected.to contain_cinder__type('vmware-linked').with( - :set_key => 'vmware:clone_type', - :set_value => 'linked') + is_expected.to contain_cinder_type('vmware-linked').with( + :ensure => :present, + :properties => ['vmware:clone_type=linked']) end end end diff --git a/spec/defines/cinder_type_set_spec.rb b/spec/defines/cinder_type_set_spec.rb index 1c3d4d02..c77186bc 100644 --- a/spec/defines/cinder_type_set_spec.rb +++ b/spec/defines/cinder_type_set_spec.rb @@ -9,25 +9,13 @@ describe 'cinder::type_set' do let :default_params do { :type => 'sith', :key => 'monchichi', - :os_password => 'asdf', - :os_tenant_name => 'admin', - :os_username => 'admin', - :os_auth_url => 'http://127.127.127.1:5000/v2.0/', } end describe 'by default' do let(:params){ default_params } - it 'should have its execs' do - is_expected.to contain_exec('cinder type-key sith set monchichi=hippo').with( - :command => 'cinder type-key sith set monchichi=hippo', - :unless => "cinder extra-specs-list | grep -Eq '\\bsith\\b.*\\bmonchichi\\b.*\\bhippo\\b'", - :environment => [ - 'OS_TENANT_NAME=admin', - 'OS_USERNAME=admin', - 'OS_PASSWORD=asdf', - 'OS_AUTH_URL=http://127.127.127.1:5000/v2.0/'], - :require => 'Package[python-cinderclient]') + it 'should create type with properties' do + should contain_cinder_type('sith').with(:ensure => :present, :properties => ['monchichi=hippo']) end end @@ -35,16 +23,8 @@ describe 'cinder::type_set' do let(:params){ default_params.merge({:value => 'hippi'}) } - it 'should have its execs' do - is_expected.to contain_exec('cinder type-key sith set monchichi=hippi').with( - :command => 'cinder type-key sith set monchichi=hippi', - :unless => "cinder extra-specs-list | grep -Eq '\\bsith\\b.*\\bmonchichi\\b.*\\bhippi\\b'", - :environment => [ - 'OS_TENANT_NAME=admin', - 'OS_USERNAME=admin', - 'OS_PASSWORD=asdf', - 'OS_AUTH_URL=http://127.127.127.1:5000/v2.0/'], - :require => 'Package[python-cinderclient]') + it 'should create type with properties' do + should contain_cinder_type('sith').with(:ensure => :present, :properties => ['monchichi=hippi']) end end end diff --git a/spec/defines/cinder_type_spec.rb b/spec/defines/cinder_type_spec.rb index 67388a82..b572698b 100644 --- a/spec/defines/cinder_type_spec.rb +++ b/spec/defines/cinder_type_spec.rb @@ -6,29 +6,20 @@ describe 'cinder::type' do let(:title) {'hippo'} - let :params do { - :set_value => ['name1','name2'], - :set_key => 'volume_backend_name', - :os_password => 'asdf', - :os_tenant_name => 'admin', - :os_username => 'admin', - :os_auth_url => 'http://127.127.127.1:5000/v2.0/', - } + context 'default creation' do + it 'should create type basic' do + should contain_cinder_type('hippo').with(:ensure => :present) + end end - it 'should have its execs' do - is_expected.to contain_exec('cinder type-create hippo').with( - :command => 'cinder type-create hippo', - :environment => [ - 'OS_TENANT_NAME=admin', - 'OS_USERNAME=admin', - 'OS_PASSWORD=asdf', - 'OS_AUTH_URL=http://127.127.127.1:5000/v2.0/'], - :unless => "cinder type-list | grep -qP '\\shippo\\s'", - :tries => '2', - :try_sleep => '5', - :require => 'Package[python-cinderclient]') - is_expected.to contain_exec('cinder type-key hippo set volume_backend_name=name1') - is_expected.to contain_exec('cinder type-key hippo set volume_backend_name=name2') + context 'creation with properties' do + let :params do { + :set_value => ['name1','name2'], + :set_key => 'volume_backend_name', + } + end + it 'should create type with properties' do + should contain_cinder_type('hippo').with(:ensure => :present, :properties => ['volume_backend_name=name1,name2']) + end end end diff --git a/spec/unit/provider/cinder_spec.rb b/spec/unit/provider/cinder_spec.rb new file mode 100644 index 00000000..cfc88500 --- /dev/null +++ b/spec/unit/provider/cinder_spec.rb @@ -0,0 +1,46 @@ +require 'puppet' +require 'spec_helper' +require 'puppet/provider/cinder' +require 'tempfile' + +klass = Puppet::Provider::Cinder + +describe Puppet::Provider::Cinder do + + after :each do + klass.reset + end + + describe 'when retrieving the auth credentials' do + + it 'should fail if no auth params are passed and the glance config file does not have the expected contents' do + mock = {} + Puppet::Util::IniConfig::File.expects(:new).returns(mock) + mock.expects(:read).with('/etc/cinder/cinder.conf') + expect do + klass.cinder_credentials + end.to raise_error(Puppet::Error, /Cinder types will not work/) + end + + it 'should read conf file with all sections' do + creds_hash = { + 'auth_uri' => 'https://192.168.56.210:35357/v2.0/', + 'admin_tenant_name' => 'admin_tenant', + 'admin_user' => 'admin', + 'admin_password' => 'password', + } + mock = { + 'keystone_authtoken' => { + 'auth_uri' => 'https://192.168.56.210:35357/v2.0/', + 'admin_tenant_name' => 'admin_tenant', + 'admin_user' => 'admin', + 'admin_password' => 'password', + } + } + Puppet::Util::IniConfig::File.expects(:new).returns(mock) + mock.expects(:read).with('/etc/cinder/cinder.conf') + expect(klass.cinder_credentials).to eq(creds_hash) + end + + end +end diff --git a/spec/unit/provider/cinder_type/openstack_spec.rb b/spec/unit/provider/cinder_type/openstack_spec.rb new file mode 100644 index 00000000..1dcc5b7f --- /dev/null +++ b/spec/unit/provider/cinder_type/openstack_spec.rb @@ -0,0 +1,83 @@ +require 'puppet' +require 'puppet/provider/cinder_type/openstack' + +provider_class = Puppet::Type.type(:cinder_type).provider(:openstack) + +describe provider_class do + + let(:set_creds_env) do + ENV['OS_USERNAME'] = 'test' + ENV['OS_PASSWORD'] = 'abc123' + ENV['OS_PROJECT_NAME'] = 'test' + ENV['OS_AUTH_URL'] = 'http://127.0.0.1:5000' + end + + let(:type_attributes) do + { + :name => 'Backend_1', + :ensure => :present, + :properties => ['key=value', 'new_key=new_value'], + } + end + + let(:resource) do + Puppet::Type::Cinder_type.new(type_attributes) + end + + let(:provider) do + provider_class.new(resource) + end + + before(:each) { set_creds_env } + + after(:each) do + Puppet::Type.type(:cinder_type).provider(:openstack).reset + provider_class.reset + end + + describe 'managing type' do + describe '#create' do + it 'creates a type' do + provider_class.expects(:openstack) + .with('volume type', 'create', '--format', 'shell', ['--property', 'key=value', '--property', 'new_key=new_value', 'Backend_1']) + .returns('id="90e19aff-1b35-4d60-9ee3-383c530275ab" +name="Backend_1" +properties="key=\'value\', new_key=\'new_value\'" +') + provider.create + expect(provider.exists?).to be_truthy + end + end + + describe '#destroy' do + it 'destroys a type' do + provider_class.expects(:openstack) + .with('volume type', 'delete', 'Backend_1') + provider.destroy + expect(provider.exists?).to be_falsey + end + end + + describe '#instances' do + it 'finds types' do + provider_class.expects(:openstack) + .with('volume type', 'list', '--quiet', '--format', 'csv', '--long') + .returns('"ID","Name","Properties" +"28b632e8-6694-4bba-bf68-67b19f619019","type-1","key1=\'value1\'" +"4f992f69-14ec-4132-9313-55cc06a6f1f6","type-2","key2=\'value2\'" +') + instances = provider_class.instances + expect(instances.count).to eq(2) + expect(instances[0].name).to eq('type-1') + expect(instances[1].name).to eq('type-2') + end + end + + describe '#string2array' do + it 'should return an array with key-value' do + s = "key='value', key2='value2'" + expect(provider_class.string2array(s)).to eq(['key=value', 'key2=value2']) + end + end + end +end diff --git a/spec/unit/type/cinder_type_spec.rb b/spec/unit/type/cinder_type_spec.rb new file mode 100644 index 00000000..c9b0a0ca --- /dev/null +++ b/spec/unit/type/cinder_type_spec.rb @@ -0,0 +1,32 @@ +require 'puppet' +require 'puppet/type/cinder_type' + +describe Puppet::Type.type(:cinder_type) do + + before :each do + Puppet::Type.rmtype(:cinder_type) + end + + it 'should reject an invalid propertie value' do + incorrect_input = { + :name => 'test_type', + :properties => ['some_key1 = some_value2'] + } + expect { Puppet::Type.type(:cinder_type).new(incorrect_input) }.to raise_error(Puppet::ResourceError, /Parameter properties failed/) + end + + it 'should autorequire cinder-api service' do + catalog = Puppet::Resource::Catalog.new + service = Puppet::Type.type(:service).new(:name => 'cinder-api') + correct_input = { + :name => 'test_type', + :properties => ['some_key1=value', 'some_key2=value1,value2'] + } + cinder_type = Puppet::Type.type(:cinder_type).new(correct_input) + catalog.add_resource service, cinder_type + dependency = cinder_type.autorequire + expect(dependency.size).to eq(1) + expect(dependency[0].target).to eq(cinder_type) + expect(dependency[0].source).to eq(service) + end +end