diff options
Diffstat (limited to 'heartbeat/openstack-cinder-volume')
-rwxr-xr-x | heartbeat/openstack-cinder-volume | 294 |
1 files changed, 294 insertions, 0 deletions
diff --git a/heartbeat/openstack-cinder-volume b/heartbeat/openstack-cinder-volume new file mode 100755 index 0000000..116442c --- /dev/null +++ b/heartbeat/openstack-cinder-volume @@ -0,0 +1,294 @@ +#!/bin/sh +# +# +# OCF resource agent to attach a cinder volume to an instance. +# +# Copyright (c) 2018 Mathieu GRZYBEK +# Based on code of Markus Guertler +# All Rights Reserved. +# +# This program is free software; you can redistribute it and/or modify +# it under the terms of version 2 of the GNU General Public License as +# published by the Free Software Foundation. +# +# This program is distributed in the hope that it would be useful, but +# WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +# +# Further, this software is distributed without any warranty that it is +# free of the rightful claim of any third person regarding infringement +# or the like. Any license provided herein, whether implied or +# otherwise, applies only to this software file. Patent licenses, if +# any, provided herein do not apply to combinations of this program with +# other software, or any other product whatsoever. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write the Free Software Foundation, +# Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. +# + + +####################################################################### +# Initialization: + +: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat} +. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs + +. ${OCF_FUNCTIONS_DIR}/openstack-common.sh + +# Defaults +OCF_RESKEY_volume_local_check_default="true" + +: ${OCF_RESKEY_volume_local_check=${OCF_RESKEY_volume_local_check_default}} + +####################################################################### + + +USAGE="usage: $0 {start|stop|status|meta-data}"; +############################################################################### + + +############################################################################### +# +# Functions +# +############################################################################### + + +metadata() { +cat <<END +<?xml version="1.0"?> +<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd"> +<resource-agent name="openstack-cinder-volume" version="2.0"> +<version>1.0</version> +<longdesc lang="en"> +Resource Agent to attach a cinder volume to an instance. +It relies on attributes given by openstack-info resource agent (openstack_id attribute). +</longdesc> +<shortdesc lang="en">Attach a cinder volume</shortdesc> + +<parameters> +END + +common_meta_data + +cat <<END +<parameter name="volume_local_check"> +<longdesc lang="en"> +This option allows the cluster to monitor the cinder volume presence without +calling the API. +</longdesc> +<shortdesc lang="en">Monitor cinder volume locally</shortdesc> +<content type="boolean" default="${OCF_RESKEY_volume_local_check_default}" /> +</parameter> + +<parameter name="volume_id" required="1"> +<longdesc lang="en"> +Cinder volume identifier to use to attach the block storage. +</longdesc> +<shortdesc lang="en">Volume ID</shortdesc> +<content type="string" /> +</parameter> +</parameters> + +<actions> +<action name="start" timeout="180s" /> +<action name="stop" timeout="180s" /> +<action name="monitor" depth="0" timeout="180s" interval="60s" /> +<action name="validate-all" timeout="5s" /> +<action name="meta-data" timeout="5s" /> +</actions> +</resource-agent> +END +} + +_get_node_id() { + node_id=$(${HA_SBIN_DIR}/attrd_updater --query -n openstack_id -N $(crm_node -n) | + awk -F= '{gsub("\"","");print $NF}') + + if ! echo $node_id|grep -P "^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}$"; then + ocf_exit_reason "openstack_id attribute must be set for node $crm_node" + exit $OCF_ERR_CONFIGURED + fi +} + +osvol_validate() { + local result + + check_binary "$OCF_RESKEY_openstackcli" + + get_config + + result=$(run_openstackcli "volume list") + if ! echo "$result" | grep -q $OCF_RESKEY_volume_id; then + ocf_exit_reason "volume-id $OCF_RESKEY_volume_id not found" + return $OCF_ERR_CONFIGURED + fi + + ${HA_SBIN_DIR}/attrd_updater --query -n openstack_id -N $(crm_node -n) > /dev/null 2>&1 + if [ $? -ne 0 ] ; then + ocf_log warn "attr_updater failed to get openstack_id attribute of node $OCF_RESOURCE_INSTANCE" + return $OCF_ERR_GENERIC + fi + + return $OCF_SUCCESS +} + +osvol_monitor() { + local result + local node_id + local short_volume_id + + node_id=$(_get_node_id) + + if [ "$__OCF_ACTION" = "monitor" ] && ocf_is_true $OCF_RESKEY_volume_local_check ; then + # + # Is the volue attached? + # We check the local devices + # + short_volume_id=$(echo $OCF_RESKEY_volume_id | awk '{print substr($0, 0, 20)}') + if lsblk /dev/disk/by-id/virtio-$short_volume_id 1>/dev/null 2>&1; then + return $OCF_SUCCESS + else + ocf_log warn "$OCF_RESKEY_volume_id is not attached to instance $node_id" + return $OCF_NOT_RUNNING + fi + fi + + # + # Is the volue attached? + # We use the API + # + result=$(run_openstackcli "volume show \ + --column status \ + --column attachments \ + --format value \ + $OCF_RESKEY_volume_id") + + if echo "$result" | grep -q available; then + ocf_log warn "$OCF_RESKEY_volume_id is not attached to any instance" + return $OCF_NOT_RUNNING + else + export attached_server_id=$(echo "$result"|head -n1| + grep -P -o "'server_id': '[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}'"| + grep -P -o "[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12}") + ocf_log info "$OCF_RESKEY_volume_id is attached to instance $attached_server_id" + + # Compare node_id and the id of the node the volume is attached to + + if [ "$node_id" != "$attached_server_id" ] ; then + ocf_log warn "$OCF_RESKEY_volume_id is not attached to this instance" + return $OCF_NOT_RUNNING + fi + fi + + return $OCF_SUCCESS +} + +osvol_stop() { + local node_id + + # + # Is the volume already attached? + # + osvol_monitor + if [ $? = $OCF_NOT_RUNNING ]; then + ocf_log info "Volume $OCF_RESKEY_volume_id already available" + return $OCF_SUCCESS + fi + + node_id=$(_get_node_id) + + # + # Detach the volume + # + if ! run_openstackcli "server remove volume $node_id $OCF_RESKEY_volume_id"; then + ocf_log error "Couldn't remove volume $OCF_RESKEY_volume_id from instance $node_id" + return $OCF_ERR_GENERIC + fi + + ocf_log info "Successfully removed $OCF_RESKEY_volume_id from instance $node_id" + return $OCF_SUCCESS +} + +osvol_start() { + local node_id + + # + # Is the volume already attached? + # + osvol_monitor + if [ $? = $OCF_SUCCESS ]; then + ocf_log info "$OCF_RESKEY_volume_id already attached" + return $OCF_SUCCESS + fi + + # + # Detach it from another node + # TODO: make it optional in case multi-attachment is allowed by Cinder + # + if [ ! -z $attached_server_id ] ; then + if ! run_openstackcli "server remove volume $attached_server_id $OCF_RESKEY_volume_id"; then + ocf_log error "Couldn't remove volume $OCF_RESKEY_volume_id from instance $attached_server_id" + return $OCF_ERR_GENERIC + fi + fi + + export attached_server_id="" + + node_id=$(_get_node_id) + + # + # Attach the volume + # + run_openstackcli "server add volume $node_id $OCF_RESKEY_volume_id" + if [ $? != $OCF_SUCCESS ]; then + ocf_log error "Couldn't add volume $OCF_RESKEY_volume_id to instance $node_id" + return $OCF_ERR_GENERIC + fi + + return $OCF_SUCCESS +} + +############################################################################### +# +# MAIN +# +############################################################################### + +case $__OCF_ACTION in + meta-data) + metadata + exit $OCF_SUCCESS + ;; + usage|help) + echo $USAGE + exit $OCF_SUCCESS + ;; +esac + +if ! ocf_is_root; then + ocf_log err "You must be root for $__OCF_ACTION operation." + exit $OCF_ERR_PERM +fi + +case $__OCF_ACTION in + start) + osvol_validate || exit $? + osvol_start;; + stop) + osvol_validate || exit $? + osvol_stop;; + monitor|status) + osvol_validate || exit $? + osvol_monitor;; + validate-all) + osvol_validate + ;; + *) + echo $USAGE + exit $OCF_ERR_UNIMPLEMENTED + ;; +esac + +exit $? |