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
This commit is contained in:
parent
bdb9ef6e3e
commit
99b3203923
@ -1,11 +1,45 @@
|
||||
require 'csv'
|
||||
require 'puppet/util/inifile'
|
||||
# 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) }
|
||||
|
||||
class Puppet::Provider::Neutron < Puppet::Provider
|
||||
require 'puppet/util/inifile'
|
||||
require 'puppet/provider/openstack'
|
||||
require 'puppet/provider/openstack/auth'
|
||||
require 'puppet/provider/openstack/credentials'
|
||||
require 'csv'
|
||||
|
||||
class Puppet::Provider::Neutron < Puppet::Provider::Openstack
|
||||
|
||||
extend Puppet::Provider::Openstack::Auth
|
||||
|
||||
initvars
|
||||
commands :neutron => 'neutron'
|
||||
|
||||
def self.request(service, action, properties=nil)
|
||||
begin
|
||||
super
|
||||
rescue Puppet::Error::OpenstackAuthInputError => error
|
||||
neutron_request(service, action, error, properties)
|
||||
end
|
||||
end
|
||||
|
||||
def self.neutron_request(service, action, error, properties=nil)
|
||||
properties ||= []
|
||||
@credentials.username = neutron_credentials['username']
|
||||
@credentials.password = neutron_credentials['password']
|
||||
@credentials.project_name = neutron_credentials['project_name']
|
||||
@credentials.auth_url = auth_endpoint
|
||||
if @credentials.version == '3'
|
||||
@credentials.user_domain_name = neutron_credentials['user_domain_name']
|
||||
@credentials.project_domain_name = neutron_credentials['project_domain_name']
|
||||
end
|
||||
if neutron_credentials['region_name']
|
||||
@credentials.region_name = neutron_credentials['region_name']
|
||||
end
|
||||
raise error unless @credentials.set?
|
||||
Puppet::Provider::Openstack.request(service, action, properties, @credentials)
|
||||
end
|
||||
|
||||
def self.conf_filename
|
||||
'/etc/neutron/neutron.conf'
|
||||
end
|
||||
@ -24,33 +58,6 @@ class Puppet::Provider::Neutron < Puppet::Provider
|
||||
end
|
||||
end
|
||||
|
||||
def self.neutron_credentials
|
||||
@neutron_credentials ||= get_neutron_credentials
|
||||
end
|
||||
|
||||
def self.get_neutron_credentials
|
||||
auth_keys = ['project_name', 'username', 'password', 'auth_url']
|
||||
conf = neutron_conf
|
||||
if conf and conf['keystone_authtoken'] and
|
||||
!conf['keystone_authtoken']['password'].nil? 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
|
||||
return creds
|
||||
else
|
||||
raise(Puppet::Error, "File: #{conf_filename} does not contain all \
|
||||
required sections. Neutron types will not work if neutron is not \
|
||||
correctly configured.")
|
||||
end
|
||||
end
|
||||
|
||||
def neutron_credentials
|
||||
self.class.neutron_credentials
|
||||
end
|
||||
|
||||
def self.neutron_conf
|
||||
return @neutron_conf if @neutron_conf
|
||||
@neutron_conf = Puppet::Util::IniConfig::File.new
|
||||
@ -58,10 +65,56 @@ correctly configured.")
|
||||
@neutron_conf
|
||||
end
|
||||
|
||||
def self.neutron_credentials
|
||||
@neutron_credentials ||= get_neutron_credentials
|
||||
end
|
||||
|
||||
def neutron_credentials
|
||||
self.class.neutron_credentials
|
||||
end
|
||||
|
||||
def self.get_neutron_credentials
|
||||
#needed keys for authentication
|
||||
auth_keys = ['auth_uri', 'project_name', 'username', 'password']
|
||||
conf = neutron_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['neutron'] and conf['neutron']['region_name']
|
||||
creds['region_name'] = conf['neutron']['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. Neutron types will not work if neutron is not " +
|
||||
"correctly configured.")
|
||||
end
|
||||
end
|
||||
|
||||
def self.get_auth_endpoint
|
||||
q = neutron_credentials
|
||||
"#{q['auth_uri']}"
|
||||
end
|
||||
|
||||
def self.auth_endpoint
|
||||
@auth_endpoint ||= get_auth_endpoint
|
||||
end
|
||||
|
||||
def self.auth_neutron(*args)
|
||||
q = neutron_credentials
|
||||
authenv = {
|
||||
:OS_AUTH_URL => q['auth_url'],
|
||||
:OS_AUTH_URL => self.auth_endpoint,
|
||||
:OS_USERNAME => q['username'],
|
||||
:OS_PROJECT_NAME => q['project_name'],
|
||||
:OS_PASSWORD => q['password']
|
||||
|
76
lib/puppet/provider/neutron_security_group/openstack.rb
Normal file
76
lib/puppet/provider/neutron_security_group/openstack.rb
Normal file
@ -0,0 +1,76 @@
|
||||
require File.join(File.dirname(__FILE__), '..','..','..',
|
||||
'puppet/provider/neutron')
|
||||
|
||||
Puppet::Type.type(:neutron_security_group).provide(
|
||||
:openstack,
|
||||
:parent => Puppet::Provider::Neutron
|
||||
) do
|
||||
desc <<-EOT
|
||||
Manage Neutron security group
|
||||
EOT
|
||||
|
||||
@credentials = Puppet::Provider::Openstack::CredentialsV3.new
|
||||
|
||||
def initialize(value={})
|
||||
super(value)
|
||||
end
|
||||
|
||||
def create
|
||||
opts = [@resource[:name]]
|
||||
(opts << '--id' << @resource[:id]) if @resource[:id]
|
||||
(opts << '--description' << @resource[:description]) if @resource[:description]
|
||||
(opts << '--project' << @resource[:project]) if @resource[:project]
|
||||
(opts << '--project-domain' << @resource[:project_domain]) if @resource[:project_domain]
|
||||
@property_hash = self.class.request('security group', 'create', opts)
|
||||
@property_hash[:ensure] = :present
|
||||
end
|
||||
|
||||
def exists?
|
||||
@property_hash[:ensure] == :present
|
||||
end
|
||||
|
||||
def destroy
|
||||
self.class.request('security group', 'delete', @property_hash[:id])
|
||||
end
|
||||
|
||||
mk_resource_methods
|
||||
|
||||
def id=(value)
|
||||
fail('id is read only')
|
||||
end
|
||||
|
||||
def description=(value)
|
||||
fail('description is read only')
|
||||
end
|
||||
|
||||
def project=(value)
|
||||
fail('project is read only')
|
||||
end
|
||||
|
||||
def project_domain=(value)
|
||||
fail('project_domain is read only')
|
||||
end
|
||||
|
||||
def self.instances
|
||||
request('security group', 'list', ['--all']).collect do |attrs|
|
||||
new(
|
||||
:ensure => :present,
|
||||
:name => attrs[:name],
|
||||
:id => attrs[:id],
|
||||
:description => attrs[:description],
|
||||
:project => attrs[:project],
|
||||
:project_domain => attrs[:project_domain]
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
def self.prefetch(resources)
|
||||
sec_groups = instances
|
||||
resources.keys.each do |name|
|
||||
if provider = sec_groups.find{ |sg| sg.name == name }
|
||||
resources[name].provider = provider
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
76
lib/puppet/type/neutron_security_group.rb
Normal file
76
lib/puppet/type/neutron_security_group.rb
Normal file
@ -0,0 +1,76 @@
|
||||
# neutron_security_group type
|
||||
#
|
||||
# == Parameters
|
||||
# [*name*]
|
||||
# Name for the security group
|
||||
# Required
|
||||
#
|
||||
# [*id*]
|
||||
# Unique ID (integer or UUID) for the security group.
|
||||
# Optional
|
||||
#
|
||||
# [*description*]
|
||||
# Description of the security group.
|
||||
# Optional
|
||||
#
|
||||
# [*project*]
|
||||
# Project of the security group.
|
||||
# Optional
|
||||
#
|
||||
# [*project_domain*]
|
||||
# Project domain of the security group.
|
||||
# Optional
|
||||
#
|
||||
require 'puppet'
|
||||
|
||||
Puppet::Type.newtype(:neutron_security_group) do
|
||||
|
||||
@doc = "Manage creation of neutron security group"
|
||||
|
||||
ensurable
|
||||
|
||||
autorequire(:neutron_config) do
|
||||
['auth_uri', 'project_name', 'username', 'password']
|
||||
end
|
||||
|
||||
# Require the neutron-server service to be running
|
||||
autorequire(:service) do
|
||||
['neutron-server']
|
||||
end
|
||||
|
||||
newparam(:name, :namevar => true) do
|
||||
desc 'Name for the security group'
|
||||
validate do |value|
|
||||
if not value.is_a? String
|
||||
raise ArgumentError, "name parameter must be a String"
|
||||
end
|
||||
unless value =~ /^[a-zA-Z0-9\-\._]+$/
|
||||
raise ArgumentError, "#{value} is not a valid name"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
newparam(:id) do
|
||||
desc 'Unique ID (integer or UUID) for the security group.'
|
||||
end
|
||||
|
||||
newparam(:description) do
|
||||
desc 'Description of the security group.'
|
||||
end
|
||||
|
||||
newparam(:project) do
|
||||
desc 'Project of the security group.'
|
||||
end
|
||||
|
||||
newparam(:project_domain) do
|
||||
desc 'Project domain of the security group.'
|
||||
end
|
||||
|
||||
validate do
|
||||
unless self[:name]
|
||||
raise(ArgumentError, 'Name must be set')
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -0,0 +1,5 @@
|
||||
---
|
||||
features:
|
||||
- Added Openstack Client for Neutron providers.
|
||||
It will help to add new provider classes for
|
||||
puppet Neutron module.
|
@ -78,6 +78,12 @@ describe 'basic neutron' do
|
||||
}
|
||||
class { '::neutron::services::lbaas::haproxy': }
|
||||
class { '::neutron::services::lbaas::octavia': }
|
||||
|
||||
# Create Neutron security group for admin tenant
|
||||
neutron_security_group { 'test':
|
||||
ensure => present,
|
||||
description => 'Test security group',
|
||||
}
|
||||
EOS
|
||||
|
||||
|
||||
|
71
spec/unit/provider/neutron_security_group/openstack_spec.rb
Normal file
71
spec/unit/provider/neutron_security_group/openstack_spec.rb
Normal file
@ -0,0 +1,71 @@
|
||||
require 'puppet'
|
||||
require 'spec_helper'
|
||||
require 'puppet/provider/neutron_security_group/openstack'
|
||||
|
||||
provider_class = Puppet::Type.type(:neutron_security_group).provider(:openstack)
|
||||
|
||||
describe provider_class do
|
||||
|
||||
let(:set_env) do
|
||||
ENV['OS_USERNAME'] = 'admin'
|
||||
ENV['OS_PASSWORD'] = 'password'
|
||||
ENV['OS_PROJECT_NAME'] = 'admin_tenant'
|
||||
ENV['OS_AUTH_URL'] = 'https://192.168.56.210:35357/v2.0/'
|
||||
end
|
||||
|
||||
before(:each) do
|
||||
set_env
|
||||
end
|
||||
|
||||
describe 'managing security group' do
|
||||
let(:sec_group_attrs) do
|
||||
{
|
||||
:name => 'example',
|
||||
:id => '593db854-a47d-411e-a894-66bf90959768',
|
||||
:description => 'test',
|
||||
:project => '1a2b3c',
|
||||
:project_domain => 'Default',
|
||||
:ensure => 'present',
|
||||
}
|
||||
end
|
||||
|
||||
let :resource do
|
||||
Puppet::Type::Neutron_security_group.new(sec_group_attrs)
|
||||
end
|
||||
|
||||
let(:provider) do
|
||||
provider_class.new(resource)
|
||||
end
|
||||
|
||||
describe '#create' do
|
||||
it 'creates security group' do
|
||||
provider.class.stubs(:openstack)
|
||||
.with('security group', 'list', ['--all'])
|
||||
.returns('"ID", "Name", "Description", "Project"')
|
||||
provider.class.stubs(:openstack)
|
||||
.with('security group', 'create', 'shell', ['example', 'description', 'test', 'project', '1a2b3c', 'project_domain', 'Default'])
|
||||
.returns('created_at="2017-03-15T09:32:03Z"
|
||||
description="test"
|
||||
headers=""
|
||||
id="593db854-a47d-411e-a894-66bf90959768"
|
||||
name="example"
|
||||
project_id="1a2b3c"
|
||||
project_id="1a2b3c"
|
||||
revision_number="1"
|
||||
rules="created_at=\'2017-03-15T09:32:03Z\', direction=\'egress\', ethertype=\'IPv4\', id=\'cf462eac-821e-4583-8e91-3294d5be5cce\', project_id=\'1a2b3c\', revision_number=\'1\', updated_at=\'2017-03-15T09:32:03Z\'
|
||||
created_at=\'2017-03-15T09:32:03Z\', direction=\'egress\', ethertype=\'IPv6\', id=\'afac00e8-4fec-4a1e-8faa-43e2278a0d79\', project_id=\'1a2b3c\', revision_number=\'1\', updated_at=\'2017-03-15T09:32:03Z\'"
|
||||
updated_at="2017-03-15T09:32:03Z"')
|
||||
end
|
||||
end
|
||||
|
||||
describe '#destroy' do
|
||||
it 'removes security group' do
|
||||
provider_class.expects(:openstack)
|
||||
.with('security group', 'delete', '593db854-a47d-411e-a894-66bf90959768')
|
||||
provider.instance_variable_set(:@property_hash, sec_group_attrs)
|
||||
provider.destroy
|
||||
expect(provider.exists?).to be_falsey
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
@ -14,7 +14,7 @@ describe Puppet::Provider::Neutron do
|
||||
'project_name' => 'admin_tenant',
|
||||
'username' => 'admin',
|
||||
'password' => 'password',
|
||||
'auth_url' => 'https://192.168.56.210:35357'
|
||||
'auth_uri' => 'https://192.168.56.210:35357/v2.0/',
|
||||
}
|
||||
end
|
||||
|
||||
@ -56,13 +56,14 @@ describe Puppet::Provider::Neutron do
|
||||
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_url'],
|
||||
:OS_AUTH_URL => credential_hash['auth_uri'],
|
||||
:OS_USERNAME => credential_hash['username'],
|
||||
:OS_PROJECT_NAME => credential_hash['project_name'],
|
||||
:OS_PASSWORD => credential_hash['password'],
|
||||
@ -74,7 +75,7 @@ describe Puppet::Provider::Neutron do
|
||||
|
||||
it 'should set region in the environment if needed' do
|
||||
authenv = {
|
||||
:OS_AUTH_URL => credential_hash['auth_url'],
|
||||
:OS_AUTH_URL => credential_hash['auth_uri'],
|
||||
:OS_USERNAME => credential_hash['username'],
|
||||
:OS_PROJECT_NAME => credential_hash['project_name'],
|
||||
:OS_PASSWORD => credential_hash['password'],
|
||||
|
Loading…
Reference in New Issue
Block a user