]> git.proxmox.com Git - ceph.git/blob - ceph/src/ocf/rbd.in
import 15.2.9
[ceph.git] / ceph / src / ocf / rbd.in
1 #!/bin/sh
2 #
3 # OCF resource agent for mapping and unmapping
4 # RADOS Block Devices (RBDs)
5 #
6 # License: GNU Lesser General Public License (LGPL) 2.1 or 3.0
7 # (c) 2012 Florian Haas, hastexo
8 #
9
10 # Initialization:
11 : ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat}
12 . ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs
13
14 # Convenience variables
15 # When sysconfdir isn't passed in as a configure flag,
16 # it's defined in terms of prefix
17 prefix=@prefix@
18
19 # Defaults
20 OCF_RESKEY_pool_default="rbd"
21 OCF_RESKEY_cephconf_default="@sysconfdir@/@PACKAGE_TARNAME@/@PACKAGE_TARNAME@.conf"
22 : ${OCF_RESKEY_pool=${OCF_RESKEY_pool_default}}
23 : ${OCF_RESKEY_cephconf=${OCF_RESKEY_cephconf_default}}
24
25 rbd_meta_data() {
26 cat <<EOF
27 <?xml version="1.0"?>
28 <!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
29 <resource-agent name="rbd" version="0.1">
30 <version>0.1</version>
31 <longdesc lang="en">
32 Manages RADOS Block Devices (RBDs) as a highly available
33 resource. Maps and unmaps RBDs as needed.
34 </longdesc>
35 <shortdesc lang="en">Maps and unmaps RADOS Block Devices</shortdesc>
36 <parameters>
37 <parameter name="name" unique="0" required="1">
38 <longdesc lang="en">
39 Name of the RBD device.
40 </longdesc>
41 <shortdesc lang="en">RBD device name</shortdesc>
42 <content type="string"/>
43 </parameter>
44 <parameter name="pool_namespace" unique="0" required="0">
45 <longdesc lang="en">
46 Name of the RADOS pool namespace where the RBD has been created
47 </longdesc>
48 <shortdesc lang="en">RADOS pool namespace name</shortdesc>
49 </parameter>
50 <parameter name="pool" unique="0" required="0">
51 <longdesc lang="en">
52 Name of the RADOS pool where the RBD has been created
53 </longdesc>
54 <shortdesc lang="en">RADOS pool name</shortdesc>
55 <content type="string" default="${OCF_RESKEY_pool_default}"/>
56 </parameter>
57 <parameter name="snap" unique="0" required="0">
58 <longdesc lang="en">
59 Name of the device snapshot to map.
60 </longdesc>
61 <shortdesc lang="en">Snapshot name</shortdesc>
62 <content type="string"/>
63 </parameter>
64 <parameter name="cephconf" unique="0" required="0">
65 <longdesc lang="en">
66 Location of the Ceph configuration file
67 </longdesc>
68 <shortdesc lang="en">Ceph configuration file</shortdesc>
69 <content type="string" default="${OCF_RESKEY_cephconf_default}"/>
70 </parameter>
71 <parameter name="mon" unique="0" required="0">
72 <longdesc lang="en">
73 Address (or comma-separated list of addresses) of
74 monitor servers to connect to. Overrides values from
75 configuration file.
76 </longdesc>
77 <shortdesc lang="en">Monitor address(es)</shortdesc>
78 <content type="string"/>
79 </parameter>
80 <parameter name="user" unique="0" required="0">
81 <longdesc lang="en">
82 Username to use when mapping the device. Required
83 if Ceph authentication is enabled on the monitor.
84 </longdesc>
85 <shortdesc lang="en">Authentication username</shortdesc>
86 <content type="string"/>
87 </parameter>
88 <parameter name="secret" unique="0" required="0">
89 <longdesc lang="en">
90 File containing an authentication secret. Required
91 if Ceph authentication is enabled on the monitor.
92 </longdesc>
93 <shortdesc lang="en">Authentication secret file</shortdesc>
94 <content type="string"/>
95 </parameter>
96 </parameters>
97 <actions>
98 <action name="start" timeout="20" />
99 <action name="stop" timeout="20" />
100 <action name="monitor" timeout="20"
101 interval="10" depth="0" />
102 <action name="meta-data" timeout="5" />
103 <action name="validate-all" timeout="20" />
104 </actions>
105 </resource-agent>
106 EOF
107 }
108
109 rbd_usage() {
110 cat <<EOF
111 usage: $0 {start|stop|status|monitor|validate-all|meta-data}
112
113 Expects to have a fully populated OCF RA-compliant environment set.
114 EOF
115 }
116
117 get_rbd_options() {
118 local rbd_options
119
120 if [ -n "${OCF_RESKEY_cephconf}" ]; then
121 rbd_options="$rbd_options -c ${OCF_RESKEY_cephconf}"
122 fi
123 if [ -n "${OCF_RESKEY_mon}" ]; then
124 rbd_options="$rbd_options -m ${OCF_RESKEY_mon}"
125 fi
126
127 echo "${rbd_options}"
128 }
129
130
131 # rbd command wrapper: builds an option string for invoking RBD based
132 # on resource parameters, and invokes rbd through ocf_run.
133 do_rbd() {
134 local rbd_options="$(get_rbd_options)"
135
136 ocf_run rbd $rbd_options $@
137 }
138
139 # Convenience function that uses "rbd device list" to retrieve the
140 # mapped device name from the pool, RBD name, and snapshot.
141 find_rbd_dev() {
142 local rbd_options="$(get_rbd_options)"
143 local sedpat
144
145 # Example output from "rbd device list" (tab separated):
146 # id pool namespace image snap device
147 # 0 rbd test - /dev/rbd0
148 # 1 rbd ns1 test - /dev/rbd1
149
150 # Build the sed pattern, substituting "-" for the snapshot name if
151 # it's unset
152 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]\+\).*"
153
154 # Run "rbd device list", filter out the header line, then try to
155 # extract the device name
156 rbd $rbd_options device list | tail -n +2 | sed -n -e "s,$sedpat,\1,p"
157 }
158
159 rbd_validate_all() {
160 # Test for configuration errors first
161 if [ -z "$OCF_RESKEY_name" ]; then
162 ocf_log err 'Required parameter "name" is unset!'
163 exit $OCF_ERR_CONFIGURED
164 fi
165
166 # Test for required binaries
167 check_binary rbd
168
169 return $OCF_SUCCESS
170 }
171
172 rbd_monitor() {
173 local rc
174 local rbd_dev
175
176 if ! [ -d /sys/bus/rbd ]; then
177 ocf_log debug "rbd module is not loaded"
178 return $OCF_NOT_RUNNING
179 fi
180
181 rbd_dev=`find_rbd_dev`
182
183 if [ -z "$rbd_dev" ]; then
184 ocf_log debug "RBD device is unmapped"
185 rc=$OCF_NOT_RUNNING
186 elif [ -b "$rbd_dev" ]; then
187 ocf_log debug "RBD device is mapped to $rbd_dev"
188 rc=$OCF_SUCCESS
189 else
190 # Device is listed, but the corresponding path is not a block
191 # device.
192 ocf_log err "$rbd_dev is not a block device!"
193 rc=$OCF_ERR_GENERIC
194 fi
195
196 return $rc
197 }
198
199 rbd_start() {
200 local rbd_map_options
201 local rbd_name
202
203 # if resource is already running, bail out early
204 if rbd_monitor; then
205 ocf_log info "Resource is already running"
206 return $OCF_SUCCESS
207 fi
208
209 # actually start up the resource here (make sure to immediately
210 # exit with an $OCF_ERR_ error code if anything goes seriously
211 # wrong)
212
213 if [ ! -d /sys/bus/rbd ]; then
214 ocf_run modprobe -v rbd || exit $OCF_ERR_INSTALLED
215 fi
216
217 if [ -n "${OCF_RESKEY_user}" ]; then
218 rbd_map_options="--id ${OCF_RESKEY_user}"
219 fi
220 if [ -n "${OCF_RESKEY_secret}" ]; then
221 rbd_map_options="$rbd_map_options --keyfile ${OCF_RESKEY_secret}"
222 fi
223
224 rbd_name="${OCF_RESKEY_pool}"
225 if [ -n "${OCF_RESKEY_pool_namespace}" ]; then
226 rbd_name="${rbd_name}/${OCF_RESKEY_pool_namespace}"
227 fi
228 rbd_name="${rbd_name}/${OCF_RESKEY_name}"
229 if [ -n "${OCF_RESKEY_snap}" ]; then
230 rbd_name="${rbd_name}@${OCF_RESKEY_snap}"
231 fi
232
233 do_rbd device map $rbd_name $rbd_map_options || exit $OCF_ERR_GENERIC
234
235 # After the resource has been started, check whether it started up
236 # correctly. If the resource starts asynchronously, the agent may
237 # spin on the monitor function here -- if the resource does not
238 # start up within the defined timeout, the cluster manager will
239 # consider the start action failed
240 while ! rbd_monitor; do
241 ocf_log debug "Resource has not started yet, waiting"
242 sleep 1
243 done
244
245 # only return $OCF_SUCCESS if _everything_ succeeded as expected
246 return $OCF_SUCCESS
247 }
248
249 rbd_stop() {
250 local rc
251 local rbd_dev
252
253 rbd_monitor
254 rc=$?
255 case "$rc" in
256 "$OCF_SUCCESS")
257 # Currently running. Normal, expected behavior.
258 ocf_log debug "Resource is currently running"
259 ;;
260 "$OCF_NOT_RUNNING")
261 # Currently not running. Nothing to do.
262 ocf_log info "Resource is already stopped"
263 return $OCF_SUCCESS
264 ;;
265 esac
266
267 # actually shut down the resource here (make sure to immediately
268 # exit with an $OCF_ERR_ error code if anything goes seriously
269 # wrong)
270 rbd_dev=`find_rbd_dev`
271 do_rbd device unmap $rbd_dev || exit $OCF_ERR_GENERIC
272
273 # After the resource has been stopped, check whether it shut down
274 # correctly. If the resource stops asynchronously, the agent may
275 # spin on the monitor function here -- if the resource does not
276 # shut down within the defined timeout, the cluster manager will
277 # consider the stop action failed
278 while rbd_monitor; do
279 ocf_log debug "Resource has not stopped yet, waiting"
280 sleep 1
281 done
282
283 # only return $OCF_SUCCESS if _everything_ succeeded as expected
284 return $OCF_SUCCESS
285
286 }
287
288 # Make sure meta-data and usage always succeed
289 case $__OCF_ACTION in
290 meta-data) rbd_meta_data
291 exit $OCF_SUCCESS
292 ;;
293 usage|help) rbd_usage
294 exit $OCF_SUCCESS
295 ;;
296 esac
297
298 # Anything other than meta-data and usage must pass validation
299 rbd_validate_all || exit $?
300
301 # Translate each action into the appropriate function call
302 case $__OCF_ACTION in
303 start) rbd_start;;
304 stop) rbd_stop;;
305 status|monitor) rbd_monitor;;
306 validate-all) ;;
307 *) rbd_usage
308 exit $OCF_ERR_UNIMPLEMENTED
309 ;;
310 esac
311 rc=$?
312
313 # The resource agent may optionally log a debug message
314 ocf_log debug "${OCF_RESOURCE_INSTANCE} $__OCF_ACTION returned $rc"
315 exit $rc