/scripts/ha-cluster-init

https://github.com/tserong/sleha-bootstrap · #! · 663 lines · 585 code · 78 blank · 0 comment · 0 complexity · 2210ad27677048fc75e74a3cfadf6566 MD5 · raw file

  1. #!/bin/bash
  2. #
  3. # Copyright (c) 2010-2013 SUSE LLC, All Rights Reserved.
  4. #
  5. # Author: Tim Serong <tserong@suse.com>
  6. #
  7. # This program is free software; you can redistribute it and/or modify
  8. # it under the terms of version 2 of the GNU General Public License as
  9. # published by the Free Software Foundation.
  10. #
  11. # This program is distributed in the hope that it would be useful, but
  12. # WITHOUT ANY WARRANTY; without even the implied warranty of
  13. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  14. #
  15. # Further, this software is distributed without any warranty that it is
  16. # free of the rightful claim of any third person regarding infringement
  17. # or the like. Any license provided herein, whether implied or
  18. # otherwise, applies only to this software file. Patent licenses, if
  19. # any, provided herein do not apply to combinations of this program with
  20. # other software, or any other product whatsoever.
  21. #
  22. # You should have received a copy of the GNU General Public License
  23. # along with this program; if not, write the Free Software Foundation,
  24. # Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
  25. #
  26. . /usr/lib/ha-cluster-functions
  27. declare SHARED_DEVICE
  28. declare SBD_DEVICE
  29. declare OCFS2_DEVICE
  30. declare TEMPLATE
  31. usage()
  32. {
  33. cat <<END
  34. Usage: $0 [options] [stage]
  35. Options:
  36. -h,--help Display this usage information
  37. -q Be quiet (don't describe what's happening, just do it)
  38. -y Answer "yes" to all prompts (use with caution, this is
  39. destructive, especially during the "storage" stage)
  40. -i <if> Default to IP address on interface 'if' instead of eth0
  41. -s <dev> Block device to use for SBD fencing
  42. -t <name> Optionally configure cluster with template 'name'
  43. (currently only "ocfs2" is valid here)
  44. Options for ocfs2 template:
  45. -p <dev> Partition this shared storage device (only used in
  46. "storage" stage)
  47. -o <dev> Block device to use for OCFS2 (only used in "vgfs" stage)
  48. Stage can be one of:
  49. ssh Create SSH keys for passwordless SSH between cluster nodes
  50. csync2 Configure csync2
  51. corosync Configure corosync
  52. storage Partition shared storage (ocfs2 template only)
  53. sbd Configure SBD (requires -s <dev>)
  54. cluster Bring the cluster online
  55. vgfs Create volume group and filesystem (ocfs2 template only,
  56. requires -o <dev>)
  57. Note:
  58. - If stage is not specified, the script will run through each stage
  59. in sequence, with prompts for required information.
  60. - If using the ocfs2 template, the storage stage will partition a block
  61. device into two pieces, one for SBD, the remainder for OCFS2. This is
  62. good for testing and demonstration, but not ideal for production.
  63. To use storage you have already configured, pass -s and -o to specify
  64. the block devices for SBD and OCFS2, and the automatic partitioning
  65. will be skipped.
  66. END
  67. exit 0
  68. }
  69. init_ssh()
  70. {
  71. start_service sshd.service
  72. invoke mkdir -m 700 -p /root/.ssh
  73. if [ -f /root/.ssh/id_rsa ]; then
  74. confirm \
  75. '/root/.ssh/id_rsa already exists - overwrite?' || return
  76. invoke rm -f /root/.ssh/id_rsa
  77. fi
  78. status "Generating ssh key"
  79. invoke ssh-keygen -q -f /root/.ssh/id_rsa \
  80. -C 'Cluster Internal' -N '' \
  81. || error "Failed to generate SSH key"
  82. append /root/.ssh/id_rsa.pub /root/.ssh/authorized_keys
  83. }
  84. # This handles the slightly obscure case where the seed node has ssh keys,
  85. # but those keys aren't present in the seed node's authorized_keys file.
  86. init_ssh_remote()
  87. {
  88. for key in id_rsa id_dsa id_ecdsa id_ed25519 ; do
  89. [ -f /root/.ssh/$key ] || continue
  90. grep -q -s "$(cat /root/.ssh/$key.pub)" /root/.ssh/authorized_keys \
  91. || append /root/.ssh/$key.pub /root/.ssh/authorized_keys
  92. done
  93. }
  94. init_csync2()
  95. {
  96. status "Configuring csync2"
  97. # Not automatically updating /etc/hosts - risky in the general case.
  98. #etc_hosts_add_me
  99. #[ -n "$(etc_hosts_get_me)" ] || error "No valid entry for $(hostname) in /etc/hosts - csync2 can't work"
  100. if [ -f "$CSYNC2_KEY" ] || \
  101. grep -v -q -s '^[[:space:]]*\(#.*\)*$' $CSYNC2_CFG
  102. then
  103. confirm 'csync2 is already configured - overwrite?' || return
  104. fi
  105. invoke rm -f $CSYNC2_KEY
  106. status_long "Generating csync2 shared key (this may take a while)"
  107. # On a quiet VM, "a while" can be "way too long" (not enough entropy)
  108. invoke csync2 -k $CSYNC2_KEY || error "Can't create csync2 key $keyfile"
  109. status_done
  110. local tmp_conf=${CSYNC2_CFG}.$$
  111. cat > $tmp_conf <<END
  112. group ha_group
  113. {
  114. key /etc/csync2/key_hagroup;
  115. host $(hostname);
  116. include /etc/booth/booth.conf;
  117. include /etc/corosync/corosync.conf;
  118. include /etc/corosync/authkey;
  119. include /etc/csync2/csync2.cfg;
  120. include /etc/csync2/key_hagroup;
  121. include /etc/ctdb/nodes;
  122. include /etc/drbd.conf;
  123. include /etc/drbd.d;
  124. include /etc/ha.d/ldirectord.cf;
  125. include /etc/lvm/lvm.conf;
  126. include /etc/multipath.conf;
  127. include /etc/samba/smb.conf;
  128. include /etc/sysconfig/pacemaker;
  129. include /etc/sysconfig/sbd;
  130. }
  131. END
  132. install_tmp $tmp_conf $CSYNC2_CFG
  133. start_service csync2.socket
  134. status "csync2 checking files"
  135. invoke csync2 -cr /
  136. }
  137. # It would be nice if we could just have csync2.cfg include a directory,
  138. # which in turn included one file per node which would be referenced via
  139. # something like "group ha_group { ... config: /etc/csync2/hosts/*; }"
  140. # That way, adding a new node would just mean adding a single new file
  141. # to that directory. Unfortunately, the 'config' statement only allows
  142. # inclusion of specific individual files, not multiple files via wildcard.
  143. # So we have this function which is called by ha-cluster-join to add the new
  144. # remote node to csync2 config on some existing node. It is intentionally
  145. # not documented in ha-cluster-init's user-visible usage information.
  146. init_csync2_remote()
  147. {
  148. local newhost=$1
  149. #local newline="$2"
  150. local thishost=$(hostname)
  151. [ -n "$newhost" ] || error "Hostname not specified"
  152. BE_QUIET=true
  153. # Not automatically updating /etc/hosts - risky in the general case.
  154. #if [ -n "$newline" ]; then
  155. # etc_hosts_add_one $newhost "$newline"
  156. #else
  157. # log ": Not updating /etc/hosts - remote host line not specified"
  158. #fi
  159. # If host doesn't already exist in csync2 config, add it
  160. if ! egrep -q -s \
  161. "^[[:space:]]*host.*[[:space:]]+${newhost}[[:space:];]" \
  162. $CSYNC2_CFG
  163. then
  164. local tmp_conf=${CSYNC2_CFG}.$$
  165. awk '/^[[:space:]]*host[[:space:]]/ \
  166. { if (h==0) print "\thost '$newhost';"; h=1; } \
  167. { print $0 } ' $CSYNC2_CFG > $tmp_conf
  168. install_tmp $tmp_conf $CSYNC2_CFG
  169. invoke csync2 -c $CSYNC2_CFG
  170. else
  171. log ": Not updating $CSYNC2_CFG - remote host $newhost already exists"
  172. fi
  173. }
  174. init_corosync()
  175. {
  176. if $YES_TO_ALL; then
  177. status 'Configuring corosync'
  178. else
  179. status "
  180. Configure Corosync:
  181. This will configure the cluster messaging layer. You will need
  182. to specify a network address over which to communicate (default
  183. is ${NET_IF}'s network, but you can use the network address of any
  184. active interface), a multicast address and multicast port.
  185. "
  186. fi
  187. if [ -f "$COROSYNC_CONF" ]; then
  188. confirm \
  189. "$COROSYNC_CONF already exists - overwrite?" || return
  190. fi
  191. local bindnetaddr=$(prompt_for_string \
  192. 'Network address to bind to (e.g.: 192.168.1.0)' \
  193. '([0-9]+\.){3}[0-9]+' "$IP_NETWORK")
  194. [ -z "$bindnetaddr" ] && error 'No value for bindnetaddr'
  195. local mcastaddr=$(prompt_for_string \
  196. 'Multicast address (e.g.: 239.x.x.x)' \
  197. '([0-9]+\.){3}[0-9]+' \
  198. 239.$(random_256).$(random_256).$(random_256))
  199. [ -z "$mcastaddr" ] && error 'No value for mcastaddr'
  200. local mcastport=$(prompt_for_string \
  201. 'Multicast port' \
  202. '[0-9]+' 5405);
  203. [ -z "$mcastport" ] && error 'No value for mcastport'
  204. local tmp_conf=${COROSYNC_CONF}.$$
  205. # for now, use our inline corosync.conf to force quorum expected_votes...
  206. # if grep -q -s '^[[:space:]]*name:[[:space:]]*pacemaker' ${COROSYNC_CONF}.example; then
  207. # # "name: pacemaker" in corosync example conf is our assumption
  208. # # that the example is sane, so use it:
  209. # sed \
  210. # -e 's/^\([[:space:]]*bindnetaddr:[[:space:]]*\).*/\1'$bindnetaddr'/' \
  211. # -e 's/^\([[:space:]]*mcastaddr:[[:space:]]*\).*/\1'$mcastaddr'/' \
  212. # -e 's/^\([[:space:]]*mcastport:[[:space:]]*\).*/\1'$mcastport'/' \
  213. # /etc/corosync/corosync.conf.example > $tmp_conf
  214. # else
  215. # # Fallback to known sane config (defaults from SLE HA 11 SP1
  216. # # corosync.conf.example.patch)
  217. cat > $tmp_conf <<END
  218. # Please read the corosync.conf.5 manual page
  219. totem {
  220. version: 2
  221. secauth: off
  222. cluster_name: hacluster
  223. clear_node_high_bit: yes
  224. # Following are old corosync 1.4.x defaults from SLES
  225. # token: 5000
  226. # token_retransmits_before_loss_const: 10
  227. # join: 60
  228. # consensus: 6000
  229. # vsftype: none
  230. # max_messages: 20
  231. # threads: 0
  232. crypto_cipher: none
  233. crypto_hash: none
  234. interface {
  235. ringnumber: 0
  236. bindnetaddr: $bindnetaddr
  237. mcastaddr: $mcastaddr
  238. mcastport: $mcastport
  239. ttl: 1
  240. }
  241. }
  242. logging {
  243. fileline: off
  244. to_stderr: no
  245. to_logfile: no
  246. logfile: /var/log/cluster/corosync.log
  247. to_syslog: yes
  248. debug: off
  249. timestamp: on
  250. logger_subsys {
  251. subsys: QUORUM
  252. debug: off
  253. }
  254. }
  255. quorum {
  256. # Enable and configure quorum subsystem (default: off)
  257. # see also corosync.conf.5 and votequorum.5
  258. provider: corosync_votequorum
  259. expected_votes: 1
  260. two_node: 0
  261. }
  262. END
  263. # fi
  264. install_tmp $tmp_conf $COROSYNC_CONF
  265. invoke csync2 -m $COROSYNC_CONF
  266. invoke csync2 -f $COROSYNC_CONF
  267. invoke csync2 -xv $COROSYNC_CONF
  268. }
  269. # Non-generic, i.e. not for use with every type of cluster you can imagine:
  270. # requires shared storage, and specifically configures one block device as
  271. # sbd partition + remainder for OCFS2 filesystem (created later).
  272. init_storage()
  273. {
  274. local dev="$SHARED_DEVICE"
  275. local partitions
  276. local part
  277. local -a devices
  278. local -i dev_looks_sane=0
  279. if $YES_TO_ALL || [ -n "$SHARED_DEVICE" ]; then
  280. status 'Configuring shared storage'
  281. else
  282. status "
  283. Configure Shared Storage:
  284. You will need to provide the path to a shared storage device,
  285. for example a SAN volume or iSCSI target. The device path must
  286. be persistent and consistent across all nodes in the cluster,
  287. so /dev/disk/by-id/* devices are a good choice. This device
  288. will be automatically paritioned into two pieces, 1MB for SBD
  289. fencing, and the remainder for an OCFS2 filesystem.
  290. "
  291. fi
  292. while [ $dev_looks_sane -eq 0 ]; do
  293. dev=$(prompt_for_string \
  294. 'Path to storage device (e.g. /dev/disk/by-id/...)' \
  295. '\/.*' "$dev")
  296. # This will be empty if -y was specified but -p wasn't
  297. [ -z "$dev" ] && error "No value for shared storage device"
  298. if [ ! -b "$dev" ]; then
  299. $YES_TO_ALL && error "$dev is not a block device" \
  300. || echo " That doesn't look like a block device" >&2
  301. else
  302. #
  303. # Got something that looks like a block device, there
  304. # are four possibilities now:
  305. #
  306. # 1) It's completely broken/inaccessible
  307. # 2) No recognizable partition table
  308. # 3) Empty partition table
  309. # 4) Non-empty parition table
  310. #
  311. partitions=$(parted -s $dev print | awk '/^[[:space:]]*[0-9]+/ { print $1; }')
  312. if [ -n "$partitions" ]; then
  313. # Partitions exist
  314. status "WARNING: Partitions exist on $dev!"
  315. confirm 'Are you ABSOLUTELY SURE you want to overwrite?' \
  316. && dev_looks_sane=1 || dev=
  317. else
  318. # It's either broken, no partition table, or empty partition table
  319. status "$dev appears to be empty"
  320. confirm 'Are you sure you wish to use this device' \
  321. && dev_looks_sane=1 || dev=
  322. fi
  323. fi
  324. done
  325. if [ -n "$partitions" ]; then
  326. confirm 'Really?' || exit
  327. status_long "Erasing existing partitions..."
  328. for part in $partitions; do
  329. invoke parted -s $dev rm $part \
  330. || error "Failed to remove partition $part"
  331. done
  332. status_done
  333. fi
  334. status_long "Creating partitions..."
  335. invoke parted -s $dev mklabel msdos || error "Failed to create partition table"
  336. # This is a bit rough, and probably won't result in great performance,
  337. # but it's fine for test/demo purposes to carve off 1MB for SBD. Note
  338. # we have to specify the size of the first partition in this in bytes
  339. # rather than MB, or parted's rounding gives us a ~30Kb partition
  340. # (see rhbz#623268).
  341. invoke parted -s $dev mkpart primary 0 1048576B || error "Failed to create first partition"
  342. invoke parted -s $dev mkpart primary 1M 100% || error "Failed to create second partition"
  343. status_done
  344. # TODO: May not be strictly necessary, but...
  345. probe_partitions
  346. # TODO: THIS IS *WRONG* FOR MULTIPATH! (but possibly nothing we can do about it)
  347. devices=( $(fdisk -l $dev | awk '/^\/dev/ { print $1; }') )
  348. SBD_DEVICE=${devices[0]}
  349. [ -z "$SBD_DEVICE" ] && error "Unable to determine device path for SBD partition"
  350. OCFS2_DEVICE=${devices[1]}
  351. [ -z "$OCFS2_DEVICE" ] && error "Unable to determine device path for OCFS2 partition"
  352. status
  353. status "Created $SBD_DEVICE for SBD partition"
  354. status "Created $OCFS2_DEVICE for OCFS2 partition"
  355. }
  356. init_sbd()
  357. {
  358. local dev
  359. local -i dev_looks_sane=0
  360. if [ -z "$SBD_DEVICE" ]; then
  361. # SBD device not set up by init_storage (ocfs2 template) and
  362. # also not passed in as command line argument - prompt user
  363. if $YES_TO_ALL; then
  364. warn "Not configuring SBD ($SYSCONFIG_SBD left untouched)."
  365. return
  366. fi
  367. status "
  368. Configure SBD:
  369. If you have shared storage, for example a SAN or iSCSI target,
  370. you can use it avoid split-brain scenarios by configuring SBD.
  371. This requires a 1 MB partition, accessible to all nodes in the
  372. cluster. The device path must be persistent and consistent
  373. across all nodes in the cluster, so /dev/disk/by-id/* devices
  374. are a good choice. Note that all data on the partition you
  375. specify here will be destroyed.
  376. "
  377. if [ -n "$(configured_sbd_device)" ]; then
  378. confirm \
  379. "SBD is already configured - overwrite?" || return
  380. fi
  381. if ! confirm "Do you wish to use SBD?"; then
  382. warn "Not configuring SBD - STONITH will be disabled."
  383. # Comment out SBD devices if present
  384. if [ -f "$SYSCONFIG_SBD" ]; then
  385. local tmp_conf=$SYSCONFIG_SBD.$$
  386. sed -e 's/^\([^#].*\)$/#\1/g' $SYSCONFIG_SBD > $tmp_conf
  387. install_tmp $tmp_conf $SYSCONFIG_SBD
  388. invoke csync2 -m $SYSCONFIG_SBD
  389. invoke csync2 -f $SYSCONFIG_SBD
  390. invoke csync2 -xv $SYSCONFIG_SBD
  391. fi
  392. return
  393. fi
  394. while [ $dev_looks_sane -eq 0 ]; do
  395. dev=$(prompt_for_string \
  396. 'Path to storage device (e.g. /dev/disk/by-id/...)' \
  397. '\/.*' "$dev")
  398. if [ ! -b "$dev" ]; then
  399. echo " That doesn't look like a block device" >&2
  400. else
  401. status "All data on $dev will be destroyed"
  402. confirm 'Are you sure you wish to use this device' \
  403. && dev_looks_sane=1 || dev=
  404. fi
  405. done
  406. SBD_DEVICE="$dev"
  407. SBD_WATCHDOG="yes"
  408. if ! check_watchdog; then
  409. warn "No watchdog device detected! SBD will not work without a watchdog."
  410. fi
  411. fi
  412. [ -b "$SBD_DEVICE" ] || error "SBD device $SBD_DEVICE does not exist"
  413. # TODO: need to ensure watchdog is available
  414. # (actually, should work if watchdog unavailable, it'll just whine in the logs...)
  415. # TODO: what about timeouts for multipath devices?
  416. status_long 'Initializing SBD...'
  417. invoke sbd -d $SBD_DEVICE create || error "Failed to initialize SBD device"
  418. status_done
  419. if [ -f $SYSCONFIG_SBD ]; then
  420. if grep -E '^SBD_DEVICE=.*' $SYSCONFIG_SBD >/dev/null 2>&1; then
  421. sed -i -e "s%^SBD_DEVICE=.*%SBD_DEVICE=\"$SBD_DEVICE\"%g" $SYSCONFIG_SBD
  422. else
  423. echo "SBD_DEVICE=\"$SBD_DEVICE\"" >> $SYSCONFIG_SBD
  424. fi
  425. if grep -E '^SBD_WATCHDOG=.*' $SYSCONFIG_SBD >/dev/null 2>&1; then
  426. sed -i -e "s/^SBD_WATCHDOG=.*/SBD_WATCHDOG=\"$SBD_WATCHDOG\"/g" $SYSCONFIG_SBD
  427. else
  428. echo "SBD_WATCHDOG=\"$SBD_WATCHDOG\"" >> $SYSCONFIG_SBD
  429. fi
  430. else
  431. echo "SBD_DEVICE=\"$SBD_DEVICE\"" > $SYSCONFIG_SBD
  432. echo "SBD_WATCHDOG=\"$SBD_WATCHDOG\"" >> $SYSCONFIG_SBD
  433. fi
  434. invoke csync2 -m $SYSCONFIG_SBD
  435. invoke csync2 -f $SYSCONFIG_SBD
  436. invoke csync2 -xv $SYSCONFIG_SBD
  437. }
  438. init_cluster()
  439. {
  440. init_cluster_local
  441. local -i node_count=$(crmadmin -N|grep 'node'|wc -l)
  442. [ "$node_count" -lt 1 ] && error "No nodes found in cluster"
  443. [ "$node_count" -gt 1 ] && error "Joined existing cluster - will not reconfigure."
  444. status "Loading initial configuration"
  445. # base config
  446. local tmp_conf=/tmp/crm.$$
  447. cat > $tmp_conf <<END
  448. property \$id="cib-bootstrap-options" \\
  449. stonith-enabled="false" \\
  450. no-quorum-policy="ignore" \\
  451. placement-strategy="balanced"
  452. op_defaults \$id="op-options" \\
  453. timeout="600" \\
  454. record-pending="true"
  455. rsc_defaults \$id="rsc-options" \\
  456. resource-stickiness="1" \\
  457. migration-threshold="3"
  458. END
  459. crm_configure_load replace $tmp_conf
  460. # sbd fencing if applicable (getting local sbd_device here direct
  461. # from SBD config, in case init_cluster is invoked on its own)
  462. local sbd_device=$([ -f /etc/sysconfig/sbd ] && \
  463. . /etc/sysconfig/sbd ; echo $SBD_DEVICE)
  464. if [ -n "$sbd_device" ]; then
  465. # Can't do crm configure load update here with only
  466. # stonith-enabled, or it wipes out then entire
  467. # cib-bootstrap-options section
  468. # TODO: find out if this is a bug in the crm shell
  469. invoke crm configure primitive stonith-sbd stonith:external/sbd \
  470. || error "Can't create stonith-sbd primitive"
  471. invoke crm configure property stonith-enabled="true" \
  472. || error "Can't enable STONITH"
  473. fi
  474. }
  475. # Non-generic, i.e. not for use with every type of cluster you can imagine:
  476. # creates specific cluster config (TODO: would be nice to just directly
  477. # use Hawk's wizard template instead of including config directly here)
  478. init_vgfs()
  479. {
  480. [ -b "$OCFS2_DEVICE" ] || error "OCFS2 device $OCFS2_DEVICE does not exist"
  481. # TODO: confiugrable mountpoint and vg name
  482. local tmp_conf=/tmp/crm.$$
  483. cat > $tmp_conf <<END
  484. primitive dlm ocf:pacemaker:controld \\
  485. op start timeout="90" op stop timeout="100" \\
  486. op monitor interval="60" timeout="60"
  487. primitive clusterfs ocf:heartbeat:Filesystem \\
  488. params directory="/srv/clusterfs" fstype="ocfs2" device="$OCFS2_DEVICE" \\
  489. op monitor interval="20" timeout="40" \\
  490. op start timeout="60" op stop timeout="60" \\
  491. meta target-role="Stopped"
  492. clone base-clone dlm meta interleave="true"
  493. clone c-clusterfs clusterfs meta interleave="true"
  494. order base-then-clusterfs inf: base-clone c-clusterfs
  495. colocation clusterfs-with-base inf: c-clusterfs base-clone
  496. END
  497. crm_configure_load update $tmp_conf
  498. wait_for_resource "Waiting for DLM" dlm:0
  499. wait_for_stop "Making sure filesystem is not active" clusterfs:0
  500. if blkid $OCFS2_DEVICE 2>/dev/null | grep -q TYPE; then
  501. if ! confirm "Exiting filesystem found on $OCFS2_DEVICE - destroy?"; then
  502. for res in base-clone c-clusterfs ; do
  503. invoke crm resource stop $res
  504. wait_for_stop "Waiting for resource to stop" $res
  505. done
  506. invoke crm configure delete \
  507. dlm clusterfs \
  508. base-group base-clone c-clusterfs \
  509. base-then-clusterfs clusterfs-with-base
  510. return
  511. fi
  512. fi
  513. status_long "Creating OCFS2 filesystem"
  514. # TODO: want "-T vmstore", but this'll only fly on >2GB partition
  515. # Note: using undocumented '-x' switch to avoid prompting if overwriting
  516. # existing partition. For the commit that introduced this, see:
  517. # http://oss.oracle.com/git/?p=ocfs2-tools.git;a=commit;h=8345a068479196172190f4fa287052800fa2b66f
  518. invoke mkfs.ocfs2 --cluster-stack pcmk --cluster-name hacluster -x $OCFS2_DEVICE || error "Failed to create OCFS2 filesystem on $OCFS2_DEVICE"
  519. status_done
  520. # TODO: refactor, maybe
  521. invoke mkdir -p /srv/clusterfs || error "Can't create mountpoint /srv/clusterfs"
  522. invoke crm resource meta clusterfs delete target-role \
  523. || error "Can't start cluster filesystem clone"
  524. wait_for_resource "Waiting for /srv/clusterfs to be mounted" clusterfs:0
  525. }
  526. #------------------------------------------------------------------------------
  527. # for --help option
  528. [ "$1" == "--help" ] && usage
  529. while getopts 'hi:o:p:qs:t:y' o; do
  530. case $o in
  531. h) usage;;
  532. i) NET_IF=$OPTARG;;
  533. o) OCFS2_DEVICE=$OPTARG;;
  534. p) SHARED_DEVICE=$OPTARG;;
  535. q) BE_QUIET=true;;
  536. s) SBD_DEVICE=$OPTARG;;
  537. t) TEMPLATE=$OPTARG;;
  538. y) YES_TO_ALL=true;;
  539. esac
  540. done
  541. shift $(($OPTIND - 1))
  542. stage=$1 ; shift
  543. # vgfs stage requires running cluster, everything else requires inactive cluster,
  544. # except ssh and csync2 (which don't care) and csync2_remote (which mustn't care,
  545. # just in case this breaks ha-cluster-join on another node).
  546. systemctl -q is-active corosync.service
  547. rc=$?
  548. if [ "$stage" == "vgfs" ]; then
  549. [ $rc -ne 0 ] && error "Cluster is inactive - can't run vgfs stage"
  550. elif [ "$stage" != "ssh" -a "$stage" != "ssh_remote" -a "$stage" != "csync2" -a "$stage" != "csync2_remote" ]; then
  551. [ $rc -eq 0 ] && error "Cluster is currently active - can't run"
  552. fi
  553. # Need hostname resolution to work, want NTP (but don't block ssh_remote or csync2_remote)
  554. if [ "$stage" != "ssh_remote" -a "$stage" != "csync2_remote" ]; then
  555. check_prereqs
  556. fi
  557. case $TEMPLATE in
  558. ocfs2) ;;
  559. "") ;;
  560. *) error "Invalid template ($TEMPLATE)"
  561. esac
  562. case $stage in
  563. ssh|ssh_remote|csync2|csync2_remote|corosync|storage|sbd|cluster|vgfs)
  564. init
  565. # $2 == nasty hack to pick up IP arg to csync2_remote (not strictly
  566. # necessary currently, as we're not auto-updating /etc/hosts)
  567. init_$stage "$@"
  568. ;;
  569. "")
  570. init
  571. init_ssh
  572. init_csync2
  573. init_corosync
  574. if [ "$TEMPLATE" == "ocfs2" ]; then
  575. [ -n "$SBD_DEVICE" -a -n "$OCFS2_DEVICE" ] || init_storage
  576. fi
  577. init_sbd
  578. init_cluster
  579. [ "$TEMPLATE" == "ocfs2" ] && init_vgfs
  580. ;;
  581. *) echo -e "Invalid stage ($1)\n"
  582. usage
  583. esac
  584. status "Done (log saved to $LOG_FILE)"
  585. exit 0