diff --git a/doc/README.hb2openais b/doc/README.hb2openais new file mode 100644 index 0000000000..84612d1c9a --- /dev/null +++ b/doc/README.hb2openais @@ -0,0 +1,246 @@ +Heartbeat to OpenAIS cluster stack conversion + +Please read this description entirely before converting to +OpenAIS. Every possible precaution was taken to preclude +problems. Still, you should run the conversion only when you +understood all the steps and the consequences. + +You need to know your cluster in detail. The conversion program +will inform you about changes it makes. It is up to you to verify +that the changes are meaningful. + +Testing the conversion + +It is possible (and highly recommended) to test the conversion +with your heartbeat configuration without making any changes. +This way you will get acquainted with the process and make sure +that the conversion is done properly. + +Create a test directory and copy ha.cf, logd.cf, cib.xml, and +hostcache to it: + +$ mkdir /tmp/hb2openais-testdir +$ cp /etc/ha.d/ha.cf /tmp/hb2openais-testdir +$ cp /var/lib/heartbeat/hostcache /tmp/hb2openais-testdir +$ cp /etc/logd.cf /tmp/hb2openais-testdir +$ sudo cp /var/lib/heartbeat/crm/cib.xml /tmp/hb2openais-testdir + +Run the test conversion: + +$ /usr/lib/heartbeat/hb2openais.sh -T /tmp/hb2openais-testdir -U + +Note: You can run the test as many times as you want on the same +test directory. Copy files just once. + +Note: The directory where hb2openais.sh resides may be different, +e.g. /usr/lib64/heartbeat. + +Read and verify the resulting openais.conf and cib-out.xml: + +$ cd /tmp/hb2openais-testdir +$ less openais.conf +$ crm_verify -V -x cib-out.xml + +The conversion takes several stages: + +1. Generate openais.conf from ha.cf. + +2. Removal of the nodes section from the CIB. + +3. Upgrade of the CIB to Pacemaker v1.0 (optional) + +4. Addition of pingd resource. + +5. Conversion of ocfs2 filesystem. + +6. Replacement of EVMS2 with LVM2. + +Conversion from the Heartbeat to OpenAIS cluster stack is +implemented in hb2openais.sh which is part of the pacemaker +package. + +Prerequisites + +/etc/ha.d/ha.cf must be equal on all nodes. + +/var/lib/heartbeat/crm/cib.xml must be equal on all nodes. This +should be enforced by the CRM. + +Heartbeat must be down on all nodes. + +The ocfs2 filesystem and EVMS2 resources must be down. + +It is possible to keep other services running: just put all +resources into the unmanaged mode before stopping heartbeat. + +sshd running on all nodes with access allowed for root. + +The conversion process + +This procedure is supposed to be run on one node only. Although +the main cluster configuration (the CIB) is automatically +replicated, there are some files which have to be copied by other +means. For that to work, we need sshd running on all nodes and +root access working. + +For some operations root privileges are required. Either run +this script as the root user or, if you have a working sudo +setup, specify the privileged user (normally root) using the -u +option: + +# /usr/lib/heartbeat/hb2openais.sh -u root + +Do not run this procedure on more than one node! + +1. Generate openais.conf from ha.cf. + +/etc/ha.d/ha.cf is parsed and /etc/ais/openais.conf +correspondingly generated. + +Whereas heartbeat supports several different communication +types (broadcast, unicast, multicast), OpenAIS uses only +multicasting. The conversion tries to create equivalent media, +but with some network configurations it may produce wrong +results. Pay particular attention to the "interface" +sub-directive of the "totem" directive. The openais.conf(5) man +page is the reference documentation. + +Make sure that your network supports IP multicasts. + +OpenAIS does not support serial communication links. + +In addition, an OpenAIS authentication key is generated. + +2. Removal of the nodes section from the CIB. + +Since the nodes UUID are generated by OpenAIS in a different +manner, the nodes section must be removed. This section is +automaticaly generated when the cluster is started. + +If you had node attributes defined in the nodes section, they +will have to be manually recreated. + +3. Upgrade of the CIB to Pacemaker v1.0 (optional) + +There are significant changes introduced in the CIB since +heartbeat versions before and including 2.1.4 and the previous +pacemaker stable version 0.6. The new CRM in pacemaker still +supports the old CIB, but it is recommended to convert to the new +version. You may do so by passing the -U option to the +hb2openais.sh program. If this option is not specified, the +program will still ask if you want to upgrade the CIB to the new +version. + +If you don't convert to the new CIB version, the new crm shell +and configuration tool will not work. + +4. Addition of pingd resource. + +In heartbeat the pingd daemon could be controlled by the +heartbeat itself through the respawn ha.cf directive. Obviously, +it is not possible anymore, so a pingd resource has to be created +in the CIB. Furthermore, hosts from the "ping" directives (the +"ping" nodes) are inserted into the "host_list" pingd resource +attribute. + +5. Conversion of ocfs2 filesystem. + +The ocfs2 filesystem is closely related to the cluster stack +used. It must be converted if the stack is changed. The +conversion script will do this automatically for you. Note that +for this step it will start the cluster stack. The conversion is +performed by the tunefs.ocfs2 program: + + tunefs.ocfs2 --update-cluster-stack + +For more details on ocfs2 conversion refer to the ocfs2 +documentation. + +6. Replacement of EVMS2 with LVM2. + +Skip this in case you don't have EVMS2 resources. + +EVMS2 is replaced by the clustered LVM2. The conversion program +removes all Evmsd resources and converts the EvmsSCC to LVM +resources. + +Please supply the name of the LVM volume group when the program +asks. + +Note on logging + +The CRM still does not share the logging setup with the OpenAIS, +i.e. it does not read the logging stanza from openais.conf. This +will be rectified in future, but in the meantime the logging +configuration has to be replicated in /etc/sysconfig/pacemaker, +for instance: + +USE_LOGD=yes +SYSLOG_FACILITY=local7 + +Enforcing conversion + +There is a simple mechanism which prevents running the conversion +process twice in a row. If you know what you are doing, it is +possible to force the conversion using the -F option. + +After the conversion + +Once the conversion has been finished, you may start the new +cluster stack: + +# /etc/init.d/ais start + +Put resources back to the managed mode in case they were +previously unmanaged. + +TODO: What happens to the tunefs.ocfs2 process? We should know +when it's done and stop the cluster stack. + +Backup + +The conversion procedure also creates backup of all affected +files. It is possible to revert to the version from the time of +backup: + +# /usr/lib/heartbeat/hb2openais.sh revert + +Note that the revert process is executed only on the node on +which the conversion took place. + +TODO: Check effect of hb_uuid files removal on other nodes! They +have to be regenerated and will be different from the nodes +section. Perhaps backup/revert should take place on all nodes. + +Affected files + +All file processing is done on the node where conversion runs. + +The CIB is the only file which is converted: + +/var/lib/heartbeat/crm/cib.xml + +The CIB is removed on all other nodes. + +The following files are generated: + +/etc/ais/openais.conf +/etc/ais/authkey + +The following files are removed on all nodes: + +/var/lib/heartbeat/crm/cib.xml.sig +/var/lib/heartbeat/crm/cib.xml.last +/var/lib/heartbeat/crm/cib.xml.sig.last +/var/lib/heartbeat/hostcache +/var/lib/heartbeat/hb_uuid + +The OpenAIS specific files are copied to all nodes using ssh. + +The CIB is automatically replicated by the CRM and it is not +copied to other nodes. + +References + +Configuration_Explained.pdf +openais.conf(5) diff --git a/tools/hb2openais-helper.py b/tools/hb2openais-helper.py index 2d0a5d095a..644f4f1580 100644 --- a/tools/hb2openais-helper.py +++ b/tools/hb2openais-helper.py @@ -1,349 +1,349 @@ #!/usr/bin/env python import os,sys import getopt import xml.dom.minidom def usage(): print "usage: %s [-T] [-c ha_cf] {zap_nodes|analyze_cib|convert_cib}"%sys.argv[0] sys.exit(1) TEST = False try: optlist, arglist = getopt.getopt(sys.argv[1:], "hTc:") except getopt.GetoptError: usage() for opt,arg in optlist: if opt == '-h': usage() elif opt == '-c': HA_CF = arg elif opt == '-T': TEST = True if len(arglist) != 1: usage() def load_cib(): doc = xml.dom.minidom.parse(sys.stdin) return doc def is_whitespace(node): return node.nodeType == node.TEXT_NODE and not node.data.strip() def rmnodes(node_list): for node in node_list: node.parentNode.removeChild(node) node.unlink() def is_element(xmlnode): return xmlnode.nodeType == xmlnode.ELEMENT_NODE def xml_processnodes(xmlnode,filter,proc): ''' Process with proc all nodes that match filter. ''' node_list = [] for child in xmlnode.childNodes: if filter(child): node_list.append(child) elif child.hasChildNodes(): xml_processnodes(child,filter,proc) if node_list: proc(node_list) def skip_first(s): l = s.split('\n') return '\n'.join(l[1:]) def get_attribute(tag,node,p): attr_set = node.getElementsByTagName(tag) if not attr_set: return '' attributes = attr_set[0].getElementsByTagName("attributes") if not attributes: return '' attributes = attributes[0] for nvpair in attributes.getElementsByTagName("nvpair"): if p == nvpair.getAttribute("name"): return nvpair.getAttribute("value") return '' def get_param(node,p): return get_attribute("instance_attributes",node,p) doc = load_cib() xml_processnodes(doc,is_whitespace,rmnodes) resources = doc.getElementsByTagName("resources")[0] constraints = doc.getElementsByTagName("constraints")[0] nodes = doc.getElementsByTagName("nodes")[0] if not resources: print >> sys.stderr, "ERROR: sorry, no resources section in the CIB, cannot proceed" sys.exit(1) if not constraints: print >> sys.stderr, "ERROR: sorry, no constraints section in the CIB, cannot proceed" sys.exit(1) if not nodes: print >> sys.stderr, "ERROR: sorry, no nodes section in the CIB, cannot proceed" sys.exit(1) if arglist[0] == "zap_nodes": xml_processnodes(nodes,lambda x:1,rmnodes) s = skip_first(doc.toprettyxml()) print s sys.exit(0) if arglist[0] == "analyze_cib": rc = 0 for rsc in doc.getElementsByTagName("primitive"): rsc_type = rsc.getAttribute("type") if rsc_type == "EvmsSCC": print >> sys.stderr, "INFO: evms configuration found; conversion required" rc = 1 elif rsc_type == "Filesystem": if get_param(rsc,"fstype") == "ocfs2": print >> sys.stderr, "INFO: ocfs2 configuration found; conversion required" rc = 1 sys.exit(rc) def set_attribute(tag,node,p,value): rsc_id = node.getAttribute("id") attr_set = node.getElementsByTagName(tag) if not attr_set: return attributes = attr_set[0].getElementsByTagName("attributes") if not attributes: attributes = doc.createElement("attributes") attr_set.appendChild(attributes) else: attributes = attributes[0] for nvp in attributes.getElementsByTagName("nvpair"): if p == nvp.getAttribute("name"): nvp.setAttribute("value",value) return attributes.appendChild(nvpair(rsc_id,p,value)) def rm_attribute(tag,node,p): attr_set = node.getElementsByTagName(tag) if not attr_set: return '' attributes = attr_set[0].getElementsByTagName("attributes") if not attributes: return '' attributes = attributes[0] for nvpair in attributes.getElementsByTagName("nvpair"): if p == nvpair.getAttribute("name"): nvpair.parentNode.removeChild(nvpair) def set_param(node,p,value): set_attribute("instance_attributes",node,p,value) def rm_param(node,p): rm_attribute("instance_attributes",node,p) def rmnodes(node_list): for node in node_list: node.parentNode.removeChild(node) node.unlink() def evms2lvm(node,a): v = node.getAttribute(a) if v: v = v.replace("EVMS","LVM") v = v.replace("Evms","LVM") v = v.replace("evms","lvm") node.setAttribute(a,v) def replace_evms_strings(node_list): for node in node_list: evms2lvm(node,"id") if node.tagName in ("rsc_colocation","rsc_order"): evms2lvm(node,"to") evms2lvm(node,"from") def get_input(msg): if TEST: print >> sys.stderr, "%s: setting to /dev/null" % msg return "/dev/null" while True: ans = raw_input(msg) if ans: if os.access(ans,os.F_OK): return ans else: print >> sys.stderr, "Cannot read %s" % ans print >> sys.stderr, "We do need this input to continue." def nvpair(id,name,value): nvpair = doc.createElement("nvpair") nvpair.setAttribute("id",id + "_" + name) nvpair.setAttribute("name",name) nvpair.setAttribute("value",value) return nvpair def mk_lvm(rsc_id,volgrp): node = doc.createElement("primitive") node.setAttribute("id",rsc_id) node.setAttribute("type","LVM") node.setAttribute("provider","heartbeat") node.setAttribute("class","ocf") operations = doc.createElement("operations") node.appendChild(operations) mon_op = doc.createElement("op") operations.appendChild(mon_op) mon_op.setAttribute("id", rsc_id + "_mon") mon_op.setAttribute("name","monitor") interval = "120s" timeout = "60s" mon_op.setAttribute("interval", interval) mon_op.setAttribute("timeout", timeout) instance_attributes = doc.createElement("instance_attributes") instance_attributes.setAttribute("id", rsc_id + "_inst_attr") node.appendChild(instance_attributes) attributes = doc.createElement("attributes") instance_attributes.appendChild(attributes) attributes.appendChild(nvpair(rsc_id,"volgrpname",volgrp)) return node def mk_clone(id,ra_type,ra_class,prov): c = doc.createElement("clone") c.setAttribute("id",id + "-clone") meta = doc.createElement("meta_attributes") c.appendChild(meta) meta.setAttribute("id",id + "_meta") attributes = doc.createElement("attributes") meta.appendChild(attributes) attributes.appendChild(nvpair(id,"globally-unique","false")) attributes.appendChild(nvpair(id,"interleave","true")) p = doc.createElement("primitive") c.appendChild(p) p.setAttribute("id",id) p.setAttribute("type",ra_type) if prov: p.setAttribute("provider",prov) p.setAttribute("class",ra_class) operations = doc.createElement("operations") p.appendChild(operations) mon_op = doc.createElement("op") operations.appendChild(mon_op) mon_op.setAttribute("id", id + "_mon") mon_op.setAttribute("name","monitor") interval = "60s" timeout = "30s" mon_op.setAttribute("interval", interval) mon_op.setAttribute("timeout", timeout) return c def add_ocfs_clones(id): c1 = mk_clone("o2cb","o2cb","lsb","") c2 = mk_clone("dlm","controld","ocf","pacemaker") resources.appendChild(c1) resources.appendChild(c2) c1 = mk_order("dlm-clone","o2cb-clone") c2 = mk_colocation("dlm-clone","o2cb-clone") constraints.appendChild(c1) constraints.appendChild(c2) def mk_order(r1,r2): rsc_order = doc.createElement("rsc_order") rsc_order.setAttribute("id","rsc_order_"+r1+"_"+r2) rsc_order.setAttribute("from",r1) rsc_order.setAttribute("to",r2) rsc_order.setAttribute("type","before") rsc_order.setAttribute("symmetrical","true") return rsc_order def mk_colocation(r1,r2): rsc_colocation = doc.createElement("rsc_colocation") rsc_colocation.setAttribute("id","rsc_colocation_"+r1+"_"+r2) rsc_colocation.setAttribute("from",r1) rsc_colocation.setAttribute("to",r2) rsc_colocation.setAttribute("score","INFINITY") return rsc_colocation def add_ocfs_constraints(rsc,id): node = rsc.parentNode if node.tagName != "clone": node = rsc clone_id = node.getAttribute("id") c1 = mk_order("o2cb-clone",clone_id) c2 = mk_colocation("o2cb-clone",clone_id) constraints.appendChild(c1) constraints.appendChild(c2) def change_ocfs2_device(rsc): print >> sys.stderr, "The current device for ocfs2 depends on evms: %s"%get_param(rsc,"device") dev = get_input("Please supply the device where %s ocfs2 resource resides: "%rsc.getAttribute("id")) set_param(rsc,"device",dev) def stop_ocfs2(rsc): node = rsc.parentNode if node.tagName != "clone": node = rsc id = node.getAttribute("id") l = rsc.getElementsByTagName("meta_attributes") if l: meta = l[0] else: meta = doc.createElement("meta_attributes") meta.setAttribute("id",id + "_meta") node.appendChild(meta) attributes = doc.createElement("attributes") meta.appendChild(attributes) rm_param(rsc,"target_role") set_attribute("meta_attributes",node,"target_role","Stopped") def new_pingd_rsc(options,host_list): rsc_id = "pingd" - c = mk_clone(rsc_id,"pingd","pacemaker","ocf") + c = mk_clone(rsc_id,"pingd","ocf","pacemaker") node = c.getElementsByTagName("primitive")[0] instance_attributes = doc.createElement("instance_attributes") instance_attributes.setAttribute("id", rsc_id + "_inst_attr") node.appendChild(instance_attributes) attributes = doc.createElement("attributes") instance_attributes.appendChild(attributes) attributes.appendChild(nvpair(rsc_id,"options",options)) return c def replace_evms_ids(): return c def handle_pingd_respawn(): f = open(HA_CF or "/etc/ha.d/ha.cf", 'r') opts = '' ping_list = [] for l in f: s = l.split() if not s: continue if s[0] == "respawn" and s[2].find("pingd") > 0: opts = ' '.join(s[3:]) elif s[0] == "ping": ping_list.append(s[1]) f.close() return opts,' '.join(ping_list) def process_cib(): ocfs_clones = [] evms_present = False for rsc in doc.getElementsByTagName("primitive"): rsc_id = rsc.getAttribute("id") rsc_type = rsc.getAttribute("type") if rsc_type == "Evmsd": print >> sys.stderr, "INFO: removing the Evmsd resource" resources.removeChild(rsc) elif rsc_type == "EvmsSCC": evms_present = True print >> sys.stderr, "INFO: EvmsSCC resource is going to be replaced by LVM" vg = get_input("Please supply the VG name corresponding to %s: "%rsc_id) node = mk_lvm(rsc_id,vg) parent = rsc.parentNode parent.removeChild(rsc) parent.appendChild(node) rsc.unlink() elif rsc_type == "pingd": if pingd_host_list: set_param(rsc,"host_list",pingd_host_list) elif rsc_type == "Filesystem": if get_param(rsc,"fstype") == "ocfs2": if get_param(rsc,"device").find("evms") > 0: change_ocfs2_device(rsc) ocfs_clones.append(rsc) id = rsc.getAttribute("id") print >> sys.stderr, "INFO: adding constraints for %s"%id add_ocfs_constraints(rsc,id) print >> sys.stderr, "INFO: adding target_role=Stopped to %s"%id stop_ocfs2(rsc) if ocfs_clones: print >> sys.stderr, "INFO: adding required cloned resources for ocfs2" add_ocfs_clones(id) if evms_present: xml_processnodes(doc,lambda x:1,replace_evms_strings) if arglist[0] == "convert_cib": opts,pingd_host_list = handle_pingd_respawn() if opts: clone = new_pingd_rsc(opts,pingd_host_list) resources.appendChild(clone) process_cib() s = skip_first(doc.toprettyxml()) print s sys.exit(0) # shouldn't get here usage() # vim:ts=4:sw=4:et: diff --git a/tools/hb2openais.sh.in b/tools/hb2openais.sh.in index c933dab1ec..13f1c76973 100755 --- a/tools/hb2openais.sh.in +++ b/tools/hb2openais.sh.in @@ -1,597 +1,638 @@ #!/bin/sh # Copyright (C) 2008 Dejan Muhamedagic # # This program is free software; you can redistribute it and/or # modify it under the terms of the GNU General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This software is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # General Public License for more details. # # You should have received a copy of the GNU General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA # . @sysconfdir@/ha.d/shellfuncs . $HA_NOARCHBIN/utillib.sh PROG=`basename $0` # FIXME: once this is part of the package! PROGDIR=`dirname $0` echo "$PROGDIR" | grep -qs '^/' || { test -f @sbindir@/$PROG && PROGDIR=@sbindir@ test -f $HA_NOARCHBIN/$PROG && PROGDIR=$HA_NOARCHBIN } # the default syslog facility is not (yet) exported by heartbeat # to shell scripts # DEFAULT_HA_LOGFACILITY="daemon" export DEFAULT_HA_LOGFACILITY AIS_CONF=/etc/ais/openais.conf AIS_KEYF=/etc/ais/authkey PY_HELPER=$HA_BIN/hb2openais-helper.py -CIB=@HA_VARLIBDIR@/heartbeat/crm/cib.xml -CIBSIG=@HA_VARLIBDIR@/heartbeat/crm/cib.xml.sig -CIBLAST=@HA_VARLIBDIR@/heartbeat/crm/cib.xml.last -CIBLAST_SIG=@HA_VARLIBDIR@/heartbeat/crm/cib.xml.sig.last -HOSTCACHE=@HA_VARLIBDIR@/heartbeat/hostcache -HB_UUID=@HA_VARLIBDIR@/heartbeat/hb_uuid +CRM_VARLIB=$HA_VARLIB/crm +CIB=$CRM_VARLIB/cib.xml +CIBSIG=$CRM_VARLIB/cib.xml.sig +CIBLAST=$CRM_VARLIB/cib.xml.last +CIBLAST_SIG=$CRM_VARLIB/cib.xml.sig.last +HOSTCACHE=$HA_VARLIB/hostcache +HB_UUID=$HA_VARLIB/hb_uuid DONE_F=$HA_VARRUN/heartbeat/.$PROG.conv_done BACKUPDIR=/var/tmp/`basename $PROG .sh`.backup -BACKUP_FILES=" $CIB $CIBSIG $HOSTCACHE $HB_UUID $AIS_CONF " RM_FILES=" $CIBSIG $HOSTCACHE $HB_UUID $CIBLAST $CIBLAST_SIG" -REMOTE_RM_FILES=" $CIB $CIBSIG $HOSTCACHE $HB_UUID $CIBLAST $CIBLAST_SIG" +REMOTE_RM_FILES=" $CIB $RM_FILES" +BACKUP_FILES=" $AIS_CONF $AIS_KEYF $REMOTE_RM_FILES " DIST_FILES=" $AIS_CONF $AIS_KEYF $DONE_F " MAN_TARF=/var/tmp/`basename $PROG .sh`.tar.gz : ${SSH_OPTS="-T"} usage() { cat</dev/null else ssh -T -o Batchmode=yes $1 true 2>/dev/null fi } findsshuser() { for u in "" $TRY_SSH; do rc=0 for n in `getnodes`; do [ "$node" = "$WE" ] && continue testsshuser $n $u || { rc=1 break } done if [ $rc -eq 0 ]; then echo $u return 0 fi done return 1 } newportinfo() { info "the port number for the multicast is set to 5405" info "please update your firewall rules (if any)" } changemediainfo() { info "openais uses multicast for communication" info "please make sure that your network infrastructure supports it" } multicastinfo() { info "multicast for openais ring $1 set to $2:$3" } netaddrinfo() { info "network address for openais ring $1 set to $2" } backup_files() { [ "$TEST_DIR" ] && return info "backing up $BACKUP_FILES to $BACKUPDIR" $DRY mkdir $BACKUPDIR || { echo sorry, could not create $BACKUPDIR directory echo please cleanup exit 1 } - for f in $BACKUP_FILES; do - $DRY cp -p $f $BACKUPDIR || { - echo sorry, could not copy $f to $BACKUPDIR + if [ -z "$DRY" ]; then + tar cf - $BACKUP_FILES | gzip > $BACKUPDIR/$WE.tar.gz || { + echo sorry, could not create $BACKUPDIR/$WE.tar.gz exit 1 } - done + else + $DRY "tar cf - $BACKUP_FILES | gzip > $BACKUPDIR/$WE.tar.gz" + fi } revert() { [ "$TEST_DIR" ] && return test -d $BACKUPDIR || { echo sorry, there is no $BACKUPDIR directory echo cannot revert exit 1 } - for f in $BACKUP_FILES; do - cp -p $BACKUPDIR/`basename $f` $f || { - echo sorry, could not copy $BACKUPDIR/`basename $f` to $f - } - done + info "restoring $BACKUP_FILES from $BACKUPDIR/$WE.tar.gz" + gzip -dc $BACKUPDIR/$WE.tar.gz | (cd / && tar xf -) || { + echo sorry, could not unpack $BACKUPDIR/$WE.tar.gz + exit 1 + } } pls_press_enter() { [ "$TEST_DIR" ] && return cat< $AIS_CONF || fatal "cannot create $AIS_CONF" grep -wqs interface $AIS_CONF || fatal "no media found in $HA_CF" else openaisconf fi if [ "$TEST_DIR" ]; then info "Skipping OpenAIS authentication key generation ..." else info "Generating a key for OpenAIS authentication ..." $DRY ais-keygen || fatal "cannot generate the key using ais-keygen" fi # remove various files which could get in a way if [ -z "$TEST_DIR" ]; then $DRY rm -f $RM_FILES fi -# remove the nodes section from the CIB +fixcibperms() { + [ "$TEST_DIR" ] && return + uid=`ls -ldn $CRM_VARLIB | awk '{print $3}'` + gid=`ls -ldn $CRM_VARLIB | awk '{print $4}'` + $DRY $MYSUDO chown $uid:$gid $CIB +} +upgrade_cib() { + $DRY $MYSUDO CIB_file=$CIB cibadmin --upgrade --force +} +# remove the nodes section from the CIB tmpfile=`maketempfile` $MYSUDO sh -c "python $PY_HELPER zap_nodes <$CIB >$tmpfile" || fatal "cannot clear the nodes section from the CIB" -if [ "$TEST_DIR" ]; then - mv $tmpfile $TEST_DIR/cib-out.xml -else - $DRY $MYSUDO mv $tmpfile $CIB -fi +$DRY $MYSUDO mv $tmpfile $CIB info "Cleared the nodes section in the CIB" info "Done converting ha.cf to openais.conf" +info "Please check the resulting $AIS_CONF" +info "and in particular interface stanzas and logging." +info "If you find problems, please edit $AIS_CONF now!" # # first part done (openais), on to the CIB analyze_cib() { info "Analyzing the CIB..." $MYSUDO sh -c "python $PY_HELPER analyze_cib <$CIB" } part2() { intro_part2 || return 0 tmpfile=`maketempfile` opts="-c $HA_CF" [ "$TEST_DIR" ] && opts="-T $opts" $MYSUDO sh -c "python $PY_HELPER $opts convert_cib <$CIB >$tmpfile" || fatal "failed to process the CIB" - if [ "$TEST_DIR" ]; then - mv $tmpfile $TEST_DIR/cib-out.xml - else - $DRY $MYSUDO mv $tmpfile $CIB - fi + $DRY $MYSUDO mv $tmpfile $CIB info "Processed the CIB successfully" } dcidle() { try_crmadmin=10 dc="" while [ -z "$dc" -a $try_crmadmin -gt 0 ]; do dc=`$MYSUDO crmadmin -D | awk '{print $NF}'` try_crmadmin=$((try_crmadmin-1)) done if [ x = x"$dc" ]; then echo "sorry, no dc found/elected" exit 1 fi maxcnt=60 cnt=0 while [ $cnt -lt $maxcnt ]; do stat=`$MYSUDO crmadmin -S $dc` ec=$? echo $stat | grep -qs S_IDLE && break [ "$1" = "-v" ] && echo $stat sleep 1 printf "." cnt=$((cnt+1)) done echo status: $stat echo waited: $cnt echo $stat | grep -qs S_IDLE } start_cluster() { $DRY /etc/init.d/openais start } wait_cluster() { printf "waiting for crm to start." for i in 1 2 3 4 5; do for j in 1 2; do sleep 1; printf "." done done dcidle } tune_ocfs2() { [ "$TEST_DIR" ] && return cat< $MAN_TARF) fi