summaryrefslogtreecommitdiffstats
path: root/heartbeat/aliyun-vpc-move-ip
diff options
context:
space:
mode:
Diffstat (limited to '')
-rwxr-xr-xheartbeat/aliyun-vpc-move-ip378
1 files changed, 378 insertions, 0 deletions
diff --git a/heartbeat/aliyun-vpc-move-ip b/heartbeat/aliyun-vpc-move-ip
new file mode 100755
index 0000000..1a3a1a0
--- /dev/null
+++ b/heartbeat/aliyun-vpc-move-ip
@@ -0,0 +1,378 @@
+#!/bin/sh
+#
+# OCF resource agent to move an IP address within a VPC in the Aliyun
+# Based on code of Markus Guertler (GitHub AWS-VPC-move-IP)
+# Based on code of Adam Gandelman (GitHub ec2-resource-agents/elasticip)
+#
+
+#######################################################################
+# Initialization:
+: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat}
+. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs
+
+# Parameter defaults
+
+OCF_RESKEY_address_default=""
+OCF_RESKEY_routing_table_default=""
+OCF_RESKEY_interface_default="eth0"
+OCF_RESKEY_profile_default="default"
+OCF_RESKEY_endpoint_default="vpc.aliyuncs.com"
+OCF_RESKEY_aliyuncli_default="detect"
+
+
+: ${OCF_RESKEY_address=${OCF_RESKEY_address_default}}
+: ${OCF_RESKEY_routing_table=${OCF_RESKEY_routing_table_default}}
+: ${OCF_RESKEY_interface=${OCF_RESKEY_interface_default}}
+: ${OCF_RESKEY_profile=${OCF_RESKEY_profile_default}}
+: ${OCF_RESKEY_endpoint=${OCF_RESKEY_endpoint_default}}
+: ${OCF_RESKEY_aliyuncli=${OCF_RESKEY_aliyuncli_default}}
+
+#######################################################################
+
+# aliyun cli doesnt work without HOME parameter
+export HOME="/root"
+
+USAGE="usage: $0 {start|stop|status|meta-data}";
+
+if [ "${OCF_RESKEY_aliyuncli}" = "detect" ]; then
+ OCF_RESKEY_aliyuncli="$(which aliyuncli 2> /dev/null || which aliyun 2> /dev/null)"
+fi
+
+if [ "${OCF_RESKEY_aliyuncli##*/}" = 'aliyuncli' ]; then
+ OUTPUT="text"
+ EXECUTING='{ print $3 }'
+ IFS_=" "
+ ENDPOINT=""
+elif [ "${OCF_RESKEY_aliyuncli##*/}" = 'aliyun' ]; then
+ OUTPUT="table cols=InstanceId,DestinationCidrBlock rows=RouteTables.RouteTable[].RouteEntrys.RouteEntry[]"
+ EXECUTING='{ gsub (" ", "", $0); print $1 }'
+ IFS_="|"
+ ENDPOINT="--endpoint $OCF_RESKEY_endpoint"
+fi
+###############################################################################
+
+
+###############################################################################
+#
+# Functions
+#
+###############################################################################
+
+request_create_route_entry() {
+ cmd="${OCF_RESKEY_aliyuncli} vpc CreateRouteEntry --RouteTableId $OCF_RESKEY_routing_table --DestinationCidrBlock ${OCF_RESKEY_address}/32 --NextHopId $ECS_INSTANCE_ID --NextHopType Instance ${ENDPOINT}"
+ ocf_log debug "executing command: $cmd"
+ res=$($cmd 2>&1)
+ rc=$?
+ if [ $rc -eq 0 ]
+ then
+ ocf_log debug "result: $res; rc: $rc"
+ else
+ ocf_log err "result: $res; cmd: $cmd; rc: $rc"
+ fi
+ return $rc
+}
+
+request_delete_route_entry() {
+ cmd="${OCF_RESKEY_aliyuncli} vpc DeleteRouteEntry --RouteTableId $OCF_RESKEY_routing_table --DestinationCidrBlock ${OCF_RESKEY_address}/32 --NextHopId $ROUTE_TO_INSTANCE ${ENDPOINT}"
+ ocf_log debug "executing command: $cmd"
+ res=$($cmd)
+ rc=$?
+ if [ $rc -eq 0 ]
+ then
+ ocf_log debug "result: $res; rc: $rc"
+ else
+ ocf_log err "result: $res; cmd: $cmd; rc: $rc"
+ fi
+ return $rc
+}
+
+request_describe_route_tables() {
+ cmd="${OCF_RESKEY_aliyuncli} vpc DescribeRouteTables --RouteTableId $OCF_RESKEY_routing_table --output ${OUTPUT} ${ENDPOINT}"
+ ocf_log debug "executing command: $cmd"
+ res=$($cmd)
+ rc=$?
+ if [ $rc -eq 0 ]
+ then
+ ROUTE_TO_INSTANCE=$(echo "$res" |grep "\s${OCF_RESKEY_address}/" | awk -F "${IFS_}" "${EXECUTING}")
+ ocf_log debug "ROUTE_TO_INSTANCE: $ROUTE_TO_INSTANCE"
+ else
+ ocf_log err "result: $res; cmd: $cmd; rc: $rc"
+ fi
+}
+
+ip_get_and_configure() {
+ ocf_log debug "function: ip_get_and_configure"
+
+ request_describe_route_tables
+ if [ "$ECS_INSTANCE_ID" != "$ROUTE_TO_INSTANCE" ]; then
+ if [ -n "$ROUTE_TO_INSTANCE" ]; then
+ ip_drop
+ fi
+ request_create_route_entry
+ rc=$?
+ while [ $rc -ne 0 ]; do
+ sleep 1
+ request_create_route_entry
+ rc=$?
+ done
+ wait_for_started
+ fi
+
+
+ # Reconfigure the local ip address
+ ip addr add "${OCF_RESKEY_address}/32" dev $OCF_RESKEY_interface
+ rc=$?
+ if [ $rc -ne 0 ]; then
+ ocf_log err "command failed, rc: $rc"
+ return $OCF_ERR_GENERIC
+ fi
+
+ ocf_log debug "IP added"
+
+ return $OCF_SUCCESS
+}
+
+ip_drop() {
+ ocf_log debug "function: ip_drop"
+ cmd="ip addr delete ${OCF_RESKEY_address}/32 dev $OCF_RESKEY_interface"
+ ocf_log debug "executing command: $cmd"
+ res=$($cmd)
+ rc=$?
+ if [ $rc -ne 0 ] && [ $rc -ne 2 ]; then
+ ocf_log err "command failed, rc: $rc; cmd: $cmd; result: $res"
+ return $OCF_ERR_GENERIC
+ fi
+ request_delete_route_entry
+ rc=$?
+ if [ $rc -ne 0 ]; then
+ ocf_log err "command failed, rc: $rc"
+ return $OCF_ERR_GENERIC
+ fi
+ wait_for_deleted
+
+ ocf_log debug "IP dropped"
+
+ return $OCF_SUCCESS
+}
+
+wait_for_started() {
+ request_describe_route_tables
+ while [ "$ECS_INSTANCE_ID" != "$ROUTE_TO_INSTANCE" ]; do
+ sleep 3
+ request_describe_route_tables
+ done
+}
+
+wait_for_deleted() {
+ request_describe_route_tables
+ while [ ! -z "$ROUTE_TO_INSTANCE" ]; do
+ sleep 1
+ request_describe_route_tables
+ done
+}
+
+ecs_ip_metadata() {
+ cat <<END
+<?xml version="1.0"?>
+<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
+<resource-agent name="aliyun-vpc-move-ip" version="2.0">
+<version>1.0</version>
+<longdesc lang="en">
+Resource Agent to move IP addresses within a VPC of the Aliyun Webservices ECS
+by changing an entry in an specific routing table
+</longdesc>
+<shortdesc lang="en">Move IP within a VPC of the Aliyun ECS</shortdesc>
+
+<parameters>
+<parameter name="aliyuncli" required="0">
+<longdesc lang="en">
+Path to command line tools for Aliyun
+</longdesc>
+<shortdesc lang="en">Path to Aliyun CLI tools</shortdesc>
+<content type="string" default="${OCF_RESKEY_aliyuncli_default}" />
+</parameter>
+
+<parameter name="address" required="1">
+<longdesc lang="en">
+VPC private IP address
+</longdesc>
+<shortdesc lang="en">vpc ip</shortdesc>
+<content type="string" default="${OCF_RESKEY_address_default}" />
+</parameter>
+
+<parameter name="routing_table" required="1">
+<longdesc lang="en">
+Name of the routing table, where the route for the IP address should be changed, i.e. vtb-...
+</longdesc>
+<shortdesc lang="en">routing table name</shortdesc>
+<content type="string" default="${OCF_RESKEY_routing_table_default}" />
+</parameter>
+
+<parameter name="interface" required="1">
+<longdesc lang="en">
+Name of the network interface, i.e. eth0
+</longdesc>
+<shortdesc lang="en">network interface name</shortdesc>
+<content type="string" default="${OCF_RESKEY_interface_default}" />
+</parameter>
+
+<parameter name="endpoint" required="0">
+<longdesc lang="en">
+An endpoint is the service entry of an Alibaba Cloud service, i.e. vpc.cn-beijing.aliyuncs.com
+</longdesc>
+<shortdesc lang="en">service endpoint</shortdesc>
+<content type="string" default="${OCF_RESKEY_endpoint_default}" />
+</parameter>
+
+<parameter name="profile" required="0">
+<longdesc lang="en">
+Valid Aliyun CLI profile name (see 'aliyun cli configure').
+See https://www.alibabacloud.com/help/zh/product/29991.htm for more information about aliyun cli.
+</longdesc>
+<shortdesc lang="en">profile name</shortdesc>
+<content type="string" default="${OCF_RESKEY_profile_default}" />
+</parameter>
+</parameters>
+
+<actions>
+<action name="start" timeout="180s" />
+<action name="stop" timeout="180s" />
+<action name="monitor" depth="0" timeout="30s" interval="30s" />
+<action name="validate-all" timeout="5s" />
+<action name="meta-data" timeout="5s" />
+</actions>
+</resource-agent>
+END
+}
+
+ecs_ip_validate() {
+ ocf_log debug "function: validate"
+
+ if [ -z "${OCF_RESKEY_aliyuncli}" ]; then
+ ocf_exit_reason "unable to detect aliyuncli binary"
+ exit $OCF_ERR_INSTALLED
+ fi
+
+ # IP address
+ if [ -z "$OCF_RESKEY_address" ]; then
+ ocf_log err "IP address parameter not set $OCF_RESKEY_ADDRESS!"
+ exit $OCF_ERR_CONFIGURED
+ fi
+
+ # Network Interface
+ if [ -z "$OCF_RESKEY_interface" ]; then
+ ocf_log err "Network interface parameter not set $OCF_RESKEY_INTERFACE!"
+ exit $OCF_ERR_CONFIGURED
+ fi
+
+ # Routing Table
+ if [ -z "$OCF_RESKEY_routing_table" ]; then
+ ocf_log err "Routing table parameter not set $OCF_RESKEY_ROUTING_TABLE!"
+ exit $OCF_ERR_CONFIGURED
+ fi
+
+ if [ -z "${ECS_INSTANCE_ID}" ]; then
+ ocf_exit_reason "Instance ID not found. Is this a ECS instance?"
+ return $OCF_ERR_GENERIC
+ fi
+
+ return $OCF_SUCCESS
+}
+
+ecs_ip_start() {
+ ocf_log info "ECS: Moving IP address $OCF_RESKEY_address to this host by adjusting routing table $OCF_RESKEY_routing_table"
+
+ ecs_ip_monitor
+ if [ $? = $OCF_SUCCESS ]; then
+ ocf_log info "ECS: $OCF_RESKEY_address already started"
+ return $OCF_SUCCESS
+ fi
+
+ ocf_log info "ECS: Adjusting routing table and locally configuring IP address"
+ ip_get_and_configure
+ rc=$?
+ if [ $rc -ne 0 ]; then
+ ocf_log err "Received $rc from 'aliyun cli'"
+ return $OCF_ERR_GENERIC
+ fi
+
+ ecs_ip_monitor
+ rc=$?
+ if [ $rc -ne $OCF_SUCCESS ]; then
+ ocf_log err "IP address couldn't be configured on this host (IP: $OCF_RESKEY_address, Interface: $OCF_RESKEY_interface)"
+ return $rc
+ fi
+
+ return $OCF_SUCCESS
+}
+
+ecs_ip_stop() {
+ ocf_log info "ECS: Bringing down IP address $OCF_RESKEY_address"
+
+ ecs_ip_monitor
+ if [ $? = $OCF_NOT_RUNNING ]; then
+ ocf_log info "ECS: Address $OCF_RESKEY_address already down"
+ return $OCF_SUCCESS
+ fi
+
+ ip_drop
+ if [ $? -ne $OCF_SUCCESS ]; then
+ ocf_log err "ECS: Couldn't drop IP address $OCF_RESKEY_address on interface $OCF_RESKEY_interface."
+ return $OCF_ERR_GENERIC
+ fi
+
+ ecs_ip_monitor
+ if [ $? = $OCF_NOT_RUNNING ]; then
+ ocf_log info "ECS: Successfully brought down $OCF_RESKEY_address"
+ return $OCF_SUCCESS
+ fi
+
+ ocf_log err "ECS: Couldn't bring down IP address $OCF_RESKEY_address on interface $OCF_RESKEY_interface."
+ return $OCF_ERR_GENERIC
+}
+
+ecs_ip_monitor() {
+ ocf_log debug "function: ecsip_monitor: check routing table"
+ request_describe_route_tables
+
+ if [ "$ECS_INSTANCE_ID" != "$ROUTE_TO_INSTANCE" ]; then
+ ocf_log debug "not routed to this instance ($ECS_INSTANCE_ID) but to instance $ROUTE_TO_INSTANCE"
+ return $OCF_NOT_RUNNING
+ fi
+
+ cmd="ping -W 1 -c 1 $OCF_RESKEY_address"
+ ocf_log debug "executing command: $cmd"
+ $cmd > /dev/null
+ if [ $? -ne 0 ]; then
+ ocf_log debug "IP $OCF_RESKEY_address not locally reachable via ping on this system"
+ return $OCF_NOT_RUNNING
+ fi
+ ocf_log debug "routed in VPC and locally reachable"
+ return $OCF_SUCCESS
+}
+
+
+###############################################################################
+#
+# MAIN
+#
+###############################################################################
+
+case $__OCF_ACTION in
+ meta-data) ecs_ip_metadata
+ exit $OCF_SUCCESS;;
+ validate-all) ecs_ip_validate;;
+esac
+
+ECS_INSTANCE_ID="$(curl -s http://100.100.100.200/latest/meta-data/instance-id)"
+
+case $__OCF_ACTION in
+ start)
+ ecs_ip_validate
+ ecs_ip_start;;
+ stop)
+ ecs_ip_stop;;
+ monitor)
+ ecs_ip_monitor;;
+ *) exit $OCF_ERR_UNIMPLEMENTED;;
+esac