diff --git a/lib/puppet/provider/trove.rb b/lib/puppet/provider/trove.rb index c814bc9e..3210290d 100644 --- a/lib/puppet/provider/trove.rb +++ b/lib/puppet/provider/trove.rb @@ -1,49 +1,43 @@ -require 'json' -require 'puppet/util/inifile' +# Add openstacklib code to $LOAD_PATH so that we can load this during +# standalone compiles without error. +File.expand_path('../../../../openstacklib/lib', File.dirname(__FILE__)).tap { |dir| $LOAD_PATH.unshift(dir) unless $LOAD_PATH.include?(dir) } -class Puppet::Provider::Trove < Puppet::Provider +require 'puppet/util/inifile' +require 'puppet/provider/openstack' +require 'puppet/provider/openstack/auth' +require 'puppet/provider/openstack/credentials' + +class Puppet::Provider::Trove < Puppet::Provider::Openstack + + extend Puppet::Provider::Openstack::Auth + + def self.request(service, action, properties=nil) + begin + super + rescue Puppet::Error::OpenstackAuthInputError => error + trove_request(service, action, error, properties) + end + end + + def self.trove_request(service, action, error, properties=nil) + properties ||= [] + @credentials.username = trove_credentials['username'] + @credentials.password = trove_credentials['password'] + @credentials.project_name = trove_credentials['project_name'] + @credentials.auth_url = auth_endpoint + @credentials.user_domain_name = trove_credentials['user_domain_name'] + @credentials.project_domain_name = trove_credentials['project_domain_name'] + if trove_credentials['region_name'] + @credentials.region_name = trove_credentials['region_name'] + end + raise error unless @credentials.set? + Puppet::Provider::Openstack.request(service, action, properties, @credentials) + end def self.conf_filename '/etc/trove/trove.conf' end - def self.withenv(hash, &block) - saved = ENV.to_hash - hash.each do |name, val| - ENV[name.to_s] = val - end - - yield - ensure - ENV.clear - saved.each do |name, val| - ENV[name] = val - end - end - - def self.trove_credentials - @trove_credentials ||= get_trove_credentials - end - - def self.get_trove_credentials - auth_keys = ['auth_url', 'project_name', 'username', 'password', - 'project_domain_name', 'user_domain_name'] - conf = trove_conf - if conf and conf['keystone_authtoken'] and - auth_keys.all?{|k| !conf['keystone_authtoken'][k].nil?} - return Hash[ auth_keys.map \ - { |k| [k, conf['keystone_authtoken'][k].strip] } ] - else - raise(Puppet::Error, "File: #{conf_filename} does not contain all \ -required sections. Trove types will not work if trove is not \ -correctly configured.") - end - end - - def trove_credentials - self.class.trove_credentials - end - def self.trove_conf return @trove_conf if @trove_conf @trove_conf = Puppet::Util::IniConfig::File.new @@ -51,35 +45,63 @@ correctly configured.") @trove_conf end - def self.auth_trove(*args) - q = trove_credentials - authenv = { - :OS_AUTH_URL => q['auth_url'], - :OS_USERNAME => q['username'], - :OS_PROJECT_NAME => q['project_name'], - :OS_PASSWORD => q['password'], - :OS_PROJECT_DOMAIN_NAME => q['project_domain_name'], - :OS_USER_DOMAIN_NAME => q['user_domain_name'] - } - begin - withenv authenv do - trove(args) + def self.trove_credentials + @trove_credentials ||= get_trove_credentials + end + + def trove_credentials + self.class.trove_credentials + end + + def self.get_trove_credentials + #needed keys for authentication + auth_keys = ['auth_url', 'project_name', 'username', 'password'] + conf = trove_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] } ] + if !conf['keystone_authtoken']['region_name'].nil? + creds['region_name'] = conf['keystone_authtoken']['region_name'].strip end - rescue Exception => e - if (e.message =~ /\[Errno 111\] Connection refused/) or - (e.message =~ /\(HTTP 400\)/) - sleep 10 - withenv authenv do - trove(args) - end + + if !conf['keystone_authtoken']['project_domain_name'].nil? + creds['project_domain_name'] = conf['keystone_authtoken']['project_domain_name'].strip else - raise(e) + creds['project_domain_name'] = 'Default' end + + if !conf['keystone_authtoken']['user_domain_name'].nil? + creds['user_domain_name'] = conf['keystone_authtoken']['user_domain_name'].strip + else + creds['user_domain_name'] = 'Default' + end + + return creds + else + raise(Puppet::Error, "File: #{conf_filename} does not contain all " + + "required sections. Trove types will not work if trove is not " + + "correctly configured.") end end - def auth_trove(*args) - self.class.auth_trove(args) + def self.conf_filename + '/etc/trove/trove.conf' + end + + def self.get_auth_endpoint + q = trove_credentials + "#{q['auth_url']}" + end + + def self.auth_endpoint + @auth_endpoint ||= get_auth_endpoint + end + + def self.reset + @auth_endpoint = nil + @trove_conf = nil + @trove_credentials = nil end def trove_manage(*args) @@ -87,20 +109,4 @@ correctly configured.") output = `#{cmd}` $?.exitstatus end - - def self.reset - @trove_conf = nil - @trove_credentials = nil - end - - def self.list_trove_resources(type, *args) - json = auth_trove("--json", "#{type}-list", *args) - return JSON.parse(json) - end - - def self.get_trove_resource_attrs(type, id) - json = auth_trove("--json", "#{type}-show", id) - return JSON.parse(json) - end - end diff --git a/lib/puppet/provider/trove_datastore/trove.rb b/lib/puppet/provider/trove_datastore/trove.rb index d356637e..ec01af49 100644 --- a/lib/puppet/provider/trove_datastore/trove.rb +++ b/lib/puppet/provider/trove_datastore/trove.rb @@ -9,16 +9,16 @@ Puppet::Type.type(:trove_datastore).provide( Trove provider to manage datastore type. EOT - commands :trove => "trove" - mk_resource_methods + @credentials = Puppet::Provider::Openstack::CredentialsV3.new + def self.instances - list_trove_resources("datastore").collect do |attrs| + request('datastore', 'list').collect do |attrs| new( - :ensure => :present, - :name => attrs["name"], - :id => attrs["id"] + :ensure => :present, + :name => attrs[:name], + :id => attrs[:id] ) end end diff --git a/lib/puppet/provider/trove_datastore_version/trove.rb b/lib/puppet/provider/trove_datastore_version/trove.rb index f02ba236..c7291f5e 100644 --- a/lib/puppet/provider/trove_datastore_version/trove.rb +++ b/lib/puppet/provider/trove_datastore_version/trove.rb @@ -9,10 +9,10 @@ Puppet::Type.type(:trove_datastore_version).provide( Trove provider to manage datastore version type. EOT - commands :trove => "trove" - mk_resource_methods + @credentials = Puppet::Provider::Openstack::CredentialsV3.new + def self.prefetch(resource) @datastore_version_hash = nil end @@ -30,7 +30,7 @@ Puppet::Type.type(:trove_datastore_version).provide( end def exists? - datastore_version_hash(resource[:datastore])[resource[:name]] + datastore_version_hash(@resource[:datastore])[@resource[:name]] end def create @@ -49,12 +49,12 @@ Puppet::Type.type(:trove_datastore_version).provide( private - def self.build_datastore_version_hash(datastore) - dvs = {} - list_trove_resources("datastore-version", datastore).collect do |attrs| - dvs[attrs["name"]] = attrs - end - dvs + def self.build_datastore_version_hash(datastore) + dvs = {} + request('datastore version', 'list', datastore).each do |attrs| + dvs[attrs[:name]] = attrs end + dvs + end end diff --git a/spec/unit/provider/trove_datastore/trove_spec.rb b/spec/unit/provider/trove_datastore/trove_spec.rb index 8fff66f5..4d6c0b54 100644 --- a/spec/unit/provider/trove_datastore/trove_spec.rb +++ b/spec/unit/provider/trove_datastore/trove_spec.rb @@ -6,6 +6,13 @@ provider_class = Puppet::Type.type(:trove_datastore).provider(:trove) describe provider_class do + let(:set_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 :datastore_name do 'foo' end @@ -23,32 +30,35 @@ describe provider_class do end before :each do - described_class.stubs(:list_trove_resources).with('datastore').returns([ - resource - ]) + set_env end describe "self.instances" do - it "should have an instances method" do - expect(provider.class).to respond_to(:instances) - end - - it "should list instances" do - datastores = described_class.instances - expect(datastores.size).to eq(1) - datastores.map {|provider| provider.name} == datastore_name + it 'lists datastores' do + provider_class.expects(:openstack) + .with('datastore', 'list', '--quiet', '--format', 'csv', []) + .returns('"ID","Name" +"1275b24c-73af-4c51-98ec-c9938a94a153","store1" +"18088802-efe2-42f8-ac85-ecfddd37d24e","store2" +') + instances = provider_class.instances + expect(instances.length).to eq(2) + expect(instances[0].id).to eq('1275b24c-73af-4c51-98ec-c9938a94a153') + expect(instances[0].name).to eq('store1') + expect(instances[1].id).to eq('18088802-efe2-42f8-ac85-ecfddd37d24e') + expect(instances[1].name).to eq('store2') end end describe '#create' do - it 'should call trove-manage' do - provider.expects(:trove_manage).with( - ['trove-manage', 'datastore_update', datastore_name, "''"] - ).returns(0) + it 'creates datastore' do + provider.expects(:trove_manage) + .with(['trove-manage', 'datastore_update', datastore_name, "''"]) + .returns(0) - provider.expects(:trove_manage).with( - ['trove-manage', 'datastore_update', datastore_name, "0.1"] - ).returns(0) + provider.expects(:trove_manage) + .with(['trove-manage', 'datastore_update', datastore_name, "0.1"]) + .returns(0) provider.create end diff --git a/spec/unit/provider/trove_datastore_version/trove_spec.rb b/spec/unit/provider/trove_datastore_version/trove_spec.rb index cce3720f..e6e74c1b 100644 --- a/spec/unit/provider/trove_datastore_version/trove_spec.rb +++ b/spec/unit/provider/trove_datastore_version/trove_spec.rb @@ -6,12 +6,19 @@ provider_class = Puppet::Type.type(:trove_datastore_version).provider(:trove) describe provider_class do + let(:set_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 :datastore_name do - 'foo' + 'mysql' end let :datastore_version do - '1.0' + '5.7.29' end let :resource do @@ -30,7 +37,11 @@ describe provider_class do described_class.new(resource) end - describe "self.instances" do + before :each do + set_env + end + + describe "#instances" do it "should have an instances method" do expect(provider.class).to respond_to(:instances) end @@ -39,12 +50,24 @@ describe provider_class do describe '#create' do it 'should call trove-manage' do provider.expects(:trove_manage).with( - ['trove-manage', 'datastore_version_update', datastore_name, "1.0", - 'mysql', '1234', 'mysql', '1'] + ['trove-manage', 'datastore_version_update', datastore_name, + datastore_version, 'mysql', '1234', 'mysql', '1'] ).returns(0) provider.create end end + describe '#exists' do + it 'should list datastore versions' do + provider_class.expects(:openstack) + .with('datastore version', 'list', '--quiet', '--format', 'csv', + datastore_name) + .returns('"ID","Name","Version" +"9c4d3fb1-644c-4543-9c37-49b3a801b66c","5.7.29","5.7.29" +"406b75fb-0727-4923-a702-d677e3fd84ab","5.7.30","5.7.30" +') + expect(provider.exists?).to be_truthy + end + end end