fuel-library/deployment/puppet/l23network/lib/puppet/parser/functions/generate_network_config.rb

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 :