diff options
Diffstat (limited to 'src/ocf')
-rw-r--r-- | src/ocf/.gitignore | 2 | ||||
-rw-r--r-- | src/ocf/CMakeLists.txt | 10 | ||||
-rw-r--r-- | src/ocf/rbd.in | 315 |
3 files changed, 327 insertions, 0 deletions
diff --git a/src/ocf/.gitignore b/src/ocf/.gitignore new file mode 100644 index 000000000..0d609338e --- /dev/null +++ b/src/ocf/.gitignore @@ -0,0 +1,2 @@ +/ceph +/rbd diff --git a/src/ocf/CMakeLists.txt b/src/ocf/CMakeLists.txt new file mode 100644 index 000000000..9a87d02f1 --- /dev/null +++ b/src/ocf/CMakeLists.txt @@ -0,0 +1,10 @@ +# The root of the OCF resource agent hierarchy +# Per the OCF standard, it's always "lib", +# not "lib64" (even on 64-bit platforms). +set(ocf_dir ${CMAKE_INSTALL_PREFIX}/lib/ocf) + +# The ceph provider directory +set(ra_dir ${ocf_dir}/resource.d/${PROJECT_NAME}) + +configure_file(rbd.in rbd @ONLY) +install(PROGRAMS ${CMAKE_CURRENT_BINARY_DIR}/rbd DESTINATION ${ra_dir}) diff --git a/src/ocf/rbd.in b/src/ocf/rbd.in new file mode 100644 index 000000000..cbcc1d5b3 --- /dev/null +++ b/src/ocf/rbd.in @@ -0,0 +1,315 @@ +#!/bin/sh +# +# OCF resource agent for mapping and unmapping +# RADOS Block Devices (RBDs) +# +# License: GNU Lesser General Public License (LGPL) 2.1 or 3.0 +# (c) 2012 Florian Haas, hastexo +# + +# Initialization: +: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat} +. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs + +# Convenience variables +# When sysconfdir isn't passed in as a configure flag, +# it's defined in terms of prefix +prefix=@prefix@ + +# Defaults +OCF_RESKEY_pool_default="rbd" +OCF_RESKEY_cephconf_default="@sysconfdir@/@PACKAGE_TARNAME@/@PACKAGE_TARNAME@.conf" +: ${OCF_RESKEY_pool=${OCF_RESKEY_pool_default}} +: ${OCF_RESKEY_cephconf=${OCF_RESKEY_cephconf_default}} + +rbd_meta_data() { + cat <<EOF +<?xml version="1.0"?> +<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd"> +<resource-agent name="rbd" version="0.1"> + <version>0.1</version> + <longdesc lang="en"> +Manages RADOS Block Devices (RBDs) as a highly available +resource. Maps and unmaps RBDs as needed. + </longdesc> + <shortdesc lang="en">Maps and unmaps RADOS Block Devices</shortdesc> + <parameters> + <parameter name="name" unique="0" required="1"> + <longdesc lang="en"> + Name of the RBD device. + </longdesc> + <shortdesc lang="en">RBD device name</shortdesc> + <content type="string"/> + </parameter> + <parameter name="pool_namespace" unique="0" required="0"> + <longdesc lang="en"> + Name of the RADOS pool namespace where the RBD has been created + </longdesc> + <shortdesc lang="en">RADOS pool namespace name</shortdesc> + </parameter> + <parameter name="pool" unique="0" required="0"> + <longdesc lang="en"> + Name of the RADOS pool where the RBD has been created + </longdesc> + <shortdesc lang="en">RADOS pool name</shortdesc> + <content type="string" default="${OCF_RESKEY_pool_default}"/> + </parameter> + <parameter name="snap" unique="0" required="0"> + <longdesc lang="en"> + Name of the device snapshot to map. + </longdesc> + <shortdesc lang="en">Snapshot name</shortdesc> + <content type="string"/> + </parameter> + <parameter name="cephconf" unique="0" required="0"> + <longdesc lang="en"> + Location of the Ceph configuration file + </longdesc> + <shortdesc lang="en">Ceph configuration file</shortdesc> + <content type="string" default="${OCF_RESKEY_cephconf_default}"/> + </parameter> + <parameter name="mon" unique="0" required="0"> + <longdesc lang="en"> + Address (or comma-separated list of addresses) of + monitor servers to connect to. Overrides values from + configuration file. + </longdesc> + <shortdesc lang="en">Monitor address(es)</shortdesc> + <content type="string"/> + </parameter> + <parameter name="user" unique="0" required="0"> + <longdesc lang="en"> + Username to use when mapping the device. Required + if Ceph authentication is enabled on the monitor. + </longdesc> + <shortdesc lang="en">Authentication username</shortdesc> + <content type="string"/> + </parameter> + <parameter name="secret" unique="0" required="0"> + <longdesc lang="en"> + File containing an authentication secret. Required + if Ceph authentication is enabled on the monitor. + </longdesc> + <shortdesc lang="en">Authentication secret file</shortdesc> + <content type="string"/> + </parameter> + </parameters> + <actions> + <action name="start" timeout="20" /> + <action name="stop" timeout="20" /> + <action name="monitor" timeout="20" + interval="10" depth="0" /> + <action name="meta-data" timeout="5" /> + <action name="validate-all" timeout="20" /> + </actions> +</resource-agent> +EOF +} + +rbd_usage() { + cat <<EOF +usage: $0 {start|stop|status|monitor|validate-all|meta-data} + +Expects to have a fully populated OCF RA-compliant environment set. +EOF +} + +get_rbd_options() { + local rbd_options + + if [ -n "${OCF_RESKEY_cephconf}" ]; then + rbd_options="$rbd_options -c ${OCF_RESKEY_cephconf}" + fi + if [ -n "${OCF_RESKEY_mon}" ]; then + rbd_options="$rbd_options -m ${OCF_RESKEY_mon}" + fi + + echo "${rbd_options}" +} + + +# rbd command wrapper: builds an option string for invoking RBD based +# on resource parameters, and invokes rbd through ocf_run. +do_rbd() { + local rbd_options="$(get_rbd_options)" + + ocf_run rbd $rbd_options $@ +} + +# Convenience function that uses "rbd device list" to retrieve the +# mapped device name from the pool, RBD name, and snapshot. +find_rbd_dev() { + local rbd_options="$(get_rbd_options)" + local sedpat + + # Example output from "rbd device list" (tab separated): + # id pool namespace image snap device + # 0 rbd test - /dev/rbd0 + # 1 rbd ns1 test - /dev/rbd1 + + # Build the sed pattern, substituting "-" for the snapshot name if + # it's unset + sedpat="[0-9]\+[ \t]\+${OCF_RESKEY_pool}[ \t]\+${OCF_RESKEY_pool_namespace}[ \t]\+${OCF_RESKEY_name}[ \t]\+${OCF_RESKEY_snap:--}[ \t]\+\(/dev/rbd[0-9]\+\).*" + + # Run "rbd device list", filter out the header line, then try to + # extract the device name + rbd $rbd_options device list | tail -n +2 | sed -n -e "s,$sedpat,\1,p" +} + +rbd_validate_all() { + # Test for configuration errors first + if [ -z "$OCF_RESKEY_name" ]; then + ocf_log err 'Required parameter "name" is unset!' + exit $OCF_ERR_CONFIGURED + fi + + # Test for required binaries + check_binary rbd + + return $OCF_SUCCESS +} + +rbd_monitor() { + local rc + local rbd_dev + + if ! [ -d /sys/bus/rbd ]; then + ocf_log debug "rbd module is not loaded" + return $OCF_NOT_RUNNING + fi + + rbd_dev=`find_rbd_dev` + + if [ -z "$rbd_dev" ]; then + ocf_log debug "RBD device is unmapped" + rc=$OCF_NOT_RUNNING + elif [ -b "$rbd_dev" ]; then + ocf_log debug "RBD device is mapped to $rbd_dev" + rc=$OCF_SUCCESS + else + # Device is listed, but the corresponding path is not a block + # device. + ocf_log err "$rbd_dev is not a block device!" + rc=$OCF_ERR_GENERIC + fi + + return $rc +} + +rbd_start() { + local rbd_map_options + local rbd_name + + # if resource is already running, bail out early + if rbd_monitor; then + ocf_log info "Resource is already running" + return $OCF_SUCCESS + fi + + # actually start up the resource here (make sure to immediately + # exit with an $OCF_ERR_ error code if anything goes seriously + # wrong) + + if [ ! -d /sys/bus/rbd ]; then + ocf_run modprobe -v rbd || exit $OCF_ERR_INSTALLED + fi + + if [ -n "${OCF_RESKEY_user}" ]; then + rbd_map_options="--id ${OCF_RESKEY_user}" + fi + if [ -n "${OCF_RESKEY_secret}" ]; then + rbd_map_options="$rbd_map_options --keyfile ${OCF_RESKEY_secret}" + fi + + rbd_name="${OCF_RESKEY_pool}" + if [ -n "${OCF_RESKEY_pool_namespace}" ]; then + rbd_name="${rbd_name}/${OCF_RESKEY_pool_namespace}" + fi + rbd_name="${rbd_name}/${OCF_RESKEY_name}" + if [ -n "${OCF_RESKEY_snap}" ]; then + rbd_name="${rbd_name}@${OCF_RESKEY_snap}" + fi + + do_rbd device map $rbd_name $rbd_map_options || exit $OCF_ERR_GENERIC + + # After the resource has been started, check whether it started up + # correctly. If the resource starts asynchronously, the agent may + # spin on the monitor function here -- if the resource does not + # start up within the defined timeout, the cluster manager will + # consider the start action failed + while ! rbd_monitor; do + ocf_log debug "Resource has not started yet, waiting" + sleep 1 + done + + # only return $OCF_SUCCESS if _everything_ succeeded as expected + return $OCF_SUCCESS +} + +rbd_stop() { + local rc + local rbd_dev + + rbd_monitor + rc=$? + case "$rc" in + "$OCF_SUCCESS") + # Currently running. Normal, expected behavior. + ocf_log debug "Resource is currently running" + ;; + "$OCF_NOT_RUNNING") + # Currently not running. Nothing to do. + ocf_log info "Resource is already stopped" + return $OCF_SUCCESS + ;; + esac + + # actually shut down the resource here (make sure to immediately + # exit with an $OCF_ERR_ error code if anything goes seriously + # wrong) + rbd_dev=`find_rbd_dev` + do_rbd device unmap $rbd_dev || exit $OCF_ERR_GENERIC + + # After the resource has been stopped, check whether it shut down + # correctly. If the resource stops asynchronously, the agent may + # spin on the monitor function here -- if the resource does not + # shut down within the defined timeout, the cluster manager will + # consider the stop action failed + while rbd_monitor; do + ocf_log debug "Resource has not stopped yet, waiting" + sleep 1 + done + + # only return $OCF_SUCCESS if _everything_ succeeded as expected + return $OCF_SUCCESS + +} + +# Make sure meta-data and usage always succeed +case $__OCF_ACTION in +meta-data) rbd_meta_data + exit $OCF_SUCCESS + ;; +usage|help) rbd_usage + exit $OCF_SUCCESS + ;; +esac + +# Anything other than meta-data and usage must pass validation +rbd_validate_all || exit $? + +# Translate each action into the appropriate function call +case $__OCF_ACTION in +start) rbd_start;; +stop) rbd_stop;; +status|monitor) rbd_monitor;; +validate-all) ;; +*) rbd_usage + exit $OCF_ERR_UNIMPLEMENTED + ;; +esac +rc=$? + +# The resource agent may optionally log a debug message +ocf_log debug "${OCF_RESOURCE_INSTANCE} $__OCF_ACTION returned $rc" +exit $rc |