|
|
b4b3ce |
From e45d0ca9ccc3d5fbe94372f40bedb7559dc9530a Mon Sep 17 00:00:00 2001
|
|
|
b4b3ce |
From: "feng.changf1" <feng.changf1@alibaba-inc.com>
|
|
|
b4b3ce |
Date: Tue, 24 Jul 2018 15:08:45 +0800
|
|
|
b4b3ce |
Subject: [PATCH] Add Aliyun vpc-move-ip agent.
|
|
|
b4b3ce |
|
|
|
b4b3ce |
---
|
|
|
b4b3ce |
heartbeat/aliyun-vpc-move-ip | 258 +++++++++++++++++++++++++++++++++++++++++++
|
|
|
b4b3ce |
1 file changed, 258 insertions(+)
|
|
|
b4b3ce |
create mode 100644 heartbeat/aliyun-vpc-move-ip
|
|
|
b4b3ce |
|
|
|
b4b3ce |
diff --git a/heartbeat/aliyun-vpc-move-ip b/heartbeat/aliyun-vpc-move-ip
|
|
|
b4b3ce |
new file mode 100644
|
|
|
b4b3ce |
index 000000000..bc97822a8
|
|
|
b4b3ce |
--- /dev/null
|
|
|
b4b3ce |
+++ b/heartbeat/aliyun-vpc-move-ip
|
|
|
b4b3ce |
@@ -0,0 +1,258 @@
|
|
|
b4b3ce |
+#!/bin/bash
|
|
|
b4b3ce |
+#
|
|
|
b4b3ce |
+# OCF resource agent to move an IP address within a VPC in the Aliyun
|
|
|
b4b3ce |
+# Based on code of Markus Guertler (GitHub AWS-VPC-move-IP)
|
|
|
b4b3ce |
+# Based on code of Adam Gandelman (GitHub ec2-resource-agents/elasticip)
|
|
|
b4b3ce |
+#
|
|
|
b4b3ce |
+
|
|
|
b4b3ce |
+###############################################################################
|
|
|
b4b3ce |
+# For testing purposes delete OCF_ROOT after testing
|
|
|
b4b3ce |
+OCF_ROOT=/usr/lib/ocf/
|
|
|
b4b3ce |
+#
|
|
|
b4b3ce |
+# INIT
|
|
|
b4b3ce |
+#: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/resource.d/heartbeat}
|
|
|
b4b3ce |
+#if [ -f ${OCF_FUNCTIONS_DIR}/.ocf-shellfuncs ]; then
|
|
|
b4b3ce |
+# . ${OCF_FUNCTIONS_DIR}/.ocf-shellfuncs
|
|
|
b4b3ce |
+#fi
|
|
|
b4b3ce |
+
|
|
|
b4b3ce |
+#######################################################################
|
|
|
b4b3ce |
+# Initialization:
|
|
|
b4b3ce |
+
|
|
|
b4b3ce |
+: ${OCF_FUNCTIONS=${OCF_ROOT}/resource.d/heartbeat/.ocf-shellfuncs}
|
|
|
b4b3ce |
+. ${OCF_FUNCTIONS}
|
|
|
b4b3ce |
+: ${__OCF_ACTION=$1}
|
|
|
b4b3ce |
+export HOME=/root
|
|
|
b4b3ce |
+#######################################################################
|
|
|
b4b3ce |
+
|
|
|
b4b3ce |
+
|
|
|
b4b3ce |
+USAGE="usage: $0 {start|stop|status|meta-data}";
|
|
|
b4b3ce |
+###############################################################################
|
|
|
b4b3ce |
+
|
|
|
b4b3ce |
+
|
|
|
b4b3ce |
+###############################################################################
|
|
|
b4b3ce |
+#
|
|
|
b4b3ce |
+# Functions
|
|
|
b4b3ce |
+#
|
|
|
b4b3ce |
+###############################################################################
|
|
|
b4b3ce |
+
|
|
|
b4b3ce |
+
|
|
|
b4b3ce |
+metadata() {
|
|
|
b4b3ce |
+cat <
|
|
|
b4b3ce |
+
|
|
|
b4b3ce |
+
|
|
|
b4b3ce |
+<resource-agent name="vpc-move-ip">
|
|
|
b4b3ce |
+<version>2.0</version>
|
|
|
b4b3ce |
+<longdesc lang="en">
|
|
|
b4b3ce |
+Resource Agent to move IP addresses within a VPC of the Aliyun Webservices ECS
|
|
|
b4b3ce |
+by changing an entry in an specific routing table
|
|
|
b4b3ce |
+</longdesc>
|
|
|
b4b3ce |
+<shortdesc lang="en">Move IP within a APC of the Aliyun ECS</shortdesc>
|
|
|
b4b3ce |
+<parameters>
|
|
|
b4b3ce |
+<parameter name="address" required="1">
|
|
|
b4b3ce |
+<longdesc lang="en">
|
|
|
b4b3ce |
+VPC private IP address
|
|
|
b4b3ce |
+</longdesc>
|
|
|
b4b3ce |
+<shortdesc lang="en">vpc ip</shortdesc>
|
|
|
b4b3ce |
+<content type="string" default="" />
|
|
|
b4b3ce |
+</parameter>
|
|
|
b4b3ce |
+<parameter name="routing_table" required="1">
|
|
|
b4b3ce |
+<longdesc lang="en">
|
|
|
b4b3ce |
+Name of the routing table, where the route for the IP address should be changed, i.e. rtb-...
|
|
|
b4b3ce |
+</longdesc>
|
|
|
b4b3ce |
+<shortdesc lang="en">routing table name</shortdesc>
|
|
|
b4b3ce |
+<content type="string" default="" />
|
|
|
b4b3ce |
+</parameter>
|
|
|
b4b3ce |
+<parameter name="interface" required="1">
|
|
|
b4b3ce |
+<longdesc lang="en">
|
|
|
b4b3ce |
+Name of the network interfacen, i.e. eth0
|
|
|
b4b3ce |
+</longdesc>
|
|
|
b4b3ce |
+<shortdesc lang="en">network interface name</shortdesc>
|
|
|
b4b3ce |
+<content type="string" default="eth0" />
|
|
|
b4b3ce |
+</parameter>
|
|
|
b4b3ce |
+<parameter name="profile" required="0">
|
|
|
b4b3ce |
+<longdesc lang="en">
|
|
|
b4b3ce |
+Valid Aliyun CLI profile name
|
|
|
b4b3ce |
+</longdesc>
|
|
|
b4b3ce |
+<shortdesc lang="en">profile name</shortdesc>
|
|
|
b4b3ce |
+<content type="string" default="default" />
|
|
|
b4b3ce |
+</parameter>
|
|
|
b4b3ce |
+</parameters>
|
|
|
b4b3ce |
+<actions>
|
|
|
b4b3ce |
+<action name="start" timeout="180" />
|
|
|
b4b3ce |
+<action name="stop" timeout="180" />
|
|
|
b4b3ce |
+<action name="monitor" depth="0" timeout="30" interval="30" />
|
|
|
b4b3ce |
+<action name="validate-all" timeout="5" />
|
|
|
b4b3ce |
+<action name="meta-data" timeout="5" />
|
|
|
b4b3ce |
+</actions>
|
|
|
b4b3ce |
+</resource-agent>
|
|
|
b4b3ce |
+END
|
|
|
b4b3ce |
+}
|
|
|
b4b3ce |
+
|
|
|
b4b3ce |
+debugger() {
|
|
|
b4b3ce |
+ ocf_log info "DEBUG: $1"
|
|
|
b4b3ce |
+}
|
|
|
b4b3ce |
+
|
|
|
b4b3ce |
+ecs_ip_validate() {
|
|
|
b4b3ce |
+ debugger "function: validate"
|
|
|
b4b3ce |
+
|
|
|
b4b3ce |
+ # IP address
|
|
|
b4b3ce |
+ [[ -z "$OCF_RESKEY_address" ]] && ocf_log error "IP address parameter not set $OCF_RESKEY_ADDRESS!" && exit $OCF_ERR_CONFIGURED
|
|
|
b4b3ce |
+
|
|
|
b4b3ce |
+ # Network Interface
|
|
|
b4b3ce |
+ [[ -z "$OCF_RESKEY_interface" ]] && ocf_log error "Network interface parameter not set $OCF_RESKEY_INTERFACE!" && exit $OCF_ERR_CONFIGURED
|
|
|
b4b3ce |
+
|
|
|
b4b3ce |
+ # Routing Table
|
|
|
b4b3ce |
+ [[ -z "$OCF_RESKEY_routing_table" ]] && ocf_log error "Routing table parameter not set $OCF_RESKEY_ROUTING_TABLE!" && exit $OCF_ERR_CONFIGURED
|
|
|
b4b3ce |
+
|
|
|
b4b3ce |
+ ECS_INSTANCE_ID="$(curl -s http://100.100.100.200/latest/meta-data/instance-id)"
|
|
|
b4b3ce |
+
|
|
|
b4b3ce |
+ if [ -z "${ECS_INSTANCE_ID}" ]; then
|
|
|
b4b3ce |
+ ocf_exit_reason "Instance ID not found. Is this a ECS instance?"
|
|
|
b4b3ce |
+ return $OCF_ERR_GENERIC
|
|
|
b4b3ce |
+ fi
|
|
|
b4b3ce |
+
|
|
|
b4b3ce |
+ return $OCF_SUCCESS
|
|
|
b4b3ce |
+}
|
|
|
b4b3ce |
+
|
|
|
b4b3ce |
+ecs_ip_monitor() {
|
|
|
b4b3ce |
+ ecs_ip_validate
|
|
|
b4b3ce |
+ debugger "function: ecsip_monitor: check routing table"
|
|
|
b4b3ce |
+ cmd="aliyuncli vpc DescribeRouteTables --RouteTableId $OCF_RESKEY_routing_table --output text"
|
|
|
b4b3ce |
+ debugger "executing command: $cmd"
|
|
|
b4b3ce |
+ ROUTE_TO_INSTANCE="$($cmd |grep $OCF_RESKEY_address | awk '{ print $3 }')"
|
|
|
b4b3ce |
+ if [ -z "$ROUTE_TO_INSTANCE" ]; then
|
|
|
b4b3ce |
+ ROUTE_TO_INSTANCE="<unknown>"
|
|
|
b4b3ce |
+ fi
|
|
|
b4b3ce |
+
|
|
|
b4b3ce |
+ [[ "$ECS_INSTANCE_ID" != "$ROUTE_TO_INSTANCE" ]] && debugger "not routed to this instance ($ECS_INSTANCE_ID) but to instance $ROUTE_TO_INSTANCE" && return $OCF_NOT_RUNNING
|
|
|
b4b3ce |
+ cmd="ping -W 1 -c 1 $OCF_RESKEY_address"
|
|
|
b4b3ce |
+ debugger "executing command: $cmd"
|
|
|
b4b3ce |
+ $cmd > /dev/null
|
|
|
b4b3ce |
+ [[ $? -gt 0 ]] && debugger "IP $OCF_RESKEY_address not locally reachable via ping on this system" && return $OCF_NOT_RUNNING
|
|
|
b4b3ce |
+ debugger "routed in VPC and locally reachable"
|
|
|
b4b3ce |
+ return $OCF_SUCCESS
|
|
|
b4b3ce |
+}
|
|
|
b4b3ce |
+
|
|
|
b4b3ce |
+
|
|
|
b4b3ce |
+ecs_ip_drop() {
|
|
|
b4b3ce |
+ debugger "function: ecsip_drop"
|
|
|
b4b3ce |
+ cmd="ip addr delete ${OCF_RESKEY_address}/32 dev $OCF_RESKEY_interface"
|
|
|
b4b3ce |
+ debugger "executing command: $cmd"
|
|
|
b4b3ce |
+ $cmd
|
|
|
b4b3ce |
+ rc=$?
|
|
|
b4b3ce |
+ [[ $rc -gt 2 ]] && debugger "command failed, rc $rc" && return $OCF_ERR_GENERIC
|
|
|
b4b3ce |
+ debugger "command succeeded"
|
|
|
b4b3ce |
+ return $OCF_SUCCESS
|
|
|
b4b3ce |
+}
|
|
|
b4b3ce |
+
|
|
|
b4b3ce |
+wait_for_deleted() {
|
|
|
b4b3ce |
+ while [ ! -z "$ROUTE_TO_INSTANCE" ]; do
|
|
|
b4b3ce |
+ sleep 1
|
|
|
b4b3ce |
+ cmd="aliyuncli vpc DescribeRouteTables --RouteTableId $OCF_RESKEY_routing_table --output text"
|
|
|
b4b3ce |
+ debugger "executing command: $cmd"
|
|
|
b4b3ce |
+ ROUTE_TO_INSTANCE="$($cmd |grep $OCF_RESKEY_address | awk '{ print $3 }')"
|
|
|
b4b3ce |
+ done
|
|
|
b4b3ce |
+ sleep 5
|
|
|
b4b3ce |
+}
|
|
|
b4b3ce |
+
|
|
|
b4b3ce |
+wait_for_started() {
|
|
|
b4b3ce |
+ cmd="aliyuncli vpc DescribeRouteTables --RouteTableId $OCF_RESKEY_routing_table --output text"
|
|
|
b4b3ce |
+ debugger "executing command: $cmd"
|
|
|
b4b3ce |
+ ROUTE_TO_INSTANCE="$($cmd |grep $OCF_RESKEY_address | awk '{ print $3 }')"
|
|
|
b4b3ce |
+
|
|
|
b4b3ce |
+ while [ "$ECS_INSTANCE_ID" != "$ROUTE_TO_INSTANCE" ]; do
|
|
|
b4b3ce |
+ sleep 1
|
|
|
b4b3ce |
+ cmd="aliyuncli vpc DescribeRouteTables --RouteTableId $OCF_RESKEY_routing_table --output text"
|
|
|
b4b3ce |
+ debugger "executing command: $cmd"
|
|
|
b4b3ce |
+ ROUTE_TO_INSTANCE="$($cmd |grep $OCF_RESKEY_address | awk '{ print $3 }')"
|
|
|
b4b3ce |
+ done
|
|
|
b4b3ce |
+ sleep 5
|
|
|
b4b3ce |
+}
|
|
|
b4b3ce |
+
|
|
|
b4b3ce |
+ecs_ip_get_and_configure() {
|
|
|
b4b3ce |
+ debugger "function: ecsip_get_and_configure"
|
|
|
b4b3ce |
+
|
|
|
b4b3ce |
+ if [ "$ECS_INSTANCE_ID" != "$ROUTE_TO_INSTANCE" ]; then
|
|
|
b4b3ce |
+
|
|
|
b4b3ce |
+ if [ $ROUTE_TO_INSTANCE != "<unknown>" ]; then
|
|
|
b4b3ce |
+ # Adjusting the routing table
|
|
|
b4b3ce |
+ cmd="aliyuncli vpc DeleteRouteEntry --RouteTableId $OCF_RESKEY_routing_table --DestinationCidrBlock ${OCF_RESKEY_address}/32 --NextHopId $ROUTE_TO_INSTANCE --output text"
|
|
|
b4b3ce |
+ debugger "executing command: $cmd"
|
|
|
b4b3ce |
+ $cmd
|
|
|
b4b3ce |
+ rc=$?
|
|
|
b4b3ce |
+ [[ $rc != 0 ]] && debugger "command failed, rc: $rc" && return $OCF_ERR_GENERIC
|
|
|
b4b3ce |
+ #wait_for_deleted
|
|
|
b4b3ce |
+ sleep 3
|
|
|
b4b3ce |
+ fi
|
|
|
b4b3ce |
+
|
|
|
b4b3ce |
+ cmd="aliyuncli vpc CreateRouteEntry --RouteTableId $OCF_RESKEY_routing_table --DestinationCidrBlock ${OCF_RESKEY_address}/32 --NextHopId $ECS_INSTANCE_ID --NextHopType Instance --output text"
|
|
|
b4b3ce |
+ debugger "executing command: $cmd"
|
|
|
b4b3ce |
+ $cmd
|
|
|
b4b3ce |
+ rc=$?
|
|
|
b4b3ce |
+ #[[ $rc != 0 ]] && debugger "command failed, rc: $rc" && return $OCF_ERR_GENERIC
|
|
|
b4b3ce |
+ while [ $rc != 0 ]; do
|
|
|
b4b3ce |
+ sleep 2
|
|
|
b4b3ce |
+ cmd="aliyuncli vpc CreateRouteEntry --RouteTableId $OCF_RESKEY_routing_table --DestinationCidrBlock ${OCF_RESKEY_address}/32 --NextHopId $ECS_INSTANCE_ID --NextHopType Instance --output text"
|
|
|
b4b3ce |
+ debugger "executing command: $cmd"
|
|
|
b4b3ce |
+ $cmd
|
|
|
b4b3ce |
+ rc=$?
|
|
|
b4b3ce |
+ done
|
|
|
b4b3ce |
+ wait_for_started
|
|
|
b4b3ce |
+ fi
|
|
|
b4b3ce |
+
|
|
|
b4b3ce |
+
|
|
|
b4b3ce |
+ # Reconfigure the local ip address
|
|
|
b4b3ce |
+ ecs_ip_drop
|
|
|
b4b3ce |
+ ip addr add "${OCF_RESKEY_address}/32" dev $OCF_RESKEY_interface
|
|
|
b4b3ce |
+ rc=$?
|
|
|
b4b3ce |
+ [[ $rc != 0 ]] && debugger "command failed, rc: $rc" && return $OCF_ERR_GENERIC
|
|
|
b4b3ce |
+ debugger "-success"
|
|
|
b4b3ce |
+ return $OCF_SUCCESS
|
|
|
b4b3ce |
+}
|
|
|
b4b3ce |
+
|
|
|
b4b3ce |
+ecs_ip_stop() {
|
|
|
b4b3ce |
+ ocf_log info "ECS: Bringing down IP address $OCF_RESKEY_address"
|
|
|
b4b3ce |
+ ecs_ip_validate
|
|
|
b4b3ce |
+ ecs_ip_monitor
|
|
|
b4b3ce |
+ [[ $? == $OCF_NOT_RUNNING ]] && ocf_log info "ECS: Address $OCF_RESKEY_address already down" && return $OCF_SUCCESS
|
|
|
b4b3ce |
+ ecs_ip_drop
|
|
|
b4b3ce |
+ [[ $? != $OCF_SUCCESS ]] && return $OCF_ERR_GENERIC
|
|
|
b4b3ce |
+ ecs_ip_monitor
|
|
|
b4b3ce |
+ [[ $? == $OCF_NOT_RUNNING ]] && ocf_log info "ECS: Successfully brought down $OCF_RESKEY_address" && return $OCF_SUCCESS
|
|
|
b4b3ce |
+ ocf_log error "ECS: Couldn't bring down IP address $OCF_RESKEY_address on interface $OCF_RESKEY_interface."
|
|
|
b4b3ce |
+ return $OCF_ERR_GENERIC
|
|
|
b4b3ce |
+}
|
|
|
b4b3ce |
+
|
|
|
b4b3ce |
+ecs_ip_start() {
|
|
|
b4b3ce |
+ ocf_log info "ECS: Moving IP address $OCF_RESKEY_address to this host by adjusting routing table $OCF_RESKEY_routing_table"
|
|
|
b4b3ce |
+ ecs_ip_validate
|
|
|
b4b3ce |
+ ecs_ip_monitor
|
|
|
b4b3ce |
+ [[ $? == $OCF_SUCCESS ]] && ocf_log info "ECS: $OCF_RESKEY_address already started" && return $OCF_SUCCESS
|
|
|
b4b3ce |
+ ocf_log info "ECS: Adjusting routing table and locally configuring IP address"
|
|
|
b4b3ce |
+ ecs_ip_get_and_configure
|
|
|
b4b3ce |
+ [[ $? != 0 ]] && ocf_log error "Received $? from 'aliyun cli'" && return $OCF_ERR_GENERIC
|
|
|
b4b3ce |
+ return $OCF_SUCCESS
|
|
|
b4b3ce |
+ ecs_ip_monitor
|
|
|
b4b3ce |
+ [[ $? == $OCF_SUCCESS ]] && return $?
|
|
|
b4b3ce |
+ ocf_log error "ECS: IP address couldn't be configured on this host (IP: $OCF_RESKEY_address, Interface: $OCF_RESKEY_interface)"
|
|
|
b4b3ce |
+ return $OCF_ERR_GENERIC
|
|
|
b4b3ce |
+}
|
|
|
b4b3ce |
+
|
|
|
b4b3ce |
+###############################################################################
|
|
|
b4b3ce |
+#
|
|
|
b4b3ce |
+# MAIN
|
|
|
b4b3ce |
+#
|
|
|
b4b3ce |
+###############################################################################
|
|
|
b4b3ce |
+
|
|
|
b4b3ce |
+case $__OCF_ACTION in
|
|
|
b4b3ce |
+ meta-data) metadata
|
|
|
b4b3ce |
+ exit $OCF_SUCCESS;;
|
|
|
b4b3ce |
+ monitor)
|
|
|
b4b3ce |
+ ecs_ip_monitor;;
|
|
|
b4b3ce |
+ stop)
|
|
|
b4b3ce |
+ ecs_ip_stop;;
|
|
|
b4b3ce |
+ validate-all) ecs_ip_validate;;
|
|
|
b4b3ce |
+ start)
|
|
|
b4b3ce |
+ ecs_ip_start;;
|
|
|
b4b3ce |
+ *) exit $OCF_ERR_UNIMPLEMENTED;;
|
|
|
b4b3ce |
+esac
|
|
|
b4b3ce |
\ No newline at end of file
|