335 lines
13 KiB
Ruby
335 lines
13 KiB
Ruby
require 'ipaddr'
|
|
require 'forwardable'
|
|
require 'puppet/parser'
|
|
require 'puppet/parser/templatewrapper'
|
|
require 'puppet/resource/type_collection_helper'
|
|
require 'puppet/util/methodhelper'
|
|
|
|
begin
|
|
require 'puppet/parser/functions/lib/l23network_scheme.rb'
|
|
rescue LoadError => e
|
|
# puppet apply does not add module lib directories to the $LOAD_PATH (See
|
|
# #4248). It should (in the future) but for the time being we need to be
|
|
# defensive which is what this rescue block is doing.
|
|
rb_file = File.join(File.dirname(__FILE__),'lib','l23network_scheme.rb')
|
|
load rb_file if File.exists?(rb_file) or raise e
|
|
end
|
|
|
|
|
|
|
|
module L23network
|
|
def self.sanitize_transformation(trans)
|
|
action = trans[:action].downcase()
|
|
# Setup defaults
|
|
rv = case action
|
|
when "add-br" then {
|
|
:name => nil,
|
|
#:stp_enable => true,
|
|
:skip_existing => true
|
|
}
|
|
when "add-port" then {
|
|
:name => nil,
|
|
:bridge => nil,
|
|
#:type => "internal",
|
|
:tag => 0,
|
|
:trunks => [],
|
|
:port_properties => [],
|
|
:interface_properties => [],
|
|
:skip_existing => true
|
|
}
|
|
when "add-bond" then {
|
|
:name => nil,
|
|
:bridge => nil,
|
|
:interfaces => [],
|
|
:tag => 0,
|
|
:trunks => [],
|
|
:properties => [],
|
|
#:port_properties => [],
|
|
#:interface_properties => [],
|
|
:skip_existing => true
|
|
}
|
|
when "add-patch" then {
|
|
:name => "unnamed", # calculated later
|
|
:peers => [nil, nil],
|
|
:bridges => [],
|
|
:tags => [0, 0],
|
|
:trunks => [],
|
|
}
|
|
else
|
|
raise(Puppet::ParseError, "Unknown transformation: '#{action}'.")
|
|
end
|
|
# replace defaults to real parameters
|
|
rv[:action] = action
|
|
rv.each do |k,v|
|
|
if trans[k]
|
|
rv[k] = trans[k]
|
|
end
|
|
end
|
|
# Check for incorrect parameters
|
|
if not rv[:name].is_a? String
|
|
raise(Puppet::ParseError, "Unnamed transformation: '#{action}'.")
|
|
end
|
|
name = rv[:name]
|
|
if not rv[:bridge].is_a? String and !["add-patch", "add-br"].index(action)
|
|
raise(Puppet::ParseError, "Undefined bridge for transformation '#{action}' with name '#{name}'.")
|
|
end
|
|
if action == "add-patch"
|
|
if not rv[:bridges].is_a? Array and rv[:bridges].size() != 2
|
|
raise(Puppet::ParseError, "Transformation patch have wrong 'bridges' parameter.")
|
|
end
|
|
name = "patch__#{rv[:bridges][0]}__#{rv[:bridges][1]}"
|
|
if not rv[:peers].is_a? Array and rv[:peers].size() != 2
|
|
raise(Puppet::ParseError, "Transformation patch '#{name}' have wrong 'peers' parameter.")
|
|
end
|
|
rv[:name] = name
|
|
end
|
|
if action == "add-bond"
|
|
if not rv[:interfaces].is_a? Array or rv[:interfaces].size() != 2
|
|
raise(Puppet::ParseError, "Transformation bond '#{name}' have wrong 'interfaces' parameter.")
|
|
end
|
|
# rv[:interfaces].each do |i|
|
|
# if
|
|
# end
|
|
end
|
|
return rv
|
|
end
|
|
end
|
|
|
|
Puppet::Parser::Functions::newfunction(:generate_network_config, :type => :rvalue, :doc => <<-EOS
|
|
This function get Hash of network interfaces and endpoints configuration
|
|
and realized it.
|
|
|
|
EOS
|
|
) do |argv|
|
|
|
|
def default_netmask()
|
|
"/24"
|
|
end
|
|
|
|
def create_endpoint()
|
|
{
|
|
:properties => {},
|
|
:IP => []
|
|
}
|
|
end
|
|
|
|
if argv.size != 0
|
|
raise(Puppet::ParseError, "generate_network_config(): Wrong number of arguments.")
|
|
end
|
|
|
|
config_hash = L23network::Scheme.get_config(lookupvar('l3_fqdn_hostname'))
|
|
if config_hash.nil?
|
|
raise(Puppet::ParseError, "get_network_role_property(...): You must call prepare_network_config(...) first!")
|
|
end
|
|
|
|
Puppet.debug "stage1@generate_network_config:config_hash: #{config_hash.inspect}"
|
|
|
|
# define internal puppet parameters for creating resources
|
|
res_factory = {
|
|
:br => { :name_of_resource => 'l23network::l2::bridge' },
|
|
:port => { :name_of_resource => 'l23network::l2::port' },
|
|
:bond => { :name_of_resource => 'l23network::l2::bond' },
|
|
:patch => { :name_of_resource => 'l23network::l2::patch' },
|
|
:ifconfig=> { :name_of_resource => 'l23network::l3::ifconfig' }
|
|
}
|
|
res_factory.each do |k, v|
|
|
if v[:name_of_resource].index('::')
|
|
# operate by Define
|
|
res_factory[k][:resource] = lookuptype(v[:name_of_resource].downcase()) # may be find_definition(k.downcase())
|
|
res_factory[k][:type_of_resource] = :define
|
|
else
|
|
# operate by custom Type
|
|
res_factory[k][:resource] = Puppet::Type.type(v[:name_of_resource].to_sym())
|
|
res_factory[k][:type_of_resource] = :type
|
|
end
|
|
end
|
|
|
|
Puppet.debug "stage2@generate_network_config:res_factory: #{res_factory.inspect}"
|
|
|
|
# collect interfaces and endpoints
|
|
endpoints = {}
|
|
born_ports = []
|
|
config_hash[:interfaces].each do |int_name, int_properties|
|
|
int_name = int_name.to_sym()
|
|
endpoints[int_name] = create_endpoint()
|
|
born_ports.insert(-1, int_name)
|
|
end
|
|
|
|
Puppet.debug "stage3@generate_network_config:endpoints: #{endpoints.inspect}"
|
|
|
|
config_hash[:endpoints].each do |e_name, e_properties|
|
|
e_name = e_name.to_sym()
|
|
if not endpoints[e_name]
|
|
endpoints[e_name] = create_endpoint()
|
|
end
|
|
e_properties.each do |k,v|
|
|
if k.to_sym() == :IP
|
|
if !(v.is_a?(Array) || ['none','dhcp',nil].include?(v))
|
|
raise(Puppet::ParseError, "generate_network_config(): IP field for endpoint '#{e_name}' must be array of IP addresses, 'dhcp' or 'none'.")
|
|
elsif ['none','dhcp',nil].include?(v)
|
|
endpoints[e_name][:IP].insert(-1, v ? v : 'none')
|
|
else
|
|
v.each do |ip|
|
|
begin
|
|
iip = IPAddr.new(ip)
|
|
endpoints[e_name][:IP].insert(-1, ip)
|
|
rescue
|
|
raise(Puppet::ParseError, "generate_network_config(): IP address '#{ip}' for endpoint '#{e_name}' wrong!.")
|
|
end
|
|
end
|
|
end
|
|
else
|
|
endpoints[e_name][:properties][k.to_sym()] = v
|
|
end
|
|
end
|
|
end
|
|
|
|
Puppet.debug "stage4@generate_network_config:endpoints: #{endpoints.inspect}"
|
|
|
|
# execute transformations
|
|
# todo: if provider="lnx" execute transformations for LNX bridges
|
|
transformation_success = []
|
|
previous = nil
|
|
config_hash[:transformations].each do |t|
|
|
action = t[:action].strip()
|
|
if action.start_with?('add-')
|
|
action = t[:action][4..-1].to_sym()
|
|
else
|
|
action = t[:action].to_sym()
|
|
end
|
|
|
|
Puppet.debug "stage5@generate_network_config:action: #{action.inspect}"
|
|
|
|
trans = L23network.sanitize_transformation(t)
|
|
resource = res_factory[action][:resource]
|
|
p_resource = Puppet::Parser::Resource.new(
|
|
res_factory[action][:name_of_resource],
|
|
trans[:name],
|
|
:scope => self,
|
|
:source => resource
|
|
)
|
|
|
|
Puppet.debug "stage6@generate_network_config:p_resource: #{p_resource.inspect}"
|
|
|
|
# setup trunks and vlan_splinters for phys.NIC
|
|
if (action == :port) and config_hash[:interfaces][trans[:name].to_sym] and # does adding phys.interface?
|
|
config_hash[:interfaces][trans[:name].to_sym][:L2] and # does this interface have L2 section
|
|
config_hash[:interfaces][trans[:name].to_sym][:L2][:trunks] and # does this interface have TRUNKS section
|
|
config_hash[:interfaces][trans[:name].to_sym][:L2][:trunks].is_a?(Array) and
|
|
config_hash[:interfaces][trans[:name].to_sym][:L2][:trunks].size() > 0 # does trunks section non empty?
|
|
Puppet.debug("Configure trunks and vlan_splinters for #{trans[:name]} (value is '#{config_hash[:interfaces][trans[:name].to_sym][:L2][:vlan_splinters]}')")
|
|
_do_trunks = true
|
|
if config_hash[:interfaces][trans[:name].to_sym][:L2][:vlan_splinters]
|
|
if config_hash[:interfaces][trans[:name].to_sym][:L2][:vlan_splinters] == 'on'
|
|
trans[:vlan_splinters] = true
|
|
elsif config_hash[:interfaces][trans[:name].to_sym][:L2][:vlan_splinters] == 'auto'
|
|
sp_nics = lookupvar('l2_ovs_vlan_splinters_need_for')
|
|
Puppet.debug("l2_ovs_vlan_splinters_need_for: #{sp_nics}")
|
|
if sp_nics and sp_nics != :undefined and sp_nics.split(',').index(trans[:name].to_s)
|
|
Puppet.debug("enable vlan_splinters for: #{trans[:name].to_s}")
|
|
trans[:vlan_splinters] = true
|
|
else
|
|
trans[:vlan_splinters] = false
|
|
if trans[:trunks] and trans[:trunks].size() >0
|
|
Puppet.debug("disable vlan_splinters for: #{trans[:name].to_s}. Trunks will be set to '#{trans[:trunks].join(',')}'")
|
|
config_hash[:interfaces][trans[:name].to_sym][:L2][:trunks] = []
|
|
else
|
|
Puppet.debug("disable vlan_splinters for: #{trans[:name].to_s}. Trunks for this interface also disabled.")
|
|
_do_trunks = false
|
|
end
|
|
end
|
|
else
|
|
trans[:vlan_splinters] = false
|
|
end
|
|
else
|
|
trans[:vlan_splinters] = false
|
|
end
|
|
# add trunks list to the interface if it given
|
|
if _do_trunks
|
|
_trunks = [0] + trans[:trunks] + config_hash[:interfaces][trans[:name].to_sym][:L2][:trunks] # zero for pass untagged traffic
|
|
_trunks.sort!().uniq!()
|
|
trans[:trunks] = _trunks
|
|
end
|
|
Puppet.debug("Configure trunks and vlan_splinters for #{trans[:name]} done.")
|
|
end
|
|
|
|
trans.select{|k,v| k != :action}.each do |k,v|
|
|
p_resource.set_parameter(k,v)
|
|
end
|
|
|
|
Puppet.debug "stage7@generate_network_config:p_resource: #{p_resource.inspect}"
|
|
|
|
p_resource.set_parameter(:require, [previous]) if previous
|
|
resource.instantiate_resource(self, p_resource)
|
|
compiler.add_resource(self, p_resource)
|
|
transformation_success.insert(-1, "#{t[:action].strip()}(#{trans[:name]})")
|
|
born_ports.insert(-1, trans[:name].to_sym()) if action != :patch
|
|
previous = p_resource.to_s
|
|
end
|
|
|
|
# check for all in endpoints are in interfaces or born by transformation
|
|
config_hash[:endpoints].each do |e_name, e_properties|
|
|
if not born_ports.index(e_name.to_sym())
|
|
raise(Puppet::ParseError, "generate_network_config(): Endpoint '#{e_name}' not found in interfaces or transformations result.")
|
|
end
|
|
end
|
|
# execute interfaces and endpoints
|
|
# may be in future we will move interfaces before transformations
|
|
endpoints.each do |endpoint_name, endpoint_body|
|
|
# create resource
|
|
resource = res_factory[:ifconfig][:resource]
|
|
p_resource = Puppet::Parser::Resource.new(
|
|
res_factory[:ifconfig][:name_of_resource],
|
|
endpoint_name,
|
|
:scope => self,
|
|
:source => resource
|
|
)
|
|
|
|
Puppet.debug "stage8@generate_network_config:p_resource: #{p_resource.inspect}"
|
|
|
|
p_resource.set_parameter(:interface, endpoint_name)
|
|
|
|
Puppet.debug "stage9@generate_network_config:p_resource: #{p_resource.inspect}"
|
|
|
|
# set ipaddresses
|
|
if endpoint_body[:IP].empty?
|
|
p_resource.set_parameter(:ipaddr, 'none')
|
|
Puppet.debug "stage10@generate_network_config:p_resource: #{p_resource.inspect}"
|
|
elsif ['none','dhcp'].index(endpoint_body[:IP][0])
|
|
p_resource.set_parameter(:ipaddr, endpoint_body[:IP][0])
|
|
Puppet.debug "stage11@generate_network_config:p_resource: #{p_resource.inspect}"
|
|
else
|
|
ipaddrs = []
|
|
endpoint_body[:IP].each do |i|
|
|
if i =~ /\/\d+$/
|
|
ipaddrs.insert(-1, i)
|
|
else
|
|
ipaddrs.insert(-1, "#{i}#{default_netmask()}")
|
|
end
|
|
end
|
|
p_resource.set_parameter(:ipaddr, ipaddrs)
|
|
Puppet.debug "stage12@generate_network_config:p_resource: #{p_resource.inspect}"
|
|
end
|
|
#set another (see L23network::l3::ifconfig DOC) parametres
|
|
endpoint_body[:properties].each do |k,v|
|
|
p_resource.set_parameter(k,v)
|
|
end
|
|
|
|
Puppet.debug "stage13@generate_network_config:p_resource: #{p_resource.inspect}"
|
|
|
|
p_resource.set_parameter(:require, [previous]) if previous
|
|
resource.instantiate_resource(self, p_resource)
|
|
compiler.add_resource(self, p_resource)
|
|
transformation_success.insert(-1, "endpoint(#{endpoint_name})")
|
|
|
|
Puppet.debug "stage14@generate_network_config:transformation_success: #{transformation_success.inspect}"
|
|
|
|
previous = p_resource.to_s
|
|
end
|
|
|
|
Puppet.debug "stage15@generate_network_config:transformation_success: #{transformation_success.inspect}"
|
|
|
|
return transformation_success.join(" -> ")
|
|
end
|
|
# vim: set ts=2 sw=2 et :
|