Use system scope credentials in providers
This change enforces usage of system scope credentials to manage flavors and aggregates, following the new policy rule as part of SRBAC support in nova. Depends-on: https://review.opendev.org/815311 Change-Id: Ic87422ae98943054ee58343157301d8fc780211f
This commit is contained in:
parent
83f815ba87
commit
a3da1f1188
|
@ -1,9 +1,3 @@
|
|||
# Run test ie with: rspec spec/unit/provider/nova_spec.rb
|
||||
|
||||
# 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) }
|
||||
|
||||
require 'puppet/util/inifile'
|
||||
require 'puppet/provider/openstack'
|
||||
require 'puppet/provider/openstack/auth'
|
||||
|
@ -13,27 +7,44 @@ class Puppet::Provider::Nova < Puppet::Provider::Openstack
|
|||
|
||||
extend Puppet::Provider::Openstack::Auth
|
||||
|
||||
def self.request(service, action, properties=nil)
|
||||
begin
|
||||
super
|
||||
rescue Puppet::Error::OpenstackAuthInputError => error
|
||||
nova_request(service, action, error, properties)
|
||||
end
|
||||
CLOUDS_FILENAME = '/etc/nova/clouds.yaml'
|
||||
|
||||
def self.project_request(service, action, properties=nil, options={})
|
||||
self.request(service, action, properties, options, 'project')
|
||||
end
|
||||
|
||||
def self.nova_request(service, action, error, properties=nil)
|
||||
def self.system_request(service, action, properties=nil, options={})
|
||||
self.request(service, action, properties, options, 'system')
|
||||
end
|
||||
|
||||
def self.request(service, action, properties=nil, options={}, scope='project')
|
||||
super
|
||||
rescue Puppet::Error::OpenstackAuthInputError => error
|
||||
nova_request(service, action, error, properties, options, scope)
|
||||
end
|
||||
|
||||
def self.nova_request(service, action, error, properties=nil, options={}, scope='project')
|
||||
properties ||= []
|
||||
@credentials.username = nova_credentials['username']
|
||||
@credentials.password = nova_credentials['password']
|
||||
@credentials.project_name = nova_credentials['project_name']
|
||||
@credentials.auth_url = auth_endpoint
|
||||
@credentials.user_domain_name = nova_credentials['user_domain_name']
|
||||
@credentials.project_domain_name = nova_credentials['project_domain_name']
|
||||
if nova_credentials['region_name']
|
||||
@credentials.region_name = nova_credentials['region_name']
|
||||
|
||||
unless @system_credential
|
||||
@system_credential = Puppet::Provider::Openstack::CredentialsV3.new
|
||||
@system_credential.cloud = 'system'
|
||||
@system_credential.client_config_file = clouds_filename
|
||||
end
|
||||
raise error unless @credentials.set?
|
||||
Puppet::Provider::Openstack.request(service, action, properties, @credentials)
|
||||
|
||||
unless @project_credential
|
||||
@project_credential = Puppet::Provider::Openstack::CredentialsV3.new
|
||||
@project_credential.cloud = 'project'
|
||||
@project_credential.client_config_file = clouds_filename
|
||||
end
|
||||
|
||||
if scope == 'system'
|
||||
cred = @system_credential
|
||||
else
|
||||
cred = @project_credential
|
||||
end
|
||||
|
||||
Puppet::Provider::Openstack.request(service, action, properties, cred, options)
|
||||
end
|
||||
|
||||
def self.nova_manage_request(*args)
|
||||
|
@ -70,58 +81,13 @@ class Puppet::Provider::Nova < Puppet::Provider::Openstack
|
|||
@nova_conf
|
||||
end
|
||||
|
||||
def self.nova_credentials
|
||||
@nova_credentials ||= get_nova_credentials
|
||||
end
|
||||
|
||||
def nova_credentials
|
||||
self.class.nova_credentials
|
||||
end
|
||||
|
||||
def self.get_nova_credentials
|
||||
#needed keys for authentication
|
||||
auth_keys = ['auth_url', 'project_name', 'username', 'password']
|
||||
conf = nova_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
|
||||
|
||||
if !conf['keystone_authtoken']['project_domain_name'].nil?
|
||||
creds['project_domain_name'] = conf['keystone_authtoken']['project_domain_name'].strip
|
||||
else
|
||||
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. Nova types will not work if nova is not " +
|
||||
"correctly configured.")
|
||||
end
|
||||
end
|
||||
|
||||
def self.get_auth_endpoint
|
||||
q = nova_credentials
|
||||
"#{q['auth_url']}"
|
||||
end
|
||||
|
||||
def self.auth_endpoint
|
||||
@auth_endpoint ||= get_auth_endpoint
|
||||
def self.clouds_filename
|
||||
CLOUDS_FILENAME
|
||||
end
|
||||
|
||||
def self.reset
|
||||
@nova_conf = nil
|
||||
@nova_credentials = nil
|
||||
@project_credential = nil
|
||||
@system_credential = nil
|
||||
end
|
||||
|
||||
def self.str2hash(s)
|
||||
|
|
|
@ -13,8 +13,8 @@ Puppet::Type.type(:nova_aggregate).provide(
|
|||
mk_resource_methods
|
||||
|
||||
def self.instances
|
||||
request('aggregate', 'list').collect do |el|
|
||||
attrs = request('aggregate', 'show', el[:name])
|
||||
system_request('aggregate', 'list').collect do |el|
|
||||
attrs = system_request('aggregate', 'show', el[:name])
|
||||
properties = parsestring(attrs[:properties]) rescue nil
|
||||
new(
|
||||
:ensure => :present,
|
||||
|
@ -43,7 +43,7 @@ Puppet::Type.type(:nova_aggregate).provide(
|
|||
|
||||
def self.get_known_hosts
|
||||
# get list of hosts known to be active from openstack
|
||||
return request('compute service', 'list', ['--service', 'nova-compute']).map{|el| el[:host]}
|
||||
return system_request('compute service', 'list', ['--service', 'nova-compute']).map{|el| el[:host]}
|
||||
end
|
||||
|
||||
def exists?
|
||||
|
@ -53,9 +53,9 @@ Puppet::Type.type(:nova_aggregate).provide(
|
|||
def destroy
|
||||
@property_hash[:hosts].each do |h|
|
||||
properties = [@property_hash[:name], h]
|
||||
self.class.request('aggregate', 'remove host', properties)
|
||||
self.class.system_request('aggregate', 'remove host', properties)
|
||||
end
|
||||
self.class.request('aggregate', 'delete', @property_hash[:name])
|
||||
self.class.system_request('aggregate', 'delete', @property_hash[:name])
|
||||
end
|
||||
|
||||
def create
|
||||
|
@ -68,7 +68,7 @@ Puppet::Type.type(:nova_aggregate).provide(
|
|||
properties << "--property" << "#{key}=#{value}"
|
||||
end
|
||||
end
|
||||
@property_hash = self.class.request('aggregate', 'create', properties)
|
||||
@property_hash = self.class.system_request('aggregate', 'create', properties)
|
||||
if not @resource[:hosts].nil? and not @resource[:hosts].empty?
|
||||
# filter host list by known hosts if filter_hosts is set
|
||||
if @resource[:filter_hosts] == :true
|
||||
|
@ -76,13 +76,14 @@ Puppet::Type.type(:nova_aggregate).provide(
|
|||
end
|
||||
@resource[:hosts].each do |host|
|
||||
properties = [@property_hash[:name], host]
|
||||
self.class.request('aggregate', 'add host', properties)
|
||||
self.class.system_request('aggregate', 'add host', properties)
|
||||
end
|
||||
end
|
||||
@property_hash[:ensure] = :present
|
||||
end
|
||||
|
||||
def availability_zone=(value)
|
||||
self.class.request('aggregate', 'set', [ @resource[:name], '--zone', @resource[:availability_zone] ])
|
||||
self.class.system_request('aggregate', 'set', [ @resource[:name], '--zone', @resource[:availability_zone] ])
|
||||
end
|
||||
|
||||
def metadata=(value)
|
||||
|
@ -92,13 +93,13 @@ Puppet::Type.type(:nova_aggregate).provide(
|
|||
(@property_hash[:metadata].keys - @resource[:metadata].keys).each do |key|
|
||||
properties << "--property" << "#{key}"
|
||||
end
|
||||
self.class.request('aggregate', 'unset', properties)
|
||||
self.class.system_request('aggregate', 'unset', properties)
|
||||
end
|
||||
properties = [@resource[:name] ]
|
||||
@resource[:metadata].each do |key, value|
|
||||
properties << "--property" << "#{key}=#{value}"
|
||||
end
|
||||
self.class.request('aggregate', 'set', properties)
|
||||
self.class.system_request('aggregate', 'set', properties)
|
||||
end
|
||||
|
||||
def hosts=(value)
|
||||
|
@ -109,11 +110,11 @@ Puppet::Type.type(:nova_aggregate).provide(
|
|||
if not @property_hash[:hosts].nil?
|
||||
# remove hosts that are not present in update
|
||||
(@property_hash[:hosts] - value).each do |host|
|
||||
self.class.request('aggregate', 'remove host', [@property_hash[:id], host])
|
||||
self.class.system_request('aggregate', 'remove host', [@property_hash[:id], host])
|
||||
end
|
||||
# add hosts that are not already present
|
||||
(value - @property_hash[:hosts]).each do |host|
|
||||
self.class.request('aggregate', 'add host', [@property_hash[:id], host])
|
||||
self.class.system_request('aggregate', 'add host', [@property_hash[:id], host])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -26,16 +26,16 @@ Puppet::Type.type(:nova_flavor).provide(
|
|||
(opts << '--vcpus' << @resource[:vcpus]) if @resource[:vcpus]
|
||||
(opts << '--swap' << @resource[:swap]) if @resource[:swap]
|
||||
(opts << '--rxtx-factor' << @resource[:rxtx_factor]) if @resource[:rxtx_factor]
|
||||
@property_hash = self.class.request('flavor', 'create', opts)
|
||||
@property_hash = self.class.system_request('flavor', 'create', opts)
|
||||
if @resource[:properties]
|
||||
prop_opts = [@resource[:name]]
|
||||
prop_opts << props_to_s(@resource[:properties])
|
||||
self.class.request('flavor', 'set', prop_opts)
|
||||
self.class.system_request('flavor', 'set', prop_opts)
|
||||
end
|
||||
if @resource[:project]
|
||||
if @resource[:project] and @resource[:project] != ''
|
||||
proj_opts = [@resource[:name]]
|
||||
proj_opts << '--project' << @resource[:project]
|
||||
self.class.request('flavor', 'set', proj_opts)
|
||||
self.class.system_request('flavor', 'set', proj_opts)
|
||||
end
|
||||
@property_hash[:ensure] = :present
|
||||
end
|
||||
|
@ -45,7 +45,7 @@ Puppet::Type.type(:nova_flavor).provide(
|
|||
end
|
||||
|
||||
def destroy
|
||||
self.class.request('flavor', 'delete', @property_hash[:id])
|
||||
self.class.system_request('flavor', 'delete', @property_hash[:id])
|
||||
end
|
||||
|
||||
mk_resource_methods
|
||||
|
@ -87,8 +87,8 @@ Puppet::Type.type(:nova_flavor).provide(
|
|||
end
|
||||
|
||||
def self.instances
|
||||
request('flavor', 'list', ['--long', '--all']).collect do |attrs|
|
||||
project = request('flavor', 'show', [attrs[:id], '-c', 'access_project_ids'])
|
||||
system_request('flavor', 'list', ['--long', '--all']).collect do |attrs|
|
||||
project = system_request('flavor', 'show', [attrs[:id], '-c', 'access_project_ids'])
|
||||
|
||||
access_project_ids = project[:access_project_ids]
|
||||
# Client can return None and this should be considered as ''
|
||||
|
@ -133,17 +133,17 @@ Puppet::Type.type(:nova_flavor).provide(
|
|||
opts = [@resource[:name]]
|
||||
opts << props_to_s(@property_flush[:properties])
|
||||
|
||||
self.class.request('flavor', 'set', opts)
|
||||
self.class.system_request('flavor', 'set', opts)
|
||||
@property_flush.clear
|
||||
end
|
||||
unless @project_flush.empty?
|
||||
opts = [@resource[:name]]
|
||||
unless @project_flush[:project]
|
||||
unless @project_flush[:project] == ''
|
||||
opts << '--project' << @project_flush[:project]
|
||||
self.class.request('flavor', 'set', opts)
|
||||
self.class.system_request('flavor', 'set', opts)
|
||||
else
|
||||
opts << '--project' << @property_hash[:project]
|
||||
self.class.request('flavor', 'unset', opts)
|
||||
self.class.system_request('flavor', 'unset', opts)
|
||||
end
|
||||
@project_flush.clear
|
||||
end
|
||||
|
@ -154,4 +154,3 @@ Puppet::Type.type(:nova_flavor).provide(
|
|||
props.flat_map{ |k, v| ['--property', "#{k}=#{v}"] }
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@ Puppet::Type.type(:nova_service).provide(
|
|||
|
||||
def self.instances
|
||||
hosts = {}
|
||||
request('compute service', 'list').collect do |host_svc|
|
||||
system_request('compute service', 'list').collect do |host_svc|
|
||||
hname = host_svc[:host]
|
||||
if hosts[hname].nil?
|
||||
hosts[hname] = Hash.new {|h,k| h[k]=[]}
|
||||
|
@ -53,7 +53,7 @@ Puppet::Type.type(:nova_service).provide(
|
|||
svcname_id_map.each do |service_name, id|
|
||||
if (@resource[:service_name].empty? ||
|
||||
(@resource[:service_name].include? service_name))
|
||||
self.class.request('compute service', 'delete', id)
|
||||
self.class.system_request('compute service', 'delete', id)
|
||||
end
|
||||
end
|
||||
@property_hash[:ensure] = :absent
|
||||
|
|
|
@ -284,4 +284,33 @@ class nova::keystone::authtoken(
|
|||
service_type => $service_type,
|
||||
interface => $interface;
|
||||
}
|
||||
|
||||
|
||||
$system_scope_real = is_service_default($system_scope) ? {
|
||||
true => pick($::nova::keystone::auth::system_scope, 'all'),
|
||||
default => $system_scope,
|
||||
}
|
||||
|
||||
$region_name_real = is_service_default($region_name) ? {
|
||||
true => undef,
|
||||
default => $region_name,
|
||||
}
|
||||
|
||||
$interface_real = is_service_default($interface) ? {
|
||||
true => undef,
|
||||
default => $interface,
|
||||
}
|
||||
|
||||
openstacklib::clouds { '/etc/nova/clouds.yaml':
|
||||
username => $username,
|
||||
password => $password,
|
||||
auth_url => $auth_url,
|
||||
project_name => $project_name,
|
||||
system_scope => $system_scope_real,
|
||||
region_name => $region_name_real,
|
||||
interface => $interface_real,
|
||||
}
|
||||
Anchor['nova::config::begin']
|
||||
-> Openstacklib::Clouds['/etc/nova/clouds.yaml']
|
||||
-> Anchor['nova::config::end']
|
||||
}
|
||||
|
|
|
@ -24,6 +24,8 @@ describe 'nova::keystone::auth' do
|
|||
:email => 'nova@localhost',
|
||||
:tenant => 'services',
|
||||
:roles => ['admin'],
|
||||
:system_scope => 'all',
|
||||
:system_roles => ['admin'],
|
||||
:public_url => 'http://127.0.0.1:8774/v2.1',
|
||||
:internal_url => 'http://127.0.0.1:8774/v2.1',
|
||||
:admin_url => 'http://127.0.0.1:8774/v2.1',
|
||||
|
@ -46,7 +48,9 @@ describe 'nova::keystone::auth' do
|
|||
:roles => ['admin', 'service'],
|
||||
:public_url => 'https://10.10.10.10:80',
|
||||
:internal_url => 'http://10.10.10.11:81',
|
||||
:admin_url => 'http://10.10.10.12:81' }
|
||||
:admin_url => 'http://10.10.10.12:81',
|
||||
:interface => 'internal',
|
||||
}
|
||||
end
|
||||
|
||||
it { is_expected.to contain_keystone__resource__service_identity('nova').with(
|
||||
|
@ -62,6 +66,8 @@ describe 'nova::keystone::auth' do
|
|||
:email => 'alt_nova@alt_localhost',
|
||||
:tenant => 'alt_service',
|
||||
:roles => ['admin', 'service'],
|
||||
:system_scope => 'all',
|
||||
:system_roles => ['admin'],
|
||||
:public_url => 'https://10.10.10.10:80',
|
||||
:internal_url => 'http://10.10.10.11:81',
|
||||
:admin_url => 'http://10.10.10.12:81',
|
||||
|
|
|
@ -2,14 +2,12 @@ require 'puppet'
|
|||
require 'spec_helper'
|
||||
require 'puppet/provider/nova_aggregate/openstack'
|
||||
|
||||
provider_class = Puppet::Type.type(:nova_aggregate).provider(:openstack)
|
||||
describe Puppet::Type.type(:nova_aggregate).provider(:openstack) do
|
||||
|
||||
describe provider_class do
|
||||
|
||||
shared_examples 'authenticated with environment variables' do
|
||||
let(:set_env) do
|
||||
ENV['OS_USERNAME'] = 'test'
|
||||
ENV['OS_PASSWORD'] = 'abc123'
|
||||
ENV['OS_PROJECT_NAME'] = 'test'
|
||||
ENV['OS_SYSTEM_SCOPE'] = 'all'
|
||||
ENV['OS_AUTH_URL'] = 'http://127.0.0.1:5000/v3'
|
||||
end
|
||||
|
||||
|
@ -30,96 +28,93 @@ describe provider_class do
|
|||
end
|
||||
|
||||
let(:provider) do
|
||||
provider_class.new(resource)
|
||||
described_class.new(resource)
|
||||
end
|
||||
|
||||
it_behaves_like 'authenticated with environment variables' do
|
||||
describe '#instances' do
|
||||
it 'finds existing aggregates' do
|
||||
provider_class.expects(:openstack)
|
||||
.with('aggregate', 'list', '--quiet', '--format', 'csv', [])
|
||||
.returns('"ID","Name","Availability Zone"
|
||||
before(:each) do
|
||||
set_env
|
||||
end
|
||||
|
||||
describe '#instances' do
|
||||
it 'finds existing aggregates' do
|
||||
described_class.expects(:openstack)
|
||||
.with('aggregate', 'list', '--quiet', '--format', 'csv', [])
|
||||
.returns('"ID","Name","Availability Zone"
|
||||
just,"simple","just"
|
||||
')
|
||||
provider_class.expects(:openstack)
|
||||
.with('aggregate', 'show', '--format', 'shell', 'simple')
|
||||
.returns('"id="just"
|
||||
described_class.expects(:openstack)
|
||||
.with('aggregate', 'show', '--format', 'shell', 'simple')
|
||||
.returns('"id="just"
|
||||
name="simple"
|
||||
availability_zone=just"
|
||||
properties="key1=\'tomato\', key2=\'mushroom\'"
|
||||
hosts="[]"
|
||||
')
|
||||
instances = provider_class.instances
|
||||
expect(instances.count).to eq(1)
|
||||
expect(instances[0].name).to eq('simple')
|
||||
expect(instances[0].metadata).to eq({"key1"=>"tomato", "key2"=>"mushroom"})
|
||||
end
|
||||
instances = described_class.instances
|
||||
expect(instances.count).to eq(1)
|
||||
expect(instances[0].name).to eq('simple')
|
||||
expect(instances[0].metadata).to eq({"key1"=>"tomato", "key2"=>"mushroom"})
|
||||
end
|
||||
end
|
||||
|
||||
describe '#create' do
|
||||
it 'creates aggregate' do
|
||||
provider.class.stubs(:openstack)
|
||||
.with('aggregate', 'list', '--quiet', '--format', 'csv', '--long')
|
||||
.returns('"ID","Name","Availability Zone","Properties"
|
||||
')
|
||||
provider.class.stubs(:openstack)
|
||||
.with('aggregate', 'create', '--format', 'shell', ['just', '--zone', 'simple', '--property', 'nice=cookie' ])
|
||||
.returns('name="just"
|
||||
describe '#create' do
|
||||
it 'creates aggregate' do
|
||||
described_class.expects(:openstack)
|
||||
.with('aggregate', 'create', '--format', 'shell',
|
||||
['just', '--zone', 'simple', '--property', 'nice=cookie' ])
|
||||
.returns('name="just"
|
||||
id="just"
|
||||
availability_zone="simple"
|
||||
properties="{u\'nice\': u\'cookie\'}"
|
||||
hosts="[]"
|
||||
')
|
||||
provider.class.stubs(:openstack)
|
||||
.with('aggregate', 'add host', ['just', 'example'])
|
||||
.returns('name="just"
|
||||
described_class.expects(:openstack)
|
||||
.with('aggregate', 'add host', ['just', 'example'])
|
||||
.returns('name="just"
|
||||
id="just"
|
||||
availability_zone="simple"
|
||||
properties="{u\'nice\': u\'cookie\'}"
|
||||
hosts="[u\'example\']"
|
||||
')
|
||||
provider.exists?
|
||||
provider.create
|
||||
expect(provider.exists?).to be_falsey
|
||||
end
|
||||
provider.create
|
||||
expect(provider.exists?).to be_truthy
|
||||
end
|
||||
end
|
||||
|
||||
describe '#destroy' do
|
||||
it 'removes aggregate with hosts' do
|
||||
described_class.expects(:openstack)
|
||||
.with('aggregate', 'remove host', ['just', 'example'])
|
||||
described_class.expects(:openstack)
|
||||
.with('aggregate', 'delete', 'just')
|
||||
provider.instance_variable_set(:@property_hash, aggregate_attrs)
|
||||
provider.destroy
|
||||
expect(provider.exists?).to be_falsey
|
||||
end
|
||||
end
|
||||
|
||||
describe '#pythondict2hash' do
|
||||
it 'should return a hash with key-value when provided with a unicode python dict' do
|
||||
s = "{u'key': 'value', u'key2': 'value2'}"
|
||||
expect(described_class.pythondict2hash(s)).to eq({"key"=>"value", "key2"=>"value2"})
|
||||
end
|
||||
|
||||
describe '#destroy' do
|
||||
it 'removes aggregate with hosts' do
|
||||
provider_class.expects(:openstack)
|
||||
.with('aggregate', 'remove host', ['just', 'example'])
|
||||
provider_class.expects(:openstack)
|
||||
.with('aggregate', 'delete', 'just')
|
||||
provider.instance_variable_set(:@property_hash, aggregate_attrs)
|
||||
provider.destroy
|
||||
expect(provider.exists?).to be_falsey
|
||||
end
|
||||
it 'should return a hash with key-value when provided with a python dict' do
|
||||
s = "{'key': 'value', 'key2': 'value2'}"
|
||||
expect(described_class.pythondict2hash(s)).to eq({"key"=>"value", "key2"=>"value2"})
|
||||
end
|
||||
end
|
||||
|
||||
describe '#parsestring' do
|
||||
it 'should call string2hash when provided with a string' do
|
||||
s = "key='value', key2='value2'"
|
||||
expect(described_class.parsestring(s)).to eq({"key"=>"value", "key2"=>"value2"})
|
||||
end
|
||||
|
||||
describe '#pythondict2hash' do
|
||||
it 'should return a hash with key-value when provided with a unicode python dict' do
|
||||
s = "{u'key': 'value', u'key2': 'value2'}"
|
||||
expect(provider_class.pythondict2hash(s)).to eq({"key"=>"value", "key2"=>"value2"})
|
||||
end
|
||||
|
||||
it 'should return a hash with key-value when provided with a python dict' do
|
||||
s = "{'key': 'value', 'key2': 'value2'}"
|
||||
expect(provider_class.pythondict2hash(s)).to eq({"key"=>"value", "key2"=>"value2"})
|
||||
end
|
||||
it 'should call pythondict2hash when provided with a hash' do
|
||||
s = "{u'key': 'value', u'key2': 'value2'}"
|
||||
expect(described_class.parsestring(s)).to eq({"key"=>"value", "key2"=>"value2"})
|
||||
end
|
||||
|
||||
describe '#parsestring' do
|
||||
it 'should call string2hash when provided with a string' do
|
||||
s = "key='value', key2='value2'"
|
||||
expect(provider_class.parsestring(s)).to eq({"key"=>"value", "key2"=>"value2"})
|
||||
end
|
||||
|
||||
it 'should call pythondict2hash when provided with a hash' do
|
||||
s = "{u'key': 'value', u'key2': 'value2'}"
|
||||
expect(provider_class.parsestring(s)).to eq({"key"=>"value", "key2"=>"value2"})
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -143,83 +138,83 @@ hosts="[u\'example\']"
|
|||
end
|
||||
|
||||
let(:provider) do
|
||||
provider_class.new(resource)
|
||||
described_class.new(resource)
|
||||
end
|
||||
|
||||
it_behaves_like 'authenticated with environment variables' do
|
||||
before(:each) do
|
||||
set_env
|
||||
end
|
||||
|
||||
# create an aggregate and actually aggregate hosts to it
|
||||
describe 'create aggregate and add/remove hosts with filter_hosts toggled' do
|
||||
# create an aggregate and actually aggregate hosts to it
|
||||
describe 'create aggregate and add/remove hosts with filter_hosts toggled' do
|
||||
|
||||
it 'creates aggregate with filter_hosts toggled' do
|
||||
it 'creates aggregate with filter_hosts toggled' do
|
||||
|
||||
provider.class.stubs(:get_known_hosts)
|
||||
.returns(['known', 'known_too'])
|
||||
provider.class.stubs(:get_known_hosts)
|
||||
.returns(['known', 'known_too'])
|
||||
|
||||
# these expectations are the actual tests that check the provider's behaviour
|
||||
# and make sure only known hosts ('known' is the only known host) will be
|
||||
# aggregated.
|
||||
# these expectations are the actual tests that check the provider's behaviour
|
||||
# and make sure only known hosts ('known' is the only known host) will be
|
||||
# aggregated.
|
||||
|
||||
provider_class.expects(:openstack)
|
||||
.with('aggregate', 'create', '--format', 'shell', ['just', '--zone', 'simple', "--property", "nice=cookie"])
|
||||
.once
|
||||
.returns('name="just"
|
||||
described_class.expects(:openstack)
|
||||
.with('aggregate', 'create', '--format', 'shell', ['just', '--zone', 'simple', "--property", "nice=cookie"])
|
||||
.once
|
||||
.returns('name="just"
|
||||
id="just"
|
||||
availability_zone="simple"
|
||||
properties="{u\'nice\': u\'cookie\'}"
|
||||
hosts="[]"
|
||||
')
|
||||
|
||||
provider_class.expects(:openstack)
|
||||
.with('aggregate', 'add host', ['just', 'known'])
|
||||
.once
|
||||
.returns('name="just"
|
||||
described_class.expects(:openstack)
|
||||
.with('aggregate', 'add host', ['just', 'known'])
|
||||
.once
|
||||
.returns('name="just"
|
||||
id="just"
|
||||
availability_zone="simple"
|
||||
properties="{u\'nice\': u\'cookie\'}"
|
||||
hosts="[u\'known\']"
|
||||
')
|
||||
|
||||
provider_class.expects(:openstack)
|
||||
.with('aggregate', 'add host', ['just', 'known_too'])
|
||||
.once
|
||||
.returns('name="just"
|
||||
described_class.expects(:openstack)
|
||||
.with('aggregate', 'add host', ['just', 'known_too'])
|
||||
.once
|
||||
.returns('name="just"
|
||||
id="just"
|
||||
availability_zone="simple"
|
||||
properties="{u\'nice\': u\'cookie\'}"
|
||||
hosts="[u\'known\', u\'known_too\']"
|
||||
')
|
||||
|
||||
provider_class.expects(:openstack)
|
||||
.with('aggregate', 'remove host', ['just', 'known'])
|
||||
.once
|
||||
.returns('name="just"
|
||||
described_class.expects(:openstack)
|
||||
.with('aggregate', 'remove host', ['just', 'known'])
|
||||
.once
|
||||
.returns('name="just"
|
||||
id="just"
|
||||
availability_zone="simple"
|
||||
properties="{u\'nice\': u\'cookie\'}"
|
||||
hosts="[u\'known_too\']"
|
||||
')
|
||||
|
||||
# this creates a provider with the attributes defined above as 'aggregate_attrs'
|
||||
# and tries to add some hosts and then to remove some hosts.
|
||||
# the hosts will be filtered against known active hosts and the expectations
|
||||
# described above are the actual tests that check the provider's behaviour
|
||||
# this creates a provider with the attributes defined above as 'aggregate_attrs'
|
||||
# and tries to add some hosts and then to remove some hosts.
|
||||
# the hosts will be filtered against known active hosts and the expectations
|
||||
# described above are the actual tests that check the provider's behaviour
|
||||
|
||||
provider.create
|
||||
property_hash = provider.instance_variable_get(:@property_hash)
|
||||
property_hash[:hosts] = ['known']
|
||||
provider.instance_variable_set(:@property_hash, property_hash)
|
||||
provider.create
|
||||
property_hash = provider.instance_variable_get(:@property_hash)
|
||||
property_hash[:hosts] = ['known']
|
||||
provider.instance_variable_set(:@property_hash, property_hash)
|
||||
|
||||
provider.hosts = ['known', 'known_too', 'unknown']
|
||||
property_hash = provider.instance_variable_get(:@property_hash)
|
||||
property_hash[:hosts] = ['known', 'known_too']
|
||||
provider.instance_variable_set(:@property_hash, property_hash)
|
||||
provider.hosts = ['known', 'known_too', 'unknown']
|
||||
property_hash = provider.instance_variable_get(:@property_hash)
|
||||
property_hash[:hosts] = ['known', 'known_too']
|
||||
provider.instance_variable_set(:@property_hash, property_hash)
|
||||
|
||||
provider.hosts = ['known_too']
|
||||
provider.hosts = ['known_too']
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
@ -2,9 +2,14 @@ require 'puppet'
|
|||
require 'spec_helper'
|
||||
require 'puppet/provider/nova_flavor/openstack'
|
||||
|
||||
provider_class = Puppet::Type.type(:nova_flavor).provider(:openstack)
|
||||
describe Puppet::Type.type(:nova_flavor).provider(:openstack) do
|
||||
|
||||
describe provider_class do
|
||||
let(:set_env) do
|
||||
ENV['OS_USERNAME'] = 'test'
|
||||
ENV['OS_PASSWORD'] = 'abc123'
|
||||
ENV['OS_SYSTEM_SCOPE'] = 'all'
|
||||
ENV['OS_AUTH_URL'] = 'http://127.0.0.1:5000/v3'
|
||||
end
|
||||
|
||||
describe 'managing flavors' do
|
||||
let(:flavor_attrs) do
|
||||
|
@ -23,17 +28,20 @@ describe provider_class do
|
|||
end
|
||||
|
||||
let(:provider) do
|
||||
provider_class.new(resource)
|
||||
described_class.new(resource)
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
set_env
|
||||
end
|
||||
|
||||
describe '#create' do
|
||||
it 'creates flavor' do
|
||||
provider.class.stubs(:openstack)
|
||||
.with('flavor', 'list', ['--long', '--all'])
|
||||
.returns('"ID", "Name", "RAM", "Disk", "Ephemeral", "VCPUs", "Is Public", "Swap", "RXTX Factor", "Properties"')
|
||||
provider.class.stubs(:openstack)
|
||||
.with('flavor', 'create', 'shell', ['example', '--public', '--id', '1', '--ram', '512', '--disk', '1', '--vcpus', '1'])
|
||||
.returns('os-flv-disabled:disabled="False"
|
||||
described_class.expects(:openstack)
|
||||
.with('flavor', 'create', '--format', 'shell',
|
||||
['example', '--public', '--id', '1', '--ram', '512',
|
||||
'--disk', '1', '--vcpus', '1'])
|
||||
.returns('os-flv-disabled:disabled="False"
|
||||
os-flv-ext-data:ephemeral="0"
|
||||
disk="1"
|
||||
id="1"
|
||||
|
@ -43,12 +51,14 @@ ram="512"
|
|||
rxtx_factor="1.0"
|
||||
swap=""
|
||||
vcpus="1"')
|
||||
provider.create
|
||||
expect(provider.exists?).to be_truthy
|
||||
end
|
||||
end
|
||||
|
||||
describe '#destroy' do
|
||||
it 'removes flavor' do
|
||||
provider_class.expects(:openstack)
|
||||
described_class.expects(:openstack)
|
||||
.with('flavor', 'delete', '1')
|
||||
provider.instance_variable_set(:@property_hash, flavor_attrs)
|
||||
provider.destroy
|
||||
|
|
|
@ -9,7 +9,7 @@ describe provider_class do
|
|||
shared_examples 'authenticated with environment variables' do
|
||||
ENV['OS_USERNAME'] = 'test'
|
||||
ENV['OS_PASSWORD'] = 'abc123'
|
||||
ENV['OS_PROJECT_NAME'] = 'test'
|
||||
ENV['OS_SYSTEM_SCOPE'] = 'all'
|
||||
ENV['OS_AUTH_URL'] = 'http://127.0.0.1:5000/v3'
|
||||
end
|
||||
|
||||
|
|
|
@ -9,62 +9,10 @@ describe Puppet::Provider::Nova do
|
|||
described_class
|
||||
end
|
||||
|
||||
let :credential_hash do
|
||||
{
|
||||
'auth_url' => 'https://192.168.56.210:5000/v3/',
|
||||
'project_name' => 'admin_tenant',
|
||||
'username' => 'admin',
|
||||
'password' => 'password',
|
||||
'region_name' => 'Region1',
|
||||
}
|
||||
end
|
||||
|
||||
let :auth_endpoint do
|
||||
'https://192.168.56.210:5000/v3/'
|
||||
end
|
||||
|
||||
let :credential_error do
|
||||
/Nova types will not work/
|
||||
end
|
||||
|
||||
after :each do
|
||||
klass.reset
|
||||
end
|
||||
|
||||
describe 'when determining credentials' do
|
||||
|
||||
it 'should fail if config is empty' do
|
||||
conf = {}
|
||||
klass.expects(:nova_conf).returns(conf)
|
||||
expect do
|
||||
klass.nova_credentials
|
||||
end.to raise_error(Puppet::Error, credential_error)
|
||||
end
|
||||
|
||||
it 'should fail if config does not have keystone_authtoken section.' do
|
||||
conf = {'foo' => 'bar'}
|
||||
klass.expects(:nova_conf).returns(conf)
|
||||
expect do
|
||||
klass.nova_credentials
|
||||
end.to raise_error(Puppet::Error, credential_error)
|
||||
end
|
||||
|
||||
it 'should fail if config does not contain all auth params' do
|
||||
conf = {'keystone_authtoken' => {'invalid_value' => 'foo'}}
|
||||
klass.expects(:nova_conf).returns(conf)
|
||||
expect do
|
||||
klass.nova_credentials
|
||||
end.to raise_error(Puppet::Error, credential_error)
|
||||
end
|
||||
|
||||
it 'should use specified uri in the auth endpoint' do
|
||||
conf = {'keystone_authtoken' => credential_hash}
|
||||
klass.expects(:nova_conf).returns(conf)
|
||||
expect(klass.get_auth_endpoint).to eq(auth_endpoint)
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
describe 'when parse a string line' do
|
||||
it 'should return the same string' do
|
||||
res = klass.str2hash("zone1")
|
||||
|
|
Loading…
Reference in New Issue