Merge "Add quantum_router_interface custom type."
This commit is contained in:
commit
5391172b55
|
@ -48,3 +48,7 @@ quantum_router { 'demo_router':
|
||||||
gateway_network_name => 'public',
|
gateway_network_name => 'public',
|
||||||
require => Quantum_subnet['public_subnet'],
|
require => Quantum_subnet['public_subnet'],
|
||||||
}
|
}
|
||||||
|
|
||||||
|
quantum_router_interface { 'demo_router:private_subnet':
|
||||||
|
ensure => present,
|
||||||
|
}
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
|
require 'csv'
|
||||||
require 'puppet/util/inifile'
|
require 'puppet/util/inifile'
|
||||||
|
|
||||||
class Puppet::Provider::Quantum < Puppet::Provider
|
class Puppet::Provider::Quantum < Puppet::Provider
|
||||||
|
|
||||||
def self.conf_filename
|
def self.conf_filename
|
||||||
|
@ -140,4 +142,29 @@ correctly configured.")
|
||||||
return exts
|
return exts
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def self.list_router_ports(router_name_or_id)
|
||||||
|
results = []
|
||||||
|
cmd_output = auth_quantum("router-port-list",
|
||||||
|
'--format=csv',
|
||||||
|
router_name_or_id)
|
||||||
|
if ! cmd_output
|
||||||
|
return results
|
||||||
|
end
|
||||||
|
|
||||||
|
headers = nil
|
||||||
|
CSV.parse(cmd_output) do |row|
|
||||||
|
if headers == nil
|
||||||
|
headers = row
|
||||||
|
else
|
||||||
|
result = Hash[*headers.zip(row).flatten]
|
||||||
|
match_data = /.*"subnet_id": "(.*)", .*/.match(result['fixed_ips'])
|
||||||
|
if match_data
|
||||||
|
result['subnet_id'] = match_data[1]
|
||||||
|
end
|
||||||
|
results << result
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return results
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
|
@ -0,0 +1,90 @@
|
||||||
|
require File.join(File.dirname(__FILE__), '..','..','..',
|
||||||
|
'puppet/provider/quantum')
|
||||||
|
|
||||||
|
Puppet::Type.type(:quantum_router_interface).provide(
|
||||||
|
:quantum,
|
||||||
|
:parent => Puppet::Provider::Quantum
|
||||||
|
) do
|
||||||
|
desc <<-EOT
|
||||||
|
Quantum provider to manage quantum_router_interface type.
|
||||||
|
|
||||||
|
Assumes that the quantum service is configured on the same host.
|
||||||
|
|
||||||
|
It is not possible to manage an interface for the subnet used by
|
||||||
|
the gateway network, and such an interface will appear in the list
|
||||||
|
of resources ('puppet resource [type]'). Attempting to manage the
|
||||||
|
gateway interfae will result in an error.
|
||||||
|
|
||||||
|
EOT
|
||||||
|
|
||||||
|
commands :quantum => 'quantum'
|
||||||
|
|
||||||
|
mk_resource_methods
|
||||||
|
|
||||||
|
def self.instances
|
||||||
|
subnet_name_hash = {}
|
||||||
|
Puppet::Type.type('quantum_subnet').instances.each do |instance|
|
||||||
|
subnet_name_hash[instance.provider.id] = instance.provider.name
|
||||||
|
end
|
||||||
|
instances_ = []
|
||||||
|
Puppet::Type.type('quantum_router').instances.each do |instance|
|
||||||
|
list_router_ports(instance.provider.id).each do |port_hash|
|
||||||
|
router_name = instance.provider.name
|
||||||
|
subnet_name = subnet_name_hash[port_hash['subnet_id']]
|
||||||
|
name = "#{router_name}:#{subnet_name}"
|
||||||
|
instances_ << new(
|
||||||
|
:ensure => :present,
|
||||||
|
:name => name,
|
||||||
|
:id => port_hash['id']
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return instances_
|
||||||
|
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
|
||||||
|
results = auth_quantum("router-interface-add", '--format=shell',
|
||||||
|
resource[:name].split(':', 2))
|
||||||
|
|
||||||
|
if results =~ /Added interface to router/
|
||||||
|
@property_hash = {
|
||||||
|
:ensure => :present,
|
||||||
|
:name => resource[:name],
|
||||||
|
}
|
||||||
|
else
|
||||||
|
fail("did not get expected message on interface addition, got #{results}")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def router_name
|
||||||
|
name.split(':', 2).first
|
||||||
|
end
|
||||||
|
|
||||||
|
def subnet_name
|
||||||
|
name.split(':', 2).last
|
||||||
|
end
|
||||||
|
|
||||||
|
def id
|
||||||
|
# TODO: Need to look this up for newly-added resources since it is
|
||||||
|
# not returned on creation
|
||||||
|
end
|
||||||
|
|
||||||
|
def destroy
|
||||||
|
auth_quantum('router-interface-delete', router_name, subnet_name)
|
||||||
|
@property_hash[:ensure] = :absent
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -0,0 +1,47 @@
|
||||||
|
Puppet::Type.newtype(:quantum_router_interface) do
|
||||||
|
|
||||||
|
desc <<-EOT
|
||||||
|
This is currently used to model the creation of
|
||||||
|
quantum router interfaces.
|
||||||
|
|
||||||
|
Router interfaces are an association between a router and a
|
||||||
|
subnet.
|
||||||
|
EOT
|
||||||
|
|
||||||
|
ensurable
|
||||||
|
|
||||||
|
newparam(:name, :namevar => true) do
|
||||||
|
newvalues(/^\S+:\S+$/)
|
||||||
|
end
|
||||||
|
|
||||||
|
newproperty(:id) do
|
||||||
|
validate do |v|
|
||||||
|
raise(Puppet::Error, 'This is a read only property')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
newproperty(:router_name) do
|
||||||
|
validate do |v|
|
||||||
|
raise(Puppet::Error, 'This is a read only property')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
newproperty(:subnet_name) do
|
||||||
|
validate do |v|
|
||||||
|
raise(Puppet::Error, 'This is a read only property')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
autorequire(:service) do
|
||||||
|
['quantum-server']
|
||||||
|
end
|
||||||
|
|
||||||
|
autorequire(:quantum_router) do
|
||||||
|
self[:name].split(':', 2).first
|
||||||
|
end
|
||||||
|
|
||||||
|
autorequire(:quantum_subnet) do
|
||||||
|
self[:name].split(':', 2).last
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -0,0 +1,36 @@
|
||||||
|
require 'puppet'
|
||||||
|
require 'spec_helper'
|
||||||
|
require 'puppet/provider/quantum_router_interface/quantum'
|
||||||
|
|
||||||
|
provider_class = Puppet::Type.type(:quantum_router_interface).
|
||||||
|
provider(:quantum)
|
||||||
|
|
||||||
|
describe provider_class do
|
||||||
|
|
||||||
|
let :interface_attrs do
|
||||||
|
{
|
||||||
|
:name => 'router:subnet',
|
||||||
|
:ensure => 'present',
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'when accessing attributes of an interface' do
|
||||||
|
let :resource do
|
||||||
|
Puppet::Type::Quantum_router_interface.new(interface_attrs)
|
||||||
|
end
|
||||||
|
|
||||||
|
let :provider do
|
||||||
|
provider_class.new(resource)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should return the correct router name' do
|
||||||
|
provider.router_name.should eql('router')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should return the correct subnet name' do
|
||||||
|
provider.subnet_name.should eql('subnet')
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
|
@ -128,4 +128,48 @@ subnet2"
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
describe 'when listing router ports' do
|
||||||
|
|
||||||
|
let :router do
|
||||||
|
'router1'
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'should handle an empty port list' do
|
||||||
|
klass.expects(:auth_quantum).with('router-port-list',
|
||||||
|
'--format=csv',
|
||||||
|
router)
|
||||||
|
result = klass.list_router_ports(router)
|
||||||
|
result.should 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_quantum).
|
||||||
|
with('router-port-list', '--format=csv', router).
|
||||||
|
returns(output)
|
||||||
|
result = klass.list_router_ports(router)
|
||||||
|
result.should eql(expected)
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue