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