diff options
Diffstat (limited to 'heartbeat/awsvip')
-rwxr-xr-x | heartbeat/awsvip | 251 |
1 files changed, 251 insertions, 0 deletions
diff --git a/heartbeat/awsvip b/heartbeat/awsvip new file mode 100755 index 0000000..037278e --- /dev/null +++ b/heartbeat/awsvip @@ -0,0 +1,251 @@ +#!/bin/sh +# +# +# Manage Secondary Private IP with Pacemaker +# +# +# Copyright 2016-2018 guessi <guessi@gmail.com> +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# +# + +# +# Prerequisites: +# +# - preconfigured AWS CLI running environment (AccessKey, SecretAccessKey, etc.) +# - a reserved secondary private IP address for EC2 instances high availablity +# - IAM user role with the following permissions: +# * DescribeInstances +# * AssignPrivateIpAddresses +# * UnassignPrivateIpAddresses +# + +####################################################################### +# Initialization: + +: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat} +. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs + +####################################################################### + +# +# Defaults +# +OCF_RESKEY_awscli_default="/usr/bin/aws" +OCF_RESKEY_profile_default="default" +OCF_RESKEY_api_delay_default="3" + +: ${OCF_RESKEY_awscli=${OCF_RESKEY_awscli_default}} +: ${OCF_RESKEY_profile=${OCF_RESKEY_profile_default}} +: ${OCF_RESKEY_api_delay=${OCF_RESKEY_api_delay_default}} + +meta_data() { + cat <<END +<?xml version="1.0"?> +<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd"> +<resource-agent name="awsvip" version="1.0"> +<version>1.0</version> + +<longdesc lang="en"> +Resource Agent for Amazon AWS Secondary Private IP Addresses. + +It manages AWS Secondary Private IP Addresses with awscli. + +Credentials needs to be setup by running "aws configure". + +See https://aws.amazon.com/cli/ for more information about awscli. +</longdesc> +<shortdesc lang="en">Amazon AWS Secondary Private IP Address Resource Agent</shortdesc> + +<parameters> + +<parameter name="awscli" unique="0"> +<longdesc lang="en"> +command line tools for aws services +</longdesc> +<shortdesc lang="en">aws cli tools</shortdesc> +<content type="string" default="${OCF_RESKEY_awscli_default}" /> +</parameter> + +<parameter name="profile"> +<longdesc lang="en"> +Valid AWS CLI profile name (see ~/.aws/config and 'aws configure') +</longdesc> +<shortdesc lang="en">profile name</shortdesc> +<content type="string" default="${OCF_RESKEY_profile_default}" /> +</parameter> + +<parameter name="secondary_private_ip" unique="1" required="1"> +<longdesc lang="en"> +reserved secondary private ip for ec2 instance +</longdesc> +<shortdesc lang="en">reserved secondary private ip for ec2 instance</shortdesc> +<content type="string" default="" /> +</parameter> + +<parameter name="api_delay" unique="0"> +<longdesc lang="en"> +a short delay between API calls, to avoid sending API too quick +</longdesc> +<shortdesc lang="en">a short delay between API calls</shortdesc> +<content type="integer" default="${OCF_RESKEY_api_delay_default}" /> +</parameter> + +</parameters> + +<actions> +<action name="start" timeout="30s" /> +<action name="stop" timeout="30s" /> +<action name="monitor" timeout="30s" interval="20s" depth="0" /> +<action name="migrate_to" timeout="30s" /> +<action name="migrate_from" timeout="30s" /> +<action name="meta-data" timeout="5s" /> +<action name="validate" timeout="10s" /> +<action name="validate-all" timeout="10s" /> +</actions> +</resource-agent> +END +} + +####################################################################### + +awsvip_usage() { + cat <<END +usage: $0 {start|stop|monitor|migrate_to|migrate_from|validate|validate-all|meta-data} + +Expects to have a fully populated OCF RA-compliant environment set. +END +} + +awsvip_start() { + awsvip_monitor && return $OCF_SUCCESS + + $AWSCLI --profile $OCF_RESKEY_profile ec2 assign-private-ip-addresses \ + --network-interface-id ${NETWORK_ID} \ + --private-ip-addresses ${SECONDARY_PRIVATE_IP} \ + --allow-reassignment + RET=$? + + # delay to avoid sending request too fast + sleep ${OCF_RESKEY_api_delay} + + if [ $RET -ne 0 ]; then + return $OCF_NOT_RUNNING + fi + + ocf_log info "secondary_private_ip has been successfully brought up (${SECONDARY_PRIVATE_IP})" + return $OCF_SUCCESS +} + +awsvip_stop() { + awsvip_monitor || return $OCF_SUCCESS + + $AWSCLI --profile $OCF_RESKEY_profile ec2 unassign-private-ip-addresses \ + --network-interface-id ${NETWORK_ID} \ + --private-ip-addresses ${SECONDARY_PRIVATE_IP} + RET=$? + + # delay to avoid sending request too fast + sleep ${OCF_RESKEY_api_delay} + + if [ $RET -ne 0 ]; then + return $OCF_NOT_RUNNING + fi + + ocf_log info "secondary_private_ip has been successfully brought down (${SECONDARY_PRIVATE_IP})" + return $OCF_SUCCESS +} + +awsvip_monitor() { + $AWSCLI --profile ${OCF_RESKEY_profile} ec2 describe-instances \ + --instance-id "${INSTANCE_ID}" \ + --query 'Reservations[].Instances[].NetworkInterfaces[].PrivateIpAddresses[].PrivateIpAddress[]' \ + --output text | \ + grep -qE "(^|\s)${SECONDARY_PRIVATE_IP}(\s|$)" + RET=$? + + if [ $RET -ne 0 ]; then + return $OCF_NOT_RUNNING + fi + return $OCF_SUCCESS +} + +awsvip_validate() { + check_binary ${AWSCLI} + + if [ -z "$OCF_RESKEY_profile" ]; then + ocf_exit_reason "profile parameter not set" + return $OCF_ERR_CONFIGURED + fi + + if [ -z "${INSTANCE_ID}" ]; then + ocf_exit_reason "instance_id not found. Is this a EC2 instance?" + return $OCF_ERR_GENERIC + fi + + return $OCF_SUCCESS +} + +case $__OCF_ACTION in + meta-data) + meta_data + exit $OCF_SUCCESS + ;; +esac + +AWSCLI="${OCF_RESKEY_awscli}" +SECONDARY_PRIVATE_IP="${OCF_RESKEY_secondary_private_ip}" +TOKEN=$(curl -sX PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 21600") +INSTANCE_ID=$(curl -s http://169.254.169.254/latest/meta-data/instance-id -H "X-aws-ec2-metadata-token: $TOKEN") +MAC_ADDRESS=$(curl -s http://169.254.169.254/latest/meta-data/mac -H "X-aws-ec2-metadata-token: $TOKEN") +NETWORK_ID=$(curl -s http://169.254.169.254/latest/meta-data/network/interfaces/macs/${MAC_ADDRESS}/interface-id -H "X-aws-ec2-metadata-token: $TOKEN") + +case $__OCF_ACTION in + start) + awsvip_validate + awsvip_start + ;; + stop) + awsvip_stop + ;; + monitor) + awsvip_monitor + ;; + migrate_to) + ocf_log info "Migrating ${OCF_RESOURCE_INSTANCE} to ${OCF_RESKEY_CRM_meta_migrate_target}." + awsvip_stop + ;; + migrate_from) + ocf_log info "Migrating ${OCF_RESOURCE_INSTANCE} from ${OCF_RESKEY_CRM_meta_migrate_source}." + awsvip_start + ;; + reload) + ocf_log info "Reloading ${OCF_RESOURCE_INSTANCE} ..." + ;; + validate|validate-all) + awsvip_validate + ;; + usage|help) + awsvip_usage + exit $OCF_SUCCESS + ;; + *) + awsvip_usage + exit $OCF_ERR_UNIMPLEMENTED + ;; +esac + +rc=$? +ocf_log debug "${OCF_RESOURCE_INSTANCE} $__OCF_ACTION : $rc" +exit $rc |