Use system scope credentials in providers

This change enforces usage of system scope credentials to manage
flavors, aggregates, and services, following the new policy rules for
SRBAC support in nova.

The logic to look up credential for the nova service user from
[keystone_authtoken] is left to keep backward compatibility but is
deprecated and will be removed.

Depends-on: https://review.opendev.org/806474
Depends-on: https://review.opendev.org/828025
Depends-on: https://review.opendev.org/828874
Change-Id: I71779f0f1459d64914589a94a440336386266306
This commit is contained in:
Takashi Kajinami 2022-02-11 13:01:50 +09:00
parent 77138476e0
commit 0ed626e146
8 changed files with 196 additions and 165 deletions
lib/puppet/provider
nova.rb
nova_aggregate
nova_flavor
nova_service
releasenotes/notes
spec/unit/provider
nova_aggregate
nova_flavor
nova_service

@ -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,15 +7,24 @@ class Puppet::Provider::Nova < Puppet::Provider::Openstack
extend Puppet::Provider::Openstack::Auth extend Puppet::Provider::Openstack::Auth
def self.request(service, action, properties=nil) def self.project_request(service, action, properties=nil, options={})
self.request(service, action, properties, options, 'project')
end
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')
begin begin
super super
rescue Puppet::Error::OpenstackAuthInputError => error rescue Puppet::Error::OpenstackAuthInputError => error
nova_request(service, action, error, properties) nova_request(service, action, error, properties, options)
end end
end end
def self.nova_request(service, action, error, properties=nil) def self.nova_request(service, action, error, properties=nil, options={})
warning('Usage of keystone_authtoken parameters is deprecated.')
properties ||= [] properties ||= []
@credentials.username = nova_credentials['username'] @credentials.username = nova_credentials['username']
@credentials.password = nova_credentials['password'] @credentials.password = nova_credentials['password']
@ -33,7 +36,7 @@ class Puppet::Provider::Nova < Puppet::Provider::Openstack
@credentials.region_name = nova_credentials['region_name'] @credentials.region_name = nova_credentials['region_name']
end end
raise error unless @credentials.set? raise error unless @credentials.set?
Puppet::Provider::Openstack.request(service, action, properties, @credentials) Puppet::Provider::Openstack.request(service, action, properties, @credentials, options)
end end
def self.nova_manage_request(*args) def self.nova_manage_request(*args)

@ -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])
@property_hash.clear @property_hash.clear
end end
@ -69,7 +69,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
@ -77,14 +77,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 @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)
@ -94,13 +94,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)
@ -111,11 +111,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,28 +26,28 @@ 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] and !(@resources[:properties].empty?) if @resource[:properties] and !(@resources[:properties].empty?)
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] and @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)
project = self.class.request('project', 'show', @resource[:project]) project = self.class.system_request('project', 'show', @resource[:project])
@property_hash[:project_name] = project[:name] @property_hash[:project_name] = project[:name]
@property_hash[:project] = project[:id] @property_hash[:project] = project[:id]
elsif @resource[:project_name] and @resource[:project_name] != '' elsif @resource[:project_name] and @resource[:project_name] != ''
proj_opts = [@resource[:name]] proj_opts = [@resource[:name]]
proj_opts << '--project' << @resource[:project_name] proj_opts << '--project' << @resource[:project_name]
self.class.request('flavor', 'set', proj_opts) self.class.system_request('flavor', 'set', proj_opts)
project = self.class.request('project', 'show', @resource[:project_name]) project = self.class.system_request('project', 'show', @resource[:project_name])
@property_hash[:project_name] = project[:name] @property_hash[:project_name] = project[:name]
@property_hash[:project] = project[:id] @property_hash[:project] = project[:id]
end end
@ -60,7 +60,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])
@property_hash.clear @property_hash.clear
end end
@ -93,8 +93,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 ''
@ -110,7 +110,7 @@ Puppet::Type.type(:nova_flavor).provide(
project_value = project_value.gsub('\'', '') project_value = project_value.gsub('\'', '')
if project_value != '' if project_value != ''
project = request('project', 'show', project_value) project = system_request('project', 'show', project_value)
project_id = project[:id] project_id = project[:id]
project_name = project[:name] project_name = project[:name]
else else
@ -151,7 +151,7 @@ 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
@ -159,20 +159,20 @@ Puppet::Type.type(:nova_flavor).provide(
if @project_flush[:project] if @project_flush[:project]
if @property_hash[:project] and @property_hash[:project] != '' if @property_hash[:project] and @property_hash[:project] != ''
opts = [@resource[:name], '--project', @property_hash[:project]] opts = [@resource[:name], '--project', @property_hash[:project]]
self.class.request('flavor', 'unset', opts) self.class.system_request('flavor', 'unset', opts)
end end
if @project_flush[:project] != '' if @project_flush[:project] != ''
opts = [@resource[:name], '--project', @project_flush[:project]] opts = [@resource[:name], '--project', @project_flush[:project]]
self.class.request('flavor', 'set', opts) self.class.system_request('flavor', 'set', opts)
end end
elsif @project_flush[:project_name] elsif @project_flush[:project_name]
if @property_hash[:project_name] and @property_hash[:project_name] != '' if @property_hash[:project_name] and @property_hash[:project_name] != ''
opts = [@resource[:name], '--project', @property_hash[:project_name]] opts = [@resource[:name], '--project', @property_hash[:project_name]]
self.class.request('flavor', 'unset', opts) self.class.system_request('flavor', 'unset', opts)
end end
if @project_flush[:project_name] != '' if @project_flush[:project_name] != ''
opts = [@resource[:name], '--project', @project_flush[:project_name]] opts = [@resource[:name], '--project', @project_flush[:project_name]]
self.class.request('flavor', 'set', opts) self.class.system_request('flavor', 'set', opts)
end end
end end
@project_flush.clear @project_flush.clear

@ -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.clear @property_hash.clear

@ -0,0 +1,22 @@
---
upgrade:
- |
Now the following resource types uses system scope credentail instead of
project scope credential when sending requests to Nova API.
- ``nova_aggregate``
- ``nova_flavor``
- ``nova_service``
deprecations:
- |
The following resource types have been using the credential written in
the ``[keystone_authtoken]`` section of ``nova.conf``. However this
behavior has been deprecated and now these resource types first look for
the yaml files in ``/etc/openstack/puppet``. Make sure one of
``clouds.yaml`` or ``admin-clouds.yaml`` (which is created by
puppet-keystone) is created in that directory.
- ``nova_aggregate``
- ``nova_flavor``
- ``nova_service``

@ -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,18 +28,21 @@ 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
it_behaves_like 'authenticated with environment variables' do
describe '#instances' do describe '#instances' do
it 'finds existing aggregates' do it 'finds existing aggregates' do
provider_class.expects(:openstack) described_class.expects(:openstack)
.with('aggregate', 'list', '--quiet', '--format', 'csv', []) .with('aggregate', 'list', '--quiet', '--format', 'csv', [])
.returns('"ID","Name","Availability Zone" .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"
@ -49,7 +50,7 @@ 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"})
@ -58,19 +59,16 @@ hosts="[]"
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' ])
')
provider.class.stubs(:openstack)
.with('aggregate', 'create', '--format', 'shell', ['just', '--zone', 'simple', '--property', 'nice=cookie' ])
.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.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"
@ -78,6 +76,7 @@ availability_zone="simple"
properties="{u\'nice\': u\'cookie\'}" properties="{u\'nice\': u\'cookie\'}"
hosts="[u\'example\']" hosts="[u\'example\']"
') ')
provider.create provider.create
expect(provider.exists?).to be_truthy expect(provider.exists?).to be_truthy
end end
@ -85,9 +84,9 @@ hosts="[u\'example\']"
describe '#destroy' do describe '#destroy' do
it 'removes aggregate with hosts' do it 'removes aggregate with hosts' do
provider_class.expects(:openstack) described_class.expects(:openstack)
.with('aggregate', 'remove host', ['just', 'example']) .with('aggregate', 'remove host', ['just', 'example'])
provider_class.expects(:openstack) described_class.expects(:openstack)
.with('aggregate', 'delete', 'just') .with('aggregate', 'delete', 'just')
provider.instance_variable_set(:@property_hash, aggregate_attrs) provider.instance_variable_set(:@property_hash, aggregate_attrs)
provider.destroy provider.destroy
@ -98,28 +97,26 @@ hosts="[u\'example\']"
describe '#pythondict2hash' do describe '#pythondict2hash' do
it 'should return a hash with key-value when provided with a unicode python dict' 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(provider_class.pythondict2hash(s)).to eq({"key"=>"value", "key2"=>"value2"}) expect(described_class.pythondict2hash(s)).to eq({"key"=>"value", "key2"=>"value2"})
end end
it 'should return a hash with key-value when provided with a python dict' do it 'should return a hash with key-value when provided with a python dict' do
s = "{'key': 'value', 'key2': 'value2'}" s = "{'key': 'value', 'key2': 'value2'}"
expect(provider_class.pythondict2hash(s)).to eq({"key"=>"value", "key2"=>"value2"}) expect(described_class.pythondict2hash(s)).to eq({"key"=>"value", "key2"=>"value2"})
end end
end end
describe '#parsestring' do describe '#parsestring' do
it 'should call string2hash when provided with a string' do it 'should call string2hash when provided with a string' do
s = "key='value', key2='value2'" s = "key='value', key2='value2'"
expect(provider_class.parsestring(s)).to eq({"key"=>"value", "key2"=>"value2"}) expect(described_class.parsestring(s)).to eq({"key"=>"value", "key2"=>"value2"})
end end
it 'should call pythondict2hash when provided with a hash' do it 'should call pythondict2hash when provided with a hash' do
s = "{u'key': 'value', u'key2': 'value2'}" s = "{u'key': 'value', u'key2': 'value2'}"
expect(provider_class.parsestring(s)).to eq({"key"=>"value", "key2"=>"value2"}) expect(described_class.parsestring(s)).to eq({"key"=>"value", "key2"=>"value2"})
end end
end end
end
end end
@ -142,10 +139,12 @@ 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
@ -159,7 +158,7 @@ hosts="[u\'example\']"
# 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"
@ -169,7 +168,7 @@ 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"
@ -179,7 +178,7 @@ 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"
@ -189,7 +188,7 @@ 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"
@ -218,8 +217,6 @@ hosts="[u\'known_too\']"
end end
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,7 +28,11 @@ 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
@ -121,7 +130,7 @@ domain_id="domain_one_id"
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