Refactor virtual_ips task

* Use function instead of hardcoded values
* Use ocf_handlers for vrouter and vip manifests
* Add prefix option to pcmk wrapper
* Netmask_to_cidr should always return strings
* Fix naming of interfaces in vrouter OCF

Implements: blueprint templates-for-networking
Related-Blueprint: detach-components-from-controllers

Change-Id: I3527f2d85baac83b209c7af713466b593238555f
This commit is contained in:
Dmitry Ilyin 2015-07-13 19:42:36 +03:00
parent 21f304f3bb
commit cd3f8b2cb2
11 changed files with 284 additions and 310 deletions

View File

@ -20,117 +20,147 @@ define cluster::virtual_ip (
){
$vip_name = "vip__${key}"
#File<| title == 'ns-ipaddr2-ocf' |> -> Cs_resource[$vip_name]
cs_resource { $vip_name:
ensure => present,
primitive_class => 'ocf',
provided_by => 'fuel',
primitive_type => 'ns_IPaddr2',
parameters => {
'nic' => $vip[nic],
'base_veth' => $vip[base_veth],
'ns_veth' => $vip[ns_veth],
'ip' => $vip[ip],
'iflabel' => $vip[iflabel] ? {
undef => 'ka',
default => $vip[iflabel]
},
'cidr_netmask' => $vip[cidr_netmask] ? {
undef => '24',
default => $vip[cidr_netmask]
},
'ns' => $vip[namespace] ? {
undef => 'haproxy',
default => $vip[namespace]
},
'gateway' => $vip[gateway] ? {
undef => '',
default => $vip[gateway]
},
'gateway_metric' => $vip[gateway_metric] ? {
undef => '0',
default => $vip[gateway_metric]
},
'other_networks' => $vip[other_networks] ? {
undef => 'false', '' => 'false',
default => $vip[other_networks]
},
'bridge' => $vip[bridge] ? {
undef => 'false',
'' => 'false',
default => $vip[bridge]
},
'iptables_start_rules' => $vip[iptables_start_rules] ? {
undef => 'false',
'' => 'false',
default => "'${vip[iptables_start_rules]}'"
},
'iptables_stop_rules' => $vip[iptables_stop_rules] ? {
undef => 'false',
'' => 'false',
default => "'${vip[iptables_stop_rules]}'"
},
'iptables_comment' => $vip[iptables_comment] ? {
undef => 'false',
'' => 'false',
default => "'${vip[iptables_comment]}'"
},
'ns_iptables_start_rules' => $vip[ns_iptables_start_rules] ? {
undef => 'false',
'' => 'false',
default => "'${vip[ns_iptables_start_rules]}'"
},
'ns_iptables_stop_rules' => $vip[ns_iptables_stop_rules] ? {
undef => 'false',
'' => 'false',
default => "'${vip[ns_iptables_stop_rules]}'"
},
$parameters = {
'nic' => $vip['nic'],
'base_veth' => $vip['base_veth'],
'ns_veth' => $vip['ns_veth'],
'ip' => $vip['ip'],
'iflabel' => $vip['iflabel'] ? {
undef => 'ka',
default => $vip['iflabel']
},
metadata => {
'migration-threshold' => '3', # will be try start 3 times before migrate to another node
'failure-timeout' => '60', # forget any fails of starts after this timeout
'resource-stickiness' => '1'
'cidr_netmask' => $vip['cidr_netmask'] ? {
undef => '24',
default => $vip['cidr_netmask']
},
operations => {
'monitor' => {
'interval' => '3',
'timeout' => '30'
},
'start' => {
'timeout' => '30'
},
'stop' => {
'timeout' => '30'
},
'ns' => $vip['namespace'] ? {
undef => 'haproxy',
default => $vip['namespace']
},
'gateway' => $vip['gateway'] ? {
undef => '',
default => $vip['gateway']
},
'gateway_metric' => $vip['gateway_metric'] ? {
undef => '0',
default => $vip['gateway_metric']
},
'other_networks' => $vip['other_networks'] ? {
undef => 'false', '' => 'false',
default => $vip['other_networks']
},
'bridge' => $vip['bridge'] ? {
undef => 'false',
'' => 'false',
default => $vip['bridge']
},
'iptables_start_rules' => $vip['iptables_start_rules'] ? {
undef => 'false',
'' => 'false',
default => "'${vip['iptables_start_rules']}'",
},
'iptables_stop_rules' => $vip['iptables_stop_rules'] ? {
undef => 'false',
'' => 'false',
default => "'${vip['iptables_stop_rules']}'",
},
'iptables_comment' => $vip['iptables_comment'] ? {
undef => 'false',
'' => 'false',
default => "'${vip['iptables_comment']}'",
},
'ns_iptables_start_rules' => $vip['ns_iptables_start_rules'] ? {
undef => 'false',
'' => 'false',
default => "'${vip['ns_iptables_start_rules']}'",
},
'ns_iptables_stop_rules' => $vip['ns_iptables_stop_rules'] ? {
undef => 'false',
'' => 'false',
default => "'${vip['ns_iptables_stop_rules']}'",
},
}
$metadata = {
'migration-threshold' => '3', # will be try start 3 times before migrate to another node
'failure-timeout' => '60', # forget any fails of starts after this timeout
'resource-stickiness' => '1'
}
$operations = {
'monitor' => {
'interval' => '3',
'timeout' => '30',
},
'start' => {
'timeout' => '30',
},
'stop' => {
'timeout' => '30',
},
}
$primitive_type = 'ns_IPaddr2'
service { $vip_name:
ensure => 'running',
enable => true,
provider => 'pacemaker',
ensure => 'running',
enable => true,
}
Cs_resource[$vip_name] -> Service[$vip_name]
pacemaker_wrappers::service { $vip_name :
primitive_type => $primitive_type,
parameters => $parameters,
metadata => $metadata,
operations => $operations,
prefix => false,
}
if $vip[collocation] {
cs_rsc_colocation { "${vip_name}-with-vip__${vip[collocation]}":
ensure => present,
# I'am running before this other vip
# and this other vip cannot start without me running on this node
$colocation_before = $vip['colocation_before']
if $colocation_before {
$colocation_before_vip_name = "vip__${colocation_before}"
$colocation_before_constraint_name = "${colocation_before_vip_name}-with-${vip_name}"
cs_rsc_colocation { $colocation_before_constraint_name :
ensure => 'present',
score => 'INFINITY',
primitives => [
$vip_name,
"vip__${vip[collocation]}"
$colocation_before_vip_name,
$vip_name,
],
}
Service["vip__${vip[collocation]}"] -> Cs_rsc_colocation["${vip_name}-with-vip__${vip[collocation]}"]
Cs_resource <| title == $vip_name |> -> Cs_resource <| title == $colocation_before_vip_name |>
Service <| title == $vip_name |> -> Service <| title == $colocation_before_vip_name |>
Service <| title == $colocation_before_vip_name |> -> Cs_rsc_colocation[$colocation_before_constraint_name]
Service <| title == $vip_name |> -> Cs_rsc_colocation[$colocation_before_constraint_name]
}
# I'm running after this other vip
# and I cannot start without other vip running on this node
$colocation_after = $vip['colocation_after']
if $colocation_after {
$colocation_after_vip_name = "vip__${colocation_after}"
$colocation_after_constraint_name = "${vip_name}-with-${colocation_after_vip_name}"
cs_rsc_colocation { $colocation_after_constraint_name :
ensure => 'present',
score => 'INFINITY',
primitives => [
$vip_name,
$colocation_after_vip_name,
],
}
Cs_resource <| title == $colocation_after_vip_name |> -> Cs_resource <| title == $vip_name |>
Service <| title == $colocation_after_vip_name |> -> Service <| title == $vip_name |>
Service <| title == $colocation_after_vip_name |> -> Cs_rsc_colocation[$colocation_after_constraint_name]
Service <| title == $vip_name |> -> Cs_rsc_colocation[$colocation_after_constraint_name]
}
}
Class['corosync'] -> Cluster::Virtual_ip <||>
if defined(Corosync::Service['pacemaker']) {
Corosync::Service['pacemaker'] -> Cluster::Virtual_ip <||>
}

View File

@ -5,50 +5,52 @@
class cluster::vrouter_ocf (
$primary_controller,
$other_networks = false,
){
) {
$service_name = 'p_vrouter'
if $primary_controller {
cs_resource { $service_name:
ensure => present,
primitive_class => 'ocf',
provided_by => 'fuel',
primitive_type => 'ns_vrouter',
complex_type => 'clone',
ms_metadata => {
'interleave' => true,
$primitive_type = 'ns_vrouter'
$complex_type = 'clone'
$ms_metadata = {
'interleave' => true,
}
$metadata = {
'migration-threshold' => '3',
'failure-timeout' => '120',
}
$parameters = {
'ns' => 'vrouter',
'other_networks' => "'$other_networks'",
}
$operations = {
'monitor' => {
'interval' => '30',
'timeout' => '60'
},
metadata => {
'migration-threshold' => '3',
'failure-timeout' => '120',
'start' => {
'timeout' => '30'
},
parameters => {
'ns' => 'vrouter',
'other_networks' => "'$other_networks'",
},
operations => {
'monitor' => {
'interval' => '30',
'timeout' => '60'
},
'start' => {
'timeout' => '30'
},
'stop' => {
'timeout' => '60'
},
'stop' => {
'timeout' => '60'
},
}
Cs_resource[$service_name] -> Service[$service_name]
service { $service_name :
ensure => 'running',
enable => true,
hasstatus => true,
hasrestart => true,
}
pacemaker_wrappers::service { $service_name :
primitive_type => $primitive_type,
parameters => $parameters,
metadata => $metadata,
operations => $operations,
ms_metadata => $ms_metadata,
complex_type => $complex_type,
prefix => false,
}
}
service { $service_name:
ensure => 'running',
name => $service_name,
enable => true,
hasstatus => true,
hasrestart => true,
provider => 'pacemaker',
}
}

View File

@ -13,6 +13,6 @@ EOS
"given (#{arguments.size} for 1)")
end
return IPAddr.new(arguments[0]).to_i.to_s(2).count("1")
return IPAddr.new(arguments[0]).to_i.to_s(2).count("1").to_s
end
end

View File

@ -7,6 +7,9 @@ module L23network
def self.get_config(h)
@network_scheme_hash[h.to_sym]
end
def self.has_config?
@network_scheme_hash.is_a? Hash
end
end
def self.get_phys_dev_by_transformation(trans_name, host_name)

View File

@ -0,0 +1,98 @@
require 'puppetx/l23_network_scheme'
require 'puppetx/l23_hash_tools'
module Puppet::Parser::Functions
newfunction(:generate_vips) do |args|
network_metadata = function_hiera_hash ['network_metadata']
raise Puppet::ParseError, 'Missing or incorrect network_metadata in Hiera!' unless network_metadata.is_a? Hash
this_node_role = function_hiera ['role']
raise Puppet::ParseError, "Could not get this node's role from Hiera!" if this_node_role.empty?
default_node_roles = %w(controller primary-controller)
# prepare network configuration if it was not prepared
unless L23network::Scheme.has_config?
network_scheme = function_hiera_hash ['network_scheme']
raise Puppet::ParseError, 'Missing or incorrect network_scheme in Hiera!' unless network_scheme.is_a? Hash
function_prepare_network_config [ network_scheme ]
end
vips = network_metadata.fetch 'vips', {}
vips.each do |name, parameters|
network_role = parameters['network_role']
# skip vip without network role defined
next unless network_role
node_roles = parameters.fetch 'node_roles', default_node_roles
# skip vip if vip is not enables on thie node
next unless node_roles.include? this_node_role
# create a hash of vip parameters
vip = {}
short_name = name
short_name = short_name.gsub('management', 'mgmt')
short_name = short_name.gsub('public', 'pub')
short_name = short_name.gsub('vrouter', 'vr')
short_name = short_name.gsub('database', 'db')
short_name = short_name[0,10]
base_veth = "#{short_name}-base"
ns_veth = "#{short_name}-ns"
interface = function_get_network_role_property [network_role, 'interface']
netmask = function_get_network_role_property [network_role, 'netmask']
cidr_netmask = function_netmask_to_cidr [netmask]
vip['nic'] = interface
vip['base_veth'] = base_veth
vip['ns_veth'] = ns_veth
vip['ip'] = parameters['ipaddr']
vip['cidr_netmask'] = cidr_netmask
vip['bridge'] = interface
vip['gateway'] = parameters['gateway'] if parameters['gateway']
vip['gateway_metric'] = parameters['gateway_metric'] if parameters['gateway_metric']
vip['namespace'] = parameters['namespace'] if parameters['namespace']
vip['colocation_before'] = parameters['colocation_before'] if parameters['colocation_before']
vip['colocation_after'] = parameters['colocation_after'] if parameters['colocation_after']
# TODO: get_network_role_property should support gateway and metric
# gateway = function_get_network_role_property [network_role, 'gateway']
# gateway_metric = function_get_network_role_property [network_role, 'gateway_metric']
gateway = network_scheme.fetch('endpoints', {}).fetch(vip['nic'], {}).fetch('gateway', nil) unless vip['gateway']
if gateway
if name.include? 'vrouter'
gateway_metric = '0'
else
gateway_metric = '10'
end
end
# TODO: this should go from parameters instead of hardcoding
if name.include? 'vrouter_pub'
vip['ns_iptables_start_rules'] = "iptables -t nat -A POSTROUTING -o #{ns_veth} -j MASQUERADE"
vip['ns_iptables_stop_rules'] = "iptables -t nat -D POSTROUTING -o #{ns_veth} -j MASQUERADE"
# i'm running before the vip named 'vrouter' because vip 'vrouter' depends on me
vip['colocation_before'] = 'vrouter' if vips.keys.include? 'vrouter'
end
vip['gateway'] = gateway || 'none'
vip['gateway_metric'] = gateway_metric || '0'
# skip vip without mandatory data fields
unless vip['nic'] and vip['base_veth'] and vip['ns_veth'] and vip['ip']
warn "Skipping incorrect VIP '#{name}': '#{vip.inspect}'"
next
end
debug "Create VIP '#{name}': '#{vip.inspect}'"
function_create_resources [ 'cluster::virtual_ip', { name => { 'vip' => vip } } ]
end
end
end

View File

@ -51,8 +51,9 @@ if $operatingsystem == 'Ubuntu' {
},
}
# TODO: vip__vrouter_pub should not be hardcoded here
cs_colocation { 'conntrackd-with-public-vip':
primitives => [ 'master_p_conntrackd:Master', 'vip__public_vrouter' ],
primitives => [ 'master_p_conntrackd:Master', 'vip__vrouter_pub' ],
}
File['/etc/conntrackd/conntrackd.conf'] -> Cs_resource['p_conntrackd'] -> Service['p_conntrackd'] -> Cs_colocation['conntrackd-with-public-vip']

View File

@ -1,149 +1,3 @@
notice('MODULAR: virtual_ips.pp')
$internal_int = hiera('internal_int')
$public_int = hiera('public_int', undef)
$primary_controller_nodes = hiera('primary_controller_nodes', false)
$network_scheme = hiera('network_scheme', {})
$use_neutron = hiera('use_neutron', false)
$deploy_vrouter = hiera('deploy_vrouter', true)
if ( hiera('vip_management_cidr_netmask', false )){
$vip_management_cidr_netmask = hiera('vip_management_cidr_netmask')
} else {
$vip_management_cidr_netmask = netmask_to_cidr($primary_controller_nodes[0]['internal_netmask'])
}
if ( hiera('vip_public_cidr_netmask', false )){
$vip_public_cidr_netmask = hiera('vip_public_cidr_netmask')
} else {
$vip_public_cidr_netmask = netmask_to_cidr($primary_controller_nodes[0]['public_netmask'])
}
# todo:(sv): temporary commented. Will be uncommented while 'multiple-l2-network' feature re-implemented
# if $use_neutron {
# ip_mgmt_other_nets = join($network_scheme['endpoints']["$internal_int"]['other_nets'], ' ')
# }
$management_vip_data = {
namespace => 'haproxy',
nic => $internal_int,
base_veth => "${internal_int}-hapr",
ns_veth => "hapr-m",
ip => hiera('management_vip'),
cidr_netmask => $vip_management_cidr_netmask,
gateway => 'none',
gateway_metric => '0',
bridge => $network_scheme['roles']['management'],
other_networks => $vip_mgmt_other_nets,
with_ping => false,
ping_host_list => "",
}
cluster::virtual_ip { 'management' :
vip => $management_vip_data,
}
if $deploy_vrouter {
$management_vrouter_vip_data = {
namespace => 'vrouter',
nic => $internal_int,
base_veth => "${internal_int}-vrouter",
ns => 'vrouter',
ns_veth => 'vr-mgmt',
ip => hiera('management_vrouter_vip'),
cidr_netmask => $vip_management_cidr_netmask,
gateway => 'none',
gateway_metric => '0',
bridge => $network_scheme['roles']['management'],
tie_with_ping => false,
ping_host_list => "",
}
cluster::virtual_ip { 'management_vrouter' :
vip => $management_vrouter_vip_data,
}
$management_vips = ['management', 'management_vrouter']
} else {
$management_vips = ['management']
}
if $public_int {
# todo:(sv): temporary commented. Will be uncommented while 'multiple-l2-network' feature re-implemented
# if $use_neutron {
# vip_publ_other_nets = join($network_scheme['endpoints']["$public_int"]['other_nets'], ' ')
# }
$public_vip_data = {
namespace => 'haproxy',
nic => $public_int,
base_veth => "${public_int}-hapr",
ns_veth => 'hapr-p',
ip => hiera('public_vip'),
cidr_netmask => $vip_public_cidr_netmask,
gateway => $network_scheme['endpoints']['br-ex']['gateway'],
gateway_metric => '10',
bridge => $network_scheme['roles']['ex'],
other_networks => $vip_publ_other_nets,
}
cluster::virtual_ip { 'public' :
vip => $public_vip_data,
}
if $deploy_vrouter {
$public_vrouter_vip_data = {
namespace => 'vrouter',
nic => $public_int,
base_veth => "${public_int}-vrouter",
ns_veth => 'vr-ex',
ns => 'vrouter',
ip => hiera('public_vrouter_vip'),
cidr_netmask => $vip_public_cidr_netmask,
gateway => $network_scheme['endpoints']['br-ex']['gateway'],
gateway_metric => '0',
bridge => $network_scheme['roles']['ex'],
ns_iptables_start_rules => "iptables -t nat -A POSTROUTING -o vr-ex -j MASQUERADE",
ns_iptables_stop_rules => "iptables -t nat -D POSTROUTING -o vr-ex -j MASQUERADE",
collocation => 'management_vrouter',
}
cluster::virtual_ip { 'public_vrouter' :
vip => $public_vrouter_vip_data,
}
$public_vips = ['public_vip', 'public_vrouter']
} else {
$public_vips = ['public_vip']
}
$vips = concat($management_vips, $public_vips)
} else {
$vips = $management_vips
}
#file { 'ns-ipaddr2-ocf':
# path =>'/usr/lib/ocf/resource.d/fuel/ns_IPaddr2',
# mode => '0755',
# owner => 'root',
# group => 'root',
# source => 'puppet:///modules/cluster/ocf/ns_IPaddr2',
#}
# Some topologies might need to keep the vips on the same node during
# deploymenet. This would only need to be changed by hand.
$keep_vips_together = false
if $keep_vips_together {
cs_rsc_colocation { 'ha_vips':
ensure => present,
primitives => [prefix($vips, "vip__")],
}
Cluster::Virtual_ip[$vips] -> Cs_rsc_colocation['ha_vips']
}
generate_vips()

View File

@ -4,6 +4,7 @@ define pacemaker_wrappers::service (
$primitive_class = 'ocf',
$primitive_provider = 'fuel',
$primitive_type = undef,
$prefix = true,
$parameters = undef,
$operations = undef,
@ -22,7 +23,11 @@ define pacemaker_wrappers::service (
) {
$service_name = $title
$primitive_name = "p_${service_name}"
if $prefix {
$primitive_name = "p_${service_name}"
} else {
$primitive_name = $service_name
}
$ocf_script_name = "${service_name}-ocf-file"
$ocf_handler_name = "ocf_handler_${service_name}"

View File

@ -1,4 +1,4 @@
#!/bin/sh
#!/bin/bash
export PATH='/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin'
export OCF_ROOT='<%= @ocf_root_path %>'
export OCF_RA_VERSION_MAJOR='1'
@ -106,6 +106,17 @@ if [ "${ACTION}" = '' ]; then
ACTION='monitor'
fi
# alias status to monitor
if [ "${ACTION}" = 'status' ]; then
ACTION='monitor'
fi
# view defined OCF parameters
if [ "${ACTION}" = 'params' ]; then
env | grep 'OCF_'
exit 0
fi
if [ "${DEBUG}" = '1' ]; then
bash -x <%= @ocf_script_path %> "${ACTION}"
else

View File

@ -32,8 +32,8 @@ OCF_ROOT_default="/usr/lib/ocf"
OCF_RESKEY_ns_default="vrouter"
OCF_RESKEY_other_networks_default=false
OCF_RESKEY_host_interface_default="vrouter-host"
OCF_RESKEY_namespace_interface_default="vr-ns"
OCF_RESKEY_host_interface_default="vr-host-base"
OCF_RESKEY_namespace_interface_default="vr-host-ns"
OCF_RESKEY_host_ip_default="240.0.0.5"
OCF_RESKEY_namespace_ip_default="240.0.0.6"
OCF_RESKEY_network_mask_default="30"

View File

@ -3,35 +3,5 @@ require 'shared-examples'
manifest = 'virtual_ips/virtual_ips.pp'
describe manifest do
shared_examples 'catalog' do
interfaces = %w(public management public_vrouter management_vrouter)
vip_interfaces = interfaces.map { |interface| "vip__#{interface}" }
let (:interfaces) { interfaces }
let (:vip_interfaces) { vip_interfaces }
vip_interfaces.each do |interface|
it do
expect(subject).to contain_cs_resource(interface).with(
:ensure => 'present',
)
end
it do
expect(subject).to contain_service(interface).with(
:provider => 'pacemaker',
:ensure => 'running',
:enable => true,
)
end
end
it do
should contain_cs_rsc_colocation('vip__public_vrouter-with-vip__management_vrouter').with(
:primitives => %w(vip__public_vrouter vip__management_vrouter),
)
end
end
test_ubuntu_and_centos manifest
end