Permalink
Cannot retrieve contributors at this time
Join GitHub today
GitHub is home to over 40 million developers working together to host and review code, manage projects, and build software together.
Sign up
Fetching contributors…
| #!@BASH_SHELL@ | |
| # | |
| # | |
| # Support: users@clusterlabs.org | |
| # License: GNU General Public License v2 | |
| # | |
| # Copyright (c) 2014 SUSE Linux Products GmbH, Lars Marowsky-Brée | |
| # All Rights Reserved. | |
| # | |
| ####################################################################### | |
| : ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat} | |
| . ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs | |
| # Parameter defaults | |
| OCF_RESKEY_hostname_default="" | |
| OCF_RESKEY_ip_default="" | |
| OCF_RESKEY_ttl_default="300" | |
| OCF_RESKEY_keyfile_default="" | |
| OCF_RESKEY_server_default="" | |
| OCF_RESKEY_serverport_default="53" | |
| OCF_RESKEY_nsupdate_opts_default="" | |
| OCF_RESKEY_unregister_on_stop_default="false" | |
| : ${OCF_RESKEY_hostname=${OCF_RESKEY_hostname_default}} | |
| : ${OCF_RESKEY_ip=${OCF_RESKEY_ip_default}} | |
| : ${OCF_RESKEY_ttl=${OCF_RESKEY_ttl_default}} | |
| : ${OCF_RESKEY_keyfile=${OCF_RESKEY_keyfile_default}} | |
| : ${OCF_RESKEY_server=${OCF_RESKEY_server_default}} | |
| : ${OCF_RESKEY_serverport=${OCF_RESKEY_serverport_default}} | |
| : ${OCF_RESKEY_nsupdate_opts=${OCF_RESKEY_nsupdate_opts_default}} | |
| : ${OCF_RESKEY_unregister_on_stop=${OCF_RESKEY_unregister_on_stop_default}} | |
| ####################################################################### | |
| # TODO: | |
| # - Should setting CNAMEs be supported? | |
| # - Should multiple A records be supported? | |
| usage() { | |
| cat <<-! | |
| usage: $0 {start|stop|status|monitor|meta-data|validate-all} | |
| ! | |
| } | |
| meta_data() { | |
| cat <<END | |
| <?xml version="1.0"?> | |
| <!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd"> | |
| <resource-agent name="dnsupdate"> | |
| <version>1.0</version> | |
| <longdesc lang="en"> | |
| This resource agent manages IP take-over via dynamic DNS updates. | |
| </longdesc> | |
| <shortdesc lang="en">IP take-over via dynamic DNS update</shortdesc> | |
| <parameters> | |
| <parameter name="hostname" unique="1" required="1"> | |
| <longdesc lang="en"> | |
| The hostname whose IP address will need to be updated. | |
| </longdesc> | |
| <shortdesc lang="en">Hostname to update</shortdesc> | |
| <content type="string" default="${OCF_RESKEY_hostname_default}" /> | |
| </parameter> | |
| <parameter name="ip" unique="0" required="1"> | |
| <longdesc lang="en"> | |
| IP address to set. | |
| </longdesc> | |
| <shortdesc lang="en">IP address to set</shortdesc> | |
| <content type="string" default="${OCF_RESKEY_ip_default}" /> | |
| </parameter> | |
| <parameter name="ttl" unique="0" required="0"> | |
| <longdesc lang="en"> | |
| Time to live, in seconds, for the DNS record. This | |
| affects how soon DNS updates propagate. It should be | |
| a reasonable compromise between update speed and DNS | |
| server load. | |
| If using booth, the ticket timeout is a good start. | |
| </longdesc> | |
| <shortdesc lang="en">TTL for the DNS record</shortdesc> | |
| <content type="integer" default="${OCF_RESKEY_ttl_default}" /> | |
| </parameter> | |
| <parameter name="keyfile" unique="0" required="0"> | |
| <longdesc lang="en"> | |
| The file containing the shared secret needed to update | |
| the DNS record. Please see the nsupdate man page for | |
| the exact syntax. | |
| </longdesc> | |
| <shortdesc lang="en">nsupdate key file</shortdesc> | |
| <content type="string" default="${OCF_RESKEY_keyfile_default}" /> | |
| </parameter> | |
| <parameter name="server" unique="0" required="0"> | |
| <longdesc lang="en"> | |
| Which DNS server to send these updates for. When no | |
| server is provided, this defaults to the master server | |
| for the correct zone. | |
| </longdesc> | |
| <shortdesc lang="en">DNS server to contact</shortdesc> | |
| <content type="string" default="${OCF_RESKEY_server_default}" /> | |
| </parameter> | |
| <parameter name="serverport" unique="0" required="0"> | |
| <longdesc lang="en"> | |
| Port number on the DNS server. | |
| Note: due to a limitation in the nsupdate command, this option will only | |
| take effect if you also specify the DNS server! | |
| </longdesc> | |
| <shortdesc lang="en">Port number on the DNS server</shortdesc> | |
| <content type="integer" default="${OCF_RESKEY_serverport_default}" /> | |
| </parameter> | |
| <parameter name="nsupdate_opts" unique="0" required="0"> | |
| <longdesc lang="en"> | |
| Additional options to be passed to nsupdate. | |
| </longdesc> | |
| <shortdesc lang="en">Additional nsupdate options</shortdesc> | |
| <content type="string" default="${OCF_RESKEY_nsupdate_opts_default}" /> | |
| </parameter> | |
| <parameter name="unregister_on_stop" unique="0" required="0"> | |
| <longdesc lang="en"> | |
| Whether or not to actively remove records on stop. This is not needed | |
| for normal operation, since the site taking over the IP address will | |
| delete all previous records. | |
| </longdesc> | |
| <shortdesc lang="en">Remove A record on stop</shortdesc> | |
| <content type="boolean" default="${OCF_RESKEY_unregister_on_stop_default}" /> | |
| </parameter> | |
| </parameters> | |
| <actions> | |
| <action name="start" timeout="30s" /> | |
| <action name="stop" timeout="30s" /> | |
| <action name="status" depth="0" timeout="30s" interval="10s" /> | |
| <action name="monitor" depth="0" timeout="30s" interval="10s" /> | |
| <action name="meta-data" timeout="5s" /> | |
| <action name="validate-all" timeout="5s" /> | |
| </actions> | |
| </resource-agent> | |
| END | |
| } | |
| dnsupdate_status() { | |
| # The resource is considered active if the current IP | |
| # address is returned as the only response. | |
| local record=$(dig ${dig_opts} ${hostname}. A +short 2>/dev/null) | |
| if [ "$record" = "$ip" ]; then | |
| return $OCF_SUCCESS | |
| fi | |
| return $OCF_NOT_RUNNING | |
| } | |
| dnsupdate_monitor() { | |
| if ocf_is_probe ; then | |
| # | |
| return $OCF_NOT_RUNNING | |
| fi | |
| dnsupdate_status | |
| } | |
| dnsupdate_start() { | |
| if dnsupdate_status ; then | |
| ocf_log info "$hostname already resolves to $ip" | |
| return $OCF_SUCCESS | |
| fi | |
| ocf_log info "Updating DNS records for $hostname" | |
| ( | |
| if [ -n "$dns_server" ]; then | |
| echo "server ${dns_server} ${dns_serverport}" | |
| fi | |
| echo "update delete $hostname A" | |
| echo "update add $hostname ${OCF_RESKEY_ttl} A $ip" | |
| echo "send" | |
| ) | nsupdate ${nsupdate_opts} | |
| dnsupdate_monitor | |
| return $? | |
| } | |
| dnsupdate_stop() { | |
| if ocf_is_true "${OCF_RESKEY_unregister_on_stop}" && dnsupdate_status ; then | |
| ocf_log info "Unregistering $hostname with $ip from DNS server" | |
| ( | |
| if [ -n "$dns_server" ]; then | |
| echo "server ${dns_server} ${dns_serverport}" | |
| fi | |
| echo "update delete $hostname A $ip" | |
| echo "send" | |
| ) | nsupdate ${nsupdate_opts} | |
| dnsupdate_monitor | |
| if [ $? -ne $OCF_NOT_RUNNING ]; then | |
| ocf_log warn "Unregistering failed!" | |
| # There's no point in invoking a stop failure | |
| # here. If another site takes over the record, | |
| # it'll delete all previous entries anyway. | |
| fi | |
| fi | |
| return $OCF_SUCCESS | |
| } | |
| dnsupdate_validate() { | |
| hostname=${OCF_RESKEY_hostname} | |
| ip=${OCF_RESKEY_ip} | |
| dig_opts="" | |
| dns_server=${OCF_RESKEY_server} | |
| : ${OCF_RESKEY_serverport:="53"} | |
| dns_serverport=${OCF_RESKEY_serverport} | |
| : ${OCF_RESKEY_ttl:="300"} | |
| nsupdate_opts=${OCF_RESKEY_nsupdate_opts} | |
| if [ -z "$nsupdate_opts" -a -n "$OCF_RESKEY_opts" ]; then | |
| nsupdate_opts=${OCF_RESKEY_opts} | |
| ocf_log warn "opts was never an advertised parameter, please use nsupdate_opts" | |
| fi | |
| if [ -z "$hostname" ]; then | |
| ocf_log err "No hostname specified." | |
| exit $OCF_ERR_CONFIGURED | |
| fi | |
| if [ -z "$ip" ]; then | |
| ocf_log err "No IP specified." | |
| exit $OCF_ERR_CONFIGURED | |
| fi | |
| if ! ocf_is_decimal $OCF_RESKEY_ttl ; then | |
| ocf_log err "ttl $OCF_RESKEY_ttl is not valid" | |
| exit $OCF_ERR_CONFIGURED | |
| fi | |
| if ! ocf_is_decimal $dns_serverport ; then | |
| ocf_log err "serverport $dns_serverport is not valid" | |
| exit $OCF_ERR_CONFIGURED | |
| fi | |
| dig_opts+=" -p ${dns_serverport}" | |
| if [ -n "$dns_server" ]; then | |
| dig_opts+=" @${dns_server}" | |
| fi | |
| if [ -n "$OCF_RESKEY_keyfile" ]; then | |
| if [ ! -f ${OCF_RESKEY_keyfile} ]; then | |
| ocf_log err "keyfile $OCF_RESKEY_keyfile does not exist" | |
| exit $OCF_ERR_CONFIGURED | |
| fi | |
| nsupdate_opts+=" -k $OCF_RESKEY_keyfile" | |
| fi | |
| } | |
| if [ $# -ne 1 ]; then | |
| usage | |
| exit $OCF_ERR_ARGS | |
| fi | |
| case $1 in | |
| meta-data) meta_data | |
| exit $OCF_SUCCESS | |
| ;; | |
| usage) usage | |
| exit $OCF_SUCCESS | |
| ;; | |
| esac | |
| check_binary dig | |
| check_binary nsupdate | |
| dnsupdate_validate | |
| case $1 in | |
| start) dnsupdate_start | |
| ;; | |
| stop) dnsupdate_stop | |
| ;; | |
| monitor) dnsupdate_monitor | |
| ;; | |
| status) dnsupdate_status | |
| ;; | |
| validate-all) # We've already run this | |
| exit $OCF_SUCCESS | |
| ;; | |
| *) usage | |
| exit $OCF_ERR_UNIMPLEMENTED | |
| ;; | |
| esac | |
| exit $? | |