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:
Takashi Kajinami 2021-10-28 22:50:37 +09:00
parent 83f815ba87
commit a3da1f1188
10 changed files with 226 additions and 272 deletions

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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']
}

View File

@ -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',

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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")