diff --git a/heartbeat/openstack-cinder-volume b/heartbeat/openstack-cinder-volume index 476fbbe28..6c2b09355 100755 --- a/heartbeat/openstack-cinder-volume +++ b/heartbeat/openstack-cinder-volume @@ -1,322 +1,348 @@ #!/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. # -set -x - ####################################################################### # Initialization: : ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat} . ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs # Defaults OCF_RESKEY_openstackcli_default="/usr/bin/openstack" OCF_RESKEY_node_id_cache_file_default="/tmp/node_id" export attached_server_id="" : ${OCF_RESKEY_openstackcli=${OCF_RESKEY_openstackcli_default}} : ${OCF_RESKEY_node_id_cache_file=${OCF_RESKEY_node_id_cache_file_default}} ####################################################################### USAGE="usage: $0 {start|stop|status|meta-data}"; ############################################################################### ############################################################################### # # Functions # ############################################################################### metadata() { cat < 2.0 Resource Agent to attach a cinder volume to an instance. It relies on attributes given by openstack-info resource agent (openstack_id attribute). Attach a cinder volume Path to command line tools for openstack. Path to Openstack CLI tool Path to Node ID cache file, used to avoid Openstack API calls: 1. Is the local file written? 2. Is openstack_id available as a node attribute? 3. Can we get it from the API? Path to Node ID cache file Valid Openstack credentials as openrc file from api_access/openrc. openrc file Cinder volume identifier to use to attach the bloc storage. Volume ID END } +# +# This is used to get the node ID from different sources: +# 1. Is the local file written? +# 2. Is openstack_id available as a node attribute? +# 3. Can we get it from the API? +# +# When the ID is retrieved, the local cache file is written. +# This prevents the agent to call the API each time the agent is used. +# _get_node_id() { local crm_node local node local node_id local result crm_node=$(crm_node -n) + # # Use local cache + # if [ -f $OCF_RESKEY_node_id_cache_file ] ; then node_id=$(cat $OCF_RESKEY_node_id_cache_file) if [ ! -z "$node_id" ] ; then echo $node_id return fi fi + # # Query the attributes database + # node_id=$(${HA_SBIN_DIR}/attrd_updater --query -n openstack_id -N $crm_node \ | tr ' ' '\n' \ | awk -F= '/value=/ {gsub("\"","");print $NF}') if [ ! -z "$node_id" ] ; then echo $node_id | awk '{print $1}' echo $node_id | awk '{print $1}' > $OCF_RESKEY_node_id_cache_file return fi + # # Use the API + # node=$(crm_node -n | awk -F. '{print $1}') result=$($OCF_RESKEY_openstackcli server list \ --format value --column ID --column Name \ | grep $node) if [ $? -eq 0 ] ; then echo $result | awk '{print $1}' echo $result | awk '{print $1}' > $OCF_RESKEY_node_id_cache_file return fi ocf_exit_reason "openstack_id attribute must be set for node $crm_node" return $OCF_ERR_CONFIGURED } osvol_validate() { local node_id - local crm_node check_binary "$OCF_RESKEY_openstackcli" check_binary "awk" check_binary "tr" - crm_node=$(crm_node -n) - . $OCF_RESKEY_openrc node_id=$(_get_node_id) if [ -z "$node_id" ] ; then ocf_exit_reason "openstack_id attribute must be set for node $crm_node" return $OCF_ERR_CONFIGURED fi if [ -z "$OCF_RESKEY_openrc" ]; then ocf_exit_reason "openrc parameter not set" return $OCF_ERR_CONFIGURED fi if [ ! -f "$OCF_RESKEY_openrc" ] ; then ocf_exit_reason "openrc file not found" return $OCF_ERR_CONFIGURED fi if ! $OCF_RESKEY_openstackcli volume list|grep -q $OCF_RESKEY_volume_id ; then ocf_exit_reason "Volume $OCF_RESKEY_volume_id not found" return $OCF_ERR_CONFIGURED fi return $OCF_SUCCESS } osvol_monitor() { local result local node_id - local crm_node + # # Is the volue attached? + # result=$($OCF_RESKEY_openstackcli volume show \ --column status \ --column attachments \ --format value \ $OCF_RESKEY_volume_id) - crm_node=$(crm_node -n) - if [[ "$result" =~ "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|awk -F "'" '{print $4}') 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 node_id=$(_get_node_id) if [ "$node_id" != "$attached_server_id" ] ; then 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) + # + # Unmout the volume + # if ! $OCF_RESKEY_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 + # + # Unmout it from another node + # TODO: make it optional in case multi-attachment is allowed by Cinder + # if [ ! -z $attached_server_id ] ; then if ! $OCF_RESKEY_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 + # $OCF_RESKEY_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 osvol_validate case $__OCF_ACTION in start) osvol_start;; stop) osvol_stop;; monitor|status) osvol_monitor;; validate-all) exit $?;; *) echo $USAGE exit $OCF_ERR_UNIMPLEMENTED ;; esac