Last active
March 12, 2017 12:23
-
-
Save congto/510d3aa158e0098e386154b18e90b9a1 to your computer and use it in GitHub Desktop.
ns_IPaddr2_Modify
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[root@controller1 fuel]# cat ns_IPaddr2 | |
#!/bin/bash | |
####################################################################### | |
# Initialization: | |
: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat} | |
. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs | |
# Defaults | |
OCF_RESKEY_cidr_netmask_default="32" | |
OCF_RESKEY_base_veth_default="" # may be omited if OVS used | |
OCF_RESKEY_gateway_default="none" # can be "none", "link", IPaddr | |
OCF_RESKEY_gateway_metric_default=0 # can be "", or metric value | |
OCF_RESKEY_also_check_interfaces_default="" # can be "", or list of interfaces | |
OCF_RESKEY_other_networks_default="" # can be "", or list of networks in CIDR format | |
: ${HA_LOGTAG="ocf-ns_IPaddr2"} | |
: ${HA_LOGFACILITY="daemon"} | |
: ${OCF_RESKEY_cidr_netmask=${OCF_RESKEY_cidr_netmask_default}} | |
: ${OCF_RESKEY_base_veth=${OCF_RESKEY_base_veth_default}} | |
: ${OCF_RESKEY_gateway=${OCF_RESKEY_gateway_default}} | |
: ${OCF_RESKEY_gateway_metric=${OCF_RESKEY_gateway_metric_default}} | |
: ${OCF_RESKEY_also_check_interfaces=${OCF_RESKEY_also_check_interfaces_default}} | |
: ${OCF_RESKEY_other_networks=${OCF_RESKEY_other_networks_default}} | |
FAMILY='inet' | |
RUN_IN_NS="ip netns exec $OCF_RESKEY_ns " | |
SH="/bin/bash" | |
####################################################################### | |
####################################################################### | |
meta_data() { | |
cat <<END | |
<?xml version="1.0"?> | |
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd"> | |
<resource-agent name="IPaddr2"> | |
<version>1.0</version> | |
<longdesc lang="en"> | |
This Linux-specific resource manages IP address inside network namespace. | |
</longdesc> | |
<shortdesc lang="en">This Linux-specific resource manages IP address inside network namespace.</shortdesc> | |
<parameters> | |
<parameter name="bridge" required="1"> | |
<longdesc lang="en"> | |
Name of the bridge that has network namespace with VIP connected to it. | |
</longdesc> | |
<shortdesc lang="en">Name of the bridge.</shortdesc> | |
<content type="string" /> | |
</parameter> | |
<parameter name="ip" unique="1" required="1"> | |
<longdesc lang="en"> | |
The IPv4 address to be configured in dotted quad notation, for example | |
"192.168.1.1". | |
</longdesc> | |
<shortdesc lang="en">IPv4 address</shortdesc> | |
<content type="string" /> | |
</parameter> | |
<parameter name="cidr_netmask"> | |
<longdesc lang="en"> | |
The netmask for the interface in CIDR format | |
(e.g., 24 and not 255.255.255.0) | |
If unspecified, the script will also try to determine this from the | |
routing table. | |
</longdesc> | |
<shortdesc lang="en">CIDR netmask</shortdesc> | |
<content type="string" default=""/> | |
</parameter> | |
<parameter name="iflabel"> | |
<longdesc lang="en"> | |
You can specify an additional label for your IP address here. | |
This label is appended to your interface name. | |
A label can be specified in nic parameter but it is deprecated. | |
If a label is specified in nic name, this parameter has no effect. | |
</longdesc> | |
<shortdesc lang="en">Interface label</shortdesc> | |
<content type="string" default=""/> | |
</parameter> | |
<parameter name="ns" required="1"> | |
<longdesc lang="en"> | |
Name of network namespace.\n | |
Should be present. | |
</longdesc> | |
<shortdesc lang="en">Name of network namespace.</shortdesc> | |
<content type="string" /> | |
</parameter> | |
<parameter name="base_veth"> | |
<longdesc lang="en"> | |
Name of base system side veth pair tail.\n | |
Should be present. | |
</longdesc> | |
<shortdesc lang="en">Name of base system side veth pair tail.</shortdesc> | |
<content type="string" default="$OCF_RESKEY_base_veth_default"/> | |
</parameter> | |
<parameter name="ns_veth" required="1"> | |
<longdesc lang="en"> | |
Name of net.namespace side veth pair tail.\n | |
Should be present. | |
</longdesc> | |
<shortdesc lang="en">Name of net.namespace side veth pair tail.</shortdesc> | |
<content type="string"/> | |
</parameter> | |
<parameter name="gateway"> | |
<longdesc lang="en"> | |
Default route address.\n | |
Can be "", "link" or IP address. | |
</longdesc> | |
<shortdesc lang="en">Default route address.</shortdesc> | |
<content type="string" default="$OCF_RESKEY_gateway_default"/> | |
</parameter> | |
<parameter name="gateway_metric"> | |
<longdesc lang="en"> | |
Default route address.\n | |
Can be "", "link" or IP address. | |
</longdesc> | |
<shortdesc lang="en">Default route address.</shortdesc> | |
<content type="string" default="$OCF_RESKEY_gateway_metric_default"/> | |
</parameter> | |
<parameter name="ns_iptables_start_rules"> | |
<longdesc lang="en"> | |
Iptables rules that should be started along with IP in the namespace.\n | |
</longdesc> | |
<shortdesc lang="en">Iptables rules associated with IP start in ns.</shortdesc> | |
<content type="string" default=""/> | |
</parameter> | |
<parameter name="ns_iptables_stop_rules"> | |
<longdesc lang="en"> | |
Iptables rules that should be stopped along with IP in the namespace.\n | |
</longdesc> | |
<shortdesc lang="en">Iptables rules associated with IP stop in ns.</shortdesc> | |
<content type="string" default=""/> | |
</parameter> | |
<parameter name="iptables_comment"> | |
<longdesc lang="en"> | |
Iptables comment to associate with rules.\n | |
</longdesc> | |
<shortdesc lang="en">Iptables comment to associate with rules.</shortdesc> | |
<content type="string" default="something_rule_for_VIP"/> | |
</parameter> | |
<parameter name="also_check_interfaces"> | |
<longdesc lang="en"> | |
Network interfaces list (ex. NIC), that should be in UP state for monitor action returns succesful.\n | |
</longdesc> | |
<shortdesc lang="en">Network interfaces list (ex. NIC), that should be in UP state for monitor action returns succesful.</shortdesc> | |
<content type="string" default="$OCF_RESKEY_also_check_interfaces_default"/> | |
</parameter> | |
<parameter name="other_networks"> | |
<longdesc lang="en"> | |
Additional routes that should be added to this resource. Routes will be added via value ns_veth. Should be space separated list of networks in CIDR format. | |
</longdesc> | |
<shortdesc lang="en">List of addtional routes to add routes for.</shortdesc> | |
<content type="string" default="$OCF_RESKEY_other_networks_default"/> | |
</parameter> | |
</parameters> | |
<actions> | |
<action name="start" timeout="20s" /> | |
<action name="stop" timeout="20s" /> | |
<action name="status" depth="0" timeout="20s" interval="10s" /> | |
<action name="monitor" depth="0" timeout="20s" interval="10s" /> | |
<action name="meta-data" timeout="5s" /> | |
<action name="validate-all" timeout="20s" /> | |
</actions> | |
</resource-agent> | |
END | |
exit $OCF_SUCCESS | |
} | |
ip_validate() { | |
if [[ X`uname -s` != "XLinux" ]] ; then | |
ocf_log err "ns_IPaddr2 only supported Linux." | |
exit $OCF_ERR_INSTALLED | |
fi | |
if [ -z "$OCF_RESKEY_ip" ] ; then | |
ocf_log err "IP address not given" | |
exit $OCF_ERR_CONFIGURED | |
fi | |
if [ -z "$OCF_RESKEY_ns" ] ; then | |
ocf_log err "Network namespace not given" | |
exit $OCF_ERR_CONFIGURED | |
fi | |
if [ -z "$OCF_RESKEY_cidr_netmask" ] ; then | |
ocf_log err "CIDR Netmask not given" | |
exit $OCF_ERR_CONFIGURED | |
fi | |
if [ -z "$OCF_RESKEY_ns_veth" ] ; then | |
ocf_log err "NS veth tail name not given" | |
exit $OCF_ERR_CONFIGURED | |
fi | |
if ! ocf_is_decimal "$OCF_RESKEY_gateway_metric"; then | |
ocf_log err "Gateway_metric should be a positive digital value" | |
exit $OCF_ERR_CONFIGURED | |
fi | |
return $OCF_SUCCESS | |
} | |
# | |
# Find out which interfaces serve the given IP address and netmask. | |
# The arguments are an IP address and a netmask. | |
# Its output are interface names devided by spaces (e.g., "eth0 eth1"). | |
# | |
find_interface() { | |
local ipaddr="$1" | |
local netmask="$2" | |
[ -z "$netmask" ] || ipaddr="$ipaddr/$netmask" | |
# | |
# List interfaces but exclude FreeS/WAN ipsecN virtual interfaces | |
local iface="`ip -o -f inet addr show \ | |
| grep "\ $ipaddr" \ | |
| cut -d ' ' -f2 \ | |
| grep -v '^ipsec[[0-9]][[0-9]]*$'`" | |
local rc=$? | |
echo "$iface" | |
return $rc | |
} | |
find_interface_in_ns() { | |
local ns="$1" | |
local ipaddr="$2" | |
local netmask="$3" | |
[ -z "$netmask" ] || ipaddr="$ipaddr/$netmask" | |
# | |
# List interfaces but exclude FreeS/WAN ipsecN virtual interfaces | |
local iface=`ip netns exec $ns ip -o -f inet addr show \ | |
| grep "\ $ipaddr" \ | |
| cut -d ' ' -f2 \ | |
| grep -v '^ipsec[[0-9]][[0-9]]*$'` | |
local rc=$? | |
echo "$iface" | |
return $rc | |
} | |
setup_routes() { | |
local network | |
if [ ! -z "$OCF_RESKEY_other_networks" ] ; then | |
for network in ${OCF_RESKEY_other_networks} ; do | |
ocf_log debug "Adding route on the host system to ${network}: ${OCF_RESKEY_namespace_ip}" | |
ocf_run $RUN_IN_NS ip route add ${network} dev ${OCF_RESKEY_ns_veth} | |
done | |
fi | |
} | |
# add veth to bridge if not already added | |
add_to_bridge() { | |
local br="$1" | |
local veth="$2" | |
local ns_veth="$3" | |
local bridge_mtu=`cat /sys/class/net/${br}/mtu` | |
# check which bridge (OVS or LNX) used | |
if [[ -d /sys/class/net/${br}/brif ]] ; then | |
# LNX | |
if [[ ! -d /sys/class/net/${br}/brif/${veth} ]] ; then | |
# attach 1-st jack to an LNX bridge | |
ocf_run brctl addif $br $veth || return $OCF_ERR_GENERIC | |
fi | |
else | |
# OVS | |
ovs-vsctl list port $veth > /dev/null 2>&1 | |
if [[ $? != 0 ]] ; then | |
# attach 1-st jack to an OVS bridge | |
ocf_run ovs-vsctl --may-exist add-port $br $veth || return $OCF_ERR_GENERIC | |
fi | |
fi | |
# adjust MTU | |
ocf_run ip link set mtu $bridge_mtu dev $veth | |
ocf_run $RUN_IN_NS ip link set mtu $bridge_mtu dev $ns_veth | |
return $OCF_SUCCESS | |
} | |
remove_from_bridge() { | |
if [[ -d /sys/class/net/${OCF_RESKEY_bridge}/brif ]] ; then | |
# native linux bridges | |
if [[ -d /sys/class/net/${OCF_RESKEY_bridge}/brif/${OCF_RESKEY_base_veth} ]] ; then | |
ocf_run brctl delif $OCF_RESKEY_bridge $OCF_RESKEY_base_veth || return $OCF_ERR_GENERIC | |
else | |
ocf_log warn "Jack ${OCF_RESKEY_base_veth} not a member of ${OCF_RESKEY_bridge} yet." | |
fi | |
else | |
# OVS bridge | |
ocf_run ovs-vsctl del-port $OCF_RESKEY_bridge $OCF_RESKEY_base_veth || return $OCF_ERR_GENERIC | |
fi | |
return $OCF_SUCCESS | |
} | |
####################################################################### | |
check_ns() { | |
local ns=$(ip netns list | awk "/${OCF_RESKEY_ns}/ {print \$1}") | |
[[ "$ns" != "$OCF_RESKEY_ns" ]] && return $OCF_ERR_GENERIC | |
return $OCF_SUCCESS | |
} | |
get_ns() { | |
local rc | |
check_ns || ocf_run ip netns add $OCF_RESKEY_ns | |
ocf_run $RUN_IN_NS ip link set up dev lo || return $OCF_ERR_GENERIC | |
return $OCF_SUCCESS | |
} | |
get_or_create_veth_pair() { | |
local rc | |
local rc1 | |
# check tail of veth-pair in base system | |
ip link show $OCF_RESKEY_base_veth 2>&1 > /dev/null | |
rc=$? | |
if [[ $rc != 0 ]] ; then | |
# 1st jack not found, need to create pair and attach 2nd jack to the net.namespace | |
# create veth pair and put 2nd jack to the net.ns | |
ocf_run ip link add $OCF_RESKEY_base_veth type veth peer name $OCF_RESKEY_ns_veth | |
ocf_run ip link set dev $OCF_RESKEY_ns_veth netns $OCF_RESKEY_ns | |
ocf_run ip link set up dev $OCF_RESKEY_base_veth | |
ocf_run $RUN_IN_NS ip link set up dev $OCF_RESKEY_ns_veth | |
sleep 1 | |
# connect veth-pair to the bridge and adjust MTU | |
add_to_bridge $OCF_RESKEY_bridge $OCF_RESKEY_base_veth $OCF_RESKEY_ns_veth | |
fi | |
return $OCF_SUCCESS | |
} | |
check_interfaces_for_up_state() { | |
local interfaces=$(echo "$1" | tr " ,:;" "\n") | |
local rc=$OCF_SUCCESS | |
for i in $interfaces ; do | |
rv=$(cat /sys/class/net/$i/carrier) # can return non-zero error-code for administrative-downed interface | |
if [[ $? != 0 || $rv != "1" ]] ; then | |
rc=$OCF_NOT_RUNNING | |
break | |
fi | |
done | |
return $rc | |
} | |
ip_prepare() { | |
local rc | |
ip_validate | |
[[ $? != 0 ]] && return $OCF_ERR_GENERIC | |
# create or get existing network namespace | |
get_ns || return $OCF_ERR_GENERIC | |
# create or get existing pair of veth interfaces | |
get_or_create_veth_pair || return $OCF_ERR_GENERIC | |
# attach IP address inside network namespace | |
ocf_run $RUN_IN_NS ip addr replace "$OCF_RESKEY_ip/$OCF_RESKEY_cidr_netmask" dev $OCF_RESKEY_ns_veth | |
[[ $? != 0 ]] && return $OCF_ERR_GENERIC | |
# setup default routing in namespace if gateway given | |
if [[ "$OCF_RESKEY_gateway" == 'link' ]] ; then | |
ocf_run $RUN_IN_NS ip route replace default dev $OCF_RESKEY_ns_veth metric $OCF_RESKEY_gateway_metric | |
elif [[ "$OCF_RESKEY_gateway" == 'none' ]] ; then | |
echo "Setup default gateway -- do nothing." | |
else | |
ocf_run $RUN_IN_NS ip route replace default via $OCF_RESKEY_gateway metric $OCF_RESKEY_gateway_metric | |
fi | |
# Send Gratuitous ARP REQUEST packets to update all neighbours in a detached background process | |
ARGS="-U -c 32 -w 10 -I $OCF_RESKEY_ns_veth -q $OCF_RESKEY_ip" | |
$RUN_IN_NS arping $ARGS 2>&1 > /dev/null & | |
# Send Gratuitous ARP REPLY packets to update all neighbours in a detached background process | |
ARGS="-A -c 32 -w 10 -I $OCF_RESKEY_ns_veth -q $OCF_RESKEY_ip" | |
$RUN_IN_NS arping $ARGS 2>&1 > /dev/null & | |
return $OCF_SUCCESS | |
} | |
iptables_start() { | |
local ns_iptables_rules | |
local rule | |
# setup iptables rules if given | |
if [[ "$OCF_RESKEY_ns_iptables_start_rules" != "false" ]] ; then | |
IFS=';' read -a ns_iptables_rules <<< "$OCF_RESKEY_ns_iptables_start_rules" | |
for rule in "${ns_iptables_rules[@]}" ; do | |
ocf_run $RUN_IN_NS $rule | |
done | |
fi | |
setup_routes | |
return $OCF_SUCCESS | |
} | |
iptables_stop() { | |
local ns_iptables_rules | |
local rule | |
# remove iptables rules if given | |
if [[ $OCF_RESKEY_ns_iptables_stop_rules != "false" ]] ; then | |
IFS=';' read -a ns_iptables_rules <<< "$OCF_RESKEY_ns_iptables_stop_rules" | |
for rule in "${ns_iptables_rules[@]}" ; do | |
ocf_run $RUN_IN_NS $rule | |
done | |
fi | |
return $OCF_SUCCESS | |
} | |
ip_start() { | |
check_interfaces_for_up_state "$OCF_RESKEY_bridge:$OCF_RESKEY_also_check_interfaces" || return $OCF_ERR_GENERIC | |
ip_prepare | |
rc=$? | |
if [[ $rc != $OCF_SUCCESS ]] ; then | |
# cleanun ns | |
ip_stop | |
rc=$OCF_ERR_GENERIC | |
else | |
iptables_start | |
fi | |
return $rc | |
} | |
ip_stop() { | |
local rc | |
ip_validate | |
if [ -n "$OCF_RESKEY_bridge" ] ; then | |
remove_from_bridge | |
fi | |
# destroy veth-pair in base system | |
ocf_run ip link show $OCF_RESKEY_base_veth | |
rc=$? | |
if [[ $rc == 0 ]] ; then | |
ocf_run ip link set down dev $OCF_RESKEY_base_veth && | |
sleep 1 && # prevent race | |
ocf_run ip link del dev $OCF_RESKEY_base_veth | |
rc=$? | |
else | |
rc=0 | |
fi | |
if [[ $rc == 0 ]] ; then | |
rc=$OCF_SUCCESS # it means stop was success | |
iptables_stop | |
else | |
rc=$OCF_ERR_GENERIC | |
fi | |
return $rc | |
} | |
ip_monitor() { | |
local rc | |
ip_validate | |
check_ns || return $OCF_NOT_RUNNING | |
local iface=$(find_interface_in_ns $OCF_RESKEY_ns $OCF_RESKEY_ip $OCF_RESKEY_cidr_netmask) | |
[ -z "$iface" ] && return $OCF_NOT_RUNNING | |
check_interfaces_for_up_state "$OCF_RESKEY_bridge:$OCF_RESKEY_also_check_interfaces" || return $OCF_NOT_RUNNING | |
# use arping here, because no IP from VIP network allowed on host system | |
ocf_run arping -c 10 -w 2 -I $OCF_RESKEY_bridge -q $OCF_RESKEY_ip 2>&1 > /dev/null & | |
# Send Gratuitous ARP REQUEST packets to update all neighbours in a detached background process | |
ARGS="-U -c 5 -w 2 -I $OCF_RESKEY_ns_veth -q $OCF_RESKEY_ip" | |
$RUN_IN_NS arping $ARGS 2>&1 > /dev/null & | |
# Send Gratuitous ARP REPLY packets to update all neighbours in a detached background process | |
ARGS="-A -c 5 -w 2 -I $OCF_RESKEY_ns_veth -q $OCF_RESKEY_ip" | |
$RUN_IN_NS arping $ARGS 2>&1 > /dev/null & | |
return $OCF_SUCCESS | |
} | |
ip_usage() { | |
cat <<END | |
usage: $0 {start|stop|status|monitor|validate-all|meta-data} | |
Expects to have a fully populated OCF RA-compliant environment set. | |
END | |
} | |
## main | |
rc=$OCF_SUCCESS | |
case $__OCF_ACTION in | |
meta-data) | |
meta_data | |
exit $OCF_SUCCESS | |
;; | |
usage|help) | |
ip_usage | |
exit $OCF_SUCCESS | |
;; | |
start) | |
ip_start | |
rc=$? | |
;; | |
stop) | |
ip_stop | |
rc=$? | |
;; | |
monitor) | |
ip_monitor | |
rc=$? | |
;; | |
validate-all) | |
;; | |
*) | |
ip_usage | |
exit $OCF_ERR_UNIMPLEMENTED | |
;; | |
esac | |
exit $rc | |
# vi:sw=4:ts=8: |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment