Added MidoNet gateway functionality for BGP uplink configuration

MidoNet utilizes the Border Gateway Protocol (BGP) for external connectivity.
For production deployments it is strongly recommended to use BGP due to it’s
scalability and redundancy. For demo or POC environments, alternatively static
routing can be used.

This patch adds a new Puppet custom type and provider to let puppet deployers
to automatically set up BGP uplink configuration:

      midonet_gateway { $::hostname:
        ensure          => present,
        midonet_api_url => 'http://127.0.0.1:8080/midonet-api',
        username        => 'admin',
        password        => 'admin',
        interface       => 'testgateway',
        local_as        => '64512',
        bgp_port        => { 'port_address' => '198.51.100.2', 'net_prefix' => '198.51.100.0', 'net_length' => '30'},
        remote_peers    => [{ 'as' => '64513', 'ip' => '198.51.100.1'},
                            { 'as' => '64513', 'ip' => '203.0.113.1'}],
        advertise_net   => [{ 'net_prefix' => '192.0.2.0', 'net_length' => '24' }]
      }

Change-Id: Id362e519d12eefe5900060d6b02f92fbf6c54e08
This commit is contained in:
Carmela Rubinos 2015-07-14 18:32:21 +02:00
parent 6a54710212
commit 0ce39c5271
7 changed files with 780 additions and 12 deletions
.gitignore
lib/puppet
provider/midonet_gateway
type
spec
acceptance
unit/puppet

1
.gitignore vendored

@ -6,6 +6,7 @@
**/pkg/
/spec/reports/
/spec/fixtures/modules/*
/spec/fixtures/manifests/*
/test/tmp/
/test/version_tmp/
/tmp/

@ -0,0 +1,278 @@
require 'uri'
require 'faraday'
if RUBY_VERSION == '1.8.7'
require 'rubygems'
require 'json'
end
Puppet::Type.type(:midonet_gateway).provide(:midonet_api_caller) do
def create
define_connection(resource[:midonet_api_url])
# For each remote BGP peer, create a virtual port on
# the MidoNet Provider Router that is going to be used
# for the BGP communication. Connection to midonet api
# is assumed
router_id = call_get_provider_router()[0]['id']
message = Hash.new
message['portAddress'] = resource[:bgp_port]["port_address"]
message['networkAddress'] = resource[:bgp_port]["net_prefix"]
message['networkLength'] = resource[:bgp_port]["net_length"].to_i
message['type'] = "Router"
port = call_create_uplink_port(router_id, message)
port_id = port[0]['id']
# Configure BGP on the virtual ports. Port is
# assumed created
resource[:remote_peers].each do |rp|
message = Hash.new
message['localAS'] = resource[:local_as]
message['peerAS'] = rp["as"]
message['peerAddr'] = rp["ip"]
call_add_bgp_to_port(port_id, message)
end
# In order to provide external connectivity for hosted
# virtual machines, the floating IP network has to be
# advertised to the BGP peers. BGP connection is assumed created
bgp_connections = call_get_bgp_connections(port_id)
#TODO(carmela): make this modification more elegant... or whatever
advertise_networks = resource[:advertise_net]
if advertise_networks.class == Hash
advertise_networks = [advertise_networks]
end
bgp_connections.each do |bgp_c|
advertise_networks.each do |net|
message = Hash.new
message['nwPrefix'] = net["net_prefix"]
message['prefixLength'] = net["net_length"]
bgp_id = bgp_c["id"]
call_advertise_route_to_bgp(bgp_id, message)
end
end
# Bind the MidoNet Provider Routers virtual ports to
# the physical network interfaces on the Gateway Nodes.
# Host and port are assumed created. Interface name should
# be an string
host_id = call_get_host()[0]['id']
message = Hash.new
message['interfaceName'] = resource[:interface]
message['portId'] = port_id
call_bind_port_to_interface(host_id, message)
# Configure a stateful port group
spg = call_get_stateful_port_group()
if spg.empty?
message = Hash.new
message['name'] = "uplink-spg"
message['stateful'] = "true"
#TODO(carmela): replace with keystone call and tenant id
message['tenantId'] = "4486908d-8e15-4f01-b3b4-86f9def0fa04"
spg = call_create_stateful_port_group(message)
end
# Add the ports to the port group
message = Hash.new
message['portId'] = port_id
call_add_ports_to_port_group(spg[0]["id"], message)
end
def destroy
define_connection(resource[:midonet_api_url])
router_id = call_get_provider_router()[0]['id']
port_address = resource[:bgp_port]['port_address']
port = call_get_uplink_port(router_id, port_address)
port_id = port[0]["id"]
# Delete the stateful port group
# TODO(carmela): delete only in case is the last port on the port group
# port_group_id = call_get_stateful_port_group()[0]['id']
# call_delete_stateful_port_group(port_group_id)
# Delete uplink port
call_delete_uplink_port(port_id)
end
def exists?
define_connection(resource[:midonet_api_url])
router = call_get_provider_router()
if router.empty?
raise 'MidoNet Provider Router does not exist. We cannot create uplink ports'
end
host = call_get_host()
if host.empty?
raise 'There is no MidoNet agent running on this host'
end
uplink_port = call_get_uplink_port(router[0]['id'], resource[:bgp_port]['port_address'])
if uplink_port.empty?
return false
end
return true
end
def define_connection(url)
@connection = Faraday.new(:url => url,
:ssl => { :verify =>false }) do |builder|
builder.request(:retry, {
:max => 5,
:interval => 0.05,
:exceptions => [
Faraday::Error::TimeoutError,
Faraday::ConnectionFailed,
Errno::ETIMEDOUT,
'Timeout::Error',
],
})
builder.request(:basic_auth, resource[:username], resource[:password])
builder.adapter(:net_http)
end
@connection.headers['X-Auth-Token'] = call_get_token()
end
def call_get_token()
res = @connection.get do |req|
req.url "/midonet-api/login"
end
return JSON.parse(res.body)['key']
end
def call_get_provider_router()
res = @connection.get do |req|
req.url "/midonet-api/routers"
end
output = JSON.parse(res.body)
return output.select { |name| name['name'] == resource[:router]}
end
def call_get_stateful_port_group()
res = @connection.get do |req|
req.url "/midonet-api/port_groups"
end
output = JSON.parse(res.body)
return output.select { |name| name['name'] == 'uplink-spg'}
end
def call_get_uplink_port(router_id, port_address)
res = @connection.get do |req|
req.url "/midonet-api/routers/#{router_id}/ports"
end
output = JSON.parse(res.body)
return output.select { |port| port['portAddress'] == port_address }
end
def call_get_host()
res = @connection.get do |req|
req.url "/midonet-api/hosts"
end
output = JSON.parse(res.body)
return output.select{ |host| host['name'] == resource[:hostname].to_s }
end
def call_create_uplink_port(router_id, message)
res = @connection.post do |req|
req.url "/midonet-api/routers/#{router_id}/ports"
req.headers['Content-Type'] = "application/vnd.org.midonet.Port-v2+json"
req.body = message.to_json
end
return call_get_uplink_port(router_id, message["portAddress"])
end
def call_delete_uplink_port(port_id)
res = @connection.delete do |req|
req.url "/midonet-api/ports/#{port_id}"
end
end
def call_add_bgp_to_port(port_id, message)
res = @connection.post do |req|
req.url "/midonet-api/ports/#{port_id}/bgps"
req.headers['Content-Type'] = "application/vnd.org.midonet.Bgp-v1+json"
req.body = message.to_json
end
end
def call_get_bgp_connections(port_id)
res = @connection.get do |req|
req.url "/midonet-api/ports/#{port_id}/bgps"
end
output = JSON.parse(res.body)
return output
end
def call_advertise_route_to_bgp(bgp_id, message)
res = @connection.post do |req|
req.url "/midonet-api/bgps/#{bgp_id}/ad_routes"
req.headers['Content-Type'] = "application/vnd.org.midonet.AdRoute-v1+json"
req.body = message.to_json
end
end
def call_bind_port_to_interface(host_id, message)
res = @connection.post do |req|
req.url "/midonet-api/hosts/#{host_id}/ports"
req.headers['Content-Type'] = "application/vnd.org.midonet.HostInterfacePort-v1+json"
req.body = message.to_json
end
end
def call_create_stateful_port_group(message)
res = @connection.post do |req|
req.url "/midonet-api/port_groups"
req.headers['Content-Type'] = "application/vnd.org.midonet.PortGroup-v1+json"
req.body = message.to_json
end
return call_get_stateful_port_group()
end
def call_add_ports_to_port_group(port_group_id, message)
res = @connection.post do |req|
req.url "/midonet-api/port_groups/#{port_group_id}/ports"
req.headers['Content-Type'] = "application/vnd.org.midonet.PortGroupPort-v1+json"
req.body = message.to_json
end
end
def call_delete_stateful_port_group(port_group_id)
res = @connection.delete do |req|
req.url "/midonet-api/port_groups/#{port_group_id}"
end
end
private :call_add_bgp_to_port
:call_add_ports_to_port_group
:call_advertise_route_to_bgp
:call_bind_port_to_interface
:call_create_stateful_port_group
:call_create_uplink_port
:call_delete_stateful_port_group
:call_delete_uplink_port
:call_get_bgp_connections
:call_get_host
:call_get_stateful_port_group
:call_get_provider_router
:call_get_uplink_port
:define_connection
end

@ -0,0 +1,155 @@
require 'uri'
require 'facter'
Puppet::Type.newtype(:midonet_gateway) do
@doc = %q{BGP Uplink Configuration
Example:
midonet_gateway {'hostname':
midonet_api_url => 'http://controller:8080',
username => 'admin',
password => 'admin',
tenant_name => 'admin',
interface => 'eth1',
local_as => '64512',
bgp_port => { 'port_address' => '198.51.100.2', 'net_prefix' => '198.51.100.0', 'net_length' => '30'},
remote_peers => [ { 'as' => '64513', 'ip' => '198.51.100.1' },
{ 'as' => '64513', 'ip' => '203.0.113.1' } ],
advertise_net => [ { 'net_prefix' => '192.0.2.0', 'net_length' => '24' } ]
}
}
ensurable
autorequire(:package) do ['midolman'] end
newparam(:hostname, :namevar => true) do
desc 'Hostname of the host that will act as gateway in a MidoNet managed cloud'
# Regex obtained from StackOverflow question:
# http://stackoverflow.com/questions/1418423/the-hostname-regex
validate do |value|
unless value =~ /^(?=.{1,255}$)[0-9A-Za-z](?:(?:[0-9A-Za-z]|-){0,61}[0-9A-Za-z])?(?:\.[0-9A-Za-z](?:(?:[0-9A-Za-z]|-){0,61}[0-9A-Za-z])?)*\.?$/
raise ArgumentError, "'%s' is not a valid hostname" % value
end
end
end
newparam(:midonet_api_url) do
desc 'MidoNet API endpoint to connect to'
validate do |value|
unless value =~ /\A#{URI::regexp(['http', 'https'])}\z/
raise ArgumentError, "'%s' is not a valid URI" % value
end
end
end
newparam(:username) do
desc 'Username of the admin user in keystone'
defaultto 'admin'
validate do |value|
unless value =~ /\w+$/
raise ArgumentError, "'%s' is not a valid username" % value
end
end
end
newparam(:password) do
desc 'Password of the admin user in keystone'
defaultto 'admin'
validate do |value|
unless value =~ /\w+$/
raise ArgumentError, "'%s' is not a valid password" % value
end
end
end
newparam(:tenant_name) do
desc 'Tenant name of the admin user'
defaultto 'admin'
validate do |value|
unless value =~ /\w+$/
raise ArgumentError, "'%s' is not a tenant name" % value
end
end
end
newparam(:interface) do
desc "Physical interface where the MidoNet Provider Router's port is binded to"
defaultto 'eth0'
validate do |value|
unless value =~ /\w+$/
raise ArgumentError, "'%s' is not a valid interface" % value
end
end
end
newparam(:local_as) do
desc "Local AS number"
validate do |value|
unless value =~ /\d{5}/
raise ArgumentError, "'%s' is not a valid AS" % value
end
end
end
newparam(:remote_peers) do
desc "#to be filled"
validate do |value|
value.each do |rp|
unless rp["as"] =~ /\d{5}/
raise ArgumentError, "'%s' is not a valid AS name" % rp["as"]
end
unless rp["ip"] =~ /^(\d|[1-9]\d|1\d\d|2([0-4]\d|5[0-5]))\.(\d|[1-9]\d|1\d\d|2([0-4]\d|5[0-5]))\.(\d|[1-9]\d|1\d\d|2([0-4]\d|5[0-5]))\.(\d|[1-9]\d|1\d\d|2([0-4]\d|5[0-5]))$/
raise ArgumentError, "'%s' is not a valid IP address" % rp["ip"]
end
end
end
end
newparam(:bgp_port) do
desc "#to be filled"
validate do |value|
[:port_address, :net_prefix, :net_length].all? {|key| value.key? key}
unless value["port_address"] =~ /^(\d|[1-9]\d|1\d\d|2([0-4]\d|5[0-5]))\.(\d|[1-9]\d|1\d\d|2([0-4]\d|5[0-5]))\.(\d|[1-9]\d|1\d\d|2([0-4]\d|5[0-5]))\.(\d|[1-9]\d|1\d\d|2([0-4]\d|5[0-5]))$/
raise ArgumentError, "'%s' is not a valid IP address" % value["port_address"]
end
unless value["net_prefix"] =~ /^(\d|[1-9]\d|1\d\d|2([0-4]\d|5[0-5]))\.(\d|[1-9]\d|1\d\d|2([0-4]\d|5[0-5]))\.(\d|[1-9]\d|1\d\d|2([0-4]\d|5[0-5]))\.(\d|[1-9]\d|1\d\d|2([0-4]\d|5[0-5]))$/
raise ArgumentError, "'%s' is not a valid IPv4 network address" % value["net_prefix"]
end
unless value["net_length"] =~ /\d{2}/
raise ArgumentError, "'%s' is not a valid network prefix length" % value["net_length"]
end
end
end
newparam(:router) do
desc "The MidoNet's internal Provider router that acts as the gateway router of the cloud"
defaultto 'MidoNet Provider Router'
validate do |value|
unless value =~ /\w+$/
raise ArgumentError, "'%s' is not a valid router name" % value
end
end
end
newparam(:advertise_net) do
desc 'Floating IP network to be avertised to the BGP peers'
defaultto []
validate do |value|
if value.class == Hash
value = [value]
end
value.each do |an|
unless an["net_prefix"] =~ /^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/
raise ArgumentError, "'%s' is not a valid network prefix" % an["net_prefix"]
end
unless an["net_length"] =~ /\d{2}/
raise ArgumentError, "'%s' is not a valid network prefix length" % an["net_length"]
end
end
end
end
end

@ -2,15 +2,29 @@ require 'spec_helper_acceptance'
describe 'midonet all-in-one' do
context 'default parameters' do
it 'should work with no errors' do
pp = <<-EOS
class { 'midonet': }
EOS
context 'default parameters' do
it 'should work with no errors' do
pp = <<-EOS
class { 'midonet': } ->
exec { "/sbin/ip tuntap add mode tap testgateway": } ->
exec { "/usr/bin/midonet-cli -e 'create router name \\"MidoNet Provider Router\\"'": } ->
midonet_gateway { $::hostname:
ensure => present,
midonet_api_url => 'http://127.0.0.1:8080/midonet-api',
username => 'admin',
password => 'admin',
interface => 'testgateway',
local_as => '64512',
bgp_port => { 'port_address' => '198.51.100.2', 'net_prefix' => '198.51.100.0', 'net_length' => '30'},
remote_peers => [{ 'as' => '64513', 'ip' => '198.51.100.1'},
{ 'as' => '64513', 'ip' => '203.0.113.1'}],
advertise_net => [{ 'net_prefix' => '192.0.2.0', 'net_length' => '24' }]
}
EOS
# Run it twice for test the idempotency
apply_manifest(pp)
apply_manifest(pp)
end
end
# Run it twice for test the idempotency
apply_manifest(pp)
apply_manifest(pp)
end
end
end

@ -0,0 +1,140 @@
require 'spec_helper'
describe Puppet::Type.type(:midonet_gateway).provider(:midonet_api_caller) do
let(:provider) { described_class.new(resource) }
let(:resource) { Puppet::Type.type(:midonet_gateway).new(
{
:ensure => :present,
:hostname => 'compute.midonet',
:midonet_api_url => 'http://controller:8080',
:username => 'admin',
:password => 'admin',
:interface => 'eth0',
:local_as => '64512',
:bgp_port => { 'port_address' => '198.51.100.2', 'net_prefix' => '198.51.100.0', 'net_length' => '30' },
:remote_peers => [ { 'as' => '64513', 'ip' => '198.51.100.1' },
{ 'as' => '64513', 'ip' => '203.0.113.1' } ],
:advertise_net => [ { 'net_prefix' => '192.0.2.0', 'net_length' => '24' } ]
}
)}
describe 'BGP configuration happy path' do
# - Create virtual ports for each remote BGP peer
# - Configure BGP on the virtual ports or remove config if needed
# - Advertise routes
# - Bind virtual ports to physical network interfaces
# - Configure stateful port group and delete it if needed
# - Add ports to the port group and remove them if needed
let(:routers) {
[
{
"id" => "e6a53892-03bf-4f16-8212-e4d76ad204e3",
"name" => "MidoNet Provider Router"
}
]
}
let(:ports) {
[
{
"hostId" => "b3f2f63e-02a6-459a-af0f-44eeac441a09",
"interfaceName" => "eth0",
"id" => "20b169b1-ec0a-4639-8479-44b63e016935"
}
]
}
let(:bgps) {
[
{
"id" => "4a5e4356-3417-4c60-9cf8-7516aedb7067",
"localAS" => "64512",
"peerAS" => "64513",
"peerAddr" => "198.51.100.1",
"portId" => "f9e61b88-0a26-4d56-8f47-eb5da37225e0"
}
]
}
let(:port_groups) {
[
{
"id" => "711401b7-bf6f-4afd-8ab2-94b4342a0310",
"name" => "uplink-spg",
"stateful" => "true"
}
]
}
let(:hosts) {
[
{
"id" => "b3f2f63e-02a6-459a-af0f-44eeac441a09",
"name" => "compute.midonet"
}
]
}
before :each do
allow(provider).to receive(:call_create_uplink_port).and_return(ports)
allow(provider).to receive(:call_get_provider_router).and_return(routers)
allow(provider).to receive(:call_get_host_id).and_return(hosts[0]['id'])
allow(provider).to receive(:call_get_host).and_return(hosts)
allow(provider).to receive(:call_add_bgp_to_port)
allow(provider).to receive(:call_get_bgp_connections).and_return(bgps)
allow(provider).to receive(:call_advertise_route_to_bgp)
allow(provider).to receive(:call_bind_port_to_interface)
allow(provider).to receive(:call_get_stateful_port_group).and_return(port_groups)
allow(provider).to receive(:call_add_ports_to_port_group)
allow(provider).to receive(:call_delete_uplink_port).and_return(ports)
allow(provider).to receive(:call_unbind_port_from_interface)
allow(provider).to receive(:call_remove_ports_from_port_group)
allow(provider).to receive(:call_get_uplink_port).and_return(ports)
allow(provider).to receive(:call_get_token).and_return('thisisafaketoken')
end
it 'creates virtual ports for each remote BGP peer, advertises routes,
binds virtual ports, configures stateful port group and adds ports to it' do
# Expectations over the 'create' call
expect(provider).to receive(:call_get_provider_router)
expect(provider).to receive(:call_create_uplink_port).with(routers[0]['id'], {'portAddress' => resource[:bgp_port]['port_address'],
'networkAddress' => resource[:bgp_port]['net_prefix'],
'networkLength' => resource[:bgp_port]['net_length'].to_i,
'type' => 'Router'})
expect(provider).to receive(:call_get_bgp_connections).with(ports[0]['id'])
expect(provider).to receive(:call_add_bgp_to_port).with(ports[0]['id'], {'localAS' => resource[:local_as],
'peerAS' => resource[:remote_peers][0]['as'],
'peerAddr' => resource[:remote_peers][0]['ip']}).once
expect(provider).to receive(:call_add_bgp_to_port).with(ports[0]['id'], {'localAS' => resource[:local_as],
'peerAS' => resource[:remote_peers][1]['as'],
'peerAddr' => resource[:remote_peers][1]['ip']}).once
expect(provider).to receive(:call_advertise_route_to_bgp).with(bgps[0]['id'], {'nwPrefix' => resource[:advertise_net][0]['net_prefix'],
'prefixLength' => resource[:advertise_net][0]['net_length']}).once
expect(provider).to receive(:call_bind_port_to_interface).with(hosts[0]['id'], {'interfaceName' => resource[:interface],
'portId' => '20b169b1-ec0a-4639-8479-44b63e016935'})
expect(provider).not_to receive(:call_create_stateful_port_group)
expect(provider).to receive(:call_get_stateful_port_group)
expect(provider).to receive(:call_add_ports_to_port_group).with(port_groups[0]['id'], {'portId' => '20b169b1-ec0a-4639-8479-44b63e016935'})
provider.create
end
it 'deletes uplink port, port_group, and unconfigures BGP' do
# Expectations over the 'destroy' call
expect(provider).to receive(:call_get_provider_router)
expect(provider).to receive(:call_get_uplink_port)
expect(provider).to receive(:call_delete_uplink_port).with(ports[0]['id'])
provider.destroy
end
it 'exists with default method returns' do
# Expectations over the 'exists' call
expect(provider).to receive(:call_get_provider_router).and_return(routers)
expect(provider).to receive(:call_get_host).and_return(hosts)
expect(provider).to receive(:call_get_uplink_port).with(routers[0]['id'], resource[:bgp_port]['port_address']).and_return(ports)
expect(provider.exists?).to eq true
end
end
end

@ -16,7 +16,6 @@ describe Puppet::Type.type(:midonet_host_registry).provider(:midonet_api_caller)
}
)}
describe 'host registry happy path' do
# - Single tunnelzone zones
# - Host registered
@ -62,7 +61,6 @@ describe Puppet::Type.type(:midonet_host_registry).provider(:midonet_api_caller)
provider.create
end
it 'unregisters the host successfully' do
# Expectations over the 'destroy' call
expect(provider).to receive(:call_get_tunnelzone)
@ -83,6 +81,7 @@ describe Puppet::Type.type(:midonet_host_registry).provider(:midonet_api_caller)
}
]
}
let(:tzones) {
[
{
@ -92,6 +91,7 @@ describe Puppet::Type.type(:midonet_host_registry).provider(:midonet_api_caller)
}
]
}
it 'creates the tunnelzone and the host' do
allow(provider).to receive(:call_get_tunnelzone).and_return([])
allow(provider).to receive(:call_create_tunnelzone).and_return(tzones)
@ -116,6 +116,7 @@ describe Puppet::Type.type(:midonet_host_registry).provider(:midonet_api_caller)
}
]
}
let(:host_to_unregister) {
[
{
@ -124,6 +125,7 @@ describe Puppet::Type.type(:midonet_host_registry).provider(:midonet_api_caller)
}
]
}
let(:host_left_in_tunnelzone) {
[
{
@ -182,6 +184,7 @@ describe Puppet::Type.type(:midonet_host_registry).provider(:midonet_api_caller)
}
]
}
it 'should raise an exception' do
allow(provider).to receive(:call_get_tunnelzone).and_return(tzones)
allow(provider).to receive(:call_get_token).and_return('thisisafaketoken')
@ -210,6 +213,7 @@ describe Puppet::Type.type(:midonet_host_registry).provider(:midonet_api_caller)
}
]
}
it 'should not fail' do
allow(provider).to receive(:call_get_tunnelzone).and_return(tzones)
allow(provider).to receive(:call_get_host).and_return([])
@ -231,6 +235,7 @@ describe Puppet::Type.type(:midonet_host_registry).provider(:midonet_api_caller)
}
]
}
let(:hosts) {
[
{
@ -239,6 +244,7 @@ describe Puppet::Type.type(:midonet_host_registry).provider(:midonet_api_caller)
}
]
}
it 'should not fail' do
allow(provider).to receive(:call_get_tunnelzone).and_return(tzones)
allow(provider).to receive(:call_get_host).and_return(hosts)

@ -0,0 +1,174 @@
require 'spec_helper'
require 'puppet'
require 'puppet/type/midonet_gateway'
require 'facter'
describe Puppet::Type::type(:midonet_gateway) do
context 'on default values' do
let(:resource) do
Puppet::Type::type(:midonet_gateway).new(
:hostname => Facter['hostname'].value,
:midonet_api_url => 'http://controller:8080/midonet-api',
:username => 'admin',
:password => 'admin',
:interface => 'eth0',
:local_as => '64512',
:bgp_port => { 'port_address' => '198.51.100.2', 'net_prefix' => '198.51.100.0', 'net_length' => '30'},
:remote_peers => [ { 'as' => '64513', 'ip' => '198.51.100.1' },
{ 'as' => '64513', 'ip' => '203.0.113.1' } ],
:advertise_net => [ { 'net_prefix' => '192.0.2.0', 'net_length' => '24' } ])
end
it 'assign the default values' do
expect(resource[:username]).to eq 'admin'
expect(resource[:password]).to eq 'admin'
expect(resource[:tenant_name]).to eq 'admin'
expect(resource[:interface]).to eq 'eth0'
expect(resource[:router]).to eq 'MidoNet Provider Router'
end
end
context 'on invalid hostname' do
it do
expect {
Puppet::Type.type(:midonet_gateway).new(
:hostname => '_invalid_hostname.local',
:midonet_api_url => 'http://87.23.43.2:8080/midonet-api',
:username => 'admin',
:password => 'admin')
}.to raise_error(Puppet::ResourceError)
end
end
context 'on invalid api url' do
it do
expect {
Puppet::Type.type(:midonet_gateway).new(
:hostname => Facter['hostname'].value,
:midonet_api_url => '87.23.43.2:8080/midonet-api',
:username => 'admin',
:password => 'admin')
}.to raise_error(Puppet::ResourceError)
end
end
context 'on tenant_name valid value' do
let(:resource) do
Puppet::Type.type(:midonet_gateway).new(
:hostname => Facter['hostname'].value,
:midonet_api_url => 'http://87.23.43.2:8080/midonet-api',
:username => 'admin',
:password => 'admin',
:tenant_name => 'midokura')
end
it 'assign to it' do
expect(resource[:tenant_name]).to eq 'midokura'
end
end
context 'on valid interface name' do
let(:resource) do
Puppet::Type.type(:midonet_gateway).new(
:hostname => Facter['hostname'].value,
:midonet_api_url => 'http://87.23.43.2:8080/midonet-api',
:username => 'admin',
:password => 'admin',
:interface => 'eth0')
end
it 'assign to it' do
expect(resource[:interface]).to eq 'eth0'
end
end
context 'on valid local AS name' do
let(:resource) do
Puppet::Type.type(:midonet_gateway).new(
:hostname => Facter['hostname'].value,
:midonet_api_url => 'http://87.23.43.2:8080/midonet-api',
:username => 'admin',
:password => 'admin',
:local_as => '64512')
end
it 'assign to it' do
expect(resource[:local_as]).to eq '64512'
end
end
context 'on invalid local AS name' do
it do
expect {
Puppet::Type.type(:midonet_gateway).new(
:hostname => Facter['hostname'].value,
:midonet_api_url => 'http://87.23.43.2:8080/midonet-api',
:username => 'admin',
:password => 'admin',
:local_as => 'fake')
}.to raise_error(Puppet::ResourceError)
end
end
context 'on invalid BGP port' do
it do
expect {
Puppet::Type.type(:midonet_gateway).new(
:hostname => Facter['hostname'].value,
:midonet_api_url => 'http://87.23.43.2:8080/midonet-api',
:username => 'admin',
:password => 'admin',
:bgp_port => { 'port_address' => '_198.51.100.2',
'net_prefix' => '198.51.100.0',
'net_length' => '30' })
}.to raise_error(Puppet::ResourceError)
end
end
context 'on invalid remote BGP peers AS name and IP' do
it do
expect {
Puppet::Type.type(:midonet_gateway).new(
:hostname => Facter['hostname'].value,
:midonet_api_url => 'http://87.23.43.2:8080/midonet-api',
:username => 'admin',
:password => 'admin',
:remote_peers => [ { 'as' => 'fake',
'ip' => '_198.51.100.1' } ])
}.to raise_error(Puppet::ResourceError)
end
end
context 'on valid router name' do
let(:resource) do
Puppet::Type.type(:midonet_gateway).new(
:hostname => Facter['hostname'].value,
:midonet_api_url => 'http://87.23.43.2:8080/midonet-api',
:username => 'admin',
:password => 'admin',
:router => 'MidoNet Provider Router')
end
it 'assign to it' do
expect(resource[:router]).to eq 'MidoNet Provider Router'
end
end
context 'on invalid advertise network' do
it do
expect {
Puppet::Type.type(:midonet_gateway).new(
:hostname => Facter['hostname'].value,
:midonet_api_url => 'http://87.23.43.2:8080/midonet-api',
:username => 'admin',
:password => 'admin',
:advertise_net => [ { 'net_prefix' => '_192.0.2.0',
'net_length' => '24' } ] )
}.to raise_error(Puppet::ResourceError)
end
end
end