Merge "Use openstack cli to manage neutron routers"
This commit is contained in:
commit
fb68425dce
|
@ -13,7 +13,6 @@ class Puppet::Provider::Neutron < Puppet::Provider::Openstack
|
||||||
extend Puppet::Provider::Openstack::Auth
|
extend Puppet::Provider::Openstack::Auth
|
||||||
|
|
||||||
initvars
|
initvars
|
||||||
commands :neutron => 'neutron'
|
|
||||||
|
|
||||||
def self.request(service, action, properties=nil)
|
def self.request(service, action, properties=nil)
|
||||||
begin
|
begin
|
||||||
|
@ -42,20 +41,6 @@ class Puppet::Provider::Neutron < Puppet::Provider::Openstack
|
||||||
'/etc/neutron/neutron.conf'
|
'/etc/neutron/neutron.conf'
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.withenv(hash, &block)
|
|
||||||
saved = ENV.to_hash
|
|
||||||
hash.each do |name, val|
|
|
||||||
ENV[name.to_s] = val
|
|
||||||
end
|
|
||||||
|
|
||||||
yield
|
|
||||||
ensure
|
|
||||||
ENV.clear
|
|
||||||
saved.each do |name, val|
|
|
||||||
ENV[name] = val
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.neutron_conf
|
def self.neutron_conf
|
||||||
return @neutron_conf if @neutron_conf
|
return @neutron_conf if @neutron_conf
|
||||||
@neutron_conf = Puppet::Util::IniConfig::File.new
|
@neutron_conf = Puppet::Util::IniConfig::File.new
|
||||||
|
@ -113,58 +98,6 @@ class Puppet::Provider::Neutron < Puppet::Provider::Openstack
|
||||||
@auth_endpoint ||= get_auth_endpoint
|
@auth_endpoint ||= get_auth_endpoint
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.auth_neutron(*args)
|
|
||||||
q = neutron_credentials
|
|
||||||
authenv = {
|
|
||||||
:OS_AUTH_URL => self.auth_endpoint,
|
|
||||||
:OS_USERNAME => q['username'],
|
|
||||||
:OS_PROJECT_NAME => q['project_name'],
|
|
||||||
:OS_PASSWORD => q['password'],
|
|
||||||
:OS_PROJECT_DOMAIN_NAME => q['project_domain_name'],
|
|
||||||
:OS_USER_DOMAIN_NAME => q['user_domain_name']
|
|
||||||
}
|
|
||||||
if q.key?('region_name')
|
|
||||||
authenv[:OS_REGION_NAME] = q['region_name']
|
|
||||||
end
|
|
||||||
rv = nil
|
|
||||||
timeout = 10
|
|
||||||
end_time = Time.now.to_i + timeout
|
|
||||||
loop do
|
|
||||||
begin
|
|
||||||
withenv authenv do
|
|
||||||
rv = neutron(args)
|
|
||||||
end
|
|
||||||
break
|
|
||||||
rescue Puppet::ExecutionFailure => e
|
|
||||||
if ! e.message =~ /(\(HTTP\s+400\))|
|
|
||||||
(400-\{\'message\'\:\s+\'\'\})|
|
|
||||||
(\[Errno 111\]\s+Connection\s+refused)|
|
|
||||||
(503\s+Service\s+Unavailable)|
|
|
||||||
(504\s+Gateway\s+Time-out)|
|
|
||||||
(\:\s+Maximum\s+attempts\s+reached)|
|
|
||||||
(Unauthorized\:\s+bad\s+credentials)|
|
|
||||||
(Max\s+retries\s+exceeded)/
|
|
||||||
raise(e)
|
|
||||||
end
|
|
||||||
current_time = Time.now.to_i
|
|
||||||
if current_time > end_time
|
|
||||||
break
|
|
||||||
else
|
|
||||||
wait = end_time - current_time
|
|
||||||
notice("Unable to complete neutron request due to non-fatal error: \"#{e.message}\". Retrying for #{wait} sec.")
|
|
||||||
end
|
|
||||||
sleep(2)
|
|
||||||
# Note(xarses): Don't remove, we know that there is one of the
|
|
||||||
# Recoverable erros above, So we will retry a few more times
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return rv
|
|
||||||
end
|
|
||||||
|
|
||||||
def auth_neutron(*args)
|
|
||||||
self.class.auth_neutron(args)
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.reset
|
def self.reset
|
||||||
@neutron_conf = nil
|
@neutron_conf = nil
|
||||||
@neutron_credentials = nil
|
@neutron_credentials = nil
|
||||||
|
@ -194,82 +127,12 @@ class Puppet::Provider::Neutron < Puppet::Provider::Openstack
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.list_neutron_resources(type)
|
def self.parse_availability_zone_hint(value)
|
||||||
ids = []
|
hints = JSON.parse(value.gsub(/\\"/,'"').gsub('u\'', '"').gsub('\'','"'))
|
||||||
list = cleanup_csv_with_id(auth_neutron("#{type}-list", '--format=csv',
|
if hints.length > 1
|
||||||
'--column=id', '--quote=none'))
|
hints
|
||||||
if list.nil?
|
|
||||||
raise(Puppet::ExecutionFailure, "Can't retrieve #{type}-list because Neutron or Keystone API is not available.")
|
|
||||||
end
|
|
||||||
|
|
||||||
(list.split("\n")[1..-1] || []).compact.collect do |line|
|
|
||||||
ids << line.strip
|
|
||||||
end
|
|
||||||
return ids
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.get_neutron_resource_attrs(type, id)
|
|
||||||
attrs = {}
|
|
||||||
net = auth_neutron("#{type}-show", '--format=shell', id)
|
|
||||||
if net.nil?
|
|
||||||
raise(Puppet::ExecutionFailure, "Can't retrieve #{type}-show because Neutron or Keystone API is not available.")
|
|
||||||
end
|
|
||||||
|
|
||||||
last_key = nil
|
|
||||||
(net.split("\n") || []).compact.collect do |line|
|
|
||||||
if line.include? '='
|
|
||||||
k, v = line.split('=', 2)
|
|
||||||
attrs[k] = v.gsub(/\A"|"\Z/, '')
|
|
||||||
last_key = k
|
|
||||||
else
|
|
||||||
# Handle the case of a list of values
|
|
||||||
v = line.gsub(/\A"|"\Z/, '')
|
|
||||||
attrs[last_key] = [attrs[last_key], v].flatten
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return attrs
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.get_tenant_id(catalog, name, domain='Default')
|
|
||||||
instance_type = 'keystone_tenant'
|
|
||||||
instance = catalog.resource("#{instance_type.capitalize!}[#{name}]")
|
|
||||||
if ! instance
|
|
||||||
instance = Puppet::Type.type(instance_type).instances.find do |i|
|
|
||||||
# We need to check against the Default domain name because of
|
|
||||||
# https://review.opendev.org/#/c/226919/ which changed the naming
|
|
||||||
# format for the tenant to include <Domain name>. This should be
|
|
||||||
# removed when we drop the resource without a domain name.
|
|
||||||
# TODO(aschultz): remove ::domain lookup as part of M-cycle
|
|
||||||
i.provider.name == name || i.provider.name == "#{name}::#{domain}"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if instance
|
|
||||||
return instance.provider.id
|
|
||||||
else
|
else
|
||||||
fail("Unable to find #{instance_type} for name #{name}")
|
hints.first
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.parse_creation_output(data)
|
|
||||||
hash = {}
|
|
||||||
data.split("\n").compact.each do |line|
|
|
||||||
if line.include? '='
|
|
||||||
hash[line.split('=').first] = line.split('=', 2)[1].gsub(/\A"|"\Z/, '')
|
|
||||||
end
|
|
||||||
end
|
|
||||||
hash
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.cleanup_csv(text)
|
|
||||||
# Ignore warnings - assume legitimate output starts with a double quoted
|
|
||||||
# string. Errors will be caught and raised prior to this
|
|
||||||
text = text.split("\n").drop_while { |line| line !~ /^\".*\"/ }.join("\n")
|
|
||||||
"#{text}\n"
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.cleanup_csv_with_id(text)
|
|
||||||
return nil if text.nil?
|
|
||||||
text = text.split("\n").drop_while { |line| line !~ /^\s*id$/ }.join("\n")
|
|
||||||
"#{text}\n"
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -167,15 +167,6 @@ Puppet::Type.type(:neutron_network).provide(
|
||||||
@property_hash[:ensure] = :absent
|
@property_hash[:ensure] = :absent
|
||||||
end
|
end
|
||||||
|
|
||||||
def self.parse_availability_zone_hint(value)
|
|
||||||
hints = JSON.parse(value.gsub(/\\"/,'"').gsub('u\'', '"').gsub('\'','"'))
|
|
||||||
if hints.length > 1
|
|
||||||
hints
|
|
||||||
else
|
|
||||||
hints.first
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
[
|
[
|
||||||
:admin_state_up,
|
:admin_state_up,
|
||||||
:shared,
|
:shared,
|
||||||
|
|
|
@ -1,207 +0,0 @@
|
||||||
require File.join(File.dirname(__FILE__), '..','..','..',
|
|
||||||
'puppet/provider/neutron')
|
|
||||||
|
|
||||||
Puppet::Type.type(:neutron_router).provide(
|
|
||||||
:neutron,
|
|
||||||
:parent => Puppet::Provider::Neutron
|
|
||||||
) do
|
|
||||||
desc <<-EOT
|
|
||||||
Neutron provider to manage neutron_router type.
|
|
||||||
|
|
||||||
Assumes that the neutron service is configured on the same host.
|
|
||||||
EOT
|
|
||||||
|
|
||||||
mk_resource_methods
|
|
||||||
|
|
||||||
def self.do_not_manage
|
|
||||||
@do_not_manage
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.do_not_manage=(value)
|
|
||||||
@do_not_manage = value
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.instances
|
|
||||||
self.do_not_manage = true
|
|
||||||
list = list_neutron_resources('router').collect do |id|
|
|
||||||
attrs = get_neutron_resource_attrs('router', id)
|
|
||||||
new(
|
|
||||||
:ensure => :present,
|
|
||||||
:name => attrs['name'],
|
|
||||||
:id => attrs['id'],
|
|
||||||
:admin_state_up => attrs['admin_state_up'],
|
|
||||||
:external_gateway_info => attrs['external_gateway_info'],
|
|
||||||
:status => attrs['status'],
|
|
||||||
:distributed => attrs['distributed'],
|
|
||||||
:ha => attrs['ha'],
|
|
||||||
:tenant_id => attrs['tenant_id'],
|
|
||||||
:availability_zone_hint => attrs['availability_zone_hint']
|
|
||||||
)
|
|
||||||
end
|
|
||||||
self.do_not_manage = false
|
|
||||||
list
|
|
||||||
end
|
|
||||||
|
|
||||||
def self.prefetch(resources)
|
|
||||||
instances_ = instances
|
|
||||||
resources.keys.each do |name|
|
|
||||||
if provider = instances_.find{ |instance| instance.name == name }
|
|
||||||
resources[name].provider = provider
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def exists?
|
|
||||||
@property_hash[:ensure] == :present
|
|
||||||
end
|
|
||||||
|
|
||||||
def create
|
|
||||||
if self.class.do_not_manage
|
|
||||||
fail("Not managing Neutron_router[#{@resource[:name]}] due to earlier Neutron API failures.")
|
|
||||||
end
|
|
||||||
|
|
||||||
opts = Array.new
|
|
||||||
|
|
||||||
if @resource[:admin_state_up] == 'False'
|
|
||||||
opts << '--admin-state-down'
|
|
||||||
end
|
|
||||||
|
|
||||||
if @resource[:tenant_name]
|
|
||||||
tenant_id = self.class.get_tenant_id(@resource.catalog,
|
|
||||||
@resource[:tenant_name])
|
|
||||||
opts << "--tenant_id=#{tenant_id}"
|
|
||||||
elsif @resource[:tenant_id]
|
|
||||||
opts << "--tenant_id=#{@resource[:tenant_id]}"
|
|
||||||
end
|
|
||||||
|
|
||||||
if @resource[:distributed]
|
|
||||||
opts << "--distributed=#{@resource[:distributed]}"
|
|
||||||
end
|
|
||||||
|
|
||||||
if @resource[:ha]
|
|
||||||
opts << "--ha=#{@resource[:ha]}"
|
|
||||||
end
|
|
||||||
|
|
||||||
if @resource[:availability_zone_hint]
|
|
||||||
opts << "--availability-zone-hint=#{@resource[:availability_zone_hint]}"
|
|
||||||
end
|
|
||||||
|
|
||||||
results = auth_neutron("router-create", '--format=shell',
|
|
||||||
opts, resource[:name])
|
|
||||||
|
|
||||||
attrs = self.class.parse_creation_output(results)
|
|
||||||
@property_hash = {
|
|
||||||
:ensure => :present,
|
|
||||||
:name => resource[:name],
|
|
||||||
:id => attrs['id'],
|
|
||||||
:admin_state_up => attrs['admin_state_up'],
|
|
||||||
:external_gateway_info => attrs['external_gateway_info'],
|
|
||||||
:status => attrs['status'],
|
|
||||||
:tenant_id => attrs['tenant_id'],
|
|
||||||
:availability_zone_hint => attrs['availability_zone_hint']
|
|
||||||
}
|
|
||||||
|
|
||||||
if @resource[:gateway_network_name]
|
|
||||||
results = auth_neutron('router-gateway-set',
|
|
||||||
@resource[:name],
|
|
||||||
@resource[:gateway_network_name])
|
|
||||||
attrs = self.class.get_neutron_resource_attrs('router',
|
|
||||||
@resource[:name])
|
|
||||||
@property_hash[:external_gateway_info] = \
|
|
||||||
attrs['external_gateway_info']
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def destroy
|
|
||||||
if self.class.do_not_manage
|
|
||||||
fail("Not managing Neutron_router[#{@resource[:name]}] due to earlier Neutron API failures.")
|
|
||||||
end
|
|
||||||
auth_neutron('router-delete', name)
|
|
||||||
@property_hash[:ensure] = :absent
|
|
||||||
end
|
|
||||||
|
|
||||||
def gateway_network_name
|
|
||||||
if @gateway_network_name == nil and gateway_network_id
|
|
||||||
Puppet::Type.type('neutron_network').instances.each do |instance|
|
|
||||||
if instance.provider.id == gateway_network_id
|
|
||||||
@gateway_network_name = instance.provider.name
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
@gateway_network_name
|
|
||||||
end
|
|
||||||
|
|
||||||
def gateway_network_name=(value)
|
|
||||||
if self.class.do_not_manage
|
|
||||||
fail("Not managing Neutron_router[#{@resource[:name]}] due to earlier Neutron API failures.")
|
|
||||||
end
|
|
||||||
if value == ''
|
|
||||||
auth_neutron('router-gateway-clear', name)
|
|
||||||
else
|
|
||||||
auth_neutron('router-gateway-set', name, value)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def parse_gateway_network_id(external_gateway_info_)
|
|
||||||
match_data = /\{"network_id": "(.*?)"/.match(external_gateway_info_.gsub(/\\"/,'"'))
|
|
||||||
if match_data
|
|
||||||
match_data[1]
|
|
||||||
else
|
|
||||||
''
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def gateway_network_id
|
|
||||||
@gateway_network_id ||= parse_gateway_network_id(external_gateway_info)
|
|
||||||
end
|
|
||||||
|
|
||||||
def admin_state_up=(value)
|
|
||||||
if self.class.do_not_manage
|
|
||||||
fail("Not managing Neutron_router[#{@resource[:name]}] due to earlier Neutron API failures.")
|
|
||||||
end
|
|
||||||
set_admin_state_up(value)
|
|
||||||
end
|
|
||||||
|
|
||||||
def set_admin_state_up(value)
|
|
||||||
auth_neutron('router-update', "--admin-state-up=#{value}", name)
|
|
||||||
end
|
|
||||||
|
|
||||||
def distributed=(value)
|
|
||||||
if self.class.do_not_manage
|
|
||||||
fail("Not managing Neutron_router[#{@resource[:name]}] due to earlier Neutron API failures.")
|
|
||||||
end
|
|
||||||
results = auth_neutron("router-show", '--format=shell', resource[:name])
|
|
||||||
attrs = self.class.parse_creation_output(results)
|
|
||||||
set_admin_state_up(false)
|
|
||||||
auth_neutron('router-update', "--distributed=#{value}", name)
|
|
||||||
if attrs['admin_state_up'] == 'True'
|
|
||||||
set_admin_state_up(true)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def ha=(value)
|
|
||||||
if self.class.do_not_manage
|
|
||||||
fail("Not managing Neutron_router[#{@resource[:name]}] due to earlier Neutron API failures.")
|
|
||||||
end
|
|
||||||
results = auth_neutron("router-show", '--format=shell', resource[:name])
|
|
||||||
attrs = self.class.parse_creation_output(results)
|
|
||||||
set_admin_state_up(false)
|
|
||||||
auth_neutron('router-update', "--ha=#{value}", name)
|
|
||||||
if attrs['admin_state_up'] == 'True'
|
|
||||||
set_admin_state_up(true)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
def availability_zone_hint=(value)
|
|
||||||
if self.class.do_not_manage
|
|
||||||
fail("Not managing Neutron_router[#{@resource[:name]}] due to earlier Neutron API failures.")
|
|
||||||
end
|
|
||||||
results = auth_neutron("router-show", '--format=shell', resource[:name])
|
|
||||||
attrs = self.class.parse_creation_output(results)
|
|
||||||
set_admin_state_up(false)
|
|
||||||
auth_neutron('router-update', "--availability-zone-hint=#{value}", name)
|
|
||||||
if attrs['admin_state_up'] == 'True'
|
|
||||||
set_admin_state_up(true)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
|
@ -0,0 +1,218 @@
|
||||||
|
require File.join(File.dirname(__FILE__), '..','..','..',
|
||||||
|
'puppet/provider/neutron')
|
||||||
|
|
||||||
|
Puppet::Type.type(:neutron_router).provide(
|
||||||
|
:openstack,
|
||||||
|
:parent => Puppet::Provider::Neutron
|
||||||
|
) do
|
||||||
|
desc <<-EOT
|
||||||
|
Neutron provider to manage neutron_router type.
|
||||||
|
|
||||||
|
Assumes that the neutron service is configured on the same host.
|
||||||
|
EOT
|
||||||
|
|
||||||
|
@credentials = Puppet::Provider::Openstack::CredentialsV3.new
|
||||||
|
|
||||||
|
mk_resource_methods
|
||||||
|
|
||||||
|
def initialize(value={})
|
||||||
|
super(value)
|
||||||
|
@property_flush = {}
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.do_not_manage
|
||||||
|
@do_not_manage
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.do_not_manage=(value)
|
||||||
|
@do_not_manage = value
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.instances
|
||||||
|
self.do_not_manage = true
|
||||||
|
list = request('router', 'list').collect do |attrs|
|
||||||
|
router = request('router', 'show', attrs[:id])
|
||||||
|
new(
|
||||||
|
:ensure => :present,
|
||||||
|
:name => attrs[:name],
|
||||||
|
:id => attrs[:id],
|
||||||
|
:admin_state_up => router[:admin_state_up],
|
||||||
|
:external_gateway_info => router[:external_gateway_info],
|
||||||
|
:status => router[:status],
|
||||||
|
:distributed => router[:distributed],
|
||||||
|
:ha => router[:ha],
|
||||||
|
:tenant_id => router[:tenant_id],
|
||||||
|
:availability_zone_hint => parse_availability_zone_hint(router[:availability_zone_hints])
|
||||||
|
)
|
||||||
|
end
|
||||||
|
self.do_not_manage = false
|
||||||
|
list
|
||||||
|
end
|
||||||
|
|
||||||
|
def self.prefetch(resources)
|
||||||
|
routers = instances
|
||||||
|
resources.keys.each do |name|
|
||||||
|
if provider = routers.find{ |router| router.name == name }
|
||||||
|
resources[name].provider = provider
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def exists?
|
||||||
|
@property_hash[:ensure] == :present
|
||||||
|
end
|
||||||
|
|
||||||
|
def create
|
||||||
|
if self.class.do_not_manage
|
||||||
|
fail("Not managing Neutron_router[#{@resource[:name]}] due to earlier Neutron API failures.")
|
||||||
|
end
|
||||||
|
|
||||||
|
opts = [@resource[:name]]
|
||||||
|
|
||||||
|
if @resource[:admin_state_up] == 'False'
|
||||||
|
opts << '--disable'
|
||||||
|
end
|
||||||
|
|
||||||
|
if @resource[:tenant_name]
|
||||||
|
opts << "--project=#{@resource[:tenant_name]}"
|
||||||
|
elsif @resource[:tenant_id]
|
||||||
|
opts << "--project=#{@resource[:tenant_id]}"
|
||||||
|
end
|
||||||
|
|
||||||
|
if @resource[:distributed]
|
||||||
|
if @resource[:distributed] == 'False'
|
||||||
|
opts << '--centralized'
|
||||||
|
else
|
||||||
|
opts << '--distributed'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if @resource[:ha]
|
||||||
|
if @resource[:ha] == 'False'
|
||||||
|
opts << '--no-ha'
|
||||||
|
else
|
||||||
|
opts << '--ha'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if @resource[:availability_zone_hint]
|
||||||
|
opts << \
|
||||||
|
"--availability-zone-hint=#{@resource[:availability_zone_hint]}"
|
||||||
|
end
|
||||||
|
|
||||||
|
router = self.class.request('router', 'create', opts)
|
||||||
|
|
||||||
|
if @resource[:gateway_network_id]
|
||||||
|
self.class.request('router', 'set',
|
||||||
|
[@resource[:name],
|
||||||
|
"--external-gateway=#{@resource[:gateway_network_id]}"])
|
||||||
|
router = self.class.request('router', 'show', [@resource[:name]])
|
||||||
|
elsif @resource[:gateway_network_name]
|
||||||
|
self.class.request('router', 'set',
|
||||||
|
[@resource[:name],
|
||||||
|
"--external-gateway=#{@resource[:gateway_network_name]}"])
|
||||||
|
router = self.class.request('router', 'show', [@resource[:name]])
|
||||||
|
end
|
||||||
|
|
||||||
|
@property_hash = {
|
||||||
|
:ensure => :present,
|
||||||
|
:name => router[:name],
|
||||||
|
:id => router[:id],
|
||||||
|
:admin_state_up => router[:admin_state_up],
|
||||||
|
:external_gateway_info => router[:external_gateway_info],
|
||||||
|
:status => router[:status],
|
||||||
|
:distributed => router[:distributed],
|
||||||
|
:ha => router[:ha],
|
||||||
|
:tenant_id => router[:tenant_id],
|
||||||
|
:availability_zone_hint => self.class.parse_availability_zone_hint(router[:availability_zone_hints])
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
def flush
|
||||||
|
if !@property_flush.empty?
|
||||||
|
opts = [@resource[:name]]
|
||||||
|
clear_opts = [@resource[:name]]
|
||||||
|
|
||||||
|
if @property_flush.has_key?(:admin_state_up)
|
||||||
|
if @property_flush[:admin_state_up] == 'False'
|
||||||
|
opts << '--disable'
|
||||||
|
else
|
||||||
|
opts << '--enable'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if @property_flush.has_key?(:distributed)
|
||||||
|
if @property_flush[:distributed] == 'False'
|
||||||
|
opts << '--centralized'
|
||||||
|
else
|
||||||
|
opts << '--distributed'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if @property_flush.has_key?(:gateway_network_id)
|
||||||
|
if @property_flush[:gateway_network_id] == ''
|
||||||
|
clear_opts << '--external-gateway'
|
||||||
|
else
|
||||||
|
opts << "--external-gateway=#{@property_flush[:gateway_network_id]}"
|
||||||
|
end
|
||||||
|
elsif @property_flush.has_key?(:gateway_network_name)
|
||||||
|
if @property_flush[:gateway_network_name] == ''
|
||||||
|
clear_opts << '--external-gateway'
|
||||||
|
else
|
||||||
|
opts << "--external-gateway=#{@property_flush[:gateway_network_name]}"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if @property_flush.has_key?(:ha)
|
||||||
|
if @property_flush[:ha] == 'False'
|
||||||
|
opts << '--no-ha'
|
||||||
|
else
|
||||||
|
opts << '--ha'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if clear_opts.length > 1
|
||||||
|
self.class.request('router', 'unset', clear_opts)
|
||||||
|
end
|
||||||
|
if opts.length > 1
|
||||||
|
self.class.request('router', 'set', opts)
|
||||||
|
end
|
||||||
|
@property_flush.clear
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
if self.class.do_not_manage
|
||||||
|
fail("Not managing Neutron_router[#{@resource[:name]}] due to earlier Neutron API failures.")
|
||||||
|
end
|
||||||
|
self.class.request('router', 'delete', @resource[:name])
|
||||||
|
@property_flush.clear
|
||||||
|
@property_flush[:ensure] = :absent
|
||||||
|
end
|
||||||
|
|
||||||
|
[
|
||||||
|
:admin_state_up,
|
||||||
|
:gateway_network_id,
|
||||||
|
:gateway_network_name,
|
||||||
|
:distributed,
|
||||||
|
:ha,
|
||||||
|
].each do |attr|
|
||||||
|
define_method(attr.to_s + "=") do |value|
|
||||||
|
if self.class.do_not_manage
|
||||||
|
fail("Not managing Neutron_router[#{@resource[:name]}] due to earlier Neutron API failures.")
|
||||||
|
end
|
||||||
|
@property_flush[attr] = value
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
[
|
||||||
|
:availability_zone_hint,
|
||||||
|
:tenant_id,
|
||||||
|
:tenant_name,
|
||||||
|
].each do |attr|
|
||||||
|
define_method(attr.to_s + "=") do |value|
|
||||||
|
fail("Property #{attr.to_s} does not support being updated")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -1,114 +0,0 @@
|
||||||
require 'puppet'
|
|
||||||
require 'spec_helper'
|
|
||||||
require 'puppet/provider/neutron_router/neutron'
|
|
||||||
|
|
||||||
provider_class = Puppet::Type.type(:neutron_router).provider(:neutron)
|
|
||||||
klass = Puppet::Provider::Neutron
|
|
||||||
|
|
||||||
describe provider_class do
|
|
||||||
|
|
||||||
let :router_name do
|
|
||||||
'router1'
|
|
||||||
end
|
|
||||||
|
|
||||||
let :router_attrs do
|
|
||||||
{
|
|
||||||
:name => router_name,
|
|
||||||
:ensure => 'present',
|
|
||||||
:admin_state_up => 'True',
|
|
||||||
:distributed => 'True',
|
|
||||||
:ha => 'False',
|
|
||||||
:tenant_id => '60f9544eb94c42a6b7e8e98c2be981b1',
|
|
||||||
:availability_zone_hint => 'zone1',
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
let :resource do
|
|
||||||
Puppet::Type::Neutron_router.new(router_attrs)
|
|
||||||
end
|
|
||||||
|
|
||||||
let :provider do
|
|
||||||
provider_class.new(resource)
|
|
||||||
end
|
|
||||||
|
|
||||||
describe 'when creating a router' do
|
|
||||||
|
|
||||||
it 'should call router-create with appropriate command line options' do
|
|
||||||
provider.class.stubs(:get_tenant_id).returns(router_attrs[:tenant_id])
|
|
||||||
|
|
||||||
output = 'Created a new router:
|
|
||||||
admin_state_up="True"
|
|
||||||
external_gateway_info=""
|
|
||||||
id="c5f799fa-b3e0-47ca-bdb7-abeff209b816"
|
|
||||||
name="router1"
|
|
||||||
status="ACTIVE"
|
|
||||||
distributed="True"
|
|
||||||
ha="False"
|
|
||||||
tenant_id="60f9544eb94c42a6b7e8e98c2be981b1"
|
|
||||||
availability-zone-hint="zone1"'
|
|
||||||
|
|
||||||
provider.expects(:auth_neutron).with('router-create',
|
|
||||||
'--format=shell', ["--tenant_id=#{router_attrs[:tenant_id]}",
|
|
||||||
"--distributed=#{router_attrs[:distributed]}",
|
|
||||||
"--ha=#{router_attrs[:ha]}",
|
|
||||||
"--availability-zone-hint=#{router_attrs[:availability_zone_hint]}"],
|
|
||||||
router_name).returns(output)
|
|
||||||
|
|
||||||
provider.create
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
describe 'when updating a router' do
|
|
||||||
|
|
||||||
it 'should call router-update to change admin_state_up' do
|
|
||||||
provider.expects(:auth_neutron).with('router-update',
|
|
||||||
'--admin-state-up=False',
|
|
||||||
router_name)
|
|
||||||
provider.admin_state_up=('False')
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'should call router-gateway-clear for an empty network name' do
|
|
||||||
provider.expects(:auth_neutron).with('router-gateway-clear',
|
|
||||||
router_name)
|
|
||||||
provider.gateway_network_name=('')
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'should call router-gateway-set to configure an external network' do
|
|
||||||
provider.expects(:auth_neutron).with('router-gateway-set',
|
|
||||||
router_name,
|
|
||||||
'net1')
|
|
||||||
provider.gateway_network_name=('net1')
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
describe 'when parsing an external gateway info' do
|
|
||||||
let :resource do
|
|
||||||
Puppet::Type::Neutron_router.new(router_attrs)
|
|
||||||
end
|
|
||||||
|
|
||||||
let :provider do
|
|
||||||
provider_class.new(resource)
|
|
||||||
end
|
|
||||||
|
|
||||||
after :each do
|
|
||||||
klass.reset
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'should detect a gateway net id' do
|
|
||||||
klass.stubs(:auth_neutron).returns(
|
|
||||||
'external_gateway_info="{\"network_id\": \"1b-b1\", \"enable_snat\": true, \"external_fixed_ips\": [{\"subnet_id\": \"1b-b1\", \"ip_address\": \"1.1.1.1\"}]}"'
|
|
||||||
)
|
|
||||||
result = klass.get_neutron_resource_attrs 'foo', nil
|
|
||||||
expect(provider.parse_gateway_network_id(result['external_gateway_info'])).to eql('1b-b1')
|
|
||||||
end
|
|
||||||
|
|
||||||
it 'should return empty value, if there is no net id found' do
|
|
||||||
klass.stubs(:auth_neutron).returns('external_gateway_info="{}"')
|
|
||||||
result = klass.get_neutron_resource_attrs 'foo', nil
|
|
||||||
expect(provider.parse_gateway_network_id(result['external_gateway_info'])).to eql('')
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
|
@ -0,0 +1,352 @@
|
||||||
|
require 'puppet'
|
||||||
|
require 'spec_helper'
|
||||||
|
require 'puppet/provider/neutron_router/openstack'
|
||||||
|
|
||||||
|
provider_class = Puppet::Type.type(:neutron_router).provider(:openstack)
|
||||||
|
|
||||||
|
describe provider_class do
|
||||||
|
|
||||||
|
let(:set_env) do
|
||||||
|
ENV['OS_USERNAME'] = 'test'
|
||||||
|
ENV['OS_PASSWORD'] = 'abc123'
|
||||||
|
ENV['OS_PROJECT_NAME'] = 'test'
|
||||||
|
ENV['OS_AUTH_URL'] = 'http://127.0.0.1:5000'
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'manage routers' do
|
||||||
|
let :router_name do
|
||||||
|
'router1'
|
||||||
|
end
|
||||||
|
|
||||||
|
let :router_attrs do
|
||||||
|
{
|
||||||
|
:name => router_name,
|
||||||
|
:ensure => 'present',
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
let :resource do
|
||||||
|
Puppet::Type::Neutron_router.new(router_attrs)
|
||||||
|
end
|
||||||
|
|
||||||
|
let :provider do
|
||||||
|
provider_class.new(resource)
|
||||||
|
end
|
||||||
|
|
||||||
|
before :each do
|
||||||
|
set_env
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#create' do
|
||||||
|
context 'with defaults' do
|
||||||
|
it 'creates router' do
|
||||||
|
provider_class.expects(:openstack)
|
||||||
|
.with('router', 'create', '--format', 'shell',
|
||||||
|
['router1'])
|
||||||
|
.returns('admin_state_up="True"
|
||||||
|
availability_zone_hints="[]"
|
||||||
|
distributed="False"
|
||||||
|
external_gateway_info="None"
|
||||||
|
ha="True"
|
||||||
|
id="d73f453a-77ca-4843-977a-3af0fda8dfcb"
|
||||||
|
name="router1"
|
||||||
|
project_id="60f9544eb94c42a6b7e8e98c2be981b1"
|
||||||
|
project_id="60f9544eb94c42a6b7e8e98c2be981b1"
|
||||||
|
status="ACTIVE"')
|
||||||
|
provider.create
|
||||||
|
expect(provider.exists?).to be_truthy
|
||||||
|
expect(provider.admin_state_up).to eq('True')
|
||||||
|
expect(provider.ha).to eq('True')
|
||||||
|
expect(provider.distributed).to eq('False')
|
||||||
|
expect(provider.status).to eq('ACTIVE')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with admin_state_up' do
|
||||||
|
let :router_attrs do
|
||||||
|
{
|
||||||
|
:name => router_name,
|
||||||
|
:ensure => 'present',
|
||||||
|
:admin_state_up => 'False',
|
||||||
|
}
|
||||||
|
end
|
||||||
|
it 'creates router' do
|
||||||
|
provider_class.expects(:openstack)
|
||||||
|
.with('router', 'create', '--format', 'shell',
|
||||||
|
['router1', '--disable'])
|
||||||
|
.returns('admin_state_up="False"
|
||||||
|
availability_zone_hints="[]"
|
||||||
|
distributed="False"
|
||||||
|
external_gateway_info="None"
|
||||||
|
ha="True"
|
||||||
|
id="d73f453a-77ca-4843-977a-3af0fda8dfcb"
|
||||||
|
name="router1"
|
||||||
|
project_id="60f9544eb94c42a6b7e8e98c2be981b1"
|
||||||
|
status="ACTIVE"')
|
||||||
|
provider.create
|
||||||
|
expect(provider.exists?).to be_truthy
|
||||||
|
expect(provider.admin_state_up).to eq('False')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with centralized' do
|
||||||
|
let :router_attrs do
|
||||||
|
{
|
||||||
|
:name => router_name,
|
||||||
|
:ensure => 'present',
|
||||||
|
:distributed => 'False',
|
||||||
|
}
|
||||||
|
end
|
||||||
|
it 'creates router' do
|
||||||
|
provider_class.expects(:openstack)
|
||||||
|
.with('router', 'create', '--format', 'shell',
|
||||||
|
['router1', '--centralized'])
|
||||||
|
.returns('admin_state_up="True"
|
||||||
|
availability_zone_hints="[]"
|
||||||
|
distributed="False"
|
||||||
|
external_gateway_info="None"
|
||||||
|
ha="True"
|
||||||
|
id="d73f453a-77ca-4843-977a-3af0fda8dfcb"
|
||||||
|
name="router1"
|
||||||
|
project_id="60f9544eb94c42a6b7e8e98c2be981b1"
|
||||||
|
status="ACTIVE"')
|
||||||
|
provider.create
|
||||||
|
expect(provider.exists?).to be_truthy
|
||||||
|
expect(provider.distributed).to eq('False')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with distributed' do
|
||||||
|
let :router_attrs do
|
||||||
|
{
|
||||||
|
:name => router_name,
|
||||||
|
:ensure => 'present',
|
||||||
|
:distributed => 'True',
|
||||||
|
}
|
||||||
|
end
|
||||||
|
it 'creates router' do
|
||||||
|
provider_class.expects(:openstack)
|
||||||
|
.with('router', 'create', '--format', 'shell',
|
||||||
|
['router1', '--distributed'])
|
||||||
|
.returns('admin_state_up="True"
|
||||||
|
availability_zone_hints="[]"
|
||||||
|
distributed="True"
|
||||||
|
external_gateway_info="None"
|
||||||
|
ha="True"
|
||||||
|
id="d73f453a-77ca-4843-977a-3af0fda8dfcb"
|
||||||
|
name="router1"
|
||||||
|
project_id="60f9544eb94c42a6b7e8e98c2be981b1"
|
||||||
|
status="ACTIVE"')
|
||||||
|
provider.create
|
||||||
|
expect(provider.exists?).to be_truthy
|
||||||
|
expect(provider.distributed).to eq('True')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with ha' do
|
||||||
|
let :router_attrs do
|
||||||
|
{
|
||||||
|
:name => router_name,
|
||||||
|
:ensure => 'present',
|
||||||
|
:ha => 'True',
|
||||||
|
}
|
||||||
|
end
|
||||||
|
it 'creates router' do
|
||||||
|
provider_class.expects(:openstack)
|
||||||
|
.with('router', 'create', '--format', 'shell',
|
||||||
|
['router1', '--ha'])
|
||||||
|
.returns('admin_state_up="True"
|
||||||
|
availability_zone_hints="[]"
|
||||||
|
distributed="False"
|
||||||
|
external_gateway_info="None"
|
||||||
|
ha="True"
|
||||||
|
id="d73f453a-77ca-4843-977a-3af0fda8dfcb"
|
||||||
|
name="router1"
|
||||||
|
project_id="60f9544eb94c42a6b7e8e98c2be981b1"
|
||||||
|
status="ACTIVE"')
|
||||||
|
provider.create
|
||||||
|
expect(provider.exists?).to be_truthy
|
||||||
|
expect(provider.ha).to eq('True')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with non-ha' do
|
||||||
|
let :router_attrs do
|
||||||
|
{
|
||||||
|
:name => router_name,
|
||||||
|
:ensure => 'present',
|
||||||
|
:ha => 'False',
|
||||||
|
}
|
||||||
|
end
|
||||||
|
it 'creates router' do
|
||||||
|
provider_class.expects(:openstack)
|
||||||
|
.with('router', 'create', '--format', 'shell',
|
||||||
|
['router1', '--no-ha'])
|
||||||
|
.returns('admin_state_up="True"
|
||||||
|
availability_zone_hints="[]"
|
||||||
|
distributed="False"
|
||||||
|
external_gateway_info="None"
|
||||||
|
ha="False"
|
||||||
|
id="d73f453a-77ca-4843-977a-3af0fda8dfcb"
|
||||||
|
name="router1"
|
||||||
|
project_id="60f9544eb94c42a6b7e8e98c2be981b1"
|
||||||
|
status="ACTIVE"')
|
||||||
|
provider.create
|
||||||
|
expect(provider.exists?).to be_truthy
|
||||||
|
expect(provider.ha).to eq('False')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with gateway_network_name' do
|
||||||
|
let :router_attrs do
|
||||||
|
{
|
||||||
|
:name => router_name,
|
||||||
|
:ensure => 'present',
|
||||||
|
:gateway_network_name => 'net1',
|
||||||
|
}
|
||||||
|
end
|
||||||
|
it 'creates router' do
|
||||||
|
provider_class.expects(:openstack)
|
||||||
|
.with('router', 'create', '--format', 'shell',
|
||||||
|
['router1'])
|
||||||
|
.returns('admin_state_up="True"
|
||||||
|
availability_zone_hints="[]"
|
||||||
|
distributed="False"
|
||||||
|
external_gateway_info="None"
|
||||||
|
ha="False"
|
||||||
|
id="d73f453a-77ca-4843-977a-3af0fda8dfcb"
|
||||||
|
name="router1"
|
||||||
|
project_id="60f9544eb94c42a6b7e8e98c2be981b1"
|
||||||
|
status="ACTIVE"')
|
||||||
|
provider_class.expects(:openstack)
|
||||||
|
.with('router', 'set', ['router1', '--external-gateway=net1'])
|
||||||
|
provider_class.expects(:openstack)
|
||||||
|
.with('router', 'show', '--format', 'shell',
|
||||||
|
['router1'])
|
||||||
|
.returns('admin_state_up="True"
|
||||||
|
availability_zone_hints="[]"
|
||||||
|
distributed="False"
|
||||||
|
external_gateway_info="{\'network_id\': \'076520cc-b783-4cf5-a4a9-4cb5a5e93a9b\'}"
|
||||||
|
ha="False"
|
||||||
|
id="d73f453a-77ca-4843-977a-3af0fda8dfcb"
|
||||||
|
name="router1"
|
||||||
|
project_id="60f9544eb94c42a6b7e8e98c2be981b1"
|
||||||
|
status="ACTIVE"')
|
||||||
|
provider.create
|
||||||
|
expect(provider.exists?).to be_truthy
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#destroy' do
|
||||||
|
it 'removes router' do
|
||||||
|
provider_class.expects(:openstack)
|
||||||
|
.with('router', 'delete', 'router1')
|
||||||
|
provider.destroy
|
||||||
|
expect(provider.exists?).to be_falsey
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#flush' do
|
||||||
|
context '.admin_state_up' do
|
||||||
|
it 'updates router' do
|
||||||
|
provider_class.expects(:openstack)
|
||||||
|
.with('router', 'set', ['router1', '--disable'])
|
||||||
|
provider.admin_state_up = 'False'
|
||||||
|
provider.flush
|
||||||
|
provider_class.expects(:openstack)
|
||||||
|
.with('router', 'set', ['router1', '--enable'])
|
||||||
|
provider.admin_state_up = 'True'
|
||||||
|
provider.flush
|
||||||
|
end
|
||||||
|
end
|
||||||
|
context '.distributed' do
|
||||||
|
it 'updates router' do
|
||||||
|
provider_class.expects(:openstack)
|
||||||
|
.with('router', 'set', ['router1', '--distributed'])
|
||||||
|
provider.distributed = 'True'
|
||||||
|
provider.flush
|
||||||
|
provider_class.expects(:openstack)
|
||||||
|
.with('router', 'set', ['router1', '--centralized'])
|
||||||
|
provider.distributed = 'False'
|
||||||
|
provider.flush
|
||||||
|
end
|
||||||
|
end
|
||||||
|
context '.ha' do
|
||||||
|
it 'updates router' do
|
||||||
|
provider_class.expects(:openstack)
|
||||||
|
.with('router', 'set', ['router1', '--ha'])
|
||||||
|
provider.ha = 'True'
|
||||||
|
provider.flush
|
||||||
|
provider_class.expects(:openstack)
|
||||||
|
.with('router', 'set', ['router1', '--no-ha'])
|
||||||
|
provider.ha = 'False'
|
||||||
|
provider.flush
|
||||||
|
end
|
||||||
|
end
|
||||||
|
context '.gateway_network_name' do
|
||||||
|
it 'updates router' do
|
||||||
|
provider_class.expects(:openstack)
|
||||||
|
.with('router', 'set', ['router1', '--external-gateway=net1'])
|
||||||
|
provider.gateway_network_name = 'net1'
|
||||||
|
provider.flush
|
||||||
|
provider_class.expects(:openstack)
|
||||||
|
.with('router', 'unset', ['router1', '--external-gateway'])
|
||||||
|
provider.gateway_network_name = ''
|
||||||
|
provider.flush
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#instances' do
|
||||||
|
it 'lists router' do
|
||||||
|
provider_class.expects(:openstack)
|
||||||
|
.with('router', 'list', '--quiet', '--format', 'csv', [])
|
||||||
|
.returns('"ID","Name","Status","State","Project","Distributed","HA"
|
||||||
|
"d73f453a-77ca-4843-977a-3af0fda8dfcb","router1","ACTIVE","True","60f9544eb94c42a6b7e8e98c2be981b1",True,False
|
||||||
|
"c3e93a5b-45ee-4029-b3a3-3331cb3e3f2a","router2","DOWN","False","60f9544eb94c42a6b7e8e98c2be981b1",False,True
|
||||||
|
')
|
||||||
|
provider_class.expects(:openstack)
|
||||||
|
.with('router', 'show', '--format', 'shell', 'd73f453a-77ca-4843-977a-3af0fda8dfcb')
|
||||||
|
.returns('admin_state_up="True"
|
||||||
|
availability_zone_hints="[]"
|
||||||
|
distributed="False"
|
||||||
|
external_gateway_info="None"
|
||||||
|
ha="True"
|
||||||
|
id="d73f453a-77ca-4843-977a-3af0fda8dfcb"
|
||||||
|
name="router1"
|
||||||
|
project_id="60f9544eb94c42a6b7e8e98c2be981b1"
|
||||||
|
status="ACTIVE"')
|
||||||
|
provider_class.expects(:openstack)
|
||||||
|
.with('router', 'show', '--format', 'shell', 'c3e93a5b-45ee-4029-b3a3-3331cb3e3f2a')
|
||||||
|
.returns('admin_state_up="False"
|
||||||
|
availability_zone_hints="[]"
|
||||||
|
distributed="True"
|
||||||
|
external_gateway_info="None"
|
||||||
|
ha="False"
|
||||||
|
id="c3e93a5b-45ee-4029-b3a3-3331cb3e3f2a"
|
||||||
|
name="router2"
|
||||||
|
project_id="60f9544eb94c42a6b7e8e98c2be981b1"
|
||||||
|
project_id="60f9544eb94c42a6b7e8e98c2be981b1"
|
||||||
|
status="DOWN"')
|
||||||
|
|
||||||
|
instances = provider_class.instances
|
||||||
|
expect(instances.length).to eq(2)
|
||||||
|
|
||||||
|
expect(instances[0].id).to eq('d73f453a-77ca-4843-977a-3af0fda8dfcb')
|
||||||
|
expect(instances[0].name).to eq('router1')
|
||||||
|
expect(instances[0].admin_state_up).to eq('True')
|
||||||
|
expect(instances[0].ha).to eq('True')
|
||||||
|
expect(instances[0].distributed).to eq('False')
|
||||||
|
expect(instances[0].status).to eq('ACTIVE')
|
||||||
|
|
||||||
|
expect(instances[1].id).to eq('c3e93a5b-45ee-4029-b3a3-3331cb3e3f2a')
|
||||||
|
expect(instances[1].name).to eq('router2')
|
||||||
|
expect(instances[1].admin_state_up).to eq('False')
|
||||||
|
expect(instances[1].ha).to eq('False')
|
||||||
|
expect(instances[1].distributed).to eq('True')
|
||||||
|
expect(instances[1].status).to eq('DOWN')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -57,148 +57,5 @@ describe Puppet::Provider::Neutron do
|
||||||
klass.neutron_credentials
|
klass.neutron_credentials
|
||||||
end.to raise_error(Puppet::Error, credential_error)
|
end.to raise_error(Puppet::Error, credential_error)
|
||||||
end
|
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_USERNAME => credential_hash['username'],
|
|
||||||
:OS_PROJECT_NAME => credential_hash['project_name'],
|
|
||||||
:OS_PASSWORD => credential_hash['password'],
|
|
||||||
:OS_PROJECT_DOMAIN_NAME => credential_hash['project_domain_name'],
|
|
||||||
:OS_USER_DOMAIN_NAME => credential_hash['user_domain_name'],
|
|
||||||
}
|
|
||||||
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_url'],
|
|
||||||
:OS_USERNAME => credential_hash['username'],
|
|
||||||
:OS_PROJECT_NAME => credential_hash['project_name'],
|
|
||||||
:OS_PASSWORD => credential_hash['password'],
|
|
||||||
:OS_REGION_NAME => 'REGION_NAME',
|
|
||||||
:OS_PROJECT_DOMAIN_NAME => credential_hash['project_domain_name'],
|
|
||||||
:OS_USER_DOMAIN_NAME => credential_hash['user_domain_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 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_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
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue