Files
puppet-neutron/spec/unit/provider/neutron_spec.rb
Daniel Pawlik 99b3203923 Added neutron security groups and OpenstackClient auth
Creating security group using nova module is deprecated.
This patch will give neutron puppet module adds the ability
to create security groups.

OpenstackClient will allow easier create new Puppet Neutron
provider classes.

Change-Id: I1a900fadce6b4d1c006e43164d380034ea5cef2d
Partial-Bug: #1671474
2017-03-17 11:48:40 +00:00

265 lines
8.7 KiB
Ruby

require 'puppet'
require 'spec_helper'
require 'puppet/provider/neutron'
require 'tempfile'
describe Puppet::Provider::Neutron do
def klass
described_class
end
let :credential_hash do
{
'project_name' => 'admin_tenant',
'username' => 'admin',
'password' => 'password',
'auth_uri' => 'https://192.168.56.210:35357/v2.0/',
}
end
let :credential_error do
/Neutron types will not work/
end
let :exec_error do
/Neutron or Keystone API is not available/
end
after :each do
klass.reset
end
describe 'when determining credentials' do
it 'should fail if config is empty' do
conf = {}
klass.expects(:neutron_conf).returns(conf)
expect do
klass.neutron_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(:neutron_conf).returns(conf)
expect do
klass.neutron_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(:neutron_conf).returns(conf)
expect do
klass.neutron_credentials
end.to raise_error(Puppet::Error, credential_error)
end
end
describe 'when invoking the neutron cli' do
it 'should set auth credentials in the environment' do
authenv = {
:OS_AUTH_URL => credential_hash['auth_uri'],
:OS_USERNAME => credential_hash['username'],
:OS_PROJECT_NAME => credential_hash['project_name'],
:OS_PASSWORD => credential_hash['password'],
}
klass.expects(:get_neutron_credentials).with().returns(credential_hash)
klass.expects(:withenv).with(authenv)
klass.auth_neutron('test_retries')
end
it 'should set region in the environment if needed' do
authenv = {
:OS_AUTH_URL => credential_hash['auth_uri'],
:OS_USERNAME => credential_hash['username'],
:OS_PROJECT_NAME => credential_hash['project_name'],
:OS_PASSWORD => credential_hash['password'],
:OS_REGION_NAME => 'REGION_NAME',
}
cred_hash = credential_hash.merge({'region_name' => 'REGION_NAME'})
klass.expects(:get_neutron_credentials).with().returns(cred_hash)
klass.expects(:withenv).with(authenv)
klass.auth_neutron('test_retries')
end
['[Errno 111] Connection refused',
'400-{\'message\': \'\'}',
'(HTTP 400)',
'503 Service Unavailable',
'504 Gateway Time-out',
'Maximum attempts reached',
'Unauthorized: bad credentials',
'Max retries exceeded'].reverse.each do |valid_message|
it "should retry when neutron cli returns with error #{valid_message}" do
klass.expects(:get_neutron_credentials).with().returns({})
klass.expects(:sleep).with(2).returns(nil)
klass.expects(:neutron).twice.with(['test_retries']).raises(
Puppet::ExecutionFailure, valid_message).then.returns('')
klass.auth_neutron('test_retries')
end
end
end
describe 'when listing neutron resources' do
it 'should exclude the column header' do
output = <<-EOT
id
net1
net2
EOT
klass.expects(:auth_neutron).returns(output)
result = klass.list_neutron_resources('foo')
expect(result).to eql(['net1', 'net2'])
end
it 'should return empty list when there are no neutron resources' do
output = <<-EOT
EOT
klass.stubs(:auth_neutron).returns(output)
result = klass.list_neutron_resources('foo')
expect(result).to eql([])
end
it 'should fail if resources list is nil' do
klass.stubs(:auth_neutron).returns(nil)
expect do
klass.list_neutron_resources('foo')
end.to raise_error(Puppet::Error, exec_error)
end
end
describe 'when retrieving attributes for neutron resources' do
it 'should parse single-valued attributes into a key-value pair' do
klass.expects(:auth_neutron).returns('admin_state_up="True"')
result = klass.get_neutron_resource_attrs('foo', 'id')
expect(result).to eql({"admin_state_up" => 'True'})
end
it 'should parse multi-valued attributes into a key-list pair' do
output = <<-EOT
subnets="subnet1
subnet2
subnet3"
EOT
klass.expects(:auth_neutron).returns(output)
result = klass.get_neutron_resource_attrs('foo', 'id')
expect(result).to eql({"subnets" => ['subnet1', 'subnet2', 'subnet3']})
end
end
describe 'when listing router ports' do
let :router do
'router1'
end
it 'should handle an empty port list' do
klass.expects(:auth_neutron).with('router-port-list',
'--format=csv',
router)
result = klass.list_router_ports(router)
expect(result).to eql([])
end
it 'should handle several ports' do
output = <<-EOT
"id","name","mac_address","fixed_ips"
"1345e576-a21f-4c2e-b24a-b245639852ab","","fa:16:3e:e3:e6:38","{""subnet_id"": ""839a1d2d-2c6e-44fb-9a2b-9b011dce8c2f"", ""ip_address"": ""10.0.0.1""}"
"de0dc526-02b2-467c-9832-2c3dc69ac2b4","","fa:16:3e:f6:b5:72","{""subnet_id"": ""e4db0abd-276a-4f69-92ea-8b9e4eacfd43"", ""ip_address"": ""172.24.4.226""}"
EOT
expected =
[{ "fixed_ips"=>
"{\"subnet_id\": \"839a1d2d-2c6e-44fb-9a2b-9b011dce8c2f\", \
\"ip_address\": \"10.0.0.1\"}",
"name"=>"",
"subnet_id"=>"839a1d2d-2c6e-44fb-9a2b-9b011dce8c2f",
"id"=>"1345e576-a21f-4c2e-b24a-b245639852ab",
"mac_address"=>"fa:16:3e:e3:e6:38"},
{"fixed_ips"=>
"{\"subnet_id\": \"e4db0abd-276a-4f69-92ea-8b9e4eacfd43\", \
\"ip_address\": \"172.24.4.226\"}",
"name"=>"",
"subnet_id"=>"e4db0abd-276a-4f69-92ea-8b9e4eacfd43",
"id"=>"de0dc526-02b2-467c-9832-2c3dc69ac2b4",
"mac_address"=>"fa:16:3e:f6:b5:72"}]
klass.expects(:auth_neutron).
with('router-port-list', '--format=csv', router).
returns(output)
result = klass.list_router_ports(router)
expect(result).to eql(expected)
end
end
describe 'when parsing creation output' do
it 'should parse valid output into a hash' do
data = <<-EOT
Created a new network:
admin_state_up="True"
id="5f9cbed2-d31c-4e9c-be92-87229acb3f69"
name="foo"
tenant_id="3056a91768d948d399f1d79051a7f221"
EOT
expected = {
'admin_state_up' => 'True',
'id' => '5f9cbed2-d31c-4e9c-be92-87229acb3f69',
'name' => 'foo',
'tenant_id' => '3056a91768d948d399f1d79051a7f221',
}
expect(klass.parse_creation_output(data)).to eq(expected)
end
end
describe 'garbage in the csv output' do
it '#list_router_ports' do
output = <<-EOT
/usr/lib/python2.7/dist-packages/urllib3/util/ssl_.py:90: InsecurePlatformWarning: A true SSLContext object is not available. This prevents urllib3 from configuring SSL appropriately and may cause certain SSL connections to fail. For more information, see https://urllib3.readthedocs.org/en/latest/security.html#insecureplatformwarning.
InsecurePlatformWarning
"id","name","mac_address","fixed_ips"
"1345e576-a21f-4c2e-b24a-b245639852ab","","fa:16:3e:e3:e6:38","{""subnet_id"": ""839a1d2d-2c6e-44fb-9a2b-9b011dce8c2f"", ""ip_address"": ""10.0.0.1""}"
EOT
expected = [{ "fixed_ips"=>
"{\"subnet_id\": \"839a1d2d-2c6e-44fb-9a2b-9b011dce8c2f\", \
\"ip_address\": \"10.0.0.1\"}",
"name"=>"",
"subnet_id"=>"839a1d2d-2c6e-44fb-9a2b-9b011dce8c2f",
"id"=>"1345e576-a21f-4c2e-b24a-b245639852ab",
"mac_address"=>"fa:16:3e:e3:e6:38"}]
klass.expects(:auth_neutron).
with('router-port-list', '--format=csv', 'router1').
returns(output)
result = klass.list_router_ports('router1')
expect(result).to eql(expected)
end
it '#list_neutron_resources' do
output = <<-EOT
/usr/lib/python2.7/dist-packages/urllib3/util/ssl_.py:90: InsecurePlatformWarning: A true SSLContext object is not available. This prevents urllib3 from configuring SSL appropriately and may cause certain SSL connections to fail. For more information, see https://urllib3.readthedocs.org/en/latest/security.html#insecureplatformwarning.
InsecurePlatformWarning
id
4a305398-d806-46c5-a6aa-dcd6a4a99330
EOT
klass.expects(:auth_neutron).
with('subnet-list', '--format=csv', '--column=id', '--quote=none').
returns(output)
expected = ['4a305398-d806-46c5-a6aa-dcd6a4a99330']
result = klass.list_neutron_resources('subnet')
expect(result).to eql(expected)
end
end
end