create module l23network for config L2 and L3 network

This commit is contained in:
Sergey Vasilenko 2013-02-04 18:41:49 +04:00 committed by Gerrit Code Review
parent 3d509efbab
commit 751efeb6fe
23 changed files with 690 additions and 0 deletions

View File

@ -0,0 +1,53 @@
Puppet module for configuring L2 and L3 networks.
Based on open vSwitch and iproute2.
L2 network configuation
-----------------------
Current layout is:
bridges - A "Bridge" is basically the thing you plug ports / interfaces into.
ports - A Port is a interface you plug into the bridge (switch).
USAGE:
Place this directory at:
<your module directory of choice>/l23network
Then in your manifest you can either use the things as parameterized classes:
class {"l23network": }
l23network::l2::bridge{"br-mgmt": }
l23network::l2::port{"eth0": bridge => "br-mgmt"}
l23network::l2::port{"mmm0": bridge => "br-mgmt"}
l23network::l2::port{"mmm1": bridge => "br-mgmt"}
l23network::l2::bridge{"br-ex": }
l23network::l2::port{"eth0": bridge => "br-ex"}
l23network::l2::port{"eth1": bridge => "br-ex", ifname_order_prefix='ovs'}
l23network::l2::port{"eee0": bridge => "br-ex", skip_existing => true}
l23network::l2::port{"eee1": bridge => "br-ex", type=>'internal'}
You can define type for the port. Port type can be
'system', 'internal', 'tap', 'gre', 'ipsec_gre', 'capwap', 'patch', 'null'.
If you not define type for port (or define '') -- ovs-vsctl will have default behavior
(see http://openvswitch.org/cgi-bin/ovsman.cgi?page=utilities%2Fovs-vsctl.8).
You can use skip_existing option if you not want interrupt configuration during adding existing port or bridge.
L3 network configuation
-----------------------
l23network::l3::ifconfig {"some_name0": interface=>'eth0', ipaddr=>'192.168.0.1', netmask=>'255.255.255.0'}
l23network::l3::ifconfig {"some_name1": interface=>'br-ex', ipaddr=>'192.168.10.1', netmask=>'255.255.255.0', ifname_order_prefix='ovs'}
l23network::l3::ifconfig {"some_name2": interface=>'aaa0', ipaddr=>'192.168.10.1', netmask=>'255.255.255.0', ifname_order_prefix='zzz'}
Option 'ipaddr' can contains IP address, 'dhcp', or 'none' for up empty unaddressed interface.
Centos and Ubuntu at startup started and configure network interfaces in alphabetical order interface configuration file names. In example above we change configuration process order by ifname_order_prefix keyword. We will have this order:
ifcfg-eth0
ifcfg-ovs-br-ex
ifcfg-zzz-aaa0
And OS will configure interfaces br-ex and aaa0 after eth0
---
this module based on https://github.com/ekarlso/puppet-vswitch

View File

@ -0,0 +1,27 @@
def check_kern_module(mod)
mods = File.readlines("/proc/modules")
if mods.select {|x| x =~ mod}.length > 0
return true
else
return false
end
end
Facter.add('kern_module_ovs_loaded') do
case Facter.value('osfamily')
when /(?i)(debian)/
mod = /^openvswitch_mod\s+/
when /(?i)(redhat)/
mod = /^openvswitch\s+/
end
setcode do
check_kern_module(mod)
end
end
Facter.add('kern_module_bridge_loaded') do
setcode do
check_kern_module(/^bridge\s+/)
end
end

View File

@ -0,0 +1,24 @@
def get_def_route
addr = nil
File.open("/proc/net/route", "r") do |rff|
while (line = rff.gets)
rgx = line.match('^\s*(\S+)\s+00000000\s+([\dABCDEF]{8})\s+')
if rgx
vals = rgx.to_a[2]
addr = []
0.step(6, 2) do |i|
addr << vals.slice(i,2).hex
end
addr = addr.reverse.join('.')
break
end
end
end
return addr
end
Facter.add('default_route') do
setcode do
get_def_route()
end
end

View File

@ -0,0 +1,78 @@
# Fact: openvswitch ports
#
# Purpose: On any OS - return info about ovs ports for all bridges
#
# Resolution:
#
# Caveats:
require "facter"
require "set"
def vsctl_cmd
"/usr/bin/ovs-vsctl"
end
def ofctl_cmd
"/usr/bin/ovs-ofctl"
end
module OpenVSwitch
def self.exec(bin, cmd)
result = Facter::Util::Resolution.exec(bin + " " + cmd)
if result
result = result.split("\n")
end
return result
end
# vSwitch
def self.vsctl(cmd)
return exec(vsctl_cmd, cmd)
end
def self.list_br
return vsctl("list-br")
end
def self.list_ports(bridge)
return vsctl("list-ports " + bridge)
end
# OpenFlow
def self.ofctl(cmd)
return exec(ofctl_cmd, cmd)
end
def self.of_show(bridge="")
return ofctl("show " + bridge)
end
end
#Facter.add("openvswitch_module") do
# setcode do
# Facter.value(:kernel_modules).split(",").include? "openvswitch_mod"
# end
#end
if Facter.value(:kern_module_ovs_loaded) == true && File.exists?(vsctl_cmd)
bridges = OpenVSwitch.list_br || []
Facter.add("openvswitch_bridges") do
setcode do
bridges.join(",")
end
end
bridges.each do |bridge|
ports = OpenVSwitch.list_ports(bridge)
if ports
Facter.add("openvswitch_ports_#{bridge}") do
setcode do
ports.join(",")
end
end
end
end
end

View File

@ -0,0 +1,52 @@
Puppet::Type.type(:l2_ovs_bridge).provide(:ovs) do
optional_commands :vsctl => "/usr/bin/ovs-vsctl"
def exists?
vsctl("br-exists", @resource[:bridge])
rescue Puppet::ExecutionFailure
return false
end
def create
begin
vsctl('br-exists', @resource[:bridge])
if @resource[:skip_existing]
notice("Bridge '#{@resource[:bridge]}' already exists, skip creating.")
#external_ids = @resource[:external_ids] if @resource[:external_ids]
return true
else
raise ExecutionFailure, "Bridge '#{@resource[:bridge]}' already exists."
end
rescue Puppet::ExecutionFailure
# pass
notice("Bridge '#{@resource[:bridge]}' not exists, creating...")
end
vsctl('add-br', @resource[:bridge])
notice("bridge '#{@resource[:bridge]}' created.")
external_ids = @resource[:external_ids] if @resource[:external_ids]
end
def destroy
vsctl("del-br", @resource[:bridge])
end
def _split(string, splitter=",")
return Hash[string.split(splitter).map{|i| i.split("=")}]
end
def external_ids
result = vsctl("br-get-external-id", @resource[:bridge])
return result.split("\n").join(",")
end
def external_ids=(value)
old_ids = _split(external_ids)
new_ids = _split(value)
new_ids.each_pair do |k,v|
unless old_ids.has_key?(k)
vsctl("br-set-external-id", @resource[:bridge], k, v)
end
end
end
end

View File

@ -0,0 +1,31 @@
Puppet::Type.type(:l2_ovs_port).provide(:ovs) do
optional_commands :vsctl => "/usr/bin/ovs-vsctl"
def exists?
vsctl("list-ports", @resource[:bridge]).include? @resource[:interface]
end
def create
begin
vsctl('port-to-br', @resource[:interface])
if @resource[:skip_existing]
return true
else
raise ExecutionFailure, "Port '#{@resource[:interface]}' already exists."
end
rescue Puppet::ExecutionFailure
# pass
end
cmd = [@resource[:bridge], @resource[:interface]]
if @resource[:type] and @resource[:type].to_s != ''
tt = "type=" + @resource[:type].to_s
cmd += ['--', "set", "Interface", @resource[:interface], tt]
end
cmd = ["add-port"] + cmd
vsctl(cmd)
end
def destroy
vsctl("del-port", @resource[:bridge], @resource[:interface])
end
end

View File

@ -0,0 +1,26 @@
Puppet::Type.newtype(:l2_ovs_bridge) do
@doc = "Manage a Open vSwitch bridge (virtual switch)"
desc @doc
ensurable
newparam(:bridge) do
isnamevar
desc "The bridge to configure"
#
validate do |val|
if not val =~ /^[0-9A-Za-z\.\-\_]+$/
fail("Invalid bridge name: '#{val}'")
end
end
end
newparam(:skip_existing) do
defaultto(false)
desc "Allow skip existing bridge"
end
newproperty(:external_ids) do
desc "External IDs for the bridge"
end
end

View File

@ -0,0 +1,42 @@
Puppet::Type.newtype(:l2_ovs_port) do
@doc = "Manage a Open vSwitch port"
desc @doc
ensurable
newparam(:interface) do
isnamevar
desc "The interface to attach to the bridge"
#
validate do |val|
if not val =~ /^[0-9A-Za-z\.\-\_]+$/
fail("Invalid interface name: '#{val}'")
end
end
end
newparam(:type) do
newvalues('', :system, :internal, :tap, :gre, :ipsec_gre, :capwap, :patch, :null)
defaultto('')
desc "Ovs port type"
end
newparam(:skip_existing) do
defaultto(false)
desc "Allow skip existing port"
end
newparam(:bridge) do
desc "What bridge to use"
#
validate do |val|
if not val =~ /^[0-9A-Za-z\.\-\_]+$/
fail("Invalid bridge name: '#{val}'")
end
end
end
autorequire(:l2_ovs_bridge) do
[self[:bridge]]
end
end

View File

@ -0,0 +1,8 @@
# == Class: l23network
#
# Module for configuring network. Contains L2 and L3 modules.
# Requirements, packages and services.
#
class l23network {
class {'l23network::l2': }
}

View File

@ -0,0 +1,45 @@
# == Class: l23network::l2
#
# Module for configuring L2 network.
# Requirements, packages and services.
#
class l23network::l2 {
case $::osfamily {
/(?i)(debian)/: {
$service_name = 'openvswitch-switch'
$status_cmd = '/etc/init.d/openvswitch-switch status'
$ovs_packages = ['openvswitch-datapath-dkms', 'openvswitch-switch']
}
/(?i)(redhat)/: {
$service_name = 'openvswitch' #'ovs-vswitchd'
$status_cmd = '/etc/init.d/openvswitch status'
$ovs_packages = ['kmod-openvswitch', 'openvswitch']
}
/(?i)linux/: {
case $::operatingsystem {
/(?i)archlinux/: {
$service_name = 'openvswitch.service'
$status_cmd = 'systemctl status openvswitch'
$ovs_packages = ['aur/openvswitch']
}
default: {
fail("Unsupported OS: ${::osfamily}/${::operatingsystem}")
}
}
}
default: {
fail("Unsupported OS: ${::osfamily}/${::operatingsystem}")
}
}
package {$ovs_packages:
ensure => present,
before => Service['openvswitch-service'],
}
service {'openvswitch-service':
ensure => running,
name => $service_name,
enable => true,
hasstatus => true,
status => $status_cmd,
}
}

View File

@ -0,0 +1,33 @@
# == Define: l23network::l2::bridge
#
# Create open vSwitch brigde.
#
# === Parameters
#
# [*name*]
# Bridge name.
#
# [*skip_existing*]
# If brigde with this name already exists -- we ignore this fact and
# don't create bridge without generate error.
# Must be true or false.
#
# [*external_ids*]
# See open vSwitch documentation.
# http://openvswitch.org/cgi-bin/ovsman.cgi?page=utilities%2Fovs-vsctl.8
#
define l23network::l2::bridge (
$external_ids = '',
$ensure = present,
$skip_existing = false,
) {
if ! defined (L2_ovs_bridge[$name]) {
l2_ovs_bridge {$name:
ensure => $ensure,
external_ids => $external_ids,
skip_existing=> $skip_existing,
require => Service['openvswitch-service']
}
}
}

View File

@ -0,0 +1,40 @@
# == Define: l23network::l2::port
#
# Create open vSwitch port and add to the OVS bridge.
#
# === Parameters
#
# [*name*]
# Port name.
#
# [*bridge*]
# Bridge, that will contain this port.
#
# [*type*]
# Port type. Port type can be
# 'system', 'internal', 'tap', 'gre', 'ipsec_gre', 'capwap', 'patch', 'null'.
# If you not define type for port (or define '') -- ovs-vsctl will have
# default behavior while creating port.
# (see http://openvswitch.org/cgi-bin/ovsman.cgi?page=utilities%2Fovs-vsctl.8)
#
# [*skip_existing*]
# If this port already exists -- we ignore this fact and
# don't create it without generate error.
# Must be true or false.
#
define l23network::l2::port (
$bridge,
$type = '',
$ensure = present,
$skip_existing = false,
) {
if ! defined (L2_ovs_port[$name]) {
l2_ovs_port { $name :
ensure => $ensure,
bridge => $bridge,
type => $type,
skip_existing => $skip_existing,
require => Service['openvswitch-service']
}
}
}

View File

@ -0,0 +1,14 @@
# == Define: l23network::l3::clear_ip_from_interface
#
# Flush any IP addresses from interface
#
# === Parameters
#
# [*name*]
# Specify interface.
#
define l23network::l3::clear_ip_from_interface {
exec { "ip addr flush ${name}":
path => '/usr/bin:/usr/sbin:/bin:/sbin',
}
}

View File

@ -0,0 +1,53 @@
# == Define: l23network::l3::create_br_iface
#
# Creating L2 ovs bridge, cleaning IPs from interface and add IP address to this
# bridge
#
# === Parameters
#
# [*bridge*]
# Bridge name
#
# [*interface*]
# Interface, that will be added to the bridge.
#
# [*ipaddr*]
# IP address for port in bridge.
#
# [*netmask*]
# Network mask.
#
define l23network::l3::create_br_iface (
$interface,
$bridge,
$ipaddr,
$netmask = '',
$se = true,
$external_ids = '',
){
if ! $external_ids {
$ext_ids = "bridge-id=${bridge}"
}
#
l23network::l2::bridge {$bridge:
skip_existing => $se,
external_ids => $ext_ids,
}
l23network::l2::port {$interface:
bridge => $bridge,
skip_existing => $se,
require => l23network::l2::bridge[$bridge]
}
l23network::l3::ifconfig {$interface:
interface => $interface,
ipaddr => 'none',
require => l23network::l2::port[$interface],
}
l23network::l3::ifconfig {$bridge:
interface => $bridge,
ipaddr => $ipaddr,
netmask => $netmask,
ifname_order_prefix => 'ovs',
require => l23network::l3::ifconfig[$interface],
}
}

View File

@ -0,0 +1,116 @@
# == Define: l23network::l3::ifconfig
#
# Specify IP address for network interface and put interface to the UP state.
#
# === Parameters
#
# [*interface*]
# Specify interface.
#
# [*ipaddr*]
# IP address for interface. Can contains IP address, 'dhcp', or 'none'
# for up empty unaddressed interface.
#
# [*netmask*]
# Specify network mask.
#
# [*dhcp_nowait*]
# If you put 'true' to this option dhcp agent will be started in background.
# Puppet will not wait for obtain IP address and route.
#
# [*ifname_order_prefix*]
# Centos and Ubuntu at boot time Up and configure network interfaces in
# alphabetical order of interface configuration file names.
# This option helps You change this order at system startup.
#
define l23network::l3::ifconfig (
$interface,
$ipaddr,
$netmask = '255.255.255.0',
$dhcp_nowait = false,
$ifname_order_prefix = false
){
case $ipaddr {
'dhcp': { $method = 'dhcp' }
'none': { $method = 'manual' }
default: { $method = 'static' }
}
case $::osfamily {
'Debian': {
$if_files_dir = '/etc/network/interfaces.d'
$interfaces = '/etc/network/interfaces'
}
'RedHat': {
$if_files_dir = '/etc/sysconfig/network-scripts'
$interfaces = false
}
default: {
fail("Unsupported OS: ${::osfamily}/${::operatingsystem}")
}
}
$cmd_ifup = 'ifup'
$cmd_ifdn = 'ifdown'
$cmd_flush= 'ip addr flush'
if $ifname_order_prefix {
$interface_file= "${if_files_dir}/ifcfg-${ifname_order_prefix}-${interface}"
} else {
$interface_file= "${if_files_dir}/ifcfg-${interface}"
}
if $interfaces {
if ! defined(File[$interfaces]) {
file {$interfaces:
ensure => present,
content => template('l23network/interfaces.erb'),
}
}
File[$interfaces] -> File[$if_files_dir]
}
if ! defined(File[$if_files_dir]) {
file {$if_files_dir:
ensure => directory,
owner => 'root',
mode => '0755',
recurse => true,
}
}
file {$interface_file:
ensure => present,
owner => 'root',
mode => '0644',
content => template("l23network/ipconfig_${::osfamily}_${method}.erb"),
require => File[$if_files_dir],
}
# Downing interface
exec { "ifdn_${interface}":
command => "${cmd_ifdn} ${interface}",
path => '/usr/bin:/usr/sbin:/bin:/sbin',
onlyif => "ip link show ${interface}|grep ' ${interface}:'|grep -i up",
subscribe => File[$interface_file],
refreshonly => true,
}
# Cleaning interface
exec { "flush_${interface}":
command => "${cmd_flush} ${interface}",
path => '/usr/bin:/usr/sbin:/bin:/sbin',
subscribe => Exec["ifdn_${interface}"],
refreshonly => true,
}
# Upping interface
if $dhcp_nowait {
$w = '&'
} else {
$w = ''
}
exec { "ifup_${interface}":
command => "${cmd_ifup} ${interface} ${w}",
path => '/usr/bin:/usr/sbin:/bin:/sbin',
subscribe => Exec["flush_${interface}"],
refreshonly => true,
}
}

View File

@ -0,0 +1,23 @@
# == Define: l23network::l3::set_default_route_if_none
#
# add default route to the routing table if it not exists.
#
# === Parameters
#
# [*route*]
# Route that will be added. Using default_route fact if it's not specify.
#
# [*timeout*]
# Timeout before checking exists or not default route in routing table.
#
define l23network::l3::set_default_route_if_none (
$route = $::default_route,
$timeout = 10,
){
if $route {
exec { "ip route add default via ${route}":
path => '/usr/bin:/usr/sbin:/bin:/sbin',
unless => "sleep ${timeout} ; ip route list | grep default",
}
}
}

View File

@ -0,0 +1 @@
source /etc/network/interfaces.d/*

View File

@ -0,0 +1,2 @@
auto <%= interface %>
iface <%= interface %> inet dhcp

View File

@ -0,0 +1,4 @@
auto <%= interface %>
iface <%= interface %> inet manual
up ip l set <%= interface %> up
down ip l set <%= interface %> down

View File

@ -0,0 +1,4 @@
auto <%= interface %>
iface <%= interface %> inet static
address <%= ipaddr %>
netmask <%= netmask %>

View File

@ -0,0 +1,4 @@
DEVICE=<%= interface %>
BOOTPROTO=dhcp
ONBOOT=yes
USERCTL=no

View File

@ -0,0 +1,4 @@
DEVICE=<%= interface %>
BOOTPROTO=none
ONBOOT=yes
USERCTL=no

View File

@ -0,0 +1,6 @@
DEVICE=<%= interface %>
IPADDR=<%= ipaddr %>
NETMASK=<%= netmask %>
BOOTPROTO=none
ONBOOT=yes
USERCTL=no