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