1#!/usr/local/bin/bash 2# 3# Description: Manages a named (Bind) server as an OCF High-Availability 4# resource 5# 6# Authors: Serge Dubrouski (sergeyfd@gmail.com) 7# 8# Copyright: 2011 Serge Dubrouski <sergeyfd@gmail.com> 9# 10# License: GNU General Public License (GPL) 11# 12############################################################################### 13# Initialization: 14 15: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat} 16. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs 17 18#Defaults 19OCF_RESKEY_named_default="/usr/sbin/named" 20OCF_RESKEY_rndc_default="/usr/sbin/rndc" 21OCF_RESKEY_host_default="/usr/bin/host" 22OCF_RESKEY_named_user_default=named 23OCF_RESKEY_named_config_default="" 24OCF_RESKEY_named_pidfile_default="/var/run/named/named.pid" 25OCF_RESKEY_named_rootdir_default="" 26OCF_RESKEY_named_options_default="" 27OCF_RESKEY_named_keytab_file_default="" 28OCF_RESKEY_rndc_options_default="" 29OCF_RESKEY_host_options_default="" 30OCF_RESKEY_monitor_request_default="localhost" 31OCF_RESKEY_monitor_response_default="127.0.0.1" 32OCF_RESKEY_monitor_ip_default="127.0.0.1" 33 34: ${OCF_RESKEY_named=${OCF_RESKEY_named_default}} 35: ${OCF_RESKEY_rndc=${OCF_RESKEY_rndc_default}} 36: ${OCF_RESKEY_host=${OCF_RESKEY_host_default}} 37: ${OCF_RESKEY_named_user=${OCF_RESKEY_named_user_default}} 38: ${OCF_RESKEY_named_config=${OCF_RESKEY_named_config_default}} 39: ${OCF_RESKEY_named_pidfile=${OCF_RESKEY_named_pidfile_default}} 40: ${OCF_RESKEY_named_rootdir=${OCF_RESKEY_named_rootdir_default}} 41: ${OCF_RESKEY_named_options=${OCF_RESKEY_named_options_default}} 42: ${OCF_RESKEY_named_keytab_file=${OCF_RESKEY_named_keytab_file_default}} 43: ${OCF_RESKEY_rndc_options=${OCF_RESKEY_rndc_options_default}} 44: ${OCF_RESKEY_host_options=${OCF_RESKEY_host_options_default}} 45: ${OCF_RESKEY_monitor_request=${OCF_RESKEY_monitor_request_default}} 46: ${OCF_RESKEY_monitor_response=${OCF_RESKEY_monitor_response_default}} 47: ${OCF_RESKEY_monitor_ip=${OCF_RESKEY_monitor_ip_default}} 48 49usage() { 50 cat <<EOF 51 usage: $0 start|stop|reload|status|monitor|meta-data|validate-all|methods 52 53 $0 manages named (Bind) server as an HA resource. 54 55 The 'start' operation starts named server. 56 The 'stop' operation stops named server. 57 The 'reload' operation reload named configuration. 58 The 'status' operation reports whether named is up. 59 The 'monitor' operation reports whether named is running. 60 The 'validate-all' operation reports whether parameters are valid. 61 The 'methods' operation reports on the methods $0 supports. 62EOF 63 return $OCF_ERR_ARGS 64} 65 66named_meta_data() { 67 cat <<EOF 68<?xml version="1.0"?> 69<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd"> 70<resource-agent name="named"> 71<version>1.0</version> 72 73<longdesc lang="en"> 74Resource script for named (Bind) server. It manages named as an HA resource. 75</longdesc> 76<shortdesc lang="en">Manages a named server</shortdesc> 77 78<parameters> 79<parameter name="named" unique="0" required="0"> 80<longdesc lang="en"> 81Path to the named command. 82</longdesc> 83<shortdesc lang="en">named</shortdesc> 84<content type="string" default="${OCF_RESKEY_named_default}" /> 85</parameter> 86 87<parameter name="rndc" unique="0" required="0"> 88<longdesc lang="en"> 89Path to the rndc command. 90</longdesc> 91<shortdesc lang="en">rndc</shortdesc> 92<content type="string" default="${OCF_RESKEY_rndc_default}" /> 93</parameter> 94 95<parameter name="host" unique="0" required="0"> 96<longdesc lang="en"> 97Path to the host command. 98</longdesc> 99<shortdesc lang="en">host</shortdesc> 100<content type="string" default="${OCF_RESKEY_host_default}" /> 101</parameter> 102 103<parameter name="named_user" unique="0" required="0"> 104<longdesc lang="en"> 105User that should own named process. 106</longdesc> 107<shortdesc lang="en">named_user</shortdesc> 108<content type="string" default="${OCF_RESKEY_named_user_default}" /> 109</parameter> 110 111<parameter name="named_config" unique="1" required="0"> 112<longdesc lang="en"> 113Configuration file for named. 114</longdesc> 115<shortdesc lang="en">named_config</shortdesc> 116<content type="string" default="${OCF_RESKEY_named_config_default}" /> 117</parameter> 118 119<parameter name="named_pidfile" unique="1" required="0"> 120<longdesc lang="en"> 121PIDFILE file for named. 122</longdesc> 123<shortdesc lang="en">named_pidfile</shortdesc> 124<content type="string" default="${OCF_RESKEY_named_pidfile_default}" /> 125</parameter> 126 127<parameter name="named_rootdir" unique="1" required="0"> 128<longdesc lang="en"> 129Directory that named should use for chroot if any. 130</longdesc> 131<shortdesc lang="en">named_rootdir</shortdesc> 132<content type="string" default="${OCF_RESKEY_named_rootdir_default}" /> 133</parameter> 134 135<parameter name="named_options" unique="0" required="0"> 136<longdesc lang="en"> 137Options for named process if any. 138</longdesc> 139<shortdesc lang="en">named_options</shortdesc> 140<content type="string" default="${OCF_RESKEY_named_options_default}" /> 141</parameter> 142 143<parameter name="named_keytab_file" unique="0" required="0"> 144<longdesc lang="en"> 145named service keytab file (for GSS-TSIG). 146</longdesc> 147<shortdesc lang="en">named_keytab_file</shortdesc> 148<content type="string" default="${OCF_RESKEY_named_keytab_file_default}" /> 149</parameter> 150 151<parameter name="rndc_options" unique="0" required="0"> 152<longdesc lang="en"> 153Options for rndc process if any. 154</longdesc> 155<shortdesc lang="en">rndc_options</shortdesc> 156<content type="string" default="${OCF_RESKEY_rndc_options_default}" /> 157</parameter> 158 159<parameter name="host_options" unique="0" required="0"> 160<longdesc lang="en"> 161Options for host process if any. 162</longdesc> 163<shortdesc lang="en">host_options</shortdesc> 164<content type="string" default="${OCF_RESKEY_host_options_default}" /> 165</parameter> 166 167<parameter name="monitor_request" unique="0" required="0"> 168<longdesc lang="en"> 169Request that shall be sent to named for monitoring. Usually an A record in DNS. 170</longdesc> 171<shortdesc lang="en">monitor_request</shortdesc> 172<content type="string" default="${OCF_RESKEY_monitor_request_default}" /> 173</parameter> 174 175<parameter name="monitor_response" unique="0" required="0"> 176<longdesc lang="en"> 177Expected response from named server. 178</longdesc> 179<shortdesc lang="en">monitor_response</shortdesc> 180<content type="string" default="${OCF_RESKEY_monitor_response_default}" /> 181</parameter> 182 183<parameter name="monitor_ip" unique="0" required="0"> 184<longdesc lang="en"> 185IP Address where named listens. 186</longdesc> 187<shortdesc lang="en">monitor_ip</shortdesc> 188<content type="string" default="${OCF_RESKEY_monitor_ip_default}" /> 189</parameter> 190</parameters> 191 192<actions> 193<action name="start" timeout="60s" /> 194<action name="stop" timeout="60s" /> 195<action name="reload" timeout="60s" /> 196<action name="status" timeout="10s" /> 197<action name="monitor" depth="0" timeout="30s" interval="30s"/> 198<action name="meta-data" timeout="5s" /> 199<action name="validate-all" timeout="5s" /> 200<action name="methods" timeout="5s" /> 201</actions> 202</resource-agent> 203 204EOF 205} 206 207# 208# methods: What methods/operations do we support? 209# 210 211named_methods() { 212 cat <<EOF 213 start 214 stop 215 status 216 monitor 217 methods 218 meta-data 219 validate-all 220EOF 221} 222 223# Validate most critical parameters 224named_validate_all() { 225 check_binary $OCF_RESKEY_named 226 check_binary $OCF_RESKEY_rndc 227 check_binary $OCF_RESKEY_host 228 229 if [ -n "$OCF_RESKEY_named_config" -a \ 230 ! -r "${OCF_RESKEY_named_rootdir}/${OCF_RESKEY_named_config}" ]; then 231 if ocf_is_probe; then 232 ocf_log info "Configuration file ${OCF_RESKEY_named_rootdir}/${OCF_RESKEY_named_config} not readable during probe." 233 else 234 ocf_exit_reason "Configuration file ${OCF_RESKEY_named_rootdir}/${OCF_RESKEY_named_config} doesn't exist" 235 return $OCF_ERR_INSTALLED 236 fi 237 fi 238 239 getent passwd $OCF_RESKEY_named_user >/dev/null 2>&1 240 if [ ! $? -eq 0 ]; then 241 ocf_exit_reason "User $OCF_RESKEY_named_user doesn't exist"; 242 return $OCF_ERR_INSTALLED; 243 fi 244 245 if [ -z "$OCF_RESKEY_monitor_request" -o \ 246 -z "$OCF_RESKEY_monitor_response" -o \ 247 -z "$OCF_RESKEY_monitor_ip" ]; then 248 ocf_exit_reason "None of monitor_request, monitor_response, and monitor_ip can be empty" 249 return $OCF_ERR_CONFIGURED 250 fi 251 252 # make sure that the pidfile directory exists 253 ocf_mkstatedir $OCF_RESKEY_named_user 755 `dirname $OCF_RESKEY_named_pidfile` || return $OCF_ERR_INSTALLED 254 255 return $OCF_SUCCESS 256} 257 258## 259# Attempt to generate a /etc/rndc.key if one is not present 260## 261rndc_key_generator() 262{ 263 local rndc_options="-a -r /dev/urandom -u $OCF_RESKEY_named_user" 264 265 if [ -s /etc/rndc.key ]; then 266 # file already exists 267 return 268 fi 269 270 if ! have_binary "rndc-confgen"; then 271 # can't autogen key... Report this, but not as a warning or error. 272 # It is possible that the user configured the key in named.conf 273 ocf_log info "rndc-confgen tool not present, unable to autogen /etc/rndc.key." 274 return 275 fi 276 277 if [ -n "$OCF_RESKEY_rootdir" ]; then 278 rndc_options="$rndc_options -t $OCF_RESKEY_rootdir" 279 fi 280 281 rndc-confgen $rndc_options > /dev/null 2>&1; 282 if [ $? -eq 0 ]; then 283 if have_binary "restorecon"; then 284 restorecon /etc/rndc.key 285 fi 286 else 287 ocf_log info "failed to auto-generate /etc/rndc.key file." 288 fi 289} 290 291# 292# named_getpid. Get pid of named process with a given parameters. 293# 294 295named_getpid () { 296 local pattern="$OCF_RESKEY_named" 297 298 if [ -n "$OCF_RESKEY_named_rootdir" -a "x${OCF_RESKEY_named_rootdir}" != "x/" ]; then 299 pattern="$pattern.*-t $OCF_RESKEY_named_rootdir" 300 fi 301 302 if [ -n "$OCF_RESKEY_named_config" ]; then 303 pattern="$pattern.*-c $OCF_RESKEY_named_config" 304 fi 305 306 pid=`pgrep -f "$pattern"` 307 echo $pid 308} 309 310# 311# named_status. Simple check of the status of named process by pidfile. 312# 313 314named_status () { 315 ocf_pidfile_status ${OCF_RESKEY_named_pidfile} >/dev/null 2>&1 316} 317 318# 319# named_monitor. Send a request to named and check response. 320# 321 322named_monitor() { 323 local output 324 325 if ! named_status 326 then 327 ocf_log info "named is down" 328 return $OCF_NOT_RUNNING 329 fi 330 331 output=`$OCF_RESKEY_host $OCF_RESKEY_host_options $OCF_RESKEY_monitor_request $OCF_RESKEY_monitor_ip` 332 333 if [ $? -ne 0 ] || ! echo $output | grep -q '.* has .*address '"$OCF_RESKEY_monitor_response" 334 then 335 ocf_exit_reason "named didn't answer properly for $OCF_RESKEY_monitor_request." 336 ocf_log err "Expected: $OCF_RESKEY_monitor_response." 337 ocf_log err "Got: $output" 338 return $OCF_ERR_GENERIC 339 fi 340 341 return $OCF_SUCCESS 342} 343 344# 345# Reload 346# 347 348named_reload() { 349 $OCF_RESKEY_rndc $OCF_RESKEY_rndc_options reload >/dev/null || return $OCF_ERR_GENERIC 350 351 return $OCF_SUCCESS 352} 353 354# 355# Start 356# 357 358named_start() { 359 local root_dir_opt 360 local pid 361 362 root_dir_opt="" 363 named_status && return $OCF_SUCCESS 364 365 # Remove pidfile if exists 366 rm -f ${OCF_RESKEY_named_pidfile} 367 368 if [ -n "${OCF_RESKEY_named_rootdir}" -a "x${OCF_RESKEY_named_rootdir}" != "x/" ] 369 then 370 root_dir_opt="-t ${OCF_RESKEY_named_rootdir}" 371 [ -s /etc/localtime ] && cp -fp /etc/localtime ${OCF_RESKEY_named_rootdir}/etc/localtime 372 fi 373 374 if [ -n "$OCF_RESKEY_named_config" ]; then 375 OCF_RESKEY_named_options="-c $OCF_RESKEY_named_config $OCF_RESKEY_named_options" 376 fi 377 378 rndc_key_generator 379 380 if ! ${OCF_RESKEY_named} -u ${OCF_RESKEY_named_user} $root_dir_opt ${OCF_RESKEY_named_options} 381 then 382 ocf_exit_reason "named failed to start." 383 return $OCF_ERR_GENERIC 384 fi 385 386 387 pid=`named_getpid` 388 389 if [ -n "$pid" ]; then 390 if [ ! -e ${OCF_RESKEY_named_pidfile} ]; then 391 echo $pid > ${OCF_RESKEY_named_pidfile} 392 fi 393 else 394 ocf_exit_reason "named failed to start. Probably error in configuration." 395 return $OCF_ERR_GENERIC 396 fi 397 398 while : 399 do 400 named_monitor && break 401 sleep 1 402 ocf_log debug "named hasn't started yet." 403 done 404 ocf_log info "named has started." 405 406 return $OCF_SUCCESS 407} 408 409# 410# Stop 411# 412 413named_stop () { 414 local timeout 415 local timewait 416 417 named_status || return $OCF_SUCCESS 418 419 $OCF_RESKEY_rndc $OCF_RESKEY_rndc_options stop >/dev/null 420 if [ $? -ne 0 ]; then 421 ocf_log info "rndc stop failed. Killing named." 422 kill `cat ${OCF_RESKEY_named_pidfile}` 423 fi 424 425 if [ -n "$OCF_RESKEY_CRM_meta_timeout" ]; then 426 # Allow 2/3 of the action timeout for the orderly shutdown 427 # (The origin unit is ms, hence the conversion) 428 timewait=$((OCF_RESKEY_CRM_meta_timeout/1500)) 429 else 430 timewait=20 431 fi 432 433 sleep 1; timeout=0 # Sleep here for 1 sec to let rndc finish. 434 while named_status ; do 435 if [ $timeout -ge $timewait ]; then 436 break 437 else 438 sleep 1 439 timeout=`expr $timeout + 1` 440 ocf_log debug "named appears to hung, waiting ..." 441 fi 442 done 443 444 #If still up 445 if named_status 2>&1; then 446 ocf_exit_reason "named is still up! Killing" 447 kill -9 `cat ${OCF_RESKEY_named_pidfile}` 448 fi 449 450 rm -f ${OCF_RESKEY_named_pidfile} 451 return $OCF_SUCCESS 452} 453 454 455# Main part 456 457if [ $# -ne 1 ]; then 458 usage 459 exit $OCF_ERR_GENERIC 460fi 461 462case "$1" in 463 methods) named_methods 464 exit $?;; 465 466 meta-data) named_meta_data 467 exit $OCF_SUCCESS;; 468esac 469 470named_validate_all 471rc=$? 472 473[ "$1" = "validate-all" ] && exit $rc 474 475if [ $rc -ne 0 ] 476then 477 case "$1" in 478 stop) exit $OCF_SUCCESS;; 479 monitor) exit $OCF_NOT_RUNNING;; 480 status) exit $OCF_NOT_RUNNING;; 481 *) exit $rc;; 482 esac 483fi 484 485if [ `id -u` -ne 0 ]; then 486 ocf_exit_reason "$0 must be run as root" 487 exit $OCF_ERR_GENERIC 488fi 489 490case "$1" in 491 status) if named_status 492 then 493 ocf_log info "named is up" 494 exit $OCF_SUCCESS 495 else 496 ocf_log info "named is down" 497 exit $OCF_NOT_RUNNING 498 fi;; 499 500 monitor) named_monitor 501 exit $?;; 502 503 start) named_start 504 exit $?;; 505 506 stop) named_stop 507 exit $?;; 508 reload) named_reload 509 exit $?;; 510 *) 511 exit $OCF_ERR_UNIMPLEMENTED;; 512esac 513 514# vim:ts=4:sw=4:et: 515