From 119930852024f1dc8433ed8a9a3f589a2efa0360 Mon Sep 17 00:00:00 2001 From: basebuilder_pel7ppc64bebuilder0 Date: Sun, 3 Jun 2018 11:08:41 +0200 Subject: [PATCH] resource-agent package update Signed-off-by: basebuilder_pel7ppc64bebuilder0 --- SOURCES/NovaCompute.patch | 418 + .../bz10005924-default-apache-config.patch | 69 + ...bz1014641-VirtualDomain-syntax-error.patch | 25 + .../bz1016140-start-predefined-domains.patch | 47 + .../bz1029061-virtualdomain-parse-error.patch | 29 + .../bz1033016-nfsserver-missing-etab.patch | 15 + SOURCES/bz1058102-man-page-updates.patch | 250 + SOURCES/bz1059988-db2-support.patch | 154 + .../bz1060367-vm-monitor-wo-libvirtd.patch | 113 + .../bz1060367-vm-monitor-wo-libvirtd_2.patch | 178 + SOURCES/bz1064512-clvmd-agent.patch | 441 + SOURCES/bz1077888-CTDB-fix-logging.patch | 30 + SOURCES/bz1077888-ctdb-updates.patch | 159 + ...83041-virtual-domain-monitor-lxc-fix.patch | 54 + SOURCES/bz1083231-fs-wait-module-load.patch | 116 + SOURCES/bz1091101-nfs-error-msg-fix.patch | 25 + ...z1091101-nfs-rquotad-port-option-fix.patch | 27 + SOURCES/bz1091101-nfs-updates.patch | 1196 +++ SOURCES/bz1095944-safe-umount-option.patch | 87 + SOURCES/bz1097593-LVM-warn-lvmetad.patch | 42 + ...n-restore-start-stop-default-timeout.patch | 32 + ...ry-generous-in-the-promotion-timeout.patch | 26 + ...do-not-advertise-notify-in-the-usage.patch | 41 + SOURCES/bz1116166-galera-agent.patch | 1417 ++++ ...-galera-do-not-ignore-check_password.patch | 25 + SOURCES/bz1118029-iscsi-agents.patch | 1536 ++++ .../bz1118029-iscsi-remove-write-back.patch | 13 + SOURCES/bz1118029_iscsi_syntax_fix.patch | 39 + SOURCES/bz1122285-ethmonitor-infiniband.patch | 466 ++ ...sserver-fix-systemd-status-detection.patch | 474 ++ ...sserver-fix-systemd-status-detection.patch | 337 + ...global-__ha_log_ignore_stderr_once-h.patch | 71 + ...son-implicit-format-string-s-for-sin.patch | 77 + ...ix-syntax-error-caused-by-exit_reaso.patch | 26 + ...z1128933-IPaddr2-exit-reason-support.patch | 185 + ...33-VirtualDomain-exit-reason-support.patch | 102 + ...933-binary-check-exit-reason-support.patch | 25 + ...bz1128933-exit-reason-string-updates.patch | 2118 +++++ ...1128933-exportfs-exit-reason-support.patch | 43 + ...8933-introducing-exit-reason-support.patch | 98 + ...128933-nfsnotify-exit-reason-support.patch | 52 + ...28933-nfssserver-exit-reason-support.patch | 97 + ...26-docker-handle-invalid-monitor-cmd.patch | 69 + .../bz1135026-docker-monitor_cmd-arg.patch | 145 + SOURCES/bz1135026-docker-name-arg.patch | 61 + SOURCES/bz1135026-docker-stop-fix.patch | 49 + .../bz1135026-introducing-docker-agent.patch | 375 + ...38871-avoid-check-binary-in-validate.patch | 43 + ...mysql-error-validation-fails-monitor.patch | 35 + SOURCES/bz1138871_mysql_stop_fix.patch | 26 + .../bz1159328-LVM-check_writethrough.patch | 60 + SOURCES/bz1160365-iface-vlan.patch.patch | 520 ++ SOURCES/bz1168251-SAPHana-agents-update.patch | 97 + .../bz1168251-SAPHana-agents-update2.patch | 37 + .../bz1168251-SAPHana-agents-update3.patch | 13 + SOURCES/bz1168251-SAPHana-agents.patch | 3129 +++++++ .../bz1168251-SAPHana-agents_update4.patch | 441 + SOURCES/bz1170376-galera-no-readonly.patch | 204 + SOURCES/bz1171162-clvmd-opt-fix.patch | 25 + SOURCES/bz1183136-nginx-support.patch | 113 + SOURCES/bz1189187-redis-agent.patch | 564 ++ .../bz1198681-clvm-activate-vgs-option.patch | 56 + SOURCES/bz1200756-ipsrcaddr-misconfig.patch | 92 + SOURCES/bz1212632-nagios.patch | 272 + SOURCES/bz1213971-ethmon-opt.patch | 43 + .../bz1214360-NovaCompute-update1.patch.patch | 494 ++ ...781-lvm-partial-activation-fix.patch.patch | 49 + .../bz1223615-apache-includes-fix.patch.patch | 27 + .../bz1227293-dhcpd-chroot-fix.patch.patch | 49 + SOURCES/bz1231032-redis-update.patch.patch | 121 + SOURCES/bz1232376-oracle-agent-update.diff | 246 + ...242181-virtualdomain-migrate_options.patch | 133 + ...virtualdomain-may-remove-config-file.patch | 40 + ...cluster-forget-stopped-cluster-nodes.patch | 92 + ...249430-1-tomcat-fix-selinux-enforced.patch | 45 + ...249430-2-tomcat-fix-selinux-enforced.patch | 112 + ...rp-fix-buffer-overflow-on-infiniband.patch | 1188 +++ ...z1251484-redis-client-passwd-support.patch | 33 + ...13-1-sapdatabase-process-count-suser.patch | 135 + ...13-2-sapdatabase-process-count-suser.patch | 24 + SOURCES/bz1263348-mysql-tmpfile-leak.patch | 11 + ...luster_connector-hostnames-with-dash.patch | 37 + ...use-ipv6-dad-for-collision-detection.patch | 60 + ...ompute-novaevacuate-fix-evacute-typo.patch | 728 ++ SOURCES/bz1284526-galera-crash-recovery.patch | 131 + ...bz1284526-galera-heuristic-recovered.patch | 89 + SOURCES/bz1284526-galera-no-grastate.patch | 113 + ...87303-novaevacuate-invoke-off-action.patch | 31 + ...314-novaevacuate-simplify-nova-check.patch | 23 + SOURCES/bz1289107-saphana-mcos-support.patch | 1778 ++++ ...n-migration_speed-migration_downtime.patch | 101 + .../bz1299404-galera-custom-host-port.patch | 33 + .../bz1301189-virtualdomain-fix-locale.patch | 35 + SOURCES/bz1303037-1-portblock.patch | 207 + SOURCES/bz1303037-2-portblock.patch | 31 + ...re-rabbitmq-users-during-resource-re.patch | 45 + ...va-compute-wait-nova-compute-unfence.patch | 259 + ...tify-clients-of-master-being-demoted.patch | 42 + ...rror-when-probing-nonexistent-domain.patch | 20 + .../bz1316130-systemd-drop-in-clvmd-LVM.patch | 136 + ...s-if-username-is-longer-than-8-chars.patch | 15 + ...unable-to-start-because-of-ORA-01081.patch | 22 + ...pute-wait-fix-invalid-hostname-issue.patch | 169 + .../bz1325453-nfsserver-var-lib-nfs-fix.patch | 29 + ...arbd-Introduces-garbd-resource-agent.patch | 474 ++ ...racle-monprofile-container-databases.patch | 24 + ...racle-monprofile-container-databases.patch | 49 + ...racle-monprofile-container-databases.patch | 67 + SOURCES/bz1337109-tickle_tcp-fix.patch | 23 + ...mysql-use-replication_port-parameter.patch | 55 + .../bz1337615-nfsserver-rpcpipefs_dir.patch | 60 + ...er-backup-and-restore-users-policies.patch | 29 + ...er-backup-and-restore-users-policies.patch | 24 + ...er-backup-and-restore-users-policies.patch | 167 + ...q-cluster-return-code-69-not-running.patch | 73 + ...tmq-cluster-dump-restore-users-3.6.x.patch | 102 + ...tmq-cluster-dump-restore-users-3.6.x.patch | 37 + ...tmq-cluster-dump-restore-users-3.6.x.patch | 53 + ...-rabbitmq-automatic-cluster-recovery.patch | 39 + SOURCES/bz1358895-oracle-fix-monprofile.patch | 22 + .../bz1359252-clvm-remove-reload-action.patch | 21 + ...-galera-prevent-promote-after-demote.patch | 27 + ...thmonitor-add-intel-omnipath-support.patch | 71 + ...et-properly-create-portals-for-lio-t.patch | 38 + SOURCES/bz1380405-send_arp-usage.patch | 252 + ...z1384955-nfsserver-dont-stop-rpcbind.patch | 13 + .../bz1387363-Filesystem-submount-check.patch | 16 + .../bz1387491-nfsserver-keep-options.patch | 54 + .../bz1388854-delay-change-startdelay.patch | 41 + ...389300-iSCSILogicalUnit-IPv6-support.patch | 25 + ...390974-redis-fix-selinux-permissions.patch | 29 + ...-last-commit-fix-for-mariadb-10.1.18.patch | 83 + ...turn-success-on-stop-with-invalid-ip.patch | 22 + ...bz1392432-LVM-partial_activation-fix.patch | 33 + ...393189-1-IPaddr2-detect-duplicate-IP.patch | 76 + ...393189-2-IPaddr2-detect-duplicate-IP.patch | 54 + ...142-1-update-saphana-saphanatopology.patch | 1990 +++++ ...142-2-update-saphana-saphanatopology.patch | 14 + ...tmq-cluster-reset-mnesia-before-join.patch | 169 + ...00172-IPsrcaddr-fix-duplicate-routes.patch | 22 + SOURCES/bz1402370-portblock-wait.patch | 114 + SOURCES/bz1406152-exportfs-ipv6-fix.patch | 14 + ...monitor-monitor-interface-without-ip.patch | 25 + SOURCES/bz1411225-oraasm.patch | 221 + ...1420565-pgsql-dont-use-crm_failcount.patch | 64 + ...427574-DB2-fix-HADR-DB2-V98-or-later.patch | 68 + ...log-use-same-log-format-as-pacemaker.patch | 39 + SOURCES/bz1430304-NodeUtilization.patch | 252 + ...icalUnit-iSCSITarget-concurrent-safe.patch | 61 + ...4351-IPaddr2-send-arp-monitor-action.patch | 189 + ...1-named-add-support-for-rndc-options.patch | 62 + ...82-rabbitmq-cluster-pacemaker-remote.patch | 92 + SOURCES/bz1436189-sybase.patch | 920 +++ ...28-findif-improve-IPv6-NIC-detection.patch | 44 + ...dr2-IPv6-add-preferred_lft-parameter.patch | 81 + ...hana-saphanatopology-update-0.152.21.patch | 216 + ...hana-saphanatopology-update-0.152.21.patch | 48 + ...x-bootstrap-when-cluster-has-no-data.patch | 140 + ...x-bootstrap-when-cluster-has-no-data.patch | 50 + ...x-bootstrap-when-cluster-has-no-data.patch | 52 + ...arn-when-cache-mode-not-writethrough.patch | 59 + .../bz1452049-docker-create-directories.patch | 49 + ...irtualDomain-fix-sed-migrate_options.patch | 22 + ...1457382-portblock-suppress-dd-output.patch | 22 + SOURCES/bz1462802-systemd-tmpfiles.patch | 59 + SOURCES/bz1465822-OCF-improve-locking.patch | 185 + ...7-mysql-fix-master-score-maintenance.patch | 121 + ...ERS-parameter-for-ASCS-ERS-Netweaver.patch | 73 + SOURCES/bz1484473-ethmonitor-vlan-fix.patch | 25 + ...-support-per-host-per-bundle-attribs.patch | 94 + ...-support-per-host-per-bundle-attribs.patch | 146 + ...96393-NovaEvacuate-Instance-HA-OSP12.patch | 183 + ...lera-recover-from-empty-gvwstate.dat.patch | 40 + SOURCES/bz1500352-amazon-aws-agents.patch | 867 ++ ...4112-nfsserver-allow-stop-to-timeout.patch | 18 + ...z1508362-docker-improve-exit-reasons.patch | 26 + ...ocker-dont-ignore-stopped-containers.patch | 26 + SOURCES/bz1512580-CTDB-fix-probe.patch | 22 + ...-fix-hadr-promote-when-master-failed.patch | 31 + SOURCES/bz1516435-azure-lb.patch | 255 + ...74-ocf_attribute_target-fallback-fix.patch | 35 + ...z1523953-CTDB-detect-new-config-path.patch | 24 + ...pport-for-keystone-v3-authentication.patch | 55 + ...r_connector-fix-unknown-gvi-function.patch | 106 + ...rt-for-tunneling-replication-traffic.patch | 160 + ...46083-galera-fix-temp-logfile-rights.patch | 28 + .../bz773395-clvm-autoset-locking-type.patch | 41 + SOURCES/bz773399-netmast-error.patch | 105 + SOURCES/bz799065-apache-simple-monitor.patch | 118 + SOURCES/bz884164-multi-lib-fixes.patch | 53 + ...7681-VirtualDomain-heartbeat-updates.patch | 247 + ...1-VirtualDomain-heartbeat-updates_v2.patch | 36 + SOURCES/bz917681-ipv6-send_ua-fix.patch | 743 ++ ...681-ocft_fedora_supported_test_cases.patch | 7215 +++++++++++++++++ .../bz917681-slapd-heartbeat-updates.patch | 23 + .../bz917681-tomcat-heartbeat-updates.patch | 470 ++ SOURCES/bz917681_nodename_fixes.patch | 116 + SOURCES/bz917806-oracle-tns-admin.patch | 96 + SOURCES/bz984054.patch | 76 + SOURCES/fix-LVM-clvmd-retry.patch | 25 + SOURCES/nfs-fixes-update.patch | 143 + SOURCES/rabbitmq-cluster.patch | 415 + SPECS/resource-agents.spec | 1966 +++++ 203 files changed, 45896 insertions(+) create mode 100644 SOURCES/NovaCompute.patch create mode 100644 SOURCES/bz10005924-default-apache-config.patch create mode 100644 SOURCES/bz1014641-VirtualDomain-syntax-error.patch create mode 100644 SOURCES/bz1016140-start-predefined-domains.patch create mode 100644 SOURCES/bz1029061-virtualdomain-parse-error.patch create mode 100644 SOURCES/bz1033016-nfsserver-missing-etab.patch create mode 100644 SOURCES/bz1058102-man-page-updates.patch create mode 100644 SOURCES/bz1059988-db2-support.patch create mode 100644 SOURCES/bz1060367-vm-monitor-wo-libvirtd.patch create mode 100644 SOURCES/bz1060367-vm-monitor-wo-libvirtd_2.patch create mode 100644 SOURCES/bz1064512-clvmd-agent.patch create mode 100644 SOURCES/bz1077888-CTDB-fix-logging.patch create mode 100644 SOURCES/bz1077888-ctdb-updates.patch create mode 100644 SOURCES/bz1083041-virtual-domain-monitor-lxc-fix.patch create mode 100644 SOURCES/bz1083231-fs-wait-module-load.patch create mode 100644 SOURCES/bz1091101-nfs-error-msg-fix.patch create mode 100644 SOURCES/bz1091101-nfs-rquotad-port-option-fix.patch create mode 100644 SOURCES/bz1091101-nfs-updates.patch create mode 100644 SOURCES/bz1095944-safe-umount-option.patch create mode 100644 SOURCES/bz1097593-LVM-warn-lvmetad.patch create mode 100644 SOURCES/bz1105655-virtualdomain-restore-start-stop-default-timeout.patch create mode 100644 SOURCES/bz1116166-Low-galera-be-very-generous-in-the-promotion-timeout.patch create mode 100644 SOURCES/bz1116166-Low-galera-do-not-advertise-notify-in-the-usage.patch create mode 100644 SOURCES/bz1116166-galera-agent.patch create mode 100644 SOURCES/bz1116166-galera-do-not-ignore-check_password.patch create mode 100644 SOURCES/bz1118029-iscsi-agents.patch create mode 100644 SOURCES/bz1118029-iscsi-remove-write-back.patch create mode 100644 SOURCES/bz1118029_iscsi_syntax_fix.patch create mode 100644 SOURCES/bz1122285-ethmonitor-infiniband.patch create mode 100644 SOURCES/bz1126073-1-nfsserver-fix-systemd-status-detection.patch create mode 100644 SOURCES/bz1126073-2-nfsserver-fix-systemd-status-detection.patch create mode 100644 SOURCES/bz1128933-Fix-ha_log-drop-global-__ha_log_ignore_stderr_once-h.patch create mode 100644 SOURCES/bz1128933-Fix-ocf_exit_reason-implicit-format-string-s-for-sin.patch create mode 100644 SOURCES/bz1128933-Fix-shellfuncs-fix-syntax-error-caused-by-exit_reaso.patch create mode 100644 SOURCES/bz1128933-IPaddr2-exit-reason-support.patch create mode 100644 SOURCES/bz1128933-VirtualDomain-exit-reason-support.patch create mode 100644 SOURCES/bz1128933-binary-check-exit-reason-support.patch create mode 100644 SOURCES/bz1128933-exit-reason-string-updates.patch create mode 100644 SOURCES/bz1128933-exportfs-exit-reason-support.patch create mode 100644 SOURCES/bz1128933-introducing-exit-reason-support.patch create mode 100644 SOURCES/bz1128933-nfsnotify-exit-reason-support.patch create mode 100644 SOURCES/bz1128933-nfssserver-exit-reason-support.patch create mode 100644 SOURCES/bz1135026-docker-handle-invalid-monitor-cmd.patch create mode 100644 SOURCES/bz1135026-docker-monitor_cmd-arg.patch create mode 100644 SOURCES/bz1135026-docker-name-arg.patch create mode 100644 SOURCES/bz1135026-docker-stop-fix.patch create mode 100644 SOURCES/bz1135026-introducing-docker-agent.patch create mode 100644 SOURCES/bz1138871-avoid-check-binary-in-validate.patch create mode 100644 SOURCES/bz1138871-mysql-error-validation-fails-monitor.patch create mode 100644 SOURCES/bz1138871_mysql_stop_fix.patch create mode 100644 SOURCES/bz1159328-LVM-check_writethrough.patch create mode 100644 SOURCES/bz1160365-iface-vlan.patch.patch create mode 100644 SOURCES/bz1168251-SAPHana-agents-update.patch create mode 100644 SOURCES/bz1168251-SAPHana-agents-update2.patch create mode 100644 SOURCES/bz1168251-SAPHana-agents-update3.patch create mode 100644 SOURCES/bz1168251-SAPHana-agents.patch create mode 100644 SOURCES/bz1168251-SAPHana-agents_update4.patch create mode 100644 SOURCES/bz1170376-galera-no-readonly.patch create mode 100644 SOURCES/bz1171162-clvmd-opt-fix.patch create mode 100644 SOURCES/bz1183136-nginx-support.patch create mode 100644 SOURCES/bz1189187-redis-agent.patch create mode 100644 SOURCES/bz1198681-clvm-activate-vgs-option.patch create mode 100644 SOURCES/bz1200756-ipsrcaddr-misconfig.patch create mode 100644 SOURCES/bz1212632-nagios.patch create mode 100644 SOURCES/bz1213971-ethmon-opt.patch create mode 100644 SOURCES/bz1214360-NovaCompute-update1.patch.patch create mode 100644 SOURCES/bz1214781-lvm-partial-activation-fix.patch.patch create mode 100644 SOURCES/bz1223615-apache-includes-fix.patch.patch create mode 100644 SOURCES/bz1227293-dhcpd-chroot-fix.patch.patch create mode 100644 SOURCES/bz1231032-redis-update.patch.patch create mode 100644 SOURCES/bz1232376-oracle-agent-update.diff create mode 100644 SOURCES/bz1242181-virtualdomain-migrate_options.patch create mode 100644 SOURCES/bz1242558-virtualdomain-may-remove-config-file.patch create mode 100644 SOURCES/bz1247303-rabbitmq-cluster-forget-stopped-cluster-nodes.patch create mode 100644 SOURCES/bz1249430-1-tomcat-fix-selinux-enforced.patch create mode 100644 SOURCES/bz1249430-2-tomcat-fix-selinux-enforced.patch create mode 100644 SOURCES/bz1250728-send_arp-fix-buffer-overflow-on-infiniband.patch create mode 100644 SOURCES/bz1251484-redis-client-passwd-support.patch create mode 100644 SOURCES/bz1260713-1-sapdatabase-process-count-suser.patch create mode 100644 SOURCES/bz1260713-2-sapdatabase-process-count-suser.patch create mode 100644 SOURCES/bz1263348-mysql-tmpfile-leak.patch create mode 100644 SOURCES/bz1265527-sap_redhat_cluster_connector-hostnames-with-dash.patch create mode 100644 SOURCES/bz1276699-ipaddr2-use-ipv6-dad-for-collision-detection.patch create mode 100644 SOURCES/bz1282723-novacompute-novaevacuate-fix-evacute-typo.patch create mode 100644 SOURCES/bz1284526-galera-crash-recovery.patch create mode 100644 SOURCES/bz1284526-galera-heuristic-recovered.patch create mode 100644 SOURCES/bz1284526-galera-no-grastate.patch create mode 100644 SOURCES/bz1287303-novaevacuate-invoke-off-action.patch create mode 100644 SOURCES/bz1287314-novaevacuate-simplify-nova-check.patch create mode 100644 SOURCES/bz1289107-saphana-mcos-support.patch create mode 100644 SOURCES/bz1296406-virtualdomain-migration_speed-migration_downtime.patch create mode 100644 SOURCES/bz1299404-galera-custom-host-port.patch create mode 100644 SOURCES/bz1301189-virtualdomain-fix-locale.patch create mode 100644 SOURCES/bz1303037-1-portblock.patch create mode 100644 SOURCES/bz1303037-2-portblock.patch create mode 100644 SOURCES/bz1303803-Backup-and-restore-rabbitmq-users-during-resource-re.patch create mode 100644 SOURCES/bz1305549-nova-compute-wait-nova-compute-unfence.patch create mode 100644 SOURCES/bz1305549-redis-notify-clients-of-master-being-demoted.patch create mode 100644 SOURCES/bz1307160-virtualdomain-fix-unnecessary-error-when-probing-nonexistent-domain.patch create mode 100644 SOURCES/bz1316130-systemd-drop-in-clvmd-LVM.patch create mode 100644 SOURCES/bz1317578-oralsnr-fails-if-username-is-longer-than-8-chars.patch create mode 100644 SOURCES/bz1318985-oracle-fix-unable-to-start-because-of-ORA-01081.patch create mode 100644 SOURCES/bz1320783-nova-compute-wait-fix-invalid-hostname-issue.patch create mode 100644 SOURCES/bz1325453-nfsserver-var-lib-nfs-fix.patch create mode 100644 SOURCES/bz1328018-garbd-Introduces-garbd-resource-agent.patch create mode 100644 SOURCES/bz1328386-1-oracle-monprofile-container-databases.patch create mode 100644 SOURCES/bz1328386-2-oracle-monprofile-container-databases.patch create mode 100644 SOURCES/bz1328386-3-oracle-monprofile-container-databases.patch create mode 100644 SOURCES/bz1337109-tickle_tcp-fix.patch create mode 100644 SOURCES/bz1337124-mysql-use-replication_port-parameter.patch create mode 100644 SOURCES/bz1337615-nfsserver-rpcpipefs_dir.patch create mode 100644 SOURCES/bz1342376-2-rabbitmq-cluster-backup-and-restore-users-policies.patch create mode 100644 SOURCES/bz1342376-3-rabbitmq-cluster-backup-and-restore-users-policies.patch create mode 100644 SOURCES/bz1342376-rabbitmq-cluster-backup-and-restore-users-policies.patch create mode 100644 SOURCES/bz1342478-rabbitmq-cluster-return-code-69-not-running.patch create mode 100644 SOURCES/bz1343905-1-rabbitmq-cluster-dump-restore-users-3.6.x.patch create mode 100644 SOURCES/bz1343905-2-rabbitmq-cluster-dump-restore-users-3.6.x.patch create mode 100644 SOURCES/bz1343905-3-rabbitmq-cluster-dump-restore-users-3.6.x.patch create mode 100644 SOURCES/bz1343905-rabbitmq-automatic-cluster-recovery.patch create mode 100644 SOURCES/bz1358895-oracle-fix-monprofile.patch create mode 100644 SOURCES/bz1359252-clvm-remove-reload-action.patch create mode 100644 SOURCES/bz1360768-galera-prevent-promote-after-demote.patch create mode 100644 SOURCES/bz1364242-ethmonitor-add-intel-omnipath-support.patch create mode 100644 SOURCES/bz1376588-iSCSITarget-properly-create-portals-for-lio-t.patch create mode 100644 SOURCES/bz1380405-send_arp-usage.patch create mode 100644 SOURCES/bz1384955-nfsserver-dont-stop-rpcbind.patch create mode 100644 SOURCES/bz1387363-Filesystem-submount-check.patch create mode 100644 SOURCES/bz1387491-nfsserver-keep-options.patch create mode 100644 SOURCES/bz1388854-delay-change-startdelay.patch create mode 100644 SOURCES/bz1389300-iSCSILogicalUnit-IPv6-support.patch create mode 100644 SOURCES/bz1390974-redis-fix-selinux-permissions.patch create mode 100644 SOURCES/bz1391470-galera-last-commit-fix-for-mariadb-10.1.18.patch create mode 100644 SOURCES/bz1391580-portblock-return-success-on-stop-with-invalid-ip.patch create mode 100644 SOURCES/bz1392432-LVM-partial_activation-fix.patch create mode 100644 SOURCES/bz1393189-1-IPaddr2-detect-duplicate-IP.patch create mode 100644 SOURCES/bz1393189-2-IPaddr2-detect-duplicate-IP.patch create mode 100644 SOURCES/bz1395142-1-update-saphana-saphanatopology.patch create mode 100644 SOURCES/bz1395142-2-update-saphana-saphanatopology.patch create mode 100644 SOURCES/bz1397393-rabbitmq-cluster-reset-mnesia-before-join.patch create mode 100644 SOURCES/bz1400172-IPsrcaddr-fix-duplicate-routes.patch create mode 100644 SOURCES/bz1402370-portblock-wait.patch create mode 100644 SOURCES/bz1406152-exportfs-ipv6-fix.patch create mode 100644 SOURCES/bz1408656-ethmonitor-monitor-interface-without-ip.patch create mode 100644 SOURCES/bz1411225-oraasm.patch create mode 100644 SOURCES/bz1420565-pgsql-dont-use-crm_failcount.patch create mode 100644 SOURCES/bz1427574-DB2-fix-HADR-DB2-V98-or-later.patch create mode 100644 SOURCES/bz1427611-ocf_log-use-same-log-format-as-pacemaker.patch create mode 100644 SOURCES/bz1430304-NodeUtilization.patch create mode 100644 SOURCES/bz1430385-iSCSILogicalUnit-iSCSITarget-concurrent-safe.patch create mode 100644 SOURCES/bz1434351-IPaddr2-send-arp-monitor-action.patch create mode 100644 SOURCES/bz1435171-named-add-support-for-rndc-options.patch create mode 100644 SOURCES/bz1435982-rabbitmq-cluster-pacemaker-remote.patch create mode 100644 SOURCES/bz1436189-sybase.patch create mode 100644 SOURCES/bz1445628-findif-improve-IPv6-NIC-detection.patch create mode 100644 SOURCES/bz1445861-IPaddr2-IPv6-add-preferred_lft-parameter.patch create mode 100644 SOURCES/bz1449681-1-saphana-saphanatopology-update-0.152.21.patch create mode 100644 SOURCES/bz1449681-2-saphana-saphanatopology-update-0.152.21.patch create mode 100644 SOURCES/bz1451097-1-galera-fix-bootstrap-when-cluster-has-no-data.patch create mode 100644 SOURCES/bz1451097-2-galera-fix-bootstrap-when-cluster-has-no-data.patch create mode 100644 SOURCES/bz1451097-3-galera-fix-bootstrap-when-cluster-has-no-data.patch create mode 100644 SOURCES/bz1451933-LVM-warn-when-cache-mode-not-writethrough.patch create mode 100644 SOURCES/bz1452049-docker-create-directories.patch create mode 100644 SOURCES/bz1455305-VirtualDomain-fix-sed-migrate_options.patch create mode 100644 SOURCES/bz1457382-portblock-suppress-dd-output.patch create mode 100644 SOURCES/bz1462802-systemd-tmpfiles.patch create mode 100644 SOURCES/bz1465822-OCF-improve-locking.patch create mode 100644 SOURCES/bz1465827-mysql-fix-master-score-maintenance.patch create mode 100644 SOURCES/bz1466187-SAPInstance-IS_ERS-parameter-for-ASCS-ERS-Netweaver.patch create mode 100644 SOURCES/bz1484473-ethmonitor-vlan-fix.patch create mode 100644 SOURCES/bz1489734-1-support-per-host-per-bundle-attribs.patch create mode 100644 SOURCES/bz1489734-2-support-per-host-per-bundle-attribs.patch create mode 100644 SOURCES/bz1496393-NovaEvacuate-Instance-HA-OSP12.patch create mode 100644 SOURCES/bz1499677-galera-recover-from-empty-gvwstate.dat.patch create mode 100644 SOURCES/bz1500352-amazon-aws-agents.patch create mode 100644 SOURCES/bz1504112-nfsserver-allow-stop-to-timeout.patch create mode 100644 SOURCES/bz1508362-docker-improve-exit-reasons.patch create mode 100644 SOURCES/bz1508366-docker-dont-ignore-stopped-containers.patch create mode 100644 SOURCES/bz1512580-CTDB-fix-probe.patch create mode 100644 SOURCES/bz1516180-db2-fix-hadr-promote-when-master-failed.patch create mode 100644 SOURCES/bz1516435-azure-lb.patch create mode 100644 SOURCES/bz1520574-ocf_attribute_target-fallback-fix.patch create mode 100644 SOURCES/bz1523953-CTDB-detect-new-config-path.patch create mode 100644 SOURCES/bz1533168-NovaEvacuate-add-support-for-keystone-v3-authentication.patch create mode 100644 SOURCES/bz1536548-sap_redhat_cluster_connector-fix-unknown-gvi-function.patch create mode 100644 SOURCES/bz1543366-redis-add-support-for-tunneling-replication-traffic.patch create mode 100644 SOURCES/bz1546083-galera-fix-temp-logfile-rights.patch create mode 100644 SOURCES/bz773395-clvm-autoset-locking-type.patch create mode 100644 SOURCES/bz773399-netmast-error.patch create mode 100644 SOURCES/bz799065-apache-simple-monitor.patch create mode 100644 SOURCES/bz884164-multi-lib-fixes.patch create mode 100644 SOURCES/bz917681-VirtualDomain-heartbeat-updates.patch create mode 100644 SOURCES/bz917681-VirtualDomain-heartbeat-updates_v2.patch create mode 100644 SOURCES/bz917681-ipv6-send_ua-fix.patch create mode 100644 SOURCES/bz917681-ocft_fedora_supported_test_cases.patch create mode 100644 SOURCES/bz917681-slapd-heartbeat-updates.patch create mode 100644 SOURCES/bz917681-tomcat-heartbeat-updates.patch create mode 100644 SOURCES/bz917681_nodename_fixes.patch create mode 100644 SOURCES/bz917806-oracle-tns-admin.patch create mode 100644 SOURCES/bz984054.patch create mode 100644 SOURCES/fix-LVM-clvmd-retry.patch create mode 100644 SOURCES/nfs-fixes-update.patch create mode 100644 SOURCES/rabbitmq-cluster.patch create mode 100644 SPECS/resource-agents.spec diff --git a/SOURCES/NovaCompute.patch b/SOURCES/NovaCompute.patch new file mode 100644 index 00000000..8db25328 --- /dev/null +++ b/SOURCES/NovaCompute.patch @@ -0,0 +1,418 @@ +From bd60deaa906cc5fe1cd46549b1318d2b940395ef Mon Sep 17 00:00:00 2001 +From: David Vossel +Date: Thu, 11 Jun 2015 08:41:50 -0500 +Subject: [PATCH] NovaCompute agent + +--- + doc/man/Makefile.am | 1 + + heartbeat/Makefile.am | 4 + + heartbeat/NovaCompute | 363 ++++++++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 368 insertions(+) + create mode 100644 heartbeat/NovaCompute + +diff --git a/doc/man/Makefile.am b/doc/man/Makefile.am +index 653e818..69acf3a 100644 +--- a/doc/man/Makefile.am ++++ b/doc/man/Makefile.am +@@ -73,6 +73,7 @@ man_MANS = ocf_heartbeat_AoEtarget.7 \ + ocf_heartbeat_MailTo.7 \ + ocf_heartbeat_ManageRAID.7 \ + ocf_heartbeat_ManageVE.7 \ ++ ocf_heartbeat_NovaCompute.7 \ + ocf_heartbeat_Pure-FTPd.7 \ + ocf_heartbeat_Raid1.7 \ + ocf_heartbeat_Route.7 \ +diff --git a/heartbeat/Makefile.am b/heartbeat/Makefile.am +index e4ed4fd..b77c589 100644 +--- a/heartbeat/Makefile.am ++++ b/heartbeat/Makefile.am +@@ -29,6 +29,8 @@ halibdir = $(libexecdir)/heartbeat + + ocfdir = $(OCF_RA_DIR_PREFIX)/heartbeat + ++ospdir = $(OCF_RA_DIR_PREFIX)/openstack ++ + dtddir = $(datadir)/$(PACKAGE_NAME) + dtd_DATA = ra-api-1.dtd + +@@ -50,6 +52,8 @@ send_ua_SOURCES = send_ua.c IPv6addr_utils.c + IPv6addr_LDADD = -lplumb $(LIBNETLIBS) + send_ua_LDADD = $(LIBNETLIBS) + ++osp_SCRIPTS = NovaCompute ++ + ocf_SCRIPTS = ClusterMon \ + CTDB \ + Dummy \ +diff --git a/heartbeat/NovaCompute b/heartbeat/NovaCompute +new file mode 100644 +index 0000000..f71abeb +--- /dev/null ++++ b/heartbeat/NovaCompute +@@ -0,0 +1,363 @@ ++#!/bin/sh ++# ++# ++# NovaCompute agent manages compute daemons. ++# ++# Copyright (c) 2015 ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of version 2 of the GNU General Public License as ++# published by the Free Software Foundation. ++# ++# This program is distributed in the hope that it would be useful, but ++# WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++# ++# Further, this software is distributed without any warranty that it is ++# free of the rightful claim of any third person regarding infringement ++# or the like. Any license provided herein, whether implied or ++# otherwise, applies only to this software file. Patent licenses, if ++# any, provided herein do not apply to combinations of this program with ++# other software, or any other product whatsoever. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write the Free Software Foundation, ++# Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. ++# ++ ++####################################################################### ++# Initialization: ++ ++### ++: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat} ++. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs ++### ++ ++: ${__OCF_ACTION=$1} ++ ++####################################################################### ++ ++meta_data() { ++ cat < ++ ++ ++1.0 ++ ++ ++OpenStack Nova Compute Server. ++ ++OpenStack Nova Compute Server ++ ++ ++ ++ ++ ++Authorization URL for connecting to keystone in admin context ++ ++Authorization URL ++ ++ ++ ++ ++ ++Username for connecting to keystone in admin context ++ ++Username ++ ++ ++ ++ ++Password for connecting to keystone in admin context ++ ++Password ++ ++ ++ ++ ++ ++Tenant name for connecting to keystone in admin context. ++Note that with Keystone V3 tenant names are only unique within a domain. ++ ++Tenant name ++ ++ ++ ++ ++ ++DNS domain in which hosts live, useful when the cluster uses short names and nova uses FQDN ++ ++DNS domain ++ ++ ++ ++ ++ ++Nova API location (internal, public or admin URL) ++ ++Nova API location (internal, public or admin URL) ++ ++ ++ ++ ++ ++Disable shared storage recovery for instances. Use at your own risk! ++ ++Disable shared storage recovery for instances ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++END ++} ++ ++####################################################################### ++ ++# don't exit on TERM, to test that lrmd makes sure that we do exit ++trap sigterm_handler TERM ++sigterm_handler() { ++ ocf_log info "They use TERM to bring us down. No such luck." ++ return ++} ++ ++nova_usage() { ++ cat </dev/null) ++ if [ $? = 1 ]; then ++ if [ "x${OCF_RESKEY_domain}" != x ]; then ++ NOVA_HOST=$(uname -n | awk -F. '{print $1}') ++ else ++ NOVA_HOST=$(uname -n) ++ fi ++ fi ++ ++ # We only need to check a configured value, calculated ones are fine ++ openstack-config --get /etc/nova/nova.conf DEFAULT host 2>/dev/null ++ if [ $? = 0 ]; then ++ if [ "x${OCF_RESKEY_domain}" != x ]; then ++ short_host=$(uname -n | awk -F. '{print $1}') ++ if [ "x$NOVA_HOST" != "x${short_host}" ]; then ++ ocf_exit_reason "Invalid Nova host name, must be ${short_host} in order for instance recovery to function" ++ rc=$OCF_ERR_CONFIGURED ++ fi ++ ++ elif [ "x$NOVA_HOST" != "x$(uname -n)" ]; then ++ ocf_exit_reason "Invalid Nova host name, must be $(uname -n) in order for instance recovery to function" ++ rc=$OCF_ERR_CONFIGURED ++ fi ++ fi ++ ++ if [ $rc != $OCF_SUCCESS ]; then ++ exit $rc ++ fi ++ return $rc ++} ++ ++case $__OCF_ACTION in ++meta-data) meta_data ++ exit $OCF_SUCCESS ++ ;; ++usage|help) nova_usage ++ exit $OCF_SUCCESS ++ ;; ++esac ++ ++nova_validate ++ ++case $__OCF_ACTION in ++start) nova_start;; ++stop) nova_stop;; ++monitor) nova_monitor;; ++notify) nova_notify;; ++validate-all) exit $OCF_SUCCESS;; ++*) nova_usage ++ exit $OCF_ERR_UNIMPLEMENTED ++ ;; ++esac ++rc=$? ++ocf_log debug "${OCF_RESOURCE_INSTANCE} $__OCF_ACTION : $rc" ++exit $rc +-- +1.8.4.2 + diff --git a/SOURCES/bz10005924-default-apache-config.patch b/SOURCES/bz10005924-default-apache-config.patch new file mode 100644 index 00000000..c73a6c86 --- /dev/null +++ b/SOURCES/bz10005924-default-apache-config.patch @@ -0,0 +1,69 @@ +diff --git a/heartbeat/apache b/heartbeat/apache +index 726e8fb..1369804 100755 +--- a/heartbeat/apache ++++ b/heartbeat/apache +@@ -63,7 +63,8 @@ fi + LOCALHOST="http://localhost" + HTTPDOPTS="-DSTATUS" + DEFAULT_IBMCONFIG=/opt/IBMHTTPServer/conf/httpd.conf +-DEFAULT_NORMCONFIG="/etc/apache2/httpd.conf" ++DEFAULT_SUSECONFIG="/etc/apache2/httpd.conf" ++DEFAULT_RHELCONFIG="/etc/httpd/conf/httpd.conf" + # + # You can also set + # HTTPD +@@ -82,7 +83,8 @@ CMD=`basename $0` + # assumed if no config file is specified. If this command is + # invoked as *IBM*, then the default config file name is + # $DEFAULT_IBMCONFIG, otherwise the default config file +-# will be $DEFAULT_NORMCONFIG. ++# will be either $DEFAULT_RHELCONFIG or $DEFAULT_SUSECONFIG depending ++# on which is detected. + usage() { + cat <<-! + usage: $0 action +@@ -146,7 +148,7 @@ validate_default_config() { + # the relevant config is generated and valid. We're also taking + # this opportunity to enable mod_status if it's not present. + validate_default_suse_config() { +- if [ "$CONFIGFILE" = "$DEFAULT_NORMCONFIG" ] && \ ++ if [ "$CONFIGFILE" = "$DEFAULT_SUSECONFIG" ] && \ + grep -Eq '^Include[[:space:]]+/etc/apache2/sysconfig.d/include.conf' "$CONFIGFILE" + then + [ -x "/usr/sbin/a2enmod" ] && ocf_run -q /usr/sbin/a2enmod status +@@ -336,6 +338,16 @@ apache_monitor() { + esac + } + ++detect_default_config() ++{ ++ if [ -f $DEFAULT_SUSECONFIG ]; then ++ echo $DEFAULT_SUSECONFIG ++ else ++ echo $DEFAULT_RHELCONFIG ++ fi ++} ++ ++ + apache_meta_data(){ + cat < +@@ -373,7 +385,7 @@ This file is parsed to provide defaults for various other + resource agent parameters. + + configuration file path +- ++ + + + +@@ -548,7 +560,7 @@ find_httpd_prog() { + if [ "X$OCF_RESKEY_httpd" != X -a "X$HTTPD" != X ]; then + ocf_log info "Using $HTTPD as HTTPD" + fi +- DefaultConfig=$DEFAULT_NORMCONFIG ++ DefaultConfig=$(detect_default_config) + ;; + esac + } + diff --git a/SOURCES/bz1014641-VirtualDomain-syntax-error.patch b/SOURCES/bz1014641-VirtualDomain-syntax-error.patch new file mode 100644 index 00000000..f85a5123 --- /dev/null +++ b/SOURCES/bz1014641-VirtualDomain-syntax-error.patch @@ -0,0 +1,25 @@ +From a165410d95a7976e5249530b08d4dbeca7a7df27 Mon Sep 17 00:00:00 2001 +From: David Vossel +Date: Wed, 2 Oct 2013 15:43:56 -0500 +Subject: [PATCH] Fix: VirtualDomain: Fixes comparison of uninitialized variable during force stop + +--- + heartbeat/VirtualDomain | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) + +diff --git a/heartbeat/VirtualDomain b/heartbeat/VirtualDomain +index b7ac912..04b4390 100755 +--- a/heartbeat/VirtualDomain ++++ b/heartbeat/VirtualDomain +@@ -295,7 +295,7 @@ VirtualDomain_Start() { + force_stop() + { + local out ex +- local status ++ local status=0 + + ocf_log info "Issuing forced shutdown (destroy) request for domain ${DOMAIN_NAME}." + out=$(virsh $VIRSH_OPTIONS destroy ${DOMAIN_NAME} 2>&1) +-- +1.7.1 + diff --git a/SOURCES/bz1016140-start-predefined-domains.patch b/SOURCES/bz1016140-start-predefined-domains.patch new file mode 100644 index 00000000..b96d0dfe --- /dev/null +++ b/SOURCES/bz1016140-start-predefined-domains.patch @@ -0,0 +1,47 @@ +From f00dcaf19467e3d96d9790d386b860b53ca381f9 Mon Sep 17 00:00:00 2001 +From: David Vossel +Date: Mon, 7 Oct 2013 19:37:43 -0500 +Subject: [PATCH] High: VirtualDomain: Ensure it is possible to manage a libvirt domain defined outside of VirtualDomain + +--- + heartbeat/VirtualDomain | 17 +++++++++++++++++ + 1 files changed, 17 insertions(+), 0 deletions(-) + +diff --git a/heartbeat/VirtualDomain b/heartbeat/VirtualDomain +index f7ed100..8d5e181 100755 +--- a/heartbeat/VirtualDomain ++++ b/heartbeat/VirtualDomain +@@ -257,6 +257,15 @@ VirtualDomain_Status() { + return $rc + } + ++verify_undefined() { ++ for dom in `virsh --connect=${OCF_RESKEY_hypervisor} list --all --name`; do ++ if [ "$dom" = "$DOMAIN_NAME" ]; then ++ virsh $VIRSH_OPTIONS undefine $DOMAIN_NAME > /dev/null 2>&1 ++ return ++ fi ++ done ++} ++ + VirtualDomain_Start() { + local snapshotimage + +@@ -276,6 +285,14 @@ VirtualDomain_Start() { + return $OCF_ERR_GENERIC + fi + ++ # Make sure domain is undefined before creating. ++ # The 'create' command guarantees that the domain will be ++ # undefined on shutdown, but requires the domain to be undefined. ++ # if a user defines the domain ++ # outside of this agent, we have to ensure that the domain ++ # is restored to an 'undefined' state before creating. ++ verify_undefined ++ + virsh $VIRSH_OPTIONS create ${OCF_RESKEY_config} + rc=$? + if [ $rc -ne 0 ]; then +-- +1.7.1 + diff --git a/SOURCES/bz1029061-virtualdomain-parse-error.patch b/SOURCES/bz1029061-virtualdomain-parse-error.patch new file mode 100644 index 00000000..ce867482 --- /dev/null +++ b/SOURCES/bz1029061-virtualdomain-parse-error.patch @@ -0,0 +1,29 @@ +From bd3b09252eedbeeab2635f82259714975702257e Mon Sep 17 00:00:00 2001 +From: David Vossel +Date: Mon, 20 Jan 2014 10:29:23 -0600 +Subject: [PATCH] High: VirtualDomain: Fixes parsing domain name from xml file. + +If the domain xml is not generated by virsh, it is possible +VirtualDomain will not be able to detect the domain's name +from the xml file. This is a result of the parsing command +not taking into account trailing whitespace characters. +--- + heartbeat/VirtualDomain | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/heartbeat/VirtualDomain b/heartbeat/VirtualDomain +index 3ca4f6d..11c8df9 100755 +--- a/heartbeat/VirtualDomain ++++ b/heartbeat/VirtualDomain +@@ -565,7 +565,7 @@ if [ ! -r $OCF_RESKEY_config ]; then + fi + + # Retrieve the domain name from the xml file. +-DOMAIN_NAME=`egrep '.*.*$' ${OCF_RESKEY_config} | sed -e 's/.*\(.*\)<\/name>$/\1/' 2>/dev/null` ++DOMAIN_NAME=`egrep '[[:space:]]*.*[[:space:]]*$' ${OCF_RESKEY_config} | sed -e 's/[[:space:]]*\(.*\)<\/name>[[:space:]]*$/\1/' 2>/dev/null` + if [ -z $DOMAIN_NAME ]; then + ocf_log err "This is unexpected. Cannot determine domain name." + exit $OCF_ERR_GENERIC +-- +1.8.4.2 + diff --git a/SOURCES/bz1033016-nfsserver-missing-etab.patch b/SOURCES/bz1033016-nfsserver-missing-etab.patch new file mode 100644 index 00000000..6f04b564 --- /dev/null +++ b/SOURCES/bz1033016-nfsserver-missing-etab.patch @@ -0,0 +1,15 @@ +diff --git a/heartbeat/nfsserver b/heartbeat/nfsserver +index 2f62df4..bc326e5 100755 +--- a/heartbeat/nfsserver ++++ b/heartbeat/nfsserver +@@ -307,6 +307,10 @@ prepare_directory () + [ -d "$fp/$STATD_DIR/sm.bak" ] || mkdir -p "$fp/$STATD_DIR/sm.bak" + [ -n "`id -u rpcuser`" -a "`id -g rpcuser`" ] && chown -R rpcuser.rpcuser "$fp/$STATD_DIR" + ++ [ -f "$fp/etab" ] || touch "$fp/etab" ++ [ -f "$fp/xtab" ] || touch "$fp/xtab" ++ [ -f "$fp/rmtab" ] || touch "$fp/rmtab" ++ + [ $SELINUX_ENABLED -eq 0 ] && chcon -R "$SELINUX_LABEL" "$fp" + } + diff --git a/SOURCES/bz1058102-man-page-updates.patch b/SOURCES/bz1058102-man-page-updates.patch new file mode 100644 index 00000000..355f6441 --- /dev/null +++ b/SOURCES/bz1058102-man-page-updates.patch @@ -0,0 +1,250 @@ +From 3afd24d578006d68746f9ce35321d0ed34df92e2 Mon Sep 17 00:00:00 2001 +From: David Vossel +Date: Mon, 25 Aug 2014 15:01:13 -0500 +Subject: [PATCH 3/4] High: doc: Add pcs to man page example section + +PCS and CRM SHELL now have their own example sections in the +resource-agent man pages. Below is an example of the CRM SHELL +and PCS examples for the IPaddr2 agent. + +EXAMPLE CRM SHELL + The following is an example configuration for a IPaddr2 resource using the crm(8) shell: + + primitive p_IPaddr2 ocf:heartbeat:IPaddr2 \ + params \ + ip=string \ + op monitor depth="0" timeout="20s" interval="10s" + +EXAMPLE PCS + The following is an example configuration for a IPaddr2 resource using pcs(8) + + pcs resource create p_IPaddr2 ocf:heartbeat:IPaddr2 \ + ip=string \ + op monitor depth="0" timeout="20s" interval="10s" +--- + doc/man/ra2refentry.xsl | 141 +++++++++++++++++++++++++++++++++++++++++------- + 1 file changed, 123 insertions(+), 18 deletions(-) + +diff --git a/doc/man/ra2refentry.xsl b/doc/man/ra2refentry.xsl +index 41a60aa..ac148ef 100644 +--- a/doc/man/ra2refentry.xsl ++++ b/doc/man/ra2refentry.xsl +@@ -50,7 +50,8 @@ + + + +- ++ ++ + + + +@@ -403,10 +404,10 @@ + + + +- +- ++ ++ + +- Example ++ Example CRM Shell + + The following is an example configuration for a + +@@ -428,7 +429,7 @@ + \ + params \ + +- ++ + + + \ +@@ -440,7 +441,7 @@ + + meta allow-migrate="true" \ + +- ++ + + +@@ -457,15 +458,15 @@ + + + +- +- ++ ++ + + +- ++ + + + = +- ++ + \ + + +@@ -473,7 +474,7 @@ + + + +- ++ + + + " +@@ -486,23 +487,23 @@ + + + +- ++ + +- ++ + + +- ++ + + op + + +- ++ + + \ + + + +- ++ + + + +@@ -517,9 +518,113 @@ + + + +- ++ + +- ++ ++ ++ ++ ++ ++ Example PCS ++ ++ The following is an example configuration for a ++ ++ resource using ++ pcs8 ++ ++ ++ pcs resource create p_ ++ ++ ++ ++ : ++ ++ : ++ ++ ++ ++ \ ++ ++ ++ ++ ++ \ ++ ++ ++ ++ ++ ++ ++ --master ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ = ++ ++ \ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ " ++ ++ " ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ op ++ ++ ++ ++ ++ \ ++ ++ ++ ++ ++ ++ ++ ++ ++ =" ++ ++ " ++ ++ ++ ++ ++ ++ ++ ++ ++ + + + +-- +1.8.4.2 + diff --git a/SOURCES/bz1059988-db2-support.patch b/SOURCES/bz1059988-db2-support.patch new file mode 100644 index 00000000..f6561dc2 --- /dev/null +++ b/SOURCES/bz1059988-db2-support.patch @@ -0,0 +1,154 @@ +From c954c6470fe61c73396b45ca75310d146997f81b Mon Sep 17 00:00:00 2001 +From: David Vossel +Date: Wed, 29 Apr 2015 11:16:18 -0500 +Subject: [PATCH 5/6] db2 support + +--- + heartbeat/db2 | 60 +++++++++++++++++++++++++++++++++++++++++++++-------------- + 1 file changed, 46 insertions(+), 14 deletions(-) + +diff --git a/heartbeat/db2 b/heartbeat/db2 +index f9db2f8..fed2d86 100755 +--- a/heartbeat/db2 ++++ b/heartbeat/db2 +@@ -132,6 +132,9 @@ END + db2_validate() { + local db2home db2sql db2instance + ++ # db2 uses korn shell ++ check_binary "ksh" ++ + # check required instance vars + if [ -z "$OCF_RESKEY_instance" ] + then +@@ -208,6 +211,14 @@ db2_validate() { + return $OCF_SUCCESS + } + ++master_score() ++{ ++ if ! have_binary "crm_master"; then ++ return ++ fi ++ ++ crm_master $* ++} + + # + # Run the given command as db2 instance user +@@ -380,8 +391,17 @@ db2_check_config_compatibility() { + # + db2_start() { + local output start_cmd db ++ local start_opts="dbpartitionnum $db2node" ++ ++ # If we detect that db partitions are not in use, and no ++ # partition is explicitly specified, activate without ++ # partition information. This allows db2 instances without ++ # partition support to be managed. ++ if [ -z "$OCF_RESKEY_dbpartitionnum" ] && ! [ -a "$db2sql/db2nodes.cfg" ]; then ++ start_opts="" ++ fi + +- if output=$(runasdb2 db2start dbpartitionnum $db2node) ++ if output=$(runasdb2 db2start $start_opts) + then + ocf_log info "DB2 instance $instance($db2node) started: $output" + else +@@ -473,10 +493,15 @@ db2_start() { + # + db2_stop_bg() { + local rc output ++ local stop_opts="dbpartitionnum $db2node" + + rc=$OCF_SUCCESS + +- if output=$(runasdb2 db2stop force dbpartitionnum $db2node) ++ if [ -z "$OCF_RESKEY_dbpartitionnum" ] && ! [ -a "$db2sql/db2nodes.cfg" ]; then ++ stop_opts="" ++ fi ++ ++ if output=$(runasdb2 db2stop force $stop_opts) + then + ocf_log info "DB2 instance $instance($db2node) stopped: $output" + else +@@ -502,13 +527,13 @@ db2_stop() { + local stop_timeout grace_timeout stop_bg_pid i must_kill + + # remove master score +- crm_master -D -l reboot ++ master_score -D -l reboot + + # be very early here in order to avoid stale data + rm -f $STATE_FILE + +- if ! db2_instance_status +- then ++ db2_instance_status ++ if [ $? -eq $OCF_NOT_RUNNING ]; then + ocf_log info "DB2 instance $instance already stopped" + return $OCF_SUCCESS + fi +@@ -585,7 +610,12 @@ db2_instance_status() { + local pscount + + pscount=$(runasdb2 $db2bin/db2nps $db2node | cut -c9- | grep ' db2[^ ]' | wc -l) +- test $pscount -ge 4 ++ if [ $pscount -ge 4 ]; then ++ return $OCF_SUCCESS; ++ elif [ $pscount -ge 1 ]; then ++ return $OCF_GENERIC_ERR ++ fi ++ return $OCF_NOT_RUNNING + } + + # +@@ -626,12 +656,14 @@ db2_hadr_status() { + # + db2_monitor() { + local CMD output hadr db ++ local rc + +- if ! db2_instance_status +- then ++ db2_instance_status ++ rc=$? ++ if [ $rc -ne $OCF_SUCCESS ]; then + # instance is dead remove master score +- crm_master -D -l reboot +- exit $OCF_NOT_RUNNING ++ master_score -D -l reboot ++ exit $rc + fi + + [ $db2node = 0 ] || return 0 +@@ -667,22 +699,22 @@ db2_monitor() { + ocf_log err "DB2 message: $output" + + # dead primary, remove master score +- crm_master -D -l reboot ++ master_score -D -l reboot + return $OCF_ERR_GENERIC + esac + fi + + ocf_log debug "DB2 database $instance($db2node)/$db appears to be working" +- ocf_is_ms && crm_master -v 10000 -l reboot ++ ocf_is_ms && master_score -v 10000 -l reboot + ;; + + Standby/*Peer) +- crm_master -v 8000 -l reboot ++ master_score -v 8000 -l reboot + ;; + + Standby/*) + ocf_log warn "DB2 database $instance($db2node)/$db in status $hadr can never be promoted" +- crm_master -D -l reboot ++ master_score -D -l reboot + ;; + + *) +-- +1.8.4.2 + diff --git a/SOURCES/bz1060367-vm-monitor-wo-libvirtd.patch b/SOURCES/bz1060367-vm-monitor-wo-libvirtd.patch new file mode 100644 index 00000000..06ad87ff --- /dev/null +++ b/SOURCES/bz1060367-vm-monitor-wo-libvirtd.patch @@ -0,0 +1,113 @@ +diff --git a/heartbeat/VirtualDomain b/heartbeat/VirtualDomain +index 6f80981..b159c2c 100755 +--- a/heartbeat/VirtualDomain ++++ b/heartbeat/VirtualDomain +@@ -65,10 +65,10 @@ for this virtual domain. + + Hypervisor URI to connect to. See the libvirt documentation for + details on supported URI formats. The default is system dependent. +-Determine your systems default uri by running 'virsh --quiet uri' ++Determine the system's default uri by running 'virsh --quiet uri'. + + Hypervisor URI +- ++ + + + +@@ -202,15 +202,44 @@ update_utilization() { + fi + } + ++# attempt to check domain status outside of libvirt using the emulator process ++pid_status() ++{ ++ local rc=$OCF_ERR_GENERIC ++ local emulator ++ ++ emulator=$(basename $(egrep '[[:space:]]*.*[[:space:]]*$' ${OCF_RESKEY_config} | sed -e 's/[[:space:]]*\(.*\)<\/emulator>[[:space:]]*$/\1/')) ++ ++ case "$emulator" in ++ qemu-kvm|qemu-system-*) ++ ps awx | grep -E "[q]emu-(kvm|system).*-name $DOMAIN_NAME " > /dev/null 2>&1 ++ if [ $? -eq 0 ]; then ++ # domain exists and is running ++ ocf_log debug "Virtual domain $DOMAIN_NAME is currently running." ++ rc=$OCF_SUCCESS ++ else ++ # domain pid does not exist on local machine ++ ocf_log debug "Virtual domain $DOMAIN_NAME is currently not running." ++ rc=$OCF_NOT_RUNNING ++ fi ++ ;; ++ # This can be expanded to check for additional emulators ++ *) ++ ;; ++ esac ++ ++ return $rc ++} ++ + VirtualDomain_Status() { + local try=0 + rc=$OCF_ERR_GENERIC + status="no state" + while [ "$status" = "no state" ]; do + try=$(($try + 1 )) +- status="`virsh $VIRSH_OPTIONS domstate $DOMAIN_NAME 2>&1`" ++ status=$(virsh $VIRSH_OPTIONS domstate $DOMAIN_NAME 2>&1|tr 'A-Z' 'a-z') + case "$status" in +- *"error:"*"Domain not found"*|"shut off") ++ *"error:"*"domain not found"*|"shut off") + # shut off: domain is defined, but not started, will not happen if + # domain is created but not defined + # Domain not found: domain is not defined and thus not started +@@ -226,7 +255,7 @@ VirtualDomain_Status() { + ocf_log debug "Virtual domain $DOMAIN_NAME is currently $status." + rc=$OCF_SUCCESS + ;; +- ""|*"Failed to reconnect to the hypervisor"*|"no state") ++ ""|*"failed to "*"connect to the hypervisor"*|"no state") + # Empty string may be returned when virsh does not + # receive a reply from libvirtd. + # "no state" may occur when the domain is currently +@@ -240,6 +269,14 @@ VirtualDomain_Status() { + # the domain if necessary. + ocf_log error "Virtual domain $DOMAIN_NAME has no state during stop operation, bailing out." + return $OCF_ERR_GENERIC; ++ elif [ "$__OCF_ACTION" = "monitor" ]; then ++ pid_status ++ rc=$? ++ if [ $rc -ne $OCF_ERR_GENERIC ]; then ++ # we've successfully determined the domains status outside of libvirt ++ return $rc ++ fi ++ + else + # During all other actions, we just wait and try + # again, relying on the CRM/LRM to time us out if +@@ -312,11 +349,11 @@ force_stop() + local status=0 + + ocf_log info "Issuing forced shutdown (destroy) request for domain ${DOMAIN_NAME}." +- out=$(virsh $VIRSH_OPTIONS destroy ${DOMAIN_NAME} 2>&1) ++ out=$(virsh $VIRSH_OPTIONS destroy ${DOMAIN_NAME} 2>&1|tr 'A-Z' 'a-z') + ex=$? + echo >&2 "$out" + case $ex$out in +- *"error:"*"domain is not running"*|*"error:"*"Domain not found"*) ++ *"error:"*"domain is not running"*|*"error:"*"domain not found"*) + : ;; # unexpected path to the intended outcome, all is well + [!0]*) + return $OCF_ERR_GENERIC ;; +@@ -544,8 +581,8 @@ case $1 in + ;; + esac + +-OCF_RESKEY_hypervisor_default="$(virsh --quiet uri)" +-: ${OCF_RESKEY_hypervisor=${OCF_RESKEY_hypervisor_default}} ++# Grab the virsh uri default, but only if hypervisor isn't set ++: ${OCF_RESKEY_hypervisor=$(virsh --quiet uri)} + + # Set options to be passed to virsh: + VIRSH_OPTIONS="--connect=${OCF_RESKEY_hypervisor} --quiet" diff --git a/SOURCES/bz1060367-vm-monitor-wo-libvirtd_2.patch b/SOURCES/bz1060367-vm-monitor-wo-libvirtd_2.patch new file mode 100644 index 00000000..e08c7842 --- /dev/null +++ b/SOURCES/bz1060367-vm-monitor-wo-libvirtd_2.patch @@ -0,0 +1,178 @@ +diff --git a/heartbeat/VirtualDomain b/heartbeat/VirtualDomain +index b159c2c..3a6b6a9 100755 +--- a/heartbeat/VirtualDomain ++++ b/heartbeat/VirtualDomain +@@ -21,11 +21,13 @@ OCF_RESKEY_force_stop_default=0 + OCF_RESKEY_autoset_utilization_cpu_default="true" + OCF_RESKEY_autoset_utilization_hv_memory_default="true" + OCF_RESKEY_migrateport_default=$(( 49152 + $(ocf_maybe_random) % 64 )) ++OCF_RESKEY_CRM_meta_timeout_default=90000 + + : ${OCF_RESKEY_force_stop=${OCF_RESKEY_force_stop_default}} + : ${OCF_RESKEY_autoset_utilization_cpu=${OCF_RESKEY_autoset_utilization_cpu_default}} + : ${OCF_RESKEY_autoset_utilization_hv_memory=${OCF_RESKEY_autoset_utilization_hv_memory_default}} + : ${OCF_RESKEY_migrateport=${OCF_RESKEY_migrateport_default}} ++: ${OCF_RESKEY_CRM_meta_timeout=${OCF_RESKEY_CRM_meta_timeout_default}} + ####################################################################### + + ## I'd very much suggest to make this RA use bash, +@@ -165,8 +167,8 @@ Restore state on start/stop + + + +- +- ++ ++ + + + +@@ -183,9 +185,17 @@ set_util_attr() { + local cval outp + + cval=$(crm_resource -Q -r $OCF_RESOURCE_INSTANCE -z -g $attr 2>/dev/null) ++ if [ $? -ne 0 ] && [ -z "$cval" ]; then ++ crm_resource -Q -r $OCF_RESOURCE_INSTANCE -z -g $attr 2>&1 | grep -e "not connected" > /dev/null 2>&1 ++ if [ $? -eq 0 ]; then ++ ocf_log debug "Unable to set utilization attribute, cib is not available" ++ return ++ fi ++ fi ++ + if [ "$cval" != "$val" ]; then +- outp=`crm_resource -r $OCF_RESOURCE_INSTANCE -z -p $attr -v $val 2>&1` || +- ocf_log warn "crm_resource failed to set utilization attribute $attr: $outp" ++ outp=$(crm_resource -r $OCF_RESOURCE_INSTANCE -z -p $attr -v $val 2>&1) || ++ ocf_log warn "crm_resource failed to set utilization attribute $attr: $outp" + fi + } + +@@ -193,22 +203,49 @@ update_utilization() { + local dom_cpu dom_mem + + if ocf_is_true "$OCF_RESKEY_autoset_utilization_cpu"; then +- dom_cpu=$(LANG=C virsh $VIRSH_OPTIONS dominfo ${DOMAIN_NAME} | awk '/CPU\(s\)/{print $2}') ++ dom_cpu=$(LANG=C virsh $VIRSH_OPTIONS dominfo ${DOMAIN_NAME} 2>/dev/null | awk '/CPU\(s\)/{print $2}') + test -n "$dom_cpu" && set_util_attr cpu $dom_cpu + fi + if ocf_is_true "$OCF_RESKEY_autoset_utilization_hv_memory"; then +- dom_mem=$(LANG=C virsh $VIRSH_OPTIONS dominfo ${DOMAIN_NAME} | awk '/Max memory/{printf("%d", $3/1024)}') ++ dom_mem=$(LANG=C virsh $VIRSH_OPTIONS dominfo ${DOMAIN_NAME} 2>/dev/null | awk '/Max memory/{printf("%d", $3/1024)}') + test -n "$dom_mem" && set_util_attr hv_memory "$dom_mem" + fi + } + ++get_emulator() ++{ ++ local emulator="" ++ ++ emulator=$(virsh $VIRSH_OPTIONS dumpxml $DOMAIN_NAME 2>/dev/null | sed -n -e 's/[[:space:]]*\(.*\)<\/emulator>[[:space:]]*$/\1/p') ++ if [ -z "$emulator" ] && [ -a "$EMULATOR_STATE" ]; then ++ emulator=$(cat $EMULATOR_STATE) ++ fi ++ if [ -z "$emulator" ]; then ++ emulator=$(cat ${OCF_RESKEY_config} | sed -n -e 's/[[:space:]]*\(.*\)<\/emulator>[[:space:]]*$/\1/p') ++ fi ++ ++ if [ -n "$emulator" ]; then ++ basename $emulator ++ else ++ ocf_log error "Unable to determine emulator for $DOMAIN_NAME" ++ fi ++} ++ ++update_emulator_cache() ++{ ++ local emulator ++ ++ emulator=$(get_emulator) ++ if [ -n "$emulator" ]; then ++ echo $emulator > $EMULATOR_STATE ++ fi ++} ++ + # attempt to check domain status outside of libvirt using the emulator process + pid_status() + { + local rc=$OCF_ERR_GENERIC +- local emulator +- +- emulator=$(basename $(egrep '[[:space:]]*.*[[:space:]]*$' ${OCF_RESKEY_config} | sed -e 's/[[:space:]]*\(.*\)<\/emulator>[[:space:]]*$/\1/')) ++ local emulator=$(get_emulator) + + case "$emulator" in + qemu-kvm|qemu-system-*) +@@ -237,13 +274,13 @@ VirtualDomain_Status() { + status="no state" + while [ "$status" = "no state" ]; do + try=$(($try + 1 )) +- status=$(virsh $VIRSH_OPTIONS domstate $DOMAIN_NAME 2>&1|tr 'A-Z' 'a-z') ++ status=$(virsh $VIRSH_OPTIONS domstate $DOMAIN_NAME 2>&1 | tr 'A-Z' 'a-z') + case "$status" in + *"error:"*"domain not found"*|"shut off") + # shut off: domain is defined, but not started, will not happen if + # domain is created but not defined + # Domain not found: domain is not defined and thus not started +- ocf_log debug "Virtual domain $DOMAIN_NAME is currently $status." ++ ocf_log debug "Virtual domain $DOMAIN_NAME is not running: $(echo $status | sed s/error://g)" + rc=$OCF_NOT_RUNNING + ;; + running|paused|idle|blocked|"in shutdown") +@@ -282,12 +319,13 @@ VirtualDomain_Status() { + # again, relying on the CRM/LRM to time us out if + # this takes too long. + ocf_log info "Virtual domain $DOMAIN_NAME currently has no state, retrying." +- sleep 1 + fi ++ sleep 1 + ;; + *) + # any other output is unexpected. + ocf_log error "Virtual domain $DOMAIN_NAME has unknown status \"$status\"!" ++ sleep 1 + ;; + esac + done +@@ -295,7 +333,7 @@ VirtualDomain_Status() { + } + + verify_undefined() { +- for dom in `virsh --connect=${OCF_RESKEY_hypervisor} list --all --name`; do ++ for dom in `virsh --connect=${OCF_RESKEY_hypervisor} list --all --name 2>/dev/null`; do + if [ "$dom" = "$DOMAIN_NAME" ]; then + virsh $VIRSH_OPTIONS undefine $DOMAIN_NAME > /dev/null 2>&1 + return +@@ -340,6 +378,7 @@ VirtualDomain_Start() { + while ! VirtualDomain_Monitor; do + sleep 1 + done ++ + return $OCF_SUCCESS + } + +@@ -530,6 +569,7 @@ VirtualDomain_Monitor() { + done + fi + ++ update_emulator_cache + update_utilization + + return ${rc} +@@ -582,7 +622,7 @@ case $1 in + esac + + # Grab the virsh uri default, but only if hypervisor isn't set +-: ${OCF_RESKEY_hypervisor=$(virsh --quiet uri)} ++: ${OCF_RESKEY_hypervisor=$(virsh --quiet uri 2>/dev/null)} + + # Set options to be passed to virsh: + VIRSH_OPTIONS="--connect=${OCF_RESKEY_hypervisor} --quiet" +@@ -608,6 +648,8 @@ if [ -z $DOMAIN_NAME ]; then + exit $OCF_ERR_GENERIC + fi + ++EMULATOR_STATE="${HA_RSCTMP}/VirtualDomain-${DOMAIN_NAME}-emu.state" ++ + case $1 in + start) + VirtualDomain_Start diff --git a/SOURCES/bz1064512-clvmd-agent.patch b/SOURCES/bz1064512-clvmd-agent.patch new file mode 100644 index 00000000..bc165731 --- /dev/null +++ b/SOURCES/bz1064512-clvmd-agent.patch @@ -0,0 +1,441 @@ +From 61dd0f9ca20b0f252996b6f610b4473ba83ca97a Mon Sep 17 00:00:00 2001 +From: David Vossel +Date: Wed, 12 Feb 2014 12:36:21 -0500 +Subject: [PATCH] High: clvm: Introducing clvmd resource agent + +--- + doc/man/Makefile.am | 1 + + heartbeat/Makefile.am | 1 + + heartbeat/clvm | 396 ++++++++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 398 insertions(+) + create mode 100755 heartbeat/clvm + +diff --git a/doc/man/Makefile.am b/doc/man/Makefile.am +index 3bf569a..49b5c58 100644 +--- a/doc/man/Makefile.am ++++ b/doc/man/Makefile.am +@@ -94,6 +94,7 @@ man_MANS = ocf_heartbeat_AoEtarget.7 \ + ocf_heartbeat_anything.7 \ + ocf_heartbeat_apache.7 \ + ocf_heartbeat_asterisk.7 \ ++ ocf_heartbeat_clvm.7 \ + ocf_heartbeat_conntrackd.7 \ + ocf_heartbeat_db2.7 \ + ocf_heartbeat_dhcpd.7 \ +diff --git a/heartbeat/Makefile.am b/heartbeat/Makefile.am +index bc95f89..2c3056d 100644 +--- a/heartbeat/Makefile.am ++++ b/heartbeat/Makefile.am +@@ -61,6 +61,7 @@ ocf_SCRIPTS = ClusterMon \ + asterisk \ + nginx \ + AudibleAlarm \ ++ clvm \ + conntrackd \ + db2 \ + dhcpd \ +diff --git a/heartbeat/clvm b/heartbeat/clvm +new file mode 100755 +index 0000000..3e7701d +--- /dev/null ++++ b/heartbeat/clvm +@@ -0,0 +1,396 @@ ++#!/bin/bash ++# ++# Copyright (c) 2014 David Vossel ++# All Rights Reserved. ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of version 2 of the GNU General Public License as ++# published by the Free Software Foundation. ++# ++# This program is distributed in the hope that it would be useful, but ++# WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++# ++# Further, this software is distributed without any warranty that it is ++# free of the rightful claim of any third person regarding infringement ++# or the like. Any license provided herein, whether implied or ++# otherwise, applies only to this software file. Patent licenses, if ++# any, provided herein do not apply to combinations of this program with ++# other software, or any other product whatsoever. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write the Free Software Foundation, ++# Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. ++# ++ ++####################################################################### ++# Initialization: ++ ++: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat} ++. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs ++. ${OCF_FUNCTIONS_DIR}/ocf-directories ++ ++####################################################################### ++ ++meta_data() { ++ cat < ++ ++ ++1.0 ++ ++ ++This agent manages the clvmd daemon. ++ ++clvmd ++ ++ ++ ++ ++Start with cmirrord (cluster mirror log daemon). ++ ++activate cmirrord ++ ++ ++ ++ ++ ++Options to clvmd. Refer to clvmd.8 for detailed descriptions. ++ ++Daemon Options ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++END ++} ++ ++####################################################################### ++ ++: ${OCF_RESKEY_daemon_options:="-d0"} ++ ++sbindir=$HA_SBIN_DIR ++if [ -z $sbindir ]; then ++ sbindir=/usr/sbin ++fi ++DAEMON="clvmd" ++CMIRROR="cmirrord" ++DAEMON_PATH="${sbindir}/clvmd" ++CMIRROR_PATH="${sbindir}/cmirrord" ++LOCK_FILE="/var/lock/subsys/$DAEMON" ++LVM_VGCHANGE=${sbindir}/vgchange ++LVM_VGDISPLAY=${sbindir}/vgdisplay ++LVM_VGSCAN=${sbindir}/vgscan ++ ++# Leaving this in for legacy. We do not want to advertize ++# the abilty to set options in the systconfig exists, we want ++# to expand the OCF style options as necessary instead. ++[ -f /etc/sysconfig/cluster ] && . /etc/sysconfig/cluster ++[ -f /etc/sysconfig/$DAEMON ] && . /etc/sysconfig/$DAEMON ++ ++CLVMD_TIMEOUT="90" ++if [ -n "$OCF_RESKEY_CRM_meta_timeout" ]; then ++ CLVMD_TIMEOUT=$(($OCF_RESKEY_CRM_meta_timeout/1000)) ++fi ++ ++clvmd_usage() ++{ ++ cat </dev/null | grep -a "${binary}" > /dev/null 2>&1 ++ if [ $? -eq 0 ];then ++ # shortcut without requiring pgrep to search through all procs ++ return $OCF_SUCCESS ++ fi ++ fi ++ ++ pid=$(pgrep ${binary}) ++ case $? in ++ 0) ++ ocf_log info "PID file (pid:${pid} at $pidfile) created for ${binary}." ++ echo "$pid" > $pidfile ++ return $OCF_SUCCESS;; ++ 1) ++ rm -f "$pidfile" > /dev/null 2>&1 ++ ocf_log info "$binary is not running" ++ return $OCF_NOT_RUNNING;; ++ *) ++ rm -f "$pidfile" > /dev/null 2>&1 ++ ocf_log err "Error encountered detecting pid status of $binary" ++ return $OCF_ERR_GENERIC;; ++ esac ++} ++ ++clvmd_status() ++{ ++ local rc ++ local mirror_rc ++ clvmd_validate ++ if [ $? -ne $OCF_SUCCESS ]; then ++ ocf_log error "Unable to monitor, Environment validation failed." ++ return $? ++ fi ++ ++ check_process $DAEMON ++ rc=$? ++ mirror_rc=$rc ++ ++ if ocf_is_true $OCF_RESKEY_with_cmirrord; then ++ check_process $CMIRROR ++ mirror_rc=$? ++ fi ++ ++ # If these ever don't match, return error to force recovery ++ if [ $mirror_rc -ne $rc ]; then ++ return $OCF_ERR_GENERIC ++ fi ++ ++ return $rc ++} ++ ++# NOTE: replace this with vgs, once display filter per attr is implemented. ++clustered_vgs() { ++ ${LVM_VGDISPLAY} 2>/dev/null | awk 'BEGIN {RS="VG Name"} {if (/Clustered/) print $1;}' ++} ++ ++wait_for_process() ++{ ++ local binary=$1 ++ local timeout=$2 ++ local count=0 ++ ++ ocf_log info "Waiting for $binary to exit" ++ usleep 500000 ++ while [ $count -le $timeout ]; do ++ check_process $binary ++ if [ $? -eq $OCF_NOT_RUNNING ]; then ++ ocf_log info "$binary terminated" ++ return $OCF_SUCCESS ++ fi ++ sleep 1 ++ count=$((count+1)) ++ done ++ ++ return $OCF_ERR_GENERIC ++} ++ ++time_left() ++{ ++ local end=$1 ++ local default=$2 ++ local now=$SECONDS ++ local result=0 ++ ++ result=$(( $end - $now )) ++ if [ $result -lt $default ]; then ++ return $default ++ fi ++ return $result ++} ++ ++clvmd_stop() ++{ ++ local LVM_VGS ++ local rc=$OCF_SUCCESS ++ local end=$(( $SECONDS + $CLVMD_TIMEOUT )) ++ ++ clvmd_status ++ if [ $? -eq $OCF_NOT_RUNNING ]; then ++ return $OCF_SUCCESS ++ fi ++ ++ check_process $DAEMON ++ if [ $? -ne $OCF_NOT_RUNNING ]; then ++ LVM_VGS="$(clustered_vgs)" ++ ++ if [ -n "$LVM_VGS" ]; then ++ ocf_log info "Deactivating clustered VG(s):" ++ ocf_run ${LVM_VGCHANGE} -anl $LVM_VGS ++ if [ $? -ne 0 ]; then ++ ocf_log error "Failed to deactivate volume groups, cluster vglist = $LVM_VGS" ++ return $OCF_ERR_GENERIC ++ fi ++ fi ++ ++ ocf_log info "Signaling $DAEMON to exit" ++ killall -TERM $DAEMON ++ if [ $? != 0 ]; then ++ ocf_log error "Failed to signal -TERM to $DAEMON" ++ return $OCF_ERR_GENERIC ++ fi ++ ++ wait_for_process $DAEMON $CLVMD_TIMEOUT ++ rc=$? ++ if [ $rc -ne $OCF_SUCCESS ]; then ++ ocf_log error "$DAEMON failed to exit" ++ return $rc ++ fi ++ ++ rm -f $LOCK_FILE ++ fi ++ ++ check_process $CMIRROR ++ if [ $? -ne $OCF_NOT_RUNNING ] && ocf_is_true $OCF_RESKEY_with_cmirrord; then ++ local timeout ++ ocf_log info "Signaling $CMIRROR to exit" ++ killall -INT $CMIRROR ++ ++ time_left $end 10; timeout=$? ++ wait_for_process $CMIRROR $timeout ++ rc=$? ++ if [ $rc -ne $OCF_SUCCESS ]; then ++ killall -KILL $CMIRROR ++ time_left $end 10; timeout=$? ++ wait_for_process $CMIRROR $(time_left $end 10) ++ rc=$? ++ fi ++ fi ++ ++ return $rc ++} ++ ++start_process() ++{ ++ local binary_path=$1 ++ local opts=$2 ++ ++ check_process "$(basename $binary_path)" ++ if [ $? -ne $OCF_SUCCESS ]; then ++ ocf_log info "Starting $binary_path: " ++ ocf_run $binary_path $opts ++ rc=$? ++ if [ $rc -ne 0 ]; then ++ ocf_log error "Failed to launch $binary_path, exit code $rc" ++ exit $OCF_ERR_GENERIC ++ fi ++ fi ++ ++ return $OCF_SUCCESS ++} ++ ++clvmd_activate_all() ++{ ++ # Activate all volume groups by leaving the ++ # "volume group name" parameter empty ++ ocf_run ${LVM_VGCHANGE} -aay ++ if [ $? -ne 0 ]; then ++ ocf_log info "Failed to activate VG(s):" ++ clvmd_stop ++ return $OCF_ERR_GENERIC ++ fi ++ return $OCF_SUCCESS ++} ++ ++clvmd_start() ++{ ++ local rc=0 ++ local CLVMDOPTS="-T${CLVMD_TIMEOUT} $OCF_RESKEY_daemon_options" ++ ++ clvmd_validate ++ if [ $? -ne $OCF_SUCCESS ]; then ++ ocf_log error "Unable to start, Environment validation failed." ++ return $? ++ fi ++ ++ clvmd_status ++ if [ $? -eq $OCF_SUCCESS ]; then ++ ocf_log debug "$DAEMON already started" ++ clvmd_activate_all ++ return $?; ++ fi ++ ++ # if either of these fail, script will exit OCF_ERR_GENERIC ++ if ocf_is_true $OCF_RESKEY_with_cmirrord; then ++ start_process $CMIRROR_PATH ++ fi ++ start_process $DAEMON_PATH $CLVMDOPTS ++ ++ # Refresh local cache. ++ # ++ # It's possible that new PVs were added to this, or other VGs ++ # while this node was down. So we run vgscan here to avoid ++ # any potential "Missing UUID" messages with subsequent ++ # LVM commands. ++ ++ # The following step would be better and more informative to the user: ++ # 'action "Refreshing VG(s) local cache:" ${LVM_VGSCAN}' ++ # but it could show warnings such as: ++ # 'clvmd not running on node x-y-z Unable to obtain global lock.' ++ # and the action would be shown as FAILED when in reality it didn't. ++ # Ideally vgscan should have a startup mode that would not print ++ # unnecessary warnings. ++ ++ ${LVM_VGSCAN} > /dev/null 2>&1 ++ touch $LOCK_FILE ++ ++ clvmd_activate_all ++ ++ clvmd_status ++ return $? ++} ++ ++case $__OCF_ACTION in ++ meta-data) meta_data ++ exit $OCF_SUCCESS;; ++ ++ start) clvmd_start;; ++ ++ stop) clvmd_stop;; ++ ++ monitor) clvmd_status;; ++ ++ validate-all) clvmd_validate;; ++ ++ usage|help) clvmd_usage;; ++ ++ *) clvmd_usage ++ exit $OCF_ERR_UNIMPLEMENTED;; ++esac ++ ++rc=$? ++ocf_log debug "${OCF_RESOURCE_INSTANCE} $__OCF_ACTION : $rc" ++exit $rc ++ +-- +1.8.4.2 + diff --git a/SOURCES/bz1077888-CTDB-fix-logging.patch b/SOURCES/bz1077888-CTDB-fix-logging.patch new file mode 100644 index 00000000..fbd10692 --- /dev/null +++ b/SOURCES/bz1077888-CTDB-fix-logging.patch @@ -0,0 +1,30 @@ +diff --git a/heartbeat/CTDB b/heartbeat/CTDB +index b23ffae..3e36dd0 100755 +--- a/heartbeat/CTDB ++++ b/heartbeat/CTDB +@@ -572,10 +572,22 @@ ctdb_start() { + + # Use logfile by default, or syslog if asked for +- local log_option="--logfile=$OCF_RESKEY_ctdb_logfile" +- if [ "$OCF_RESKEY_ctdb_logfile" = "syslog" ]; then +- log_option="--syslog" +- elif [ ! -d "$(dirname $OCF_RESKEY_ctdb_logfile)" ]; then ++ # --logging supported from v4.3.0 and --logfile / --syslog support ++ # has been removed from newer versions ++ version=$(ctdb version | awk '{print $NF}') ++ ocf_version_cmp "$version" "4.2.14" ++ if [ "$?" -eq "2" ]; then ++ log_option="--logging=file:$OCF_RESKEY_ctdb_logfile" ++ if [ "$OCF_RESKEY_ctdb_logfile" = "syslog" ]; then ++ log_option="--logging=syslog" ++ fi ++ else ++ log_option="--logfile=$OCF_RESKEY_ctdb_logfile" ++ if [ "$OCF_RESKEY_ctdb_logfile" = "syslog" ]; then ++ log_option="--syslog" ++ fi ++ fi ++ if [ ! -d "$(dirname $OCF_RESKEY_ctdb_logfile)" ]; then + # ensure the logfile's directory exists, otherwise ctdb will fail to start + mkdir -p $(dirname $OCF_RESKEY_ctdb_logfile) + fi diff --git a/SOURCES/bz1077888-ctdb-updates.patch b/SOURCES/bz1077888-ctdb-updates.patch new file mode 100644 index 00000000..13bdcc3d --- /dev/null +++ b/SOURCES/bz1077888-ctdb-updates.patch @@ -0,0 +1,159 @@ +From f681e6798d3a5ead5a0e077d6e73343b266ef56f Mon Sep 17 00:00:00 2001 +From: David Vossel +Date: Wed, 29 Apr 2015 11:18:25 -0500 +Subject: [PATCH 6/6] CTDB fixes + +--- + heartbeat/CTDB | 61 +++++++++++++++++++++++++++++++++++++++++++++------------- + 1 file changed, 48 insertions(+), 13 deletions(-) + +diff --git a/heartbeat/CTDB b/heartbeat/CTDB +index d1e8d03..1cf9d8c 100755 +--- a/heartbeat/CTDB ++++ b/heartbeat/CTDB +@@ -72,6 +72,19 @@ + ####################################################################### + # Default parameter values: + ++# Some distro's ctdb package stores the persistent db in /var/lib/ctdb, ++# others store in /var/ctdb. This attempts to detect the correct default ++# directory. ++var_prefix="/var/lib/ctdb" ++if [ ! -d "$var_prefix" ] && [ -d "/var/ctdb" ]; then ++ var_prefix="/var/ctdb" ++fi ++ ++run_prefix="/run" ++if [ ! -d "$var_prefix" ] && [ -d "/var/run" ]; then ++ var_prefix="/var/run" ++fi ++ + : ${OCF_RESKEY_ctdb_manages_samba:=no} + : ${OCF_RESKEY_ctdb_manages_winbind:=no} + : ${OCF_RESKEY_ctdb_service_smb:=""} +@@ -84,9 +97,10 @@ + : ${OCF_RESKEY_ctdb_config_dir:=/etc/ctdb} + : ${OCF_RESKEY_ctdb_binary:=/usr/bin/ctdb} + : ${OCF_RESKEY_ctdbd_binary:=/usr/sbin/ctdbd} +-: ${OCF_RESKEY_ctdb_socket:=/var/lib/ctdb/ctdb.socket} +-: ${OCF_RESKEY_ctdb_dbdir:=/var/lib/ctdb} ++: ${OCF_RESKEY_ctdb_dbdir:=${var_prefix}} + : ${OCF_RESKEY_ctdb_logfile:=/var/log/ctdb/log.ctdb} ++: ${OCF_RESKEY_ctdb_rundir:=${run_prefix}/ctdb} ++: ${OCF_RESKEY_ctdb_socket:=${OCF_RESKEY_ctdb_rundir}/ctdbd.socket} + : ${OCF_RESKEY_ctdb_debuglevel:=2} + + : ${OCF_RESKEY_smb_conf:=/etc/samba/smb.conf} +@@ -104,12 +118,13 @@ meta_data() { + + + This resource agent manages CTDB, allowing one to use Clustered Samba in a +-Linux-HA/Pacemaker cluster. You need a shared filesystem (e.g. OCFS2) on ++Linux-HA/Pacemaker cluster. You need a shared filesystem (e.g. OCFS2 or GFS2) on + which the CTDB lock will be stored. Create /etc/ctdb/nodes containing a list + of private IP addresses of each node in the cluster, then configure this RA +-as a clone. To have CTDB manage Samba, set ctdb_manages_samba="yes". +-Note that this option will be deprecated in future, in favour of configuring +-a separate Samba resource. ++as a clone. This agent expects the samba and windbind resources ++to be managed outside of CTDB's control as a separate set of resources controlled ++by the cluster manager. The optional support for enabling CTDB management of these ++daemons will be depreciated. + + For more information see http://linux-ha.org/wiki/CTDB_(resource_agent) + +@@ -235,7 +250,7 @@ Full path to the domain socket that ctdbd will create, used for + local clients to attach and communicate with the ctdb daemon. + + CTDB socket location +- ++ + + + +@@ -244,7 +259,7 @@ The directory to put the local CTDB database files in. + Persistent database files will be put in ctdb_dbdir/persistent. + + CTDB database directory +- ++ + + + +@@ -256,6 +271,15 @@ value "syslog". + + + ++ ++ ++Full path to ctdb runtime directory, used for storage of socket ++lock state. ++ ++CTDB runtime directory location ++ ++ ++ + + + What debug level to run at (0-10). Higher means more verbose. +@@ -538,7 +562,16 @@ ctdb_start() { + + # Use logfile by default, or syslog if asked for + local log_option="--logfile=$OCF_RESKEY_ctdb_logfile" +- [ "$OCF_RESKEY_ctdb_logfile" = "syslog" ] && log_option="--syslog" ++ if [ "$OCF_RESKEY_ctdb_logfile" = "syslog" ]; then ++ log_option="--syslog" ++ elif [ ! -d "$(dirname $OCF_RESKEY_ctdb_logfile)" ]; then ++ # ensure the logfile's directory exists, otherwise ctdb will fail to start ++ mkdir -p $(dirname $OCF_RESKEY_ctdb_logfile) ++ fi ++ ++ # ensure ctdb's rundir exists, otherwise it will fail to start ++ mkdir -p $OCF_RESKEY_ctdb_rundir 2>/dev/null ++ + # public addresses file (should not be present, but need to set for correctness if it is) + local pub_addr_option="" + [ -f "${OCF_RESKEY_ctdb_config_dir}/public_addresses" ] && \ +@@ -562,7 +595,7 @@ ctdb_start() { + if [ $? -ne 0 ]; then + # cleanup smb.conf + cleanup_smb_conf +- ++ + ocf_exit_reason "Failed to execute $OCF_RESKEY_ctdbd_binary." + return $OCF_ERR_GENERIC + else +@@ -589,10 +622,10 @@ ctdb_start() { + fi + done + fi +- ++ + # ctdbd will (or can) actually still be running at this point, so kill it + ctdb_stop +- ++ + ocf_exit_reason "Timeout waiting for CTDB to stabilize" + return $OCF_ERR_GENERIC + } +@@ -601,7 +634,7 @@ ctdb_start() { + ctdb_stop() { + # Do nothing if already stopped + pkill -0 -f $OCF_RESKEY_ctdbd_binary || return $OCF_SUCCESS +- ++ + # Tell it to die nicely + invoke_ctdb shutdown >/dev/null 2>&1 + rv=$? +@@ -645,6 +678,8 @@ ctdb_monitor() { + if [ $? -ne 0 ]; then + if echo $status | grep -qs 'Connection refused'; then + return $OCF_NOT_RUNNING ++ elif echo $status | grep -qs 'No such file or directory'; then ++ return $OCF_NOT_RUNNING + else + ocf_exit_reason "CTDB status call failed: $status" + return $OCF_ERR_GENERIC +-- +1.8.4.2 + diff --git a/SOURCES/bz1083041-virtual-domain-monitor-lxc-fix.patch b/SOURCES/bz1083041-virtual-domain-monitor-lxc-fix.patch new file mode 100644 index 00000000..c2832ed2 --- /dev/null +++ b/SOURCES/bz1083041-virtual-domain-monitor-lxc-fix.patch @@ -0,0 +1,54 @@ +From 4e2576c0b339537790e253c11d9dfcf99b7b114d Mon Sep 17 00:00:00 2001 +From: David Vossel +Date: Tue, 1 Apr 2014 17:28:39 -0400 +Subject: [PATCH] Low: VirtualDomain: Allow monitoring of lxc domains without + libvirtd + +--- + heartbeat/VirtualDomain | 20 ++++++++++++++------ + 1 file changed, 14 insertions(+), 6 deletions(-) + +diff --git a/heartbeat/VirtualDomain b/heartbeat/VirtualDomain +index b0cdd5f..692a2ef 100755 +--- a/heartbeat/VirtualDomain ++++ b/heartbeat/VirtualDomain +@@ -249,15 +249,17 @@ pid_status() + + case "$emulator" in + qemu-kvm|qemu-system-*) ++ rc=$OCF_NOT_RUNNING + ps awx | grep -E "[q]emu-(kvm|system).*-name $DOMAIN_NAME " > /dev/null 2>&1 + if [ $? -eq 0 ]; then +- # domain exists and is running +- ocf_log debug "Virtual domain $DOMAIN_NAME is currently running." + rc=$OCF_SUCCESS +- else +- # domain pid does not exist on local machine +- ocf_log debug "Virtual domain $DOMAIN_NAME is currently not running." +- rc=$OCF_NOT_RUNNING ++ fi ++ ;; ++ libvirt_lxc) ++ rc=$OCF_NOT_RUNNING ++ ps awx | grep -E "[l]ibvirt_lxc.*-name $DOMAIN_NAME " > /dev/null 2>&1 ++ if [ $? -eq 0 ]; then ++ rc=$OCF_SUCCESS + fi + ;; + # This can be expanded to check for additional emulators +@@ -265,6 +267,12 @@ pid_status() + ;; + esac + ++ if [ $rc -eq $OCF_SUCCESS ]; then ++ ocf_log debug "Virtual domain $DOMAIN_NAME is currently running." ++ elif [ $rc -eq $OCF_NOT_RUNNING ]; then ++ ocf_log debug "Virtual domain $DOMAIN_NAME is currently not running." ++ fi ++ + return $rc + } + +-- +1.8.4.2 + diff --git a/SOURCES/bz1083231-fs-wait-module-load.patch b/SOURCES/bz1083231-fs-wait-module-load.patch new file mode 100644 index 00000000..027760f8 --- /dev/null +++ b/SOURCES/bz1083231-fs-wait-module-load.patch @@ -0,0 +1,116 @@ +From d0ecd287511e49891245c68cd323e8f232aa033b Mon Sep 17 00:00:00 2001 +From: David Vossel +Date: Wed, 6 Aug 2014 14:05:18 -0400 +Subject: [PATCH] High: Filesystem: when loading kernel modules wait for + filesystem to initialize + +When the Filesystem agent is managing a filesystem type that +is not present in /proc/filesystems, the agent attempts to +load the kernel module for that filesystem. + +This patch improves on that logic by +1. verifying that modprobe worked +2. give the module a brief period of time to initialize. + +Item 2 is important because there is a brief period +of time between when modprobe returns loading the gfs2 +module, and when gfs2 will show up in the /proc/filesystems +list. Without retrying the search of the /proc/filesystems +file, a gfs2 filesystem may fail to start correctly because +it will look like the filesystem isn't supported. +--- + heartbeat/Filesystem | 71 +++++++++++++++++++++++++++++++++++++++------------- + 1 file changed, 53 insertions(+), 18 deletions(-) + +diff --git a/heartbeat/Filesystem b/heartbeat/Filesystem +index 9209818..9892b39 100755 +--- a/heartbeat/Filesystem ++++ b/heartbeat/Filesystem +@@ -450,6 +450,58 @@ is_fsck_needed() { + esac + } + ++fstype_supported() ++{ ++ local support="$FSTYPE" ++ local rc ++ ++ if [ "X${HOSTOS}" != "XOpenBSD" ];then ++ # skip checking /proc/filesystems for obsd ++ return $OCF_SUCCESS ++ fi ++ ++ if [ -z "$FSTYPE" -o "$FSTYPE" = none ]; then ++ : No FSTYPE specified, rely on the system has the right file-system support already ++ return $OCF_SUCCESS ++ fi ++ ++ # support fuse-filesystems (e.g. GlusterFS) ++ case $FSTYPE in ++ glusterfs) support="fuse";; ++ esac ++ ++ grep -w "$support"'$' /proc/filesystems >/dev/null ++ if [ $? -eq 0 ]; then ++ # found the fs type ++ return $OCF_SUCCESS ++ fi ++ ++ # if here, we should attempt to load the module and then ++ # check the if the filesystem support exists again. ++ $MODPROBE $support >/dev/null ++ if [ $? -ne 0 ]; then ++ ocf_log err "Couldn't find filesystem $FSTYPE in /proc/filesystems and failed to load kernal module" ++ return $OCF_ERR_INSTALLED ++ fi ++ ++ # It is possible for the module to load and not be complete initialized ++ # before we check /proc/filesystems again. Give this a few trys before ++ # giving up entirely. ++ for try in $(seq 5); do ++ grep -w "$support"'$' /proc/filesystems >/dev/null ++ if [ $? -eq 0 ] ; then ++ # yes. found the filesystem after doing the modprobe ++ return $OCF_SUCCESS ++ fi ++ ocf_log debug "Unable to find support for $FSTYPE in /proc/filesystems after modprobe, trying again" ++ sleep 1 ++ done ++ ++ ocf_log err "Couldn't find filesystem $FSTYPE in /proc/filesystems" ++ return $OCF_ERR_INSTALLED ++} ++ ++ + # + # START: Start up the filesystem + # +@@ -472,24 +524,7 @@ Filesystem_start() + return $OCF_SUCCESS + fi + +- if [ "X${HOSTOS}" != "XOpenBSD" ];then +- if [ -z "$FSTYPE" -o "$FSTYPE" = none ]; then +- : No FSTYPE specified, rely on the system has the right file-system support already +- else +- local support="$FSTYPE" +- # support fuse-filesystems (e.g. GlusterFS) +- case $FSTYPE in +- glusterfs) support="fuse";; +- esac +- grep -w "$support"'$' /proc/filesystems >/dev/null || +- $MODPROBE $support >/dev/null +- grep -w "$support"'$' /proc/filesystems >/dev/null +- if [ $? -ne 0 ] ; then +- ocf_log err "Couldn't find filesystem $FSTYPE in /proc/filesystems" +- return $OCF_ERR_INSTALLED +- fi +- fi +- fi ++ fstype_supported || exit $OCF_ERR_INSTALLED + + # Check the filesystem & auto repair. + # NOTE: Some filesystem types don't need this step... Please modify +-- +1.8.4.2 + diff --git a/SOURCES/bz1091101-nfs-error-msg-fix.patch b/SOURCES/bz1091101-nfs-error-msg-fix.patch new file mode 100644 index 00000000..c0c7e6ff --- /dev/null +++ b/SOURCES/bz1091101-nfs-error-msg-fix.patch @@ -0,0 +1,25 @@ +From 5475e17858d143747e69b1bf9e8d230e74642561 Mon Sep 17 00:00:00 2001 +From: David Vossel +Date: Fri, 11 Jul 2014 11:22:20 -0400 +Subject: [PATCH] Low: nfsnotify: fixes error message output + +--- + heartbeat/nfsnotify | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/heartbeat/nfsnotify b/heartbeat/nfsnotify +index 2e242de..2d0bbfc 100755 +--- a/heartbeat/nfsnotify ++++ b/heartbeat/nfsnotify +@@ -269,7 +269,7 @@ v3notify_start() + ocf_log info "sending notifications with source address $ip" + $SM_NOTIFY_BINARY -f $OCF_RESKEY_notify_args -v $ip -P "$cur_statd" + if [ $? -ne 0 ]; then +- ocf_log err "sm-notify with source host set to, $source_host, failed. view syslog for more information" ++ ocf_log err "sm-notify with source host set to, $ip, failed. view syslog for more information" + return $OCF_ERR_GENERIC + fi + done +-- +1.8.4.2 + diff --git a/SOURCES/bz1091101-nfs-rquotad-port-option-fix.patch b/SOURCES/bz1091101-nfs-rquotad-port-option-fix.patch new file mode 100644 index 00000000..309e444b --- /dev/null +++ b/SOURCES/bz1091101-nfs-rquotad-port-option-fix.patch @@ -0,0 +1,27 @@ +From 8042f21aaefd0616df4b0ef1df2f8e3f301786c4 Mon Sep 17 00:00:00 2001 +From: David Vossel +Date: Wed, 16 Jul 2014 11:18:56 -0400 +Subject: [PATCH] Low: nfsserver: only set rquotad options when port is set + +--- + heartbeat/nfsserver | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/heartbeat/nfsserver b/heartbeat/nfsserver +index e44da1c..ac921f3 100755 +--- a/heartbeat/nfsserver ++++ b/heartbeat/nfsserver +@@ -428,7 +428,9 @@ set_env_args() + set_arg "LOCKD_TCPPORT" "$OCF_RESKEY_lockd_tcp_port" "$tmpconfig" "true" + + # rquotad_port +- set_arg "RPCRQUOTADOPTS" "-p $OCF_RESKEY_rquotad_port" "$tmpconfig" "true" ++ if [ -n "$OCF_RESKEY_rquotad_port" ]; then ++ set_arg "RPCRQUOTADOPTS" "-p $OCF_RESKEY_rquotad_port" "$tmpconfig" "true" ++ fi + + # override local nfs config. preserve previous local config though. + if [ -s $tmpconfig ]; then +-- +1.8.4.2 + diff --git a/SOURCES/bz1091101-nfs-updates.patch b/SOURCES/bz1091101-nfs-updates.patch new file mode 100644 index 00000000..fe3b9cc2 --- /dev/null +++ b/SOURCES/bz1091101-nfs-updates.patch @@ -0,0 +1,1196 @@ +From 3fc7c73f7caa212ef4de4b00e38b7bde2edb0cea Mon Sep 17 00:00:00 2001 +From: David Vossel +Date: Thu, 10 Jul 2014 09:50:48 -0500 +Subject: [PATCH] nfs updates + +--- + doc/man/Makefile.am | 1 + + heartbeat/Makefile.am | 1 + + heartbeat/exportfs | 122 ++++++------- + heartbeat/nfsnotify | 315 ++++++++++++++++++++++++++++++++ + heartbeat/nfsserver | 492 ++++++++++++++++++++++++++++++++++++++++---------- + 5 files changed, 764 insertions(+), 167 deletions(-) + create mode 100644 heartbeat/nfsnotify + +diff --git a/doc/man/Makefile.am b/doc/man/Makefile.am +index 344d00d..e97c7e9 100644 +--- a/doc/man/Makefile.am ++++ b/doc/man/Makefile.am +@@ -112,6 +112,7 @@ man_MANS = ocf_heartbeat_AoEtarget.7 \ + ocf_heartbeat_mysql.7 \ + ocf_heartbeat_mysql-proxy.7 \ + ocf_heartbeat_named.7 \ ++ ocf_heartbeat_nfsnotify.7 \ + ocf_heartbeat_nfsserver.7 \ + ocf_heartbeat_nginx.7 \ + ocf_heartbeat_oracle.7 \ +diff --git a/heartbeat/Makefile.am b/heartbeat/Makefile.am +index b67c98e..aab521f 100644 +--- a/heartbeat/Makefile.am ++++ b/heartbeat/Makefile.am +@@ -90,6 +90,7 @@ ocf_SCRIPTS = ClusterMon \ + mysql \ + mysql-proxy \ + named \ ++ nfsnotify \ + nfsserver \ + oracle \ + oralsnr \ +diff --git a/heartbeat/exportfs b/heartbeat/exportfs +index ff5d4f1..471da24 100755 +--- a/heartbeat/exportfs ++++ b/heartbeat/exportfs +@@ -95,6 +95,12 @@ Unique fsid within cluster. + Relinquish NFS locks associated with this filesystem when the resource + stops. Enabling this parameter is highly recommended unless the path exported + by this ${__SCRIPT_NAME} resource is also exported by a different resource. ++ ++Note: Unlocking is only possible on Linux systems where ++/proc/fs/nfsd/unlock_filesystem exists and is writable. If your system does ++not fulfill this requirement (on account of having an nonrecent kernel, ++for example), you may set this parameter to 0 to silence the associated ++warning. + + + Unlock filesystem on stop? +@@ -141,7 +147,7 @@ Location of the rmtab backup, relative to directory. + + + +- ++ + + + +@@ -152,28 +158,41 @@ END + return $OCF_SUCCESS + } + ++exportfs_methods() { ++ cat <<-! ++ start ++ stop ++ status ++ monitor ++ validate-all ++ methods ++ meta-data ++ usage ++ ! ++} ++ + backup_rmtab() { +- local rmtab_backup +- if [ ${OCF_RESKEY_rmtab_backup} != "none" ]; then +- rmtab_backup="${OCF_RESKEY_directory}/${OCF_RESKEY_rmtab_backup}" +- grep ":${OCF_RESKEY_directory}:" /var/lib/nfs/rmtab > ${rmtab_backup} +- fi ++ local rmtab_backup ++ if [ ${OCF_RESKEY_rmtab_backup} != "none" ]; then ++ rmtab_backup="${OCF_RESKEY_directory}/${OCF_RESKEY_rmtab_backup}" ++ grep ":${OCF_RESKEY_directory}:" /var/lib/nfs/rmtab > ${rmtab_backup} ++ fi + } + + restore_rmtab() { +- local rmtab_backup +- if [ ${OCF_RESKEY_rmtab_backup} != "none" ]; then ++ local rmtab_backup ++ if [ ${OCF_RESKEY_rmtab_backup} != "none" ]; then + rmtab_backup="${OCF_RESKEY_directory}/${OCF_RESKEY_rmtab_backup}" + if [ -r ${rmtab_backup} ]; then +- local tmpf=`mktemp` +- sort -u ${rmtab_backup} /var/lib/nfs/rmtab > $tmpf && ++ local tmpf=`mktemp` ++ sort -u ${rmtab_backup} /var/lib/nfs/rmtab > $tmpf && + install -o root -m 644 $tmpf /var/lib/nfs/rmtab +- rm -f $tmpf +- ocf_log debug "Restored `wc -l ${rmtab_backup}` rmtab entries from ${rmtab_backup}." ++ rm -f $tmpf ++ ocf_log debug "Restored `wc -l ${rmtab_backup}` rmtab entries from ${rmtab_backup}." + else +- ocf_log warn "rmtab backup ${rmtab_backup} not found or not readable." ++ ocf_log warn "rmtab backup ${rmtab_backup} not found or not readable." ++ fi + fi +- fi + } + + exportfs_usage() { +@@ -186,8 +205,8 @@ is_exported() { + local dir=$1 + local spec=$2 + exportfs | +- sed -e '$! N; s/\n[[:space:]]\+/ /; t; s/[[:space:]]\+\([^[:space:]]\+\)\(\n\|$\)/ \1\2/g; P;D;' | +- grep -q -x -F "$dir $spec" ++ sed -e '$! N; s/\n[[:space:]]\+/ /; t; s/[[:space:]]\+\([^[:space:]]\+\)\(\n\|$\)/ \1\2/g; P;D;' | ++ grep -q -x -F "$dir $spec" + } + + exportfs_monitor () +@@ -209,8 +228,10 @@ exportfs_monitor () + #Adapt grep status code to OCF return code + case $rc in + 0) +- ocf_log info "Directory ${OCF_RESKEY_directory} is exported to ${OCF_RESKEY_clientspec} (started)." +- # Backup the rmtab to ensure smooth NFS-over-TCP failover ++ if [ "$__OCF_ACTION" = "start" ]; then ++ ocf_log info "Directory ${OCF_RESKEY_directory} is exported to ${OCF_RESKEY_clientspec} (started)." ++ fi ++ # Backup the rmtab to ensure smooth NFS-over-TCP failover + backup_rmtab + return $OCF_SUCCESS + ;; +@@ -324,60 +345,23 @@ exportfs_stop () + fi + } + +-exportfs_validate () ++exportfs_validate_all () + { +- # Checks for required parameters +- if [ -z "$OCF_RESKEY_directory" ]; then +- ocf_log err "Missing required parameter \"directory\"" +- exit $OCF_ERR_CONFIGURED +- fi +- if [ -z "$OCF_RESKEY_fsid" ]; then +- ocf_log err "Missing required parameter \"fsid\"" +- exit $OCF_ERR_CONFIGURED +- fi +- if [ -z "$OCF_RESKEY_clientspec" ]; then +- ocf_log err "Missing required parameter \"clientspec\"" +- exit $OCF_ERR_CONFIGURED +- fi +- +- # Checks applicable only to non-probes +- if ! ocf_is_probe; then +- if [ ! -d $OCF_RESKEY_directory ]; then +- ocf_log err "$OCF_RESKEY_directory does not exist or is not a directory" +- exit $OCF_ERR_INSTALLED +- fi ++ if [ ! -d $OCF_RESKEY_directory ]; then ++ ocf_log err "$OCF_RESKEY_directory does not exist or is not a directory" ++ return $OCF_ERR_INSTALLED + fi + } + +-if [ $# -ne 1 ]; then +- exportfs_usage +- exit $OCF_ERR_ARGS ++# If someone puts a trailing slash at the end of the export directory, ++# this agent is going to fail in some unexpected ways due to how ++# export strings are matched. The simplest solution here is to strip off ++# a trailing '/' in the directory before processing anything. ++newdir=$(echo "$OCF_RESKEY_directory" | sed -n -e 's/^\(.*\)\/$/\1/p') ++if [ -n "$newdir" ]; then ++ OCF_RESKEY_directory=$newdir + fi + +-case $__OCF_ACTION in +- meta-data) exportfs_meta_data +- exit $OCF_SUCCESS +- ;; +- usage|help) exportfs_usage +- exit $OCF_SUCCESS +- ;; +- *) +- ;; +-esac +- +-exportfs_validate +- +-case $__OCF_ACTION in +- start) exportfs_start +- ;; +- stop) exportfs_stop +- ;; +- status|monitor) exportfs_monitor +- ;; +- validate-all) +- # nothing to do -- we're already validated +- ;; +- *) exportfs_usage +- exit $OCF_ERR_UNIMPLEMENTED +- ;; +-esac ++OCF_REQUIRED_PARAMS="directory fsid clientspec" ++OCF_REQUIRED_BINARIES="exportfs" ++ocf_rarun $* +diff --git a/heartbeat/nfsnotify b/heartbeat/nfsnotify +new file mode 100644 +index 0000000..2e242de +--- /dev/null ++++ b/heartbeat/nfsnotify +@@ -0,0 +1,315 @@ ++#!/bin/bash ++# ++# Copyright (c) 2014 David Vossel ++# All Rights Reserved. ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of version 2 of the GNU General Public License as ++# published by the Free Software Foundation. ++# ++# This program is distributed in the hope that it would be useful, but ++# WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++# ++# Further, this software is distributed without any warranty that it is ++# free of the rightful claim of any third person regarding infringement ++# or the like. Any license provided herein, whether implied or ++# otherwise, applies only to this software file. Patent licenses, if ++# any, provided herein do not apply to combinations of this program with ++# other software, or any other product whatsoever. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write the Free Software Foundation, ++# Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. ++# ++ ++####################################################################### ++# Initialization: ++ ++: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat} ++. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs ++. ${OCF_FUNCTIONS_DIR}/ocf-directories ++ ++####################################################################### ++ ++sbindir=$HA_SBIN_DIR ++if [ -z "$sbindir" ]; then ++ sbindir=/usr/sbin ++fi ++ ++SELINUX_ENABLED=-1 ++ ++NFSNOTIFY_TMP_DIR="${HA_RSCTMP}/nfsnotify_${OCF_RESOURCE_INSTANCE}/" ++HA_STATD_PIDFILE="$NFSNOTIFY_TMP_DIR/rpc.statd_${OCF_RESOURCE_INSTANCE}.pid" ++HA_STATD_PIDFILE_PREV="$NFSNOTIFY_TMP_DIR/rpc.statd_${OCF_RESOURCE_INSTANCE}.pid.prev" ++STATD_PATH="/var/lib/nfs/statd" ++SM_NOTIFY_BINARY="${sbindir}/sm-notify" ++IS_RENOTIFY=0 ++ ++meta_data() { ++ cat < ++ ++ ++1.0 ++ ++ ++This agent sends NFSv3 reboot notifications to clients which informs clients to reclaim locks. ++ ++sm-notify reboot notifications ++ ++ ++ ++ ++ ++Comma separated list of floating IP addresses or host names that clients use ++to access the nfs service. This will be used to set the source address and ++mon_name of the SN_NOTIFY reboot notifications. ++ ++source IP addresses ++ ++ ++ ++ ++ ++Additional arguments to send to the sm-notify command. By default ++this agent will always set sm-notify's '-f' option. When the ++source_host option is set, the '-v' option will be used automatically ++to set the proper source address. Any additional sm-notify arguments ++set with this option will be used in addition to the previous default ++arguments. ++ ++sm-notify arguments ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++END ++} ++ ++v3notify_usage() ++{ ++ cat < /dev/null 2>&1 ++ if [ $? -eq 0 ]; then ++ # it is useful to know if sm-notify processes were actually left around ++ # or not during the stop/start operation. Whether this condition is true ++ # or false does not indicate a failure. It does indicate that ++ # there are probably some unresponsive nfs clients out there that are keeping ++ # the sm-notify processes retrying. ++ ocf_log info "previous sm-notify processes terminated before $__OCF_ACTION action." ++ fi ++} ++ ++v3notify_stop() ++{ ++ killall_smnotify ++ ++ rm -f $HA_STATD_PIDFILE_PREV > /dev/null 2>&1 ++ mv $HA_STATD_PIDFILE $HA_STATD_PIDFILE_PREV > /dev/null 2>&1 ++ ++ return $OCF_SUCCESS ++} ++ ++check_statd_pidfile() ++{ ++ local binary="rpc.statd" ++ local pidfile="$HA_STATD_PIDFILE" ++ ++ ocf_log debug "Checking status for ${binary}." ++ if [ -e "$pidfile" ]; then ++ cat /proc/$(cat $pidfile)/cmdline 2>/dev/null | grep -a "${binary}" > /dev/null 2>&1 ++ if [ $? -eq 0 ]; then ++ return $OCF_SUCCESS ++ fi ++ ++ ocf_log err "$(cat $pidfile) for $binary is no longer running, sm-notify needs to re-notify clients" ++ return $OCF_ERR_GENERIC ++ fi ++ ++ # if we don't have a pid file for rpc.statd, we have not yet sent the notifications ++ return $OCF_NOT_RUNNING ++} ++ ++write_statd_pid() ++{ ++ local binary="rpc.statd" ++ local pidfile="$HA_STATD_PIDFILE" ++ local pid ++ ++ pid=$(pgrep ${binary}) ++ case $? in ++ 0) ++ ocf_log info "PID file (pid:${pid} at $pidfile) created for ${binary}." ++ mkdir -p $(dirname $pidfile) ++ echo "$pid" > $pidfile ++ return $OCF_SUCCESS;; ++ 1) ++ rm -f "$pidfile" > /dev/null 2>&1 ++ ocf_log info "$binary is not running" ++ return $OCF_NOT_RUNNING;; ++ *) ++ rm -f "$pidfile" > /dev/null 2>&1 ++ ocf_log err "Error encountered detecting pid status of $binary" ++ return $OCF_ERR_GENERIC;; ++ esac ++} ++ ++copy_statd() ++{ ++ local src=$1 ++ local dest=$2 ++ ++ if ! [ -d "$dest" ]; then ++ mkdir -p "$dest" ++ fi ++ ++ cp -rpfn $src/sm $src/sm.bak $src/state $dest > /dev/null 2>&1 ++ ++ # make sure folder ownership and selinux lables stay consistent ++ [ -n "`id -u rpcuser`" -a "`id -g rpcuser`" ] && chown rpcuser.rpcuser "$dest" ++ [ $SELINUX_ENABLED -eq 0 ] && chcon -R "$SELINUX_LABEL" "$dest" ++} ++ ++v3notify_start() ++{ ++ local rc=$OCF_SUCCESS ++ local cur_statd ++ local statd_backup ++ local is_renotify=0 ++ ++ # monitor, see if we need to notify or not ++ v3notify_monitor ++ if [ $? -eq 0 ]; then ++ return $OCF_SUCCESS ++ fi ++ ++ # kill off any other sm-notify processes that might already be running. ++ killall_smnotify ++ ++ # record the pid of rpc.statd. if this pid ever changes, we have to re-notify ++ write_statd_pid ++ rc=$? ++ if [ $rc -ne 0 ]; then ++ return $rc ++ fi ++ ++ # if the last time we ran nfs-notify, it was with the same statd process, ++ # consider this a re-notification. During re-notifications we do not let the ++ # sm-notify binary have access to the real statd directory. ++ if [ "$(cat $HA_STATD_PIDFILE)" = "$(cat $HA_STATD_PIDFILE_PREV 2>/dev/null)" ]; then ++ ocf_log info "Renotifying clients" ++ is_renotify=1 ++ fi ++ ++ statd_backup="$STATD_PATH/nfsnotify.bu" ++ copy_statd "$STATD_PATH" "$statd_backup" ++ ++ if [ -z "$OCF_RESKEY_source_host" ]; then ++ if [ "$is_renotify" -eq 0 ]; then ++ cur_statd="$STATD_PATH" ++ else ++ cur_statd="$statd_backup" ++ fi ++ ocf_log info "sending notifications on default source address." ++ $SM_NOTIFY_BINARY -f $OCF_RESKEY_notify_args -P $cur_statd ++ if [ $? -ne 0 ]; then ++ ocf_log err "sm-notify failed, view syslog for more information." ++ return $OCF_ERR_GENERIC ++ fi ++ ++ return $OCF_SUCCESS ++ fi ++ ++ # do sm-notify for each ip ++ for ip in `echo ${OCF_RESKEY_source_host} | sed 's/,/ /g'`; do ++ ++ # have the first sm-notify use the actual statd directory so the ++ # notify list can be managed properly. ++ if [ "$is_renotify" -eq 0 ]; then ++ cur_statd="$STATD_PATH" ++ # everything after the first notify we are considering a renotification ++ # which means we don't use the real statd directory. ++ is_renotify=1 ++ else ++ # use our copied statd directory for the remaining ip addresses ++ cur_statd="$STATD_PATH/nfsnotify_${OCF_RESOURCE_INSTANCE}_${ip}" ++ copy_statd "$statd_backup" "$cur_statd" ++ fi ++ ++ ocf_log info "sending notifications with source address $ip" ++ $SM_NOTIFY_BINARY -f $OCF_RESKEY_notify_args -v $ip -P "$cur_statd" ++ if [ $? -ne 0 ]; then ++ ocf_log err "sm-notify with source host set to, $source_host, failed. view syslog for more information" ++ return $OCF_ERR_GENERIC ++ fi ++ done ++ ++ return $OCF_SUCCESS ++} ++ ++v3notify_monitor() ++{ ++ # verify rpc.statd is up, and that the rpc.statd pid is the same one we ++ # found during the start. otherwise rpc.statd recovered and we need to notify ++ # again. ++ check_statd_pidfile ++} ++ ++case $__OCF_ACTION in ++ meta-data) meta_data ++ exit $OCF_SUCCESS;; ++ usage|help) v3notify_usage ++ exit $OCF_SUCCESS;; ++ *) ++ ;; ++esac ++ ++which restorecon > /dev/null 2>&1 && selinuxenabled ++SELINUX_ENABLED=$? ++if [ $SELINUX_ENABLED -eq 0 ]; then ++ export SELINUX_LABEL="$(ls -ldZ $STATD_PATH | cut -f4 -d' ')" ++fi ++ ++case $__OCF_ACTION in ++ start) v3notify_start;; ++ stop) v3notify_stop;; ++ monitor) v3notify_monitor;; ++ validate-all) v3notify_validate;; ++ *) v3notify_usage ++ exit $OCF_ERR_UNIMPLEMENTED;; ++esac ++ ++rc=$? ++ocf_log debug "${OCF_RESOURCE_INSTANCE} $__OCF_ACTION : $rc" ++exit $rc ++ +diff --git a/heartbeat/nfsserver b/heartbeat/nfsserver +index bc326e5..e44da1c 100755 +--- a/heartbeat/nfsserver ++++ b/heartbeat/nfsserver +@@ -13,13 +13,22 @@ else + fi + + DEFAULT_INIT_SCRIPT="/etc/init.d/nfsserver" +-DEFAULT_NOTIFY_CMD="/sbin/sm-notify" ++if ! [ -f $DEFAULT_INIT_SCRIPT ]; then ++ # On some systems, the script is just called nfs ++ DEFAULT_INIT_SCRIPT="/etc/init.d/nfs" ++fi ++ ++DEFAULT_NOTIFY_CMD=`which sm-notify` ++DEFAULT_NOTIFY_CMD=${DEFAULT_NOTIFY_CMD:-"/sbin/sm-notify"} + DEFAULT_NOTIFY_FOREGROUND="false" + DEFAULT_RPCPIPEFS_DIR="/var/lib/nfs/rpc_pipefs" + EXEC_MODE=0 + SELINUX_ENABLED=-1 + STATD_PATH="/var/lib/nfs" + STATD_DIR="" ++NFS_SYSCONFIG="/etc/sysconfig/nfs" ++NFS_SYSCONFIG_LOCAL_BACKUP="/etc/sysconfig/nfs.ha.bu" ++NFS_SYSCONFIG_AUTOGEN_TAG="AUTOGENERATED by $0 high availability resource-agent" + + nfsserver_meta_data() { + cat < + + +- ++ + +-The tool to send out NSM reboot notification; it should be either sm-notify or rpc.statd. +-Failover of nfsserver can be considered as rebooting to different machines. +-The nfsserver resource agent use this command to notify all clients about the occurrence of failover. ++Do not send reboot notifications to NFSv3 clients during server startup. + + +-The tool to send out notification. ++Disable NFSv3 server reboot notifications + +- ++ + + + + +-Keeps the notify tool attached to its controlling terminal and running in the foreground. ++Keeps the sm-notify attached to its controlling terminal and running in the foreground. + + + Keeps the notify tool running in the foreground. +@@ -87,25 +94,102 @@ Specifies the length of sm-notify retry time (minutes). + + + +- ++ + +-The nfsserver resource agent will save nfs related information in this specific directory. +-And this directory must be able to fail-over before nfsserver itself. ++Comma separated list of floating IP addresses used to access the nfs service + + +-Directory to store nfs server related information. ++IP addresses. + +- ++ + + +- ++ + +-Comma separated list of floating IP addresses used to access the nfs service ++Specifies what arguments to pass to the nfs daemon on startup. View the rpc.nfsd man page for information on what arguments are available. ++Note that setting this value will override all settings placed in the local /etc/sysconfig/nfs file. + + +-IP addresses. ++rpc.nfsd options + +- ++ ++ ++ ++ ++ ++The udp port lockd should listen on. ++Note that setting this value will override all settings placed in the local /etc/sysconfig/nfs file. ++ ++ ++lockd udp port ++ ++ ++ ++ ++ ++ ++The tcp port lockd should listen on. ++Note that setting this value will override all settings placed in the local /etc/sysconfig/nfs file. ++ ++ ++lockd tcp port ++ ++ ++ ++ ++ ++ ++The source port number sm-notify uses when sending reboot notifications. ++Note that setting this value will override all settings placed in the local /etc/sysconfig/nfs file. ++ ++ ++sm-notify source port ++ ++ ++ ++ ++ ++ ++The port number used for RPC listener sockets. ++Note that setting this value will override all settings placed in the local /etc/sysconfig/nfs file. ++ ++ ++rpc.statd listener port ++ ++ ++ ++ ++ ++ ++The port number used for rpc.mountd listener sockets. ++Note that setting this value will override all settings placed in the local /etc/sysconfig/nfs file. ++ ++ ++rpc.mountd listener port ++ ++ ++ ++ ++ ++ ++The port number used for rpc.rquotad. ++Note that setting this value will override all settings placed in the local /etc/sysconfig/nfs file. ++ ++ ++rpc.rquotad port ++ ++ ++ ++ ++ ++ ++The nfsserver resource agent will save nfs related information in this specific directory. ++And this directory must be able to fail-over before nfsserver itself. ++ ++ ++Directory to store nfs server related information. ++ ++ + + + +@@ -228,6 +312,7 @@ set_exec_mode() + if which systemctl > /dev/null 2>&1; then + if systemctl list-unit-files | grep nfs-server > /dev/null && systemctl list-unit-files | grep nfs-lock > /dev/null; then + EXEC_MODE=2 ++ # when using systemd, the nfs-lock service file handles nfsv3 locking daemons for us. + return 0 + fi + fi +@@ -236,33 +321,6 @@ set_exec_mode() + exit $OCF_ERR_INSTALLED + } + +-nfs_systemd_exec() +-{ +- local cmd=$1 +- local server_res +- local lock_res +- +- if [ "$cmd" = "stop" ]; then +- systemctl $cmd nfs-server.service +- server_res=$? +- systemctl $cmd nfs-lock.service +- lock_res=$? +- else +- systemctl $cmd nfs-lock.service +- lock_res=$? +- systemctl $cmd nfs-server.service +- server_res=$? +- fi +- +- if [ $lock_res -ne $server_res ]; then +- # If one is running and the other isn't, or for whatever other reason +- # the return code's aren't the same, this is bad. +- ocf_log err "Systemd services nfs-lock and nfs-server are not in the same state after attempting $cmd command" +- return $OCF_ERR_GENERIC +- fi +- return $server_res +-} +- + ## + # wrapper for init script and systemd calls. + ## +@@ -273,21 +331,45 @@ nfs_exec() + + case $EXEC_MODE in + 1) ${OCF_RESKEY_nfs_init_script} $cmd;; +- 2) nfs_systemd_exec $cmd;; ++ 2) systemctl $cmd nfs-server.service ;; + esac + } + ++v3locking_exec() ++{ ++ local cmd=$1 ++ set_exec_mode ++ ++ if [ $EXEC_MODE -eq 2 ]; then ++ systemctl $cmd nfs-lock.service ++ else ++ case $cmd in ++ start) locking_start;; ++ stop) locking_stop;; ++ status) locking_status;; ++ esac ++ fi ++} ++ + nfsserver_monitor () + { + fn=`mktemp` + nfs_exec status > $fn 2>&1 + rc=$? +- ocf_log debug `cat $fn` ++ ocf_log debug "$(cat $fn)" + rm -f $fn + +-#Adapte LSB status code to OCF return code ++ #Adapte LSB status code to OCF return code + if [ $rc -eq 0 ]; then +- return $OCF_SUCCESS ++ # don't report success if nfs servers are up ++ # without locking daemons. ++ v3locking_exec "status" ++ rc=$? ++ if [ $rc -ne 0 ]; then ++ ocf_log error "NFS server is up, but the locking daemons are down" ++ rc=$OCF_ERR_GENERIC ++ fi ++ return $rc + elif [ $rc -eq 3 ]; then + return $OCF_NOT_RUNNING + else +@@ -295,8 +377,79 @@ nfsserver_monitor () + fi + } + ++set_arg() ++{ ++ local key="$1" ++ local value="$2" ++ local file="$3" ++ local requires_sysconfig="$4" ++ ++ if [ -z "$value" ]; then ++ return ++ fi ++ ++ # only write to the tmp /etc/sysconfig/nfs if sysconfig exists. ++ # otherwise this distro does not support setting these options. ++ if [ -d "/etc/sysconfig" ]; then ++ echo "${key}=\"${value}\"" >> $file ++ elif [ "$requires_sysconfig" = "true" ]; then ++ ocf_log warn "/etc/sysconfig/nfs not found, unable to set port and nfsd args." ++ fi ++ ++ export ${key}="${value}" ++} ++ ++set_env_args() ++{ ++ local tmpconfig=$(mktemp ${HA_RSCTMP}/nfsserver-tmp-XXXXX) ++ local statd_args ++ ++ # nfsd args ++ set_arg "RPCNFSDARGS" "$OCF_RESKEY_nfsd_args" "$tmpconfig" "true" ++ ++ # mountd args ++ if [ -n "$OCF_RESKEY_mountd_port" ]; then ++ set_arg "RPCMOUNTDOPTS" "-p $OCF_RESKEY_mountd_port" "$tmpconfig" "true" ++ fi ++ ++ # statd args. we always want to perform the notify using sm-notify after ++ # both rpc.statd and the nfsd daemons are initialized ++ statd_args="--no-notify" ++ if [ -n "$OCF_RESKEY_statd_outgoing_port" ]; then ++ statd_args="$statd_args -o $OCF_RESKEY_statd_outgoing_port" ++ fi ++ if [ -n "$OCF_RESKEY_statd_port" ]; then ++ statd_args="$statd_args -p $OCF_RESKEY_statd_port" ++ fi ++ set_arg "STATDARG" "$statd_args" "$tmpconfig" "false" ++ ++ # lockd ports ++ set_arg "LOCKD_UDPPORT" "$OCF_RESKEY_lockd_udp_port" "$tmpconfig" "true" ++ set_arg "LOCKD_TCPPORT" "$OCF_RESKEY_lockd_tcp_port" "$tmpconfig" "true" ++ ++ # rquotad_port ++ set_arg "RPCRQUOTADOPTS" "-p $OCF_RESKEY_rquotad_port" "$tmpconfig" "true" ++ ++ # override local nfs config. preserve previous local config though. ++ if [ -s $tmpconfig ]; then ++ cat $NFS_SYSCONFIG | grep -e "$NFS_SYSCONFIG_AUTOGEN_TAG" ++ if [ $? -ne 0 ]; then ++ # backup local nfs config if it doesn't have our HA autogen tag in it. ++ mv -f $NFS_SYSCONFIG $NFS_SYSCONFIG_LOCAL_BACKUP ++ fi ++ echo "# $NFS_SYSCONFIG_AUTOGEN_TAG" > $NFS_SYSCONFIG ++ echo "# local config backup stored here, '$NFS_SYSCONFIG_LOCAL_BACKUP'" >> $NFS_SYSCONFIG ++ cat $tmpconfig >> $NFS_SYSCONFIG ++ fi ++ rm -f $tmpconfig ++} ++ + prepare_directory () + { ++ if [ -z "$fp" ]; then ++ return ++ fi ++ + [ -d "$fp" ] || mkdir -p $fp + [ -d "$rpcpipefs_make_dir" ] || mkdir -p $rpcpipefs_make_dir + [ -d "$fp/v4recovery" ] || mkdir -p $fp/v4recovery +@@ -311,6 +464,8 @@ prepare_directory () + [ -f "$fp/xtab" ] || touch "$fp/xtab" + [ -f "$fp/rmtab" ] || touch "$fp/rmtab" + ++ dd if=/dev/urandom of=$fp/$STATD_DIR/state bs=1 count=4 &> /dev/null ++ [ -n "`id -u rpcuser`" -a "`id -g rpcuser`" ] && chown rpcuser.rpcuser "$fp/$STATD_DIR/state" + [ $SELINUX_ENABLED -eq 0 ] && chcon -R "$SELINUX_LABEL" "$fp" + } + +@@ -325,6 +480,10 @@ is_bound () + + bind_tree () + { ++ if [ -z "$fp" ]; then ++ return ++ fi ++ + if is_bound /var/lib/nfs; then + ocf_log debug "$fp is already bound to /var/lib/nfs" + return 0 +@@ -343,25 +502,195 @@ unbind_tree () + fi + } + ++binary_status() ++{ ++ local binary=$1 ++ local pid ++ ++ pid=$(pgrep ${binary}) ++ case $? in ++ 0) ++ echo "$pid" ++ return $OCF_SUCCESS;; ++ 1) ++ return $OCF_NOT_RUNNING;; ++ *) ++ return $OCF_ERR_GENERIC;; ++ esac ++} ++ ++locking_status() ++{ ++ binary_status "rpc.statd" > /dev/null 2>&1 ++} ++ ++locking_start() ++{ ++ local ret=$OCF_SUCCESS ++ ++ ocf_log info "Starting rpc.statd." ++ ++ rpc.statd $STATDARG ++ ++ ret=$? ++ if [ $ret -ne 0 ]; then ++ ocf_log err "Failed to start rpc.statd" ++ return $ret ++ fi ++ touch /var/lock/subsys/nfslock ++ ++ return $ret ++} ++ ++terminate() ++{ ++ declare pids ++ declare i=0 ++ ++ while : ; do ++ pids=$(binary_status $1) ++ [ -z "$pids" ] && return 0 ++ kill $pids ++ sleep 1 ++ ((i++)) ++ [ $i -gt 3 ] && return 1 ++ done ++} ++ ++ ++killkill() ++{ ++ declare pids ++ declare i=0 ++ ++ while : ; do ++ pids=$(binary_status $1) ++ [ -z "$pids" ] && return 0 ++ kill -9 $pids ++ sleep 1 ++ ((i++)) ++ [ $i -gt 3 ] && return 1 ++ done ++} ++ ++stop_process() ++{ ++ declare process=$1 ++ ++ ocf_log info "Stopping $process" ++ if terminate $process; then ++ ocf_log debug "$process is stopped" ++ else ++ if killkill $process; then ++ ocf_log debug "$process is stopped" ++ else ++ ocf_log debug "Failed to stop $process" ++ return 1 ++ fi ++ fi ++ return 0 ++} ++ ++locking_stop() ++{ ++ ret=0 ++ ++ # sm-notify can prevent umount of /var/lib/nfs/statd if ++ # it is still trying to notify unresponsive clients. ++ stop_process sm-notify ++ if [ $? -ne 0 ]; then ++ ret=$OCF_ERR_GENERIC ++ fi ++ ++ stop_process rpc.statd ++ if [ $? -ne 0 ]; then ++ ret=$OCF_ERR_GENERIC ++ fi ++ ++ return $ret ++} ++ ++notify_locks() ++{ ++ if ocf_is_true "$OCF_RESKEY_nfs_no_notify"; then ++ # we've been asked not to notify clients ++ return; ++ fi ++ ++ # run in foreground, if requested ++ if ocf_is_true "$OCF_RESKEY_nfs_notify_foreground"; then ++ opts="-d" ++ fi ++ ++ if [ -n "$OCF_RESKEY_nfs_smnotify_retry_time" ]; then ++ opts="$opts -m $OCF_RESKEY_nfs_smnotify_retry_time" ++ fi ++ ++ if [ -n "$OCF_RESKEY_statd_outgoing_port" ]; then ++ opts="$opts -p $OCF_RESKEY_statd_outgoing_port" ++ fi ++ ++ # forces re-notificaiton regardless if notifies have already gone out ++ opts="$opts -f" ++ ++ ocf_log info "executing sm-notify" ++ if [ -n "$OCF_RESKEY_nfs_ip" ]; then ++ for ip in `echo ${OCF_RESKEY_nfs_ip} | sed 's/,/ /g'`; do ++ cp -rpfn $STATD_PATH/sm.ha/* $STATD_PATH/ > /dev/null 2>&1 ++ sm-notify $opts -v $ip ++ done ++ else ++ sm-notify $opts ++ fi ++} ++ + nfsserver_start () + { ++ local rc; ++ + if nfsserver_monitor; then + ocf_log debug "NFS server is already started" + return $OCF_SUCCESS + fi + ++ set_env_args + prepare_directory + bind_tree + ++ # remove the sm-notify pid so sm-notify will be allowed to run again without requiring a reboot. ++ rm -f /var/run/sm-notify.pid ++ # ++ # Synchronize these before starting statd ++ # ++ cp -rpfn $STATD_PATH/sm.ha/* $STATD_PATH/ > /dev/null 2>&1 + rm -rf $STATD_PATH/sm.ha/* > /dev/null 2>&1 +- cp -rf $STATD_PATH/sm $STATD_PATH/sm.bak /var/lib/nfs/state $STATD_PATH/sm.ha > /dev/null 2>&1 ++ cp -rpf $STATD_PATH/sm $STATD_PATH/sm.bak /var/lib/nfs/state $STATD_PATH/sm.ha > /dev/null 2>&1 + + ocf_log info "Starting NFS server ..." + ++ # mounts /proc/fs/nfsd for us ++ lsmod | grep -q nfsd ++ if [ $? -ne 0 ]; then ++ modprobe nfsd ++ fi ++ ++ # check to see if we need to start rpc.statd ++ v3locking_exec "status" ++ if [ $? -ne $OCF_SUCCESS ]; then ++ v3locking_exec "start" ++ rc=$? ++ if [ $rc -ne 0 ]; then ++ ocf_log error "Failed to start NFS server locking daemons" ++ return $rc ++ fi ++ else ++ ocf_log info "rpc.statd already up" ++ fi ++ + fn=`mktemp` + nfs_exec start > $fn 2>&1 + rc=$? +- ocf_log debug `cat $fn` ++ ocf_log debug "$(cat $fn)" + rm -f $fn + + if [ $rc -ne 0 ]; then +@@ -369,42 +698,7 @@ nfsserver_start () + return $rc + fi + +- #Notify the nfs server has been moved or rebooted +- #The init script do that already, but with the hostname, which may be ignored by client +- #we have to do it again with the nfs_ip +- local opts +- +- case ${OCF_RESKEY_nfs_notify_cmd##*/} in +- sm-notify) +- # run in foreground, if requested +- if ocf_is_true "$OCF_RESKEY_nfs_notify_foreground"; then +- opts="-d" +- fi +- +- if [ -n "$OCF_RESKEY_nfs_smnotify_retry_time" ]; then +- opts="$opts -m $OCF_RESKEY_nfs_smnotify_retry_time" +- fi +- +- opts="$opts -f -v" +- ;; +- +- rpc.statd) +- if ocf_is_true "$OCF_RESKEY_nfs_notify_foreground"; then +- opts="-F" +- fi +- opts="$opts -n" +- ;; +- +- esac +- +- rm -rf $STATD_PATH/sm.ha.save > /dev/null 2>&1 +- cp -rf $STATD_PATH/sm.ha $STATD_PATH/sm.ha.save > /dev/null 2>&1 +- for ip in `echo ${OCF_RESKEY_nfs_ip} | sed 's/,/ /g'`; do +- ${OCF_RESKEY_nfs_notify_cmd} $opts $ip -P $STATD_PATH/sm.ha +- rm -rf $STATD_PATH/sm.ha > /dev/null 2>&1 +- cp -rf $STATD_PATH/sm.ha.save $STATD_PATH/sm.ha > /dev/null 2>&1 +- done +- ++ notify_locks + + ocf_log info "NFS server started" + return $OCF_SUCCESS +@@ -414,12 +708,23 @@ nfsserver_stop () + { + ocf_log info "Stopping NFS server ..." + ++ # backup the current sm state information to the ha folder before stopping. ++ # the ha folder will be synced after startup, restoring the statd client state ++ rm -rf $STATD_PATH/sm.ha/* > /dev/null 2>&1 ++ cp -rpf $STATD_PATH/sm $STATD_PATH/sm.bak /var/lib/nfs/state $STATD_PATH/sm.ha > /dev/null 2>&1 ++ + fn=`mktemp` + nfs_exec stop > $fn 2>&1 + rc=$? +- ocf_log debug `cat $fn` ++ ocf_log debug "$(cat $fn)" + rm -f $fn + ++ v3locking_exec "stop" ++ if [ $? -ne 0 ]; then ++ ocf_log err "Failed to stop NFS locking daemons" ++ rc=$OCF_ERR_GENERIC ++ fi ++ + if [ $rc -eq 0 ]; then + unbind_tree + ocf_log info "NFS server stopped" +@@ -437,13 +742,9 @@ nfsserver_validate () + set_exec_mode + check_binary ${OCF_RESKEY_nfs_notify_cmd} + +- if [ x = x"${OCF_RESKEY_nfs_ip}" ]; then +- ocf_log err "nfs_ip not set" +- exit $OCF_ERR_CONFIGURED +- fi + +- if [ x = "x$OCF_RESKEY_nfs_shared_infodir" ]; then +- ocf_log err "nfs_shared_infodir not set" ++ if [ -n "$OCF_RESKEY_CRM_meta_clone" ] && [ -n "$OCF_RESKEY_nfs_shared_infodir" ]; then ++ ocf_log err "This RA does not support clone mode when a shared info directory is in use." + exit $OCF_ERR_CONFIGURED + fi + +@@ -465,11 +766,6 @@ nfsserver_validate () + return $OCF_SUCCESS + } + +-if [ -n "$OCF_RESKEY_CRM_meta_clone" ]; then +- ocf_log err "THIS RA DO NOT SUPPORT CLONE MODE!" +- exit $OCF_ERR_CONFIGURED +-fi +- + nfsserver_validate + + case $__OCF_ACTION in +-- +1.8.4.2 + diff --git a/SOURCES/bz1095944-safe-umount-option.patch b/SOURCES/bz1095944-safe-umount-option.patch new file mode 100644 index 00000000..2e25a914 --- /dev/null +++ b/SOURCES/bz1095944-safe-umount-option.patch @@ -0,0 +1,87 @@ +diff --git a/heartbeat/Filesystem b/heartbeat/Filesystem +index 9209818..6a852df 100755 +--- a/heartbeat/Filesystem ++++ b/heartbeat/Filesystem +@@ -196,6 +196,26 @@ Only set this to "true" if you know what you are doing! + + + ++ ++ ++This option allows specifying how to handle processes that are ++currently accessing the mount directory. ++ ++"true" : Default value, kill processes accessing mount point ++"safe" : Kill processes accessing mount point using methods that ++ avoid functions that could potentially block during process ++ detection ++"false" : Do not kill any processes. ++ ++The 'safe' option uses shell logic to walk the /procs/ directory ++for pids using the mount point while the default option uses the ++fuser cli tool. fuser is known to perform operations that can potentially ++block if unresponsive nfs mounts are in use on the system. ++ ++Kill processes before unmount ++ ++ ++ + + + +@@ -701,6 +721,25 @@ Filesystem_notify() { + done + } + ++get_pids() ++{ ++ local dir=$1 ++ local procs ++ local mmap_procs ++ ++ if ocf_is_true "$FORCE_UNMOUNT"; then ++ if [ "X${HOSTOS}" = "XOpenBSD" ];then ++ fstat | grep $dir | awk '{print $3}' ++ else ++ $FUSER -m $dir 2>/dev/null ++ fi ++ elif [ "$FORCE_UNMOUNT" = "safe" ]; then ++ procs=$(find /proc/[0-9]*/ -type l -lname "${dir}/*" -or -lname "${dir}" 2>/dev/null | awk -F/ '{print $3}') ++ mmap_procs=$(grep " ${dir}" /proc/[0-9]*/maps | awk -F/ '{print $3}') ++ echo -e "${procs}\n${mmap_procs}" | sort | uniq ++ fi ++} ++ + signal_processes() { + local dir=$1 + local sig=$2 +@@ -708,15 +747,9 @@ signal_processes() { + # fuser returns a non-zero return code if none of the + # specified files is accessed or in case of a fatal + # error. +- pids=$( +- if [ "X${HOSTOS}" = "XOpenBSD" ];then +- fstat | grep $dir | awk '{print $3}' +- else +- $FUSER -m $dir 2>/dev/null +- fi +- ) ++ pids=$(get_pids "$dir") + if [ -z "$pids" ]; then +- ocf_log info "No processes on $dir were signalled" ++ ocf_log info "No processes on $dir were signalled. force_unmount is set to '$FORCE_UNMOUNT'" + return + fi + for pid in $pids; do +@@ -1002,6 +1035,11 @@ if [ $# -ne 1 ]; then + fi + + # Check the OCF_RESKEY_ environment variables... ++FORCE_UNMOUNT="yes" ++if [ -n "${OCF_RESKEY_force_unmount}" ]; then ++ FORCE_UNMOUNT=$OCF_RESKEY_force_unmount ++fi ++ + DEVICE=$OCF_RESKEY_device + FSTYPE=$OCF_RESKEY_fstype + if [ ! -z "$OCF_RESKEY_options" ]; then diff --git a/SOURCES/bz1097593-LVM-warn-lvmetad.patch b/SOURCES/bz1097593-LVM-warn-lvmetad.patch new file mode 100644 index 00000000..fe2cd1a3 --- /dev/null +++ b/SOURCES/bz1097593-LVM-warn-lvmetad.patch @@ -0,0 +1,42 @@ +From 4f6ebfc537b2d3671112a54873081685d47066db Mon Sep 17 00:00:00 2001 +From: David Vossel +Date: Fri, 18 Jul 2014 12:31:55 -0400 +Subject: [PATCH] Low: LVM: Warn users about the danger of lvmetad + +--- + heartbeat/LVM | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) + +diff --git a/heartbeat/LVM b/heartbeat/LVM +index 4378cd3..27cdfbd 100755 +--- a/heartbeat/LVM ++++ b/heartbeat/LVM +@@ -545,6 +545,25 @@ LVM_validate_all() { + check_binary $AWK + + ## ++ # lvmetad is a daemon that caches lvm metadata to improve the ++ # performance of LVM commands. This daemon should never be used when ++ # volume groups exist that are being managed by the cluster. The lvmetad ++ # daemon introduces a response lag, where certain LVM commands look like ++ # they have completed (like vg activation) when in fact the command ++ # is still in progress by the lvmetad. This can cause reliability issues ++ # when managing volume groups in the cluster. For Example, if you have a ++ # volume group that is a dependency for another application, it is possible ++ # the cluster will think the volume group is activated and attempt to start ++ # the application before volume group is really accesible... lvmetad is bad. ++ ## ++ lvm dumpconfig global/use_lvmetad | grep 'use_lvmetad.*=.*1' > /dev/null 2>&1 ++ if [ $? -eq 0 ]; then ++ # for now warn users that lvmetad is enabled and that they should disable it. In the ++ # future we may want to consider refusing to start, or killing the lvmetad daemon. ++ ocf_log warn "Disable lvmetad in lvm.conf. lvmetad should never be enabled in a clustered environment. Set use_lvmetad=0 and kill the lvmetad process" ++ fi ++ ++ ## + # Off-the-shelf tests... + ## + VGOUT=`vgck ${VOLUME} 2>&1` +-- +1.8.4.2 + diff --git a/SOURCES/bz1105655-virtualdomain-restore-start-stop-default-timeout.patch b/SOURCES/bz1105655-virtualdomain-restore-start-stop-default-timeout.patch new file mode 100644 index 00000000..5b2cb6e5 --- /dev/null +++ b/SOURCES/bz1105655-virtualdomain-restore-start-stop-default-timeout.patch @@ -0,0 +1,32 @@ +From 458c003e7f6f0caa2e1c7f4386e458a039500427 Mon Sep 17 00:00:00 2001 +From: David Vossel +Date: Thu, 19 Jun 2014 14:52:36 -0500 +Subject: [PATCH] High: VirtualDomain: restore advertised start and stop + timeout values to a sane value. + +The meta_timeout default value is 90000 milliseconds. That value +was used in the xml output to represent the default start and stop +timeout which is reflected in seconds... not milliseconds. A +90000 second timeout doesn't make sense as a default. +--- + heartbeat/VirtualDomain | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/heartbeat/VirtualDomain b/heartbeat/VirtualDomain +index c44c090..b0cdd5f 100755 +--- a/heartbeat/VirtualDomain ++++ b/heartbeat/VirtualDomain +@@ -167,8 +167,8 @@ Restore state on start/stop + + + +- +- ++ ++ + + + +-- +1.8.4.2 + diff --git a/SOURCES/bz1116166-Low-galera-be-very-generous-in-the-promotion-timeout.patch b/SOURCES/bz1116166-Low-galera-be-very-generous-in-the-promotion-timeout.patch new file mode 100644 index 00000000..8d8394cd --- /dev/null +++ b/SOURCES/bz1116166-Low-galera-be-very-generous-in-the-promotion-timeout.patch @@ -0,0 +1,26 @@ +From 54c26715a8eb5688081ea6e26cabe54d9de762d7 Mon Sep 17 00:00:00 2001 +From: David Vossel +Date: Wed, 30 Jul 2014 13:03:14 -0500 +Subject: [PATCH 6/6] Low: galera: be very generous in the promotion timeout to + allow SST to complete on large databases + +--- + heartbeat/galera | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/heartbeat/galera b/heartbeat/galera +index a361d7b..994aad0 100755 +--- a/heartbeat/galera ++++ b/heartbeat/galera +@@ -235,7 +235,7 @@ Cluster check user password + + + +- ++ + + + +-- +1.8.4.2 + diff --git a/SOURCES/bz1116166-Low-galera-do-not-advertise-notify-in-the-usage.patch b/SOURCES/bz1116166-Low-galera-do-not-advertise-notify-in-the-usage.patch new file mode 100644 index 00000000..307e269a --- /dev/null +++ b/SOURCES/bz1116166-Low-galera-do-not-advertise-notify-in-the-usage.patch @@ -0,0 +1,41 @@ +From bc1e7bdcedc1bb1bf473787f373261452e37e337 Mon Sep 17 00:00:00 2001 +From: David Vossel +Date: Wed, 30 Jul 2014 12:59:46 -0500 +Subject: [PATCH 5/6] Low: galera: do not advertise notify in the usage + +--- + heartbeat/galera | 4 +--- + 1 file changed, 1 insertion(+), 3 deletions(-) + +diff --git a/heartbeat/galera b/heartbeat/galera +index 386daaf..a361d7b 100755 +--- a/heartbeat/galera ++++ b/heartbeat/galera +@@ -79,7 +79,7 @@ fi + + usage() { + cat < + + +- + + + +@@ -683,7 +682,6 @@ case "$1" in + monitor) galera_monitor;; + promote) galera_promote;; + demote) galera_demote;; +- notify) galera_notify;; + validate-all) exit $OCF_SUCCESS;; + + *) usage +-- +1.8.4.2 + diff --git a/SOURCES/bz1116166-galera-agent.patch b/SOURCES/bz1116166-galera-agent.patch new file mode 100644 index 00000000..7c6132c1 --- /dev/null +++ b/SOURCES/bz1116166-galera-agent.patch @@ -0,0 +1,1417 @@ +From 591302a81c5961a03ffad70369433c20b31aebbe Mon Sep 17 00:00:00 2001 +From: David Vossel +Date: Fri, 18 Jul 2014 13:01:48 -0500 +Subject: [PATCH] galera resource agent + +--- + doc/man/Makefile.am | 1 + + heartbeat/Makefile.am | 2 + + heartbeat/galera | 693 ++++++++++++++++++++++++++++++++++++++++++++ + heartbeat/mysql | 273 +---------------- + heartbeat/mysql-common.sh | 279 ++++++++++++++++++ + heartbeat/ocf-shellfuncs.in | 1 + + 6 files changed, 991 insertions(+), 258 deletions(-) + create mode 100644 heartbeat/galera + create mode 100644 heartbeat/mysql-common.sh + +diff --git a/doc/man/Makefile.am b/doc/man/Makefile.am +index a3517aa..e97c7e9 100644 +--- a/doc/man/Makefile.am ++++ b/doc/man/Makefile.am +@@ -102,6 +102,7 @@ man_MANS = ocf_heartbeat_AoEtarget.7 \ + ocf_heartbeat_ethmonitor.7 \ + ocf_heartbeat_exportfs.7 \ + ocf_heartbeat_fio.7 \ ++ ocf_heartbeat_galera.7 \ + ocf_heartbeat_iSCSILogicalUnit.7 \ + ocf_heartbeat_iSCSITarget.7 \ + ocf_heartbeat_ids.7 \ +diff --git a/heartbeat/Makefile.am b/heartbeat/Makefile.am +index 65a2cfb..aab521f 100644 +--- a/heartbeat/Makefile.am ++++ b/heartbeat/Makefile.am +@@ -73,6 +73,7 @@ ocf_SCRIPTS = ClusterMon \ + exportfs \ + Filesystem \ + fio \ ++ galera \ + ids \ + iscsi \ + ICP \ +@@ -140,6 +141,7 @@ ocfcommon_DATA = ocf-shellfuncs \ + sapdb-nosha.sh \ + sapdb.sh \ + ora-common.sh \ ++ mysql-common.sh \ + findif.sh + + # Legacy locations +diff --git a/heartbeat/galera b/heartbeat/galera +new file mode 100644 +index 0000000..6d8cf12 +--- /dev/null ++++ b/heartbeat/galera +@@ -0,0 +1,693 @@ ++#!/bin/sh ++# ++# Copyright (c) 2014 David Vossel ++# All Rights Reserved. ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of version 2 of the GNU General Public License as ++# published by the Free Software Foundation. ++# ++# This program is distributed in the hope that it would be useful, but ++# WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++# ++# Further, this software is distributed without any warranty that it is ++# free of the rightful claim of any third person regarding infringement ++# or the like. Any license provided herein, whether implied or ++# otherwise, applies only to this software file. Patent licenses, if ++# any, provided herein do not apply to combinations of this program with ++# other software, or any other product whatsoever. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write the Free Software Foundation, ++# Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. ++# ++ ++## ++# README. ++# ++# This agent only supports being configured as a multistate Master ++# resource. ++# ++# Slave vs Master role: ++# ++# During the 'Slave' role, galera instances are in read-only mode and ++# will not attempt to connect to the cluster. This role exists only as ++# a means to determine which galera instance is the most up-to-date. The ++# most up-to-date node will be used to bootstrap a galera cluster that ++# has no current members. ++# ++# The galera instances will only begin to be promoted to the Master role ++# once all the nodes in the 'wsrep_cluster_address' connection address ++# have entered read-only mode. At that point the node containing the ++# database that is most current will be promoted to Master. Once the first ++# Master instance bootstraps the galera cluster, the other nodes will be ++# promoted to Master as well. ++# ++# Example: Create a galera cluster using nodes rhel7-node1 rhel7-node2 rhel7-node3 ++# ++# pcs resource create db galera enable_creation=true \ ++# wsrep_cluster_address="gcomm://rhel7-auto1,rhel7-auto2,rhel7-auto3" meta master-max=3 --master ++# ++# By setting the 'enable_creation' option, the database will be automatically ++# generated at startup. The meta attribute 'master-max=3' means that all 3 ++# nodes listed in the wsrep_cluster_address list will be allowed to connect ++# to the galera cluster and perform replication. ++# ++# NOTE: If you have more nodes in the pacemaker cluster then you wish ++# to have in the galera cluster, make sure to use location contraints to prevent ++# pacemaker from attempting to place a galera instance on a node that is ++# not in the 'wsrep_cluster_address" list. ++# ++## ++ ++####################################################################### ++# Initialization: ++ ++: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat} ++. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs ++. ${OCF_FUNCTIONS_DIR}/mysql-common.sh ++ ++# It is common for some galera instances to store ++# check user that can be used to query status ++# in this file ++if [ -f "/etc/sysconfig/clustercheck" ]; then ++ . /etc/sysconfig/clustercheck ++fi ++ ++####################################################################### ++ ++usage() { ++ cat < ++ ++ ++1.0 ++ ++ ++Resource script for managing galara database. ++ ++Manages a galara instance ++ ++ ++ ++ ++Location of the MySQL server binary ++ ++MySQL server binary ++ ++ ++ ++ ++ ++Location of the MySQL client binary ++ ++MySQL client binary ++ ++ ++ ++ ++ ++Configuration file ++ ++MySQL config ++ ++ ++ ++ ++ ++Directory containing databases ++ ++MySQL datadir ++ ++ ++ ++ ++ ++User running MySQL daemon ++ ++MySQL user ++ ++ ++ ++ ++ ++Group running MySQL daemon (for logfile and directory permissions) ++ ++MySQL group ++ ++ ++ ++ ++ ++The logfile to be used for mysqld. ++ ++MySQL log file ++ ++ ++ ++ ++ ++The pidfile to be used for mysqld. ++ ++MySQL pid file ++ ++ ++ ++ ++ ++The socket to be used for mysqld. ++ ++MySQL socket ++ ++ ++ ++ ++ ++If the MySQL database does not exist, it will be created ++ ++Create the database if it does not exist ++ ++ ++ ++ ++ ++Additional parameters which are passed to the mysqld on startup. ++(e.g. --skip-external-locking or --skip-grant-tables) ++ ++Additional parameters to pass to mysqld ++ ++ ++ ++ ++ ++ ++The galera cluster address. This takes the form of: ++gcomm://node,node,node ++ ++Only nodes present in this node list will be allowed to start a galera instance. ++It is expected that the galera node names listed in this address match valid ++pacemaker node names. ++ ++Galera cluster address ++ ++ ++ ++ ++ ++Cluster check user. ++ ++MySQL test user ++ ++ ++ ++ ++ ++Cluster check user password ++ ++check password ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++END ++} ++ ++get_option_variable() ++{ ++ local key=$1 ++ ++ $MYSQL $MYSQL_OPTIONS_CHECK -e "SHOW VARIABLES like '$key';" | tail -1 ++} ++ ++get_status_variable() ++{ ++ local key=$1 ++ ++ $MYSQL $MYSQL_OPTIONS_CHECK -e "show status like '$key';" | tail -1 ++} ++ ++set_bootstrap_node() ++{ ++ local node=$1 ++ ++ ${HA_SBIN_DIR}/crm_attribute -N $node -l reboot --name "${INSTANCE_ATTR_NAME}-bootstrap" -v "true" ++} ++ ++clear_bootstrap_node() ++{ ++ ${HA_SBIN_DIR}/crm_attribute -N $NODENAME -l reboot --name "${INSTANCE_ATTR_NAME}-bootstrap" -D ++} ++ ++is_bootstrap() ++{ ++ ${HA_SBIN_DIR}/crm_attribute -N $NODENAME -l reboot --name "${INSTANCE_ATTR_NAME}-bootstrap" -Q 2>/dev/null ++ ++} ++ ++clear_last_commit() ++{ ++ ${HA_SBIN_DIR}/crm_attribute -N $NODENAME -l reboot --name "${INSTANCE_ATTR_NAME}-last-committed" -D ++} ++ ++set_last_commit() ++{ ++ ${HA_SBIN_DIR}/crm_attribute -N $NODENAME -l reboot --name "${INSTANCE_ATTR_NAME}-last-committed" -v $1 ++} ++ ++get_last_commit() ++{ ++ local node=$1 ++ ++ if [ -z "$node" ]; then ++ ${HA_SBIN_DIR}/crm_attribute -N $NODENAME -l reboot --name "${INSTANCE_ATTR_NAME}-last-committed" -Q 2>/dev/null ++ else ++ ${HA_SBIN_DIR}/crm_attribute -N $node -l reboot --name "${INSTANCE_ATTR_NAME}-last-committed" -Q 2>/dev/null ++ fi ++} ++ ++wait_for_sync() ++{ ++ local state=$(get_status_variable "wsrep_local_state") ++ ++ ocf_log info "Waiting for database to sync with the cluster. " ++ while [ "$state" != "4" ]; do ++ sleep 1 ++ state=$(get_status_variable "wsrep_local_state") ++ done ++ ocf_log info "Database synced." ++} ++ ++is_primary() ++{ ++ cluster_status=$(get_status_variable "wsrep_cluster_status") ++ if [ "$cluster_status" = "Primary" ]; then ++ return 0 ++ fi ++ ++ if [ -z "$cluster_status" ]; then ++ ocf_log err "Unable to retrieve wsrep_cluster_status, verify check_user '$OCF_RESKEY_check_user' has permissions to view status" ++ else ++ ocf_log info "Galera instance wsrep_cluster_status=${cluster_status}" ++ fi ++ return 1 ++} ++ ++is_readonly() ++{ ++ local res=$(get_option_variable "read_only") ++ ++ if ! ocf_is_true "$res"; then ++ return 1 ++ fi ++ ++ cluster_status=$(get_status_variable "wsrep_cluster_status") ++ if ! [ "$cluster_status" = "Disconnected" ]; then ++ return 1 ++ fi ++ ++ return 0 ++} ++ ++master_exists() ++{ ++ # determine if a master instance is already up and is healthy ++ crm_mon --as-xml | grep "resource.*id=\"${OCF_RESOURCE_INSTANCE}\".*role=\"Master\".*active=\"true\".*orphaned=\"false\".*failed=\"false\"" > /dev/null 2>&1 ++ return $? ++} ++ ++clear_master_score() ++{ ++ local node=$1 ++ if [ -z "$node" ]; then ++ $CRM_MASTER -D ++ else ++ $CRM_MASTER -D -N $node ++ fi ++} ++ ++set_master_score() ++{ ++ local node=$1 ++ ++ if [ -z "$node" ]; then ++ $CRM_MASTER -v 100 ++ else ++ $CRM_MASTER -N $node -v 100 ++ fi ++} ++ ++promote_everyone() ++{ ++ ++ for node in $(echo "$OCF_RESKEY_wsrep_cluster_address" | sed 's/gcomm:\/\///g' | tr -d ' ' | tr -s ',' ' '); do ++ ++ set_master_score $node ++ done ++} ++ ++greater_than_equal_long() ++{ ++ # there are values we need to compare in this script ++ # that are too large for shell -gt to process ++ echo | awk -v n1="$1" -v n2="$2" '{if (n1>=n2) printf ("true"); else printf ("false");}' | grep -q "true" ++} ++ ++detect_first_master() ++{ ++ local best_commit=0 ++ local best_node="$NODENAME" ++ local last_commit=0 ++ local missing_nodes=0 ++ ++ for node in $(echo "$OCF_RESKEY_wsrep_cluster_address" | sed 's/gcomm:\/\///g' | tr -d ' ' | tr -s ',' ' '); do ++ last_commit=$(get_last_commit $node) ++ ++ if [ -z "$last_commit" ]; then ++ ocf_log info "Waiting on node <${node}> to report database status before Master instances can start." ++ missing_nodes=1 ++ continue ++ fi ++ ++ # this means -1, or that no commit has occured yet. ++ if [ "$last_commit" = "18446744073709551615" ]; then ++ last_commit="0" ++ fi ++ ++ greater_than_equal_long "$last_commit" "$best_commit" ++ if [ $? -eq 0 ]; then ++ best_node=$node ++ best_commit=$last_commit ++ fi ++ ++ done ++ ++ if [ $missing_nodes -eq 1 ]; then ++ return ++ fi ++ ++ ocf_log info "Promoting $best_node to be our bootstrap node" ++ set_master_score $best_node ++ set_bootstrap_node $best_node ++} ++ ++# For galera, promote is really start ++galera_promote() ++{ ++ local rc ++ local extra_opts ++ local bootstrap ++ ++ master_exists ++ if [ $? -eq 0 ]; then ++ # join without bootstrapping ++ extra_opts="--wsrep-cluster-address=${OCF_RESKEY_wsrep_cluster_address}" ++ else ++ bootstrap=$(is_bootstrap) ++ ++ if ocf_is_true $bootstrap; then ++ ocf_log info "Node <${NODENAME}> is bootstrapping the cluster" ++ extra_opts="--wsrep-cluster-address=gcomm://" ++ else ++ ocf_log err "Failure, Attempted to promote Master instance of $OCF_RESOURCE_INSTANCE before bootstrap node has been detected." ++ return $OCF_ERR_GENERIC ++ fi ++ ++ fi ++ ++ # make sure the read only instance is stopped ++ mysql_common_stop ++ rc=$? ++ if [ $rc -ne $OCF_SUCCESS ] && [ $rc -ne $OCF_NOT_RUNNING ]; then ++ ocf_log err "Failed to stop read-only galera instance during promotion to Master" ++ return $rc ++ fi ++ ++ sleep 4 ++ ++ mysql_common_prepare_dirs ++ mysql_common_start "$extra_opts" ++ rc=$? ++ if [ $rc != $OCF_SUCCESS ]; then ++ return $rc ++ fi ++ ++ galera_monitor ++ rc=$? ++ if [ $rc != $OCF_SUCCESS -a $rc != $OCF_RUNNING_MASTER ]; then ++ ocf_log err "Failed initial monitor action" ++ return $rc ++ fi ++ ++ is_readonly ++ if [ $? -eq 0 ]; then ++ ocf_log err "Failure. Master instance started in read-only mode, check configuration." ++ return $OCF_ERR_GENERIC ++ fi ++ ++ is_primary ++ if [ $? -ne 0 ]; then ++ ocf_log err "Failure. Master instance started, but is not in Primary mode." ++ return $OCF_ERR_GENERIC ++ fi ++ ++ if ocf_is_true $bootstrap; then ++ promote_everyone ++ clear_bootstrap_node ++ ocf_log info "Bootstrap complete, promoting the rest of the galera instances." ++ else ++ # if this is not the bootstrap node, make sure this instance ++ # syncs with the rest of the cluster before promotion returns. ++ wait_for_sync ++ fi ++ ++ # last commit is no longer relevant once promoted ++ clear_last_commit ++ ++ ocf_log info "Galera started" ++ return $OCF_SUCCESS ++} ++ ++galera_demote() ++{ ++ mysql_common_stop ++ rc=$? ++ if [ $rc -ne $OCF_SUCCESS ] && [ $rc -ne $OCF_NOT_RUNNING ]; then ++ ocf_log err "Failed to stop Master galera instance during demotion to Master" ++ return $rc ++ fi ++ ++ # if this node was previously a bootstrap node, that is no longer the case. ++ clear_bootstrap_node ++ ++ # start again in slave mode so the new last commit is recorded ++ galera_start ++} ++ ++galera_start() ++{ ++ local extra_opts='--read-only=true' ++ local last_commit ++ ++ echo $OCF_RESKEY_wsrep_cluster_address | grep -q $NODENAME ++ if [ $? -ne 0 ]; then ++ ocf_log err "local node <${NODENAME}> must be a member of the wsrep_cluster_address <${OCF_RESKEY_wsrep_cluster_address}>to start this galera instance" ++ return $OCF_ERR_CONFIGURED ++ fi ++ ++ mysql_common_prepare_dirs ++ mysql_common_start "$extra_opts" ++ ++ is_readonly ++ if [ $? -ne 0 ]; then ++ ocf_log err "Failure. Slave instance did not start correctly in read-only mode, Make sure local galera.cnf does not have wsrep_cluster_address set." ++ return $OCF_ERR_GENERIC ++ fi ++ ++ ocf_log info "attempting to detect last commit version" ++ while [ -z "$last_commit" ]; do ++ last_commit=$(get_status_variable "wsrep_last_committed") ++ if [ -z "$last_commit" ]; then ++ sleep 1 ++ fi ++ done ++ ocf_log info "Last commit version found: $last_commit" ++ ++ set_last_commit $last_commit ++ ++ master_exists ++ if [ $? -eq 0 ]; then ++ ocf_log info "Master instances are already up, setting master score so this instance will join galera cluster." ++ set_master_score $NODENAME ++ else ++ clear_master_score ++ detect_first_master ++ fi ++ ++ return $OCF_SUCCESS ++} ++ ++galera_monitor() ++{ ++ local rc ++ local status_loglevel="err" ++ ++ # Set loglevel to info during probe ++ if ocf_is_probe; then ++ status_loglevel="info" ++ fi ++ ++ mysql_common_status $status_loglevel ++ rc=$? ++ ++ # If status returned an error, return that immediately ++ if [ $rc -ne $OCF_SUCCESS ]; then ++ return $rc ++ fi ++ ++ echo $OCF_RESKEY_wsrep_cluster_address | grep -q $NODENAME ++ if [ $? -ne 0 ]; then ++ ocf_log err "local node <${NODENAME}> is started, but is not a member of the wsrep_cluster_address <${OCF_RESKEY_wsrep_cluster_address}>" ++ return $OCF_ERR_GENERIC ++ fi ++ ++ is_readonly ++ if [ $? -ne 0 ]; then ++ is_primary ++ if [ $? -ne 0 ]; then ++ ocf_log err "local node <${NODENAME}> is neither in primary mode nor in read_only mode. Unknown state." ++ return $OCF_ERR_GENERIC ++ fi ++ ++ if ocf_is_probe; then ++ # restore master score during probe ++ # if we detect this is a master instance ++ set_master_score ++ fi ++ rc=$OCF_RUNNING_MASTER ++ else ++ master_exists ++ if [ $? -ne 0 ]; then ++ detect_first_master ++ else ++ # a master instance exists and is healthy, promote this ++ # local read only instance ++ # so it can join the master galera cluster. ++ set_master_score ++ fi ++ fi ++ # TODO look at what is done in the wait script ++ ++ return $rc ++} ++ ++galera_stop() ++{ ++ local rc ++ # make sure the process is stopped ++ mysql_common_stop ++ rc=$1 ++ ++ clear_last_commit ++ clear_master_score ++ clear_bootstrap_node ++ return $rc ++} ++ ++galera_validate() ++{ ++ if ! ocf_is_ms; then ++ ocf_log err "Galera must be configured as a multistate Master/Slave resource." ++ return $OCF_ERR_CONFIGURED ++ fi ++ ++ if [ -z "$OCF_RESKEY_wsrep_cluster_address" ]; then ++ ocf_log err "Galera must be configured with a wsrep_cluster_address value." ++ return $OCF_ERR_CONFIGURED ++ fi ++ ++ mysql_common_validate ++} ++ ++case "$1" in ++ meta-data) meta_data ++ exit $OCF_SUCCESS;; ++ usage|help) usage ++ exit $OCF_SUCCESS;; ++esac ++ ++galera_validate ++rc=$? ++LSB_STATUS_STOPPED=3 ++if [ $rc -ne 0 ]; then ++ case "$1" in ++ stop) exit $OCF_SUCCESS;; ++ monitor) exit $OCF_NOT_RUNNING;; ++ status) exit $LSB_STATUS_STOPPED;; ++ *) exit $rc;; ++ esac ++fi ++ ++if [ -z "${OCF_RESKEY_check_passwd}" ]; then ++ # This value is automatically sourced from /etc/sysconfig/checkcluster if available ++ OCF_RESKEY_check_passwd=${MYSQL_PASSWORD} ++fi ++if [ -z "${OCF_RESKEY_check_user}" ]; then ++ # This value is automatically sourced from /etc/sysconfig/checkcluster if available ++ OCF_RESKEY_check_user=${MYSQL_USERNAME} ++fi ++: ${OCF_RESKEY_check_user="root"} ++ ++MYSQL_OPTIONS_CHECK="-nNE --user=${OCF_RESKEY_check_user}" ++if [ -n "${OCF_RESKEY_check_passwd}" ]; then ++ MYSQL_OPTIONS_CHECK="$MYSQL_OPTIONS_CHECK --password=${MYSQL_PASSWORD}" ++fi ++ ++# What kind of method was invoked? ++case "$1" in ++ start) galera_start;; ++ stop) galera_stop;; ++ status) mysql_common_status err;; ++ monitor) galera_monitor;; ++ promote) galera_promote;; ++ demote) galera_demote;; ++ notify) galera_notify;; ++ validate-all) exit $OCF_SUCCESS;; ++ ++ *) usage ++ exit $OCF_ERR_UNIMPLEMENTED;; ++esac ++ ++# vi:sw=4:ts=4:et: +diff --git a/heartbeat/mysql b/heartbeat/mysql +index f7eb9f2..41287d0 100755 +--- a/heartbeat/mysql ++++ b/heartbeat/mysql +@@ -51,97 +51,7 @@ + + : ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat} + . ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs +- +-####################################################################### +- +-# Attempt to detect a default binary +-OCF_RESKEY_binary_default=$(which mysqld_safe 2> /dev/null) +-if [ "$OCF_RESKEY_binary_default" = "" ]; then +- OCF_RESKEY_binary_default=$(which safe_mysqld 2> /dev/null) +-fi +- +-# Fill in some defaults if no values are specified +-HOSTOS=`uname` +-if [ "X${HOSTOS}" = "XOpenBSD" ];then +- if [ "$OCF_RESKEY_binary_default" = "" ]; then +- OCF_RESKEY_binary_default="/usr/local/bin/mysqld_safe" +- fi +- OCF_RESKEY_config_default="/etc/my.cnf" +- OCF_RESKEY_datadir_default="/var/mysql" +- OCF_RESKEY_user_default="_mysql" +- OCF_RESKEY_group_default="_mysql" +- OCF_RESKEY_log_default="/var/log/mysqld.log" +- OCF_RESKEY_pid_default="/var/mysql/mysqld.pid" +- OCF_RESKEY_socket_default="/var/run/mysql/mysql.sock" +-else +- if [ "$OCF_RESKEY_binary_default" = "" ]; then +- OCF_RESKEY_binary_default="/usr/bin/safe_mysqld" +- fi +- OCF_RESKEY_config_default="/etc/my.cnf" +- OCF_RESKEY_datadir_default="/var/lib/mysql" +- OCF_RESKEY_user_default="mysql" +- OCF_RESKEY_group_default="mysql" +- OCF_RESKEY_log_default="/var/log/mysqld.log" +- OCF_RESKEY_pid_default="/var/run/mysql/mysqld.pid" +- OCF_RESKEY_socket_default="/var/lib/mysql/mysql.sock" +-fi +-OCF_RESKEY_client_binary_default="mysql" +-OCF_RESKEY_test_user_default="root" +-OCF_RESKEY_test_table_default="mysql.user" +-OCF_RESKEY_test_passwd_default="" +-OCF_RESKEY_enable_creation_default=0 +-OCF_RESKEY_additional_parameters_default="" +-OCF_RESKEY_replication_port_default="3306" +-OCF_RESKEY_max_slave_lag_default="3600" +-OCF_RESKEY_evict_outdated_slaves_default="false" +-OCF_RESKEY_reader_attribute_default="readable" +- +-: ${OCF_RESKEY_binary=${OCF_RESKEY_binary_default}} +-MYSQL_BINDIR=`dirname ${OCF_RESKEY_binary}` +- +-: ${OCF_RESKEY_client_binary=${OCF_RESKEY_client_binary_default}} +- +-: ${OCF_RESKEY_config=${OCF_RESKEY_config_default}} +-: ${OCF_RESKEY_datadir=${OCF_RESKEY_datadir_default}} +- +-: ${OCF_RESKEY_user=${OCF_RESKEY_user_default}} +-: ${OCF_RESKEY_group=${OCF_RESKEY_group_default}} +- +-: ${OCF_RESKEY_log=${OCF_RESKEY_log_default}} +-: ${OCF_RESKEY_pid=${OCF_RESKEY_pid_default}} +-: ${OCF_RESKEY_socket=${OCF_RESKEY_socket_default}} +- +-: ${OCF_RESKEY_test_user=${OCF_RESKEY_test_user_default}} +-: ${OCF_RESKEY_test_table=${OCF_RESKEY_test_table_default}} +-: ${OCF_RESKEY_test_passwd=${OCF_RESKEY_test_passwd_default}} +- +-: ${OCF_RESKEY_enable_creation=${OCF_RESKEY_enable_creation_default}} +-: ${OCF_RESKEY_additional_parameters=${OCF_RESKEY_additional_parameters_default}} +- +-: ${OCF_RESKEY_replication_user=${OCF_RESKEY_replication_user_default}} +-: ${OCF_RESKEY_replication_passwd=${OCF_RESKEY_replication_passwd_default}} +-: ${OCF_RESKEY_replication_port=${OCF_RESKEY_replication_port_default}} +- +-: ${OCF_RESKEY_max_slave_lag=${OCF_RESKEY_max_slave_lag_default}} +-: ${OCF_RESKEY_evict_outdated_slaves=${OCF_RESKEY_evict_outdated_slaves_default}} +- +-: ${OCF_RESKEY_reader_attribute=${OCF_RESKEY_reader_attribute_default}} +- +-####################################################################### +-# Convenience variables +- +-MYSQL=$OCF_RESKEY_client_binary +-MYSQL_OPTIONS_LOCAL="-S $OCF_RESKEY_socket --connect_timeout=10" +-MYSQL_OPTIONS_REPL="$MYSQL_OPTIONS_LOCAL --user=$OCF_RESKEY_replication_user --password=$OCF_RESKEY_replication_passwd" +-MYSQL_OPTIONS_TEST="$MYSQL_OPTIONS_LOCAL --user=$OCF_RESKEY_test_user --password=$OCF_RESKEY_test_passwd" +-MYSQL_TOO_MANY_CONN_ERR=1040 +- +-CRM_MASTER="${HA_SBIN_DIR}/crm_master -l reboot " +-NODENAME=$(ocf_local_nodename) +-CRM_ATTR="${HA_SBIN_DIR}/crm_attribute -N $NODENAME " +-INSTANCE_ATTR_NAME=`echo ${OCF_RESOURCE_INSTANCE}| awk -F : '{print $1}'` +-CRM_ATTR_REPL_INFO="${HA_SBIN_DIR}/crm_attribute --type crm_config --name ${INSTANCE_ATTR_NAME}_REPL_INFO -s mysql_replication" +- ++. ${OCF_FUNCTIONS_DIR}/mysql-common.sh + ####################################################################### + + usage() { +@@ -794,57 +704,6 @@ get_local_ip() { + + # Functions invoked by resource manager actions + +-mysql_validate() { +- check_binary $OCF_RESKEY_binary +- check_binary $OCF_RESKEY_client_binary +- +- if [ ! -f $OCF_RESKEY_config ]; then +- ocf_log err "Config $OCF_RESKEY_config doesn't exist"; +- return $OCF_ERR_INSTALLED; +- fi +- +- if [ ! -d $OCF_RESKEY_datadir ]; then +- ocf_log err "Datadir $OCF_RESKEY_datadir doesn't exist"; +- return $OCF_ERR_INSTALLED; +- fi +- +- getent passwd $OCF_RESKEY_user >/dev/null 2>&1 +- if [ ! $? -eq 0 ]; then +- ocf_log err "User $OCF_RESKEY_user doesn't exit"; +- return $OCF_ERR_INSTALLED; +- fi +- +- getent group $OCF_RESKEY_group >/dev/null 2>&1 +- if [ ! $? -eq 0 ]; then +- ocf_log err "Group $OCF_RESKEY_group doesn't exist"; +- return $OCF_ERR_INSTALLED; +- fi +- +- true +-} +- +-mysql_status() { +- if [ ! -e $OCF_RESKEY_pid ]; then +- ocf_log $1 "MySQL is not running" +- return $OCF_NOT_RUNNING; +- fi +- +- pid=`cat $OCF_RESKEY_pid`; +- if [ -d /proc -a -d /proc/1 ]; then +- [ "u$pid" != "u" -a -d /proc/$pid ] +- else +- kill -s 0 $pid >/dev/null 2>&1 +- fi +- +- if [ $? -eq 0 ]; then +- return $OCF_SUCCESS; +- else +- ocf_log $1 "MySQL not running: removing old PID file" +- rm -f $OCF_RESKEY_pid +- return $OCF_NOT_RUNNING; +- fi +-} +- + mysql_monitor() { + local rc + local status_loglevel="err" +@@ -854,7 +713,7 @@ mysql_monitor() { + status_loglevel="info" + fi + +- mysql_status $status_loglevel ++ mysql_common_status $status_loglevel + + rc=$? + +@@ -865,7 +724,6 @@ mysql_monitor() { + return $rc + fi + +- + if [ $OCF_CHECK_LEVEL -gt 0 -a -n "$OCF_RESKEY_test_table" ]; then + # Check if this instance is configured as a slave, and if so + # check slave status +@@ -894,58 +752,20 @@ mysql_monitor() { + } + + mysql_start() { +- local rc pid ++ local rc + + if ocf_is_ms; then + # Initialize the ReaderVIP attribute, monitor will enable it + set_reader_attr 0 + fi + +- mysql_status info ++ mysql_common_status info + if [ $? = $OCF_SUCCESS ]; then + ocf_log info "MySQL already running" + return $OCF_SUCCESS + fi + +- touch $OCF_RESKEY_log +- chown $OCF_RESKEY_user:$OCF_RESKEY_group $OCF_RESKEY_log +- chmod 0640 $OCF_RESKEY_log +- [ -x /sbin/restorecon ] && /sbin/restorecon $OCF_RESKEY_log +- +- if ocf_is_true "$OCF_RESKEY_enable_creation" && [ ! -d $OCF_RESKEY_datadir/mysql ] ; then +- ocf_log info "Initializing MySQL database: " +- $MYSQL_BINDIR/mysql_install_db --datadir=$OCF_RESKEY_datadir +- rc=$? +- if [ $rc -ne 0 ] ; then +- ocf_log err "Initialization failed: $rc"; +- exit $OCF_ERR_GENERIC +- fi +- chown -R $OCF_RESKEY_user:$OCF_RESKEY_group $OCF_RESKEY_datadir +- fi +- +- pid_dir=`dirname $OCF_RESKEY_pid` +- if [ ! -d $pid_dir ] ; then +- ocf_log info "Creating PID dir: $pid_dir" +- mkdir -p $pid_dir +- chown $OCF_RESKEY_user:$OCF_RESKEY_group $pid_dir +- fi +- +- socket_dir=`dirname $OCF_RESKEY_socket` +- if [ ! -d $socket_dir ] ; then +- ocf_log info "Creating socket dir: $socket_dir" +- mkdir -p $socket_dir +- chown $OCF_RESKEY_user:$OCF_RESKEY_group $socket_dir +- fi +- +- # Regardless of whether we just created the directory or it +- # already existed, check whether it is writable by the configured +- # user +- for dir in $pid_dir $socket_dir; do +- if ! su -s /bin/sh - $OCF_RESKEY_user -c "test -w $dir"; then +- ocf_log err "Directory $dir is not writable by $OCF_RESKEY_user" +- exit $OCF_ERR_PERM; +- fi +- done ++ mysql_common_prepare_dirs + + # Uncomment to perform permission clensing + # - not convinced this should be enabled by default +@@ -958,34 +778,11 @@ mysql_start() { + mysql_extra_params="--skip-slave-start" + fi + +- ${OCF_RESKEY_binary} --defaults-file=$OCF_RESKEY_config \ +- --pid-file=$OCF_RESKEY_pid \ +- --socket=$OCF_RESKEY_socket \ +- --datadir=$OCF_RESKEY_datadir \ +- --log-error=$OCF_RESKEY_log \ +- --user=$OCF_RESKEY_user $OCF_RESKEY_additional_parameters \ +- $mysql_extra_params >/dev/null 2>&1 & +- pid=$! +- +- # Spin waiting for the server to come up. +- # Let the CRM/LRM time us out if required. +- start_wait=1 +- while [ $start_wait = 1 ]; do +- if ! ps $pid > /dev/null 2>&1; then +- wait $pid +- ocf_log err "MySQL server failed to start (rc=$?), please check your installation" +- return $OCF_ERR_GENERIC +- fi +- mysql_status info +- rc=$? +- if [ $rc = $OCF_SUCCESS ]; then +- start_wait=0 +- elif [ $rc != $OCF_NOT_RUNNING ]; then +- ocf_log info "MySQL start failed: $rc" +- return $rc +- fi +- sleep 2 +- done ++ mysql_common_start $mysql_extra_params ++ rc=$? ++ if [ $rc != $OCF_SUCCESS ]; then ++ return $rc ++ fi + + if ocf_is_ms; then + # We're configured as a stateful resource. We must start as +@@ -1035,7 +832,6 @@ mysql_start() { + } + + mysql_stop() { +- + if ocf_is_ms; then + # clear preference for becoming master + $CRM_MASTER -D +@@ -1044,52 +840,13 @@ mysql_stop() { + set_reader_attr 0 + fi + +- if [ ! -f $OCF_RESKEY_pid ]; then +- ocf_log info "MySQL is not running" +- return $OCF_SUCCESS +- fi +- +- pid=`cat $OCF_RESKEY_pid 2> /dev/null ` +- /bin/kill $pid > /dev/null +- rc=$? +- if [ $rc != 0 ]; then +- ocf_log err "MySQL couldn't be stopped" +- return $OCF_ERR_GENERIC +- fi +- # stop waiting +- shutdown_timeout=15 +- if [ -n "$OCF_RESKEY_CRM_meta_timeout" ]; then +- shutdown_timeout=$((($OCF_RESKEY_CRM_meta_timeout/1000)-5)) +- fi +- count=0 +- while [ $count -lt $shutdown_timeout ] +- do +- mysql_status info +- rc=$? +- if [ $rc = $OCF_NOT_RUNNING ]; then +- break +- fi +- count=`expr $count + 1` +- sleep 1 +- ocf_log debug "MySQL still hasn't stopped yet. Waiting..." +- done +- +- mysql_status info +- if [ $? != $OCF_NOT_RUNNING ]; then +- ocf_log info "MySQL failed to stop after ${shutdown_timeout}s using SIGTERM. Trying SIGKILL..." +- /bin/kill -KILL $pid > /dev/null +- fi +- +- ocf_log info "MySQL stopped"; +- rm -f /var/lock/subsys/mysqld +- rm -f $OCF_RESKEY_socket +- return $OCF_SUCCESS ++ mysql_common_stop + } + + mysql_promote() { + local master_info + +- if ( ! mysql_status err ); then ++ if ( ! mysql_common_status err ); then + return $OCF_NOT_RUNNING + fi + ocf_run $MYSQL $MYSQL_OPTIONS_REPL \ +@@ -1115,7 +872,7 @@ mysql_promote() { + } + + mysql_demote() { +- if ! mysql_status err; then ++ if ! mysql_common_status err; then + return $OCF_NOT_RUNNING + fi + +@@ -1244,7 +1001,7 @@ case "$1" in + exit $OCF_SUCCESS;; + esac + +-mysql_validate ++mysql_common_validate + rc=$? + LSB_STATUS_STOPPED=3 + if [ $rc -ne 0 ]; then +@@ -1260,7 +1017,7 @@ fi + case "$1" in + start) mysql_start;; + stop) mysql_stop;; +- status) mysql_status err;; ++ status) mysql_common_status err;; + monitor) mysql_monitor;; + promote) mysql_promote;; + demote) mysql_demote;; +diff --git a/heartbeat/mysql-common.sh b/heartbeat/mysql-common.sh +new file mode 100644 +index 0000000..5b6a991 +--- /dev/null ++++ b/heartbeat/mysql-common.sh +@@ -0,0 +1,279 @@ ++#!/bin/sh ++ ++####################################################################### ++ ++# Attempt to detect a default binary ++OCF_RESKEY_binary_default=$(which mysqld_safe 2> /dev/null) ++if [ "$OCF_RESKEY_binary_default" = "" ]; then ++ OCF_RESKEY_binary_default=$(which safe_mysqld 2> /dev/null) ++fi ++ ++# Fill in some defaults if no values are specified ++HOSTOS=`uname` ++if [ "X${HOSTOS}" = "XOpenBSD" ];then ++ if [ "$OCF_RESKEY_binary_default" = "" ]; then ++ OCF_RESKEY_binary_default="/usr/local/bin/mysqld_safe" ++ fi ++ OCF_RESKEY_config_default="/etc/my.cnf" ++ OCF_RESKEY_datadir_default="/var/mysql" ++ OCF_RESKEY_user_default="_mysql" ++ OCF_RESKEY_group_default="_mysql" ++ OCF_RESKEY_log_default="/var/log/mysqld.log" ++ OCF_RESKEY_pid_default="/var/mysql/mysqld.pid" ++ OCF_RESKEY_socket_default="/var/run/mysql/mysql.sock" ++else ++ if [ "$OCF_RESKEY_binary_default" = "" ]; then ++ OCF_RESKEY_binary_default="/usr/bin/safe_mysqld" ++ fi ++ OCF_RESKEY_config_default="/etc/my.cnf" ++ OCF_RESKEY_datadir_default="/var/lib/mysql" ++ OCF_RESKEY_user_default="mysql" ++ OCF_RESKEY_group_default="mysql" ++ OCF_RESKEY_log_default="/var/log/mysqld.log" ++ OCF_RESKEY_pid_default="/var/run/mysql/mysqld.pid" ++ OCF_RESKEY_socket_default="/var/lib/mysql/mysql.sock" ++fi ++OCF_RESKEY_client_binary_default="mysql" ++OCF_RESKEY_test_user_default="root" ++OCF_RESKEY_test_table_default="mysql.user" ++OCF_RESKEY_test_passwd_default="" ++OCF_RESKEY_enable_creation_default=0 ++OCF_RESKEY_additional_parameters_default="" ++OCF_RESKEY_replication_port_default="3306" ++OCF_RESKEY_max_slave_lag_default="3600" ++OCF_RESKEY_evict_outdated_slaves_default="false" ++OCF_RESKEY_reader_attribute_default="readable" ++ ++: ${OCF_RESKEY_binary=${OCF_RESKEY_binary_default}} ++MYSQL_BINDIR=`dirname ${OCF_RESKEY_binary}` ++ ++: ${OCF_RESKEY_client_binary=${OCF_RESKEY_client_binary_default}} ++ ++: ${OCF_RESKEY_config=${OCF_RESKEY_config_default}} ++: ${OCF_RESKEY_datadir=${OCF_RESKEY_datadir_default}} ++ ++: ${OCF_RESKEY_user=${OCF_RESKEY_user_default}} ++: ${OCF_RESKEY_group=${OCF_RESKEY_group_default}} ++ ++: ${OCF_RESKEY_log=${OCF_RESKEY_log_default}} ++: ${OCF_RESKEY_pid=${OCF_RESKEY_pid_default}} ++: ${OCF_RESKEY_socket=${OCF_RESKEY_socket_default}} ++ ++: ${OCF_RESKEY_test_user=${OCF_RESKEY_test_user_default}} ++: ${OCF_RESKEY_test_table=${OCF_RESKEY_test_table_default}} ++: ${OCF_RESKEY_test_passwd=${OCF_RESKEY_test_passwd_default}} ++ ++: ${OCF_RESKEY_enable_creation=${OCF_RESKEY_enable_creation_default}} ++: ${OCF_RESKEY_additional_parameters=${OCF_RESKEY_additional_parameters_default}} ++ ++: ${OCF_RESKEY_replication_user=${OCF_RESKEY_replication_user_default}} ++: ${OCF_RESKEY_replication_passwd=${OCF_RESKEY_replication_passwd_default}} ++: ${OCF_RESKEY_replication_port=${OCF_RESKEY_replication_port_default}} ++ ++: ${OCF_RESKEY_max_slave_lag=${OCF_RESKEY_max_slave_lag_default}} ++: ${OCF_RESKEY_evict_outdated_slaves=${OCF_RESKEY_evict_outdated_slaves_default}} ++ ++: ${OCF_RESKEY_reader_attribute=${OCF_RESKEY_reader_attribute_default}} ++ ++####################################################################### ++# Convenience variables ++ ++MYSQL=$OCF_RESKEY_client_binary ++MYSQL_OPTIONS_LOCAL="-S $OCF_RESKEY_socket --connect_timeout=10" ++MYSQL_OPTIONS_REPL="$MYSQL_OPTIONS_LOCAL --user=$OCF_RESKEY_replication_user --password=$OCF_RESKEY_replication_passwd" ++MYSQL_OPTIONS_TEST="$MYSQL_OPTIONS_LOCAL --user=$OCF_RESKEY_test_user --password=$OCF_RESKEY_test_passwd" ++MYSQL_TOO_MANY_CONN_ERR=1040 ++ ++CRM_MASTER="${HA_SBIN_DIR}/crm_master -l reboot " ++NODENAME=$(ocf_local_nodename) ++CRM_ATTR="${HA_SBIN_DIR}/crm_attribute -N $NODENAME " ++INSTANCE_ATTR_NAME=`echo ${OCF_RESOURCE_INSTANCE}| awk -F : '{print $1}'` ++CRM_ATTR_REPL_INFO="${HA_SBIN_DIR}/crm_attribute --type crm_config --name ${INSTANCE_ATTR_NAME}_REPL_INFO -s mysql_replication" ++ ++####################################################################### ++ ++mysql_common_validate() ++{ ++ check_binary $OCF_RESKEY_binary ++ check_binary $OCF_RESKEY_client_binary ++ ++ if [ ! -f $OCF_RESKEY_config ]; then ++ ocf_log err "Config $OCF_RESKEY_config doesn't exist"; ++ return $OCF_ERR_INSTALLED; ++ fi ++ ++ if [ ! -d $OCF_RESKEY_datadir ]; then ++ ocf_log err "Datadir $OCF_RESKEY_datadir doesn't exist"; ++ return $OCF_ERR_INSTALLED; ++ fi ++ ++ getent passwd $OCF_RESKEY_user >/dev/null 2>&1 ++ if [ ! $? -eq 0 ]; then ++ ocf_log err "User $OCF_RESKEY_user doesn't exit"; ++ return $OCF_ERR_INSTALLED; ++ fi ++ ++ getent group $OCF_RESKEY_group >/dev/null 2>&1 ++ if [ ! $? -eq 0 ]; then ++ ocf_log err "Group $OCF_RESKEY_group doesn't exist"; ++ return $OCF_ERR_INSTALLED; ++ fi ++ ++ return $OCF_SUCCESS ++} ++ ++mysql_common_status() { ++ local loglevel=$1 ++ local pid=$2 ++ if [ -z "$pid" ]; then ++ if [ ! -e $OCF_RESKEY_pid ]; then ++ ocf_log $loglevel "MySQL is not running" ++ return $OCF_NOT_RUNNING; ++ fi ++ ++ pid=`cat $OCF_RESKEY_pid`; ++ fi ++ if [ -d /proc -a -d /proc/1 ]; then ++ [ "u$pid" != "u" -a -d /proc/$pid ] ++ else ++ kill -s 0 $pid >/dev/null 2>&1 ++ fi ++ ++ if [ $? -eq 0 ]; then ++ return $OCF_SUCCESS; ++ else ++ ocf_log $loglevel "MySQL not running: removing old PID file" ++ rm -f $OCF_RESKEY_pid ++ return $OCF_NOT_RUNNING; ++ fi ++} ++ ++mysql_common_prepare_dirs() ++{ ++ local rc ++ ++ touch $OCF_RESKEY_log ++ chown $OCF_RESKEY_user:$OCF_RESKEY_group $OCF_RESKEY_log ++ chmod 0640 $OCF_RESKEY_log ++ [ -x /sbin/restorecon ] && /sbin/restorecon $OCF_RESKEY_log ++ ++ if ocf_is_true "$OCF_RESKEY_enable_creation" && [ ! -d $OCF_RESKEY_datadir/mysql ] ; then ++ ocf_log info "Initializing MySQL database: " ++ $MYSQL_BINDIR/mysql_install_db --datadir=$OCF_RESKEY_datadir ++ rc=$? ++ if [ $rc -ne 0 ] ; then ++ ocf_log err "Initialization failed: $rc"; ++ exit $OCF_ERR_GENERIC ++ fi ++ chown -R $OCF_RESKEY_user:$OCF_RESKEY_group $OCF_RESKEY_datadir ++ fi ++ ++ pid_dir=`dirname $OCF_RESKEY_pid` ++ if [ ! -d $pid_dir ] ; then ++ ocf_log info "Creating PID dir: $pid_dir" ++ mkdir -p $pid_dir ++ chown $OCF_RESKEY_user:$OCF_RESKEY_group $pid_dir ++ fi ++ ++ socket_dir=`dirname $OCF_RESKEY_socket` ++ if [ ! -d $socket_dir ] ; then ++ ocf_log info "Creating socket dir: $socket_dir" ++ mkdir -p $socket_dir ++ chown $OCF_RESKEY_user:$OCF_RESKEY_group $socket_dir ++ fi ++ ++ # Regardless of whether we just created the directory or it ++ # already existed, check whether it is writable by the configured ++ # user ++ for dir in $pid_dir $socket_dir; do ++ if ! su -s /bin/sh - $OCF_RESKEY_user -c "test -w $dir"; then ++ ocf_log err "Directory $dir is not writable by $OCF_RESKEY_user" ++ exit $OCF_ERR_PERM; ++ fi ++ done ++} ++ ++mysql_common_start() ++{ ++ local mysql_extra_params="$1" ++ local pid ++ ++ ${OCF_RESKEY_binary} --defaults-file=$OCF_RESKEY_config \ ++ --pid-file=$OCF_RESKEY_pid \ ++ --socket=$OCF_RESKEY_socket \ ++ --datadir=$OCF_RESKEY_datadir \ ++ --log-error=$OCF_RESKEY_log \ ++ --user=$OCF_RESKEY_user $OCF_RESKEY_additional_parameters \ ++ $mysql_extra_params >/dev/null 2>&1 & ++ pid=$! ++ ++ # Spin waiting for the server to come up. ++ # Let the CRM/LRM time us out if required. ++ start_wait=1 ++ while [ $start_wait = 1 ]; do ++ if ! ps $pid > /dev/null 2>&1; then ++ wait $pid ++ ocf_log err "MySQL server failed to start (pid=$pid) (rc=$?), please check your installation" ++ return $OCF_ERR_GENERIC ++ fi ++ mysql_common_status info ++ rc=$? ++ if [ $rc = $OCF_SUCCESS ]; then ++ start_wait=0 ++ elif [ $rc != $OCF_NOT_RUNNING ]; then ++ ocf_log info "MySQL start failed: $rc" ++ return $rc ++ fi ++ sleep 2 ++ done ++ ++ return $OCF_SUCCESS ++} ++ ++mysql_common_stop() ++{ ++ local pid ++ local rc ++ ++ if [ ! -f $OCF_RESKEY_pid ]; then ++ ocf_log info "MySQL is not running" ++ return $OCF_SUCCESS ++ fi ++ ++ pid=`cat $OCF_RESKEY_pid 2> /dev/null ` ++ /bin/kill $pid > /dev/null ++ rc=$? ++ if [ $rc != 0 ]; then ++ ocf_log err "MySQL couldn't be stopped" ++ return $OCF_ERR_GENERIC ++ fi ++ # stop waiting ++ shutdown_timeout=15 ++ if [ -n "$OCF_RESKEY_CRM_meta_timeout" ]; then ++ shutdown_timeout=$((($OCF_RESKEY_CRM_meta_timeout/1000)-5)) ++ fi ++ count=0 ++ while [ $count -lt $shutdown_timeout ] ++ do ++ mysql_common_status info $pid ++ rc=$? ++ if [ $rc = $OCF_NOT_RUNNING ]; then ++ break ++ fi ++ count=`expr $count + 1` ++ sleep 1 ++ ocf_log debug "MySQL still hasn't stopped yet. Waiting..." ++ done ++ ++ mysql_common_status info $pid ++ if [ $? != $OCF_NOT_RUNNING ]; then ++ ocf_log info "MySQL failed to stop after ${shutdown_timeout}s using SIGTERM. Trying SIGKILL..." ++ /bin/kill -KILL $pid > /dev/null ++ fi ++ ++ ocf_log info "MySQL stopped"; ++ rm -f /var/lock/subsys/mysqld ++ rm -f $OCF_RESKEY_socket ++ return $OCF_SUCCESS ++ ++} +diff --git a/heartbeat/ocf-shellfuncs.in b/heartbeat/ocf-shellfuncs.in +index 8820961..254da57 100644 +--- a/heartbeat/ocf-shellfuncs.in ++++ b/heartbeat/ocf-shellfuncs.in +@@ -518,6 +518,7 @@ ocf_local_nodename() { + which pacemakerd > /dev/null 2>&1 + if [ $? -eq 0 ]; then + local version=$(pacemakerd -$ | grep "Pacemaker .*" | awk '{ print $2 }') ++ version=$(echo $version | awk -F- '{ print $1 }') + ocf_version_cmp "$version" "1.1.8" + if [ $? -eq 2 ]; then + which crm_node > /dev/null 2>&1 +-- +1.8.4.2 + diff --git a/SOURCES/bz1116166-galera-do-not-ignore-check_password.patch b/SOURCES/bz1116166-galera-do-not-ignore-check_password.patch new file mode 100644 index 00000000..a5d41361 --- /dev/null +++ b/SOURCES/bz1116166-galera-do-not-ignore-check_password.patch @@ -0,0 +1,25 @@ +From e5c5c087ecf152bd69f5795024bfc655394c3c18 Mon Sep 17 00:00:00 2001 +From: Andreas Kurz +Date: Thu, 18 Sep 2014 23:06:36 +0200 +Subject: [PATCH 1/6] High: galera: do not ignore specified check_password + +--- + heartbeat/galera | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/heartbeat/galera b/heartbeat/galera +index 54654f8..386daaf 100755 +--- a/heartbeat/galera ++++ b/heartbeat/galera +@@ -672,7 +672,7 @@ fi + + MYSQL_OPTIONS_CHECK="-nNE --user=${OCF_RESKEY_check_user}" + if [ -n "${OCF_RESKEY_check_passwd}" ]; then +- MYSQL_OPTIONS_CHECK="$MYSQL_OPTIONS_CHECK --password=${MYSQL_PASSWORD}" ++ MYSQL_OPTIONS_CHECK="$MYSQL_OPTIONS_CHECK --password=${OCF_RESKEY_check_passwd}" + fi + + # What kind of method was invoked? +-- +1.8.4.2 + diff --git a/SOURCES/bz1118029-iscsi-agents.patch b/SOURCES/bz1118029-iscsi-agents.patch new file mode 100644 index 00000000..056ae430 --- /dev/null +++ b/SOURCES/bz1118029-iscsi-agents.patch @@ -0,0 +1,1536 @@ +From d4a36f47b36f47a847795660653b7fbc5baab706 Mon Sep 17 00:00:00 2001 +From: David Vossel +Date: Mon, 25 Aug 2014 14:55:50 -0500 +Subject: [PATCH 1/4] iscsi agent updates + +--- + heartbeat/iSCSILogicalUnit | 573 ++++++++++++++++++++++----------------- + heartbeat/iSCSITarget | 661 +++++++++++++++++++++++++-------------------- + 2 files changed, 690 insertions(+), 544 deletions(-) + +diff --git a/heartbeat/iSCSILogicalUnit b/heartbeat/iSCSILogicalUnit +index 0ab4722..c4cee0d 100755 +--- a/heartbeat/iSCSILogicalUnit ++++ b/heartbeat/iSCSILogicalUnit +@@ -3,10 +3,10 @@ + # + # iSCSILogicalUnit OCF RA. Exports and manages iSCSI Logical Units. + # +-# (c) 2013 LINBIT, Lars Ellenberg ++# (c) 2013 LINBIT, Lars Ellenberg + # (c) 2009-2010 Florian Haas, Dejan Muhamedagic, +-# and Linux-HA contributors +-# ++# and Linux-HA contributors ++# + # + # This program is free software; you can redistribute it and/or modify + # it under the terms of version 2 of the GNU General Public License as +@@ -36,11 +36,13 @@ + # Defaults + # Set a default implementation based on software installed + if have_binary ietadm; then +- OCF_RESKEY_implementation_default="iet" ++ OCF_RESKEY_implementation_default="iet" + elif have_binary tgtadm; then +- OCF_RESKEY_implementation_default="tgt" ++ OCF_RESKEY_implementation_default="tgt" + elif have_binary lio_node; then +- OCF_RESKEY_implementation_default="lio" ++ OCF_RESKEY_implementation_default="lio" ++elif have_binary targetcli; then ++ OCF_RESKEY_implementation_default="lio-t" + fi + : ${OCF_RESKEY_implementation=${OCF_RESKEY_implementation_default}} + +@@ -91,9 +93,9 @@ an SCSI Target, exported via a daemon that speaks the iSCSI protocol. + + + The iSCSI target daemon implementation. Must be one of "iet", "tgt", +-or "lio". If unspecified, an implementation is selected based on the ++"lio", or "lio-t". If unspecified, an implementation is selected based on the + availability of management utilities, with "iet" being tried first, +-then "tgt", then "lio". ++then "tgt", then "lio", then "lio-t". + + iSCSI target daemon implementation + +@@ -228,12 +230,12 @@ in /sys/kernel/config/target/core/. + + + +- +- +- +- +- +- ++ ++ ++ ++ ++ ++ + + + END +@@ -250,108 +252,150 @@ END + } + + iSCSILogicalUnit_start() { +- iSCSILogicalUnit_monitor +- if [ $? = $OCF_SUCCESS ]; then +- return $OCF_SUCCESS +- fi ++ iSCSILogicalUnit_monitor ++ if [ $? = $OCF_SUCCESS ]; then ++ return $OCF_SUCCESS ++ fi + +- local params ++ local params + +- case $OCF_RESKEY_implementation in ++ case $OCF_RESKEY_implementation in + iet) +- params="Path=${OCF_RESKEY_path}" +- # use blockio if path points to a block device, fileio +- # otherwise. +- if [ -b "${OCF_RESKEY_path}" ]; then +- params="${params} Type=blockio" +- else +- params="${params} Type=fileio" +- fi +- # in IET, we have to set LU parameters on creation +- if [ -n "${OCF_RESKEY_scsi_id}" ]; then +- params="${params} ScsiId=${OCF_RESKEY_scsi_id}" +- fi +- if [ -n "${OCF_RESKEY_scsi_sn}" ]; then +- params="${params} ScsiSN=${OCF_RESKEY_scsi_sn}" +- fi +- params="${params} ${OCF_RESKEY_additional_parameters}" +- ocf_run ietadm --op new \ +- --tid=${TID} \ +- --lun=${OCF_RESKEY_lun} \ +- --params ${params// /,} || exit $OCF_ERR_GENERIC +- ;; ++ params="Path=${OCF_RESKEY_path}" ++ # use blockio if path points to a block device, fileio ++ # otherwise. ++ if [ -b "${OCF_RESKEY_path}" ]; then ++ params="${params} Type=blockio" ++ else ++ params="${params} Type=fileio" ++ fi ++ # in IET, we have to set LU parameters on creation ++ if [ -n "${OCF_RESKEY_scsi_id}" ]; then ++ params="${params} ScsiId=${OCF_RESKEY_scsi_id}" ++ fi ++ if [ -n "${OCF_RESKEY_scsi_sn}" ]; then ++ params="${params} ScsiSN=${OCF_RESKEY_scsi_sn}" ++ fi ++ params="${params} ${OCF_RESKEY_additional_parameters}" ++ ocf_run ietadm --op new \ ++ --tid=${TID} \ ++ --lun=${OCF_RESKEY_lun} \ ++ --params ${params// /,} || exit $OCF_ERR_GENERIC ++ ;; + tgt) +- # tgt requires that we create the LU first, then set LU +- # parameters +- params="" +- local var +- local envar +- for var in scsi_id scsi_sn vendor_id product_id; do +- envar="OCF_RESKEY_${var}" +- if [ -n "${!envar}" ]; then +- params="${params} ${var}=${!envar}" ++ # tgt requires that we create the LU first, then set LU ++ # parameters ++ params="" ++ local var ++ local envar ++ for var in scsi_id scsi_sn vendor_id product_id; do ++ envar="OCF_RESKEY_${var}" ++ if [ -n "${!envar}" ]; then ++ params="${params} ${var}=${!envar}" ++ fi ++ done ++ params="${params} ${OCF_RESKEY_additional_parameters}" ++ ++ # cleanup: tgt (as of tgtadm version 1.0.24) does not like an explicit "bsoflags=direct" ++ # when used with "bstype=aio" (which always uses O_DIRECT) ++ [[ $OCF_RESKEY_tgt_bstype/$OCF_RESKEY_tgt_bsoflags = "aio/direct" ]] && OCF_RESKEY_tgt_bsoflags="" ++ ++ tgt_args="" ++ [[ $OCF_RESKEY_tgt_bstype ]] && tgt_args="$tgt_args --bstype=$OCF_RESKEY_tgt_bstype" ++ [[ $OCF_RESKEY_tgt_bsoflags ]] && tgt_args="$tgt_args --bsoflags=$OCF_RESKEY_tgt_bsoflags" ++ [[ $OCF_RESKEY_tgt_device_type ]] && tgt_args="$tgt_args --device-type=$OCF_RESKEY_tgt_device_type" ++ ++ ocf_run tgtadm --lld iscsi --op new --mode logicalunit \ ++ --tid=${TID} \ ++ --lun=${OCF_RESKEY_lun} \ ++ $tgt_args \ ++ --backing-store ${OCF_RESKEY_path} || exit $OCF_ERR_GENERIC ++ if [ -z "$params" ]; then ++ return $OCF_SUCCESS ++ else ++ ocf_run tgtadm --lld iscsi --op update --mode logicalunit \ ++ --tid=${TID} \ ++ --lun=${OCF_RESKEY_lun} \ ++ --params ${params// /,} || exit $OCF_ERR_GENERIC ++ fi ++ ;; ++ lio) ++ # For lio, we first have to create a target device, then ++ # add it to the Target Portal Group as an LU. ++ ++ block_configfs_path="/sys/kernel/config/target/core/iblock_${OCF_RESKEY_lio_iblock}/${OCF_RESOURCE_INSTANCE}/udev_path" ++ if [ ! -e "${block_configfs_path}" ]; then ++ ocf_run tcm_node --createdev=iblock_${OCF_RESKEY_lio_iblock}/${OCF_RESOURCE_INSTANCE} \ ++ ${OCF_RESKEY_path} || exit $OCF_ERR_GENERIC ++ elif [ -e "$block_configfs_path" ] && [ $(cat "$block_configfs_path") != "${OCF_RESKEY_path}" ]; then ++ ocf_exit_reason "Existing iblock_${OCF_RESKEY_lio_iblock}/${OCF_RESOURCE_INSTANCE} has incorrect path: $(cat "$block_configfs_path") != ${OCF_RESKEY_path}" ++ exit $OCF_ERR_GENERIC ++ else ++ ocf_log info "iscsi iblock already exists: ${block_configfs_path}" + fi +- done +- params="${params} ${OCF_RESKEY_additional_parameters}" + +- # cleanup: tgt (as of tgtadm version 1.0.24) does not like an explicit "bsoflags=direct" +- # when used with "bstype=aio" (which always uses O_DIRECT) +- [[ $OCF_RESKEY_tgt_bstype/$OCF_RESKEY_tgt_bsoflags = "aio/direct" ]] && OCF_RESKEY_tgt_bsoflags="" ++ if [ -n "${OCF_RESKEY_scsi_sn}" ]; then ++ ocf_run tcm_node --setunitserial=iblock_${OCF_RESKEY_lio_iblock}/${OCF_RESOURCE_INSTANCE} \ ++ ${OCF_RESKEY_scsi_sn} || exit $OCF_ERR_GENERIC ++ fi + +- tgt_args="" +- [[ $OCF_RESKEY_tgt_bstype ]] && tgt_args="$tgt_args --bstype=$OCF_RESKEY_tgt_bstype" +- [[ $OCF_RESKEY_tgt_bsoflags ]] && tgt_args="$tgt_args --bsoflags=$OCF_RESKEY_tgt_bsoflags" +- [[ $OCF_RESKEY_tgt_device_type ]] && tgt_args="$tgt_args --device-type=$OCF_RESKEY_tgt_device_type" ++ lun_configfs_path="/sys/kernel/config/target/iscsi/${OCF_RESKEY_target_iqn}/tpgt_1/lun/lun_${OCF_RESKEY_lun}/${OCF_RESOURCE_INSTANCE}/udev_path" ++ if [ ! -e "${lun_configfs_path}" ]; then ++ ocf_run lio_node --addlun=${OCF_RESKEY_target_iqn} 1 ${OCF_RESKEY_lun} \ ++ ${OCF_RESOURCE_INSTANCE} iblock_${OCF_RESKEY_lio_iblock}/${OCF_RESOURCE_INSTANCE} || exit $OCF_ERR_GENERIC ++ else ++ ocf_log info "iscsi lun already exists: ${lun_configfs_path}" ++ fi + +- ocf_run tgtadm --lld iscsi --op new --mode logicalunit \ +- --tid=${TID} \ +- --lun=${OCF_RESKEY_lun} \ +- $tgt_args \ +- --backing-store ${OCF_RESKEY_path} || exit $OCF_ERR_GENERIC +- if [ -z "$params" ]; then +- return $OCF_SUCCESS +- else +- ocf_run tgtadm --lld iscsi --op update --mode logicalunit \ +- --tid=${TID} \ +- --lun=${OCF_RESKEY_lun} \ +- --params ${params// /,} || exit $OCF_ERR_GENERIC +- fi +- ;; +- lio) +- # For lio, we first have to create a target device, then +- # add it to the Target Portal Group as an LU. +- ocf_run tcm_node --createdev=iblock_${OCF_RESKEY_lio_iblock}/${OCF_RESOURCE_INSTANCE} \ +- ${OCF_RESKEY_path} || exit $OCF_ERR_GENERIC +- if [ -n "${OCF_RESKEY_scsi_sn}" ]; then +- ocf_run tcm_node --setunitserial=iblock_${OCF_RESKEY_lio_iblock}/${OCF_RESOURCE_INSTANCE} \ +- ${OCF_RESKEY_scsi_sn} || exit $OCF_ERR_GENERIC +- fi +- ocf_run lio_node --addlun=${OCF_RESKEY_target_iqn} 1 ${OCF_RESKEY_lun} \ +- ${OCF_RESOURCE_INSTANCE} iblock_${OCF_RESKEY_lio_iblock}/${OCF_RESOURCE_INSTANCE} || exit $OCF_ERR_GENERIC +- +- if [ -n "${OCF_RESKEY_allowed_initiators}" ]; then +- for initiator in ${OCF_RESKEY_allowed_initiators}; do +- ocf_run lio_node --addlunacl=${OCF_RESKEY_target_iqn} 1 \ +- ${initiator} ${OCF_RESKEY_lun} ${OCF_RESKEY_lun} || exit $OCF_ERR_GENERIC +- done +- fi +- ;; +- esac +- +- return $OCF_SUCCESS ++ if [ -n "${OCF_RESKEY_allowed_initiators}" ]; then ++ for initiator in ${OCF_RESKEY_allowed_initiators}; do ++ acl_configfs_path="/sys/kernel/config/target/iscsi/${OCF_RESKEY_target_iqn}/tpgt_1/acls/${initiator}/lun_${OCF_RESKEY_lun}" ++ if [ ! -e "${acl_configfs_path}" ]; then ++ ocf_run lio_node --addlunacl=${OCF_RESKEY_target_iqn} 1 \ ++ ${initiator} ${OCF_RESKEY_lun} ${OCF_RESKEY_lun} || exit $OCF_ERR_GENERIC ++ else ++ ocf_log info "iscsi acl already exists: ${acl_configfs_path}" ++ fi ++ done ++ fi ++ ;; ++ lio-t) ++ # For lio, we first have to create a target device, then ++ # add it to the Target Portal Group as an LU. ++ ocf_run targetcli /backstores/block create name=${OCF_RESOURCE_INSTANCE} dev=${OCF_RESKEY_path} write_back=False || exit $OCF_ERR_GENERIC ++ if [ -n "${OCF_RESKEY_scsi_sn}" ]; then ++ echo ${OCF_RESKEY_scsi_sn} > /sys/kernel/config/target/core/iblock_${OCF_RESKEY_lio_iblock}/${OCF_RESOURCE_INSTANCE}/wwn/vpd_unit_serial ++ fi ++ ocf_run targetcli /iscsi/${OCF_RESKEY_target_iqn}/tpg1/luns create /backstores/block/${OCF_RESOURCE_INSTANCE} ${OCF_RESKEY_lun} || exit $OCF_ERR_GENERIC ++ ++ if [ -n "${OCF_RESKEY_allowed_initiators}" ]; then ++ for initiator in ${OCF_RESKEY_allowed_initiators}; do ++ ocf_run targetcli /iscsi/${OCF_RESKEY_target_iqn}/tpg1/acls create ${initiator} add_mapped_luns=False || exit $OCF_ERR_GENERIC ++ ocf_run targetcli /iscsi/${OCF_RESKEY_target_iqn}/tpg1/acls/${initiator} create ${OCF_RESKEY_lun} ${OCF_RESKEY_lun} || exit $OCF_ERR_GENERIC ++ done ++ fi ++ ;; ++ esac ++ ++ # Force the monitor operation to pass before start is considered a success. ++ iSCSILogicalUnit_monitor + } + + iSCSILogicalUnit_stop() { +- iSCSILogicalUnit_monitor +- if [ $? = $OCF_SUCCESS ]; then ++ iSCSILogicalUnit_monitor ++ if [ $? -eq $OCF_NOT_RUNNING ]; then ++ return $OCF_SUCCESS ++ fi ++ + case $OCF_RESKEY_implementation in +- iet) +- # IET allows us to remove LUs while they are in use +- ocf_run ietadm --op delete \ +- --tid=${TID} \ +- --lun=${OCF_RESKEY_lun} || exit $OCF_ERR_GENERIC ++ ++ iet) ++ # IET allows us to remove LUs while they are in use ++ ocf_run ietadm --op delete \ ++ --tid=${TID} \ ++ --lun=${OCF_RESKEY_lun} || exit $OCF_ERR_GENERIC + ;; +- tgt) ++ tgt) + # tgt will fail to remove an LU while it is in use, + # but at the same time does not allow us to + # selectively shut down a connection that is using a +@@ -359,202 +403,240 @@ iSCSILogicalUnit_stop() { + # decides that the LU is no longer in use, or we get + # timed out by the LRM. + while ! ocf_run -warn tgtadm --lld iscsi --op delete --mode logicalunit \ +- --tid ${TID} \ +- --lun=${OCF_RESKEY_lun}; do +- sleep 1 ++ --tid ${TID} \ ++ --lun=${OCF_RESKEY_lun}; do ++ sleep 1 ++ done ++ ;; ++ lio) ++ ++ acls_configfs_path="/sys/kernel/config/target/iscsi/${OCF_RESKEY_target_iqn}/tpgt_1/acls" ++ for initiatorpath in ${acls_configfs_path}/*; do ++ initiator=$(basename "${initiatorpath}") ++ if [ -e "${initiatorpath}/lun_${OCF_RESKEY_lun}" ]; then ++ ocf_log info "deleting acl at ${initiatorpath}/lun_${OCF_RESKEY_lun}" ++ ocf_run lio_node --dellunacl=${OCF_RESKEY_target_iqn} 1 \ ++ ${initiator} ${OCF_RESKEY_lun} || exit $OCF_ERR_GENERIC ++ fi + done ++ lun_configfs_path="/sys/kernel/config/target/iscsi/${OCF_RESKEY_target_iqn}/tpgt_1/lun/lun_#{${OCF_RESKEY_lun}/" ++ if [ -e "${lun_configfs_path}" ]; then ++ ocf_run lio_node --dellun=${OCF_RESKEY_target_iqn} 1 ${OCF_RESKEY_lun} || exit $OCF_ERR_GENERIC ++ fi ++ block_configfs_path="/sys/kernel/config/target/core/iblock_${OCF_RESKEY_lio_iblock}/${OCF_RESKEY_INSTANCE}/udev_path" ++ if [ -e "${block_configfs_path}" ]; then ++ ocf_run tcm_node --freedev=iblock_${OCF_RESKEY_lio_iblock}/${OCF_RESOURCE_INSTANCE} || exit $OCF_ERR_GENERIC ++ fi ++ ;; ++ lio-t) ++ ocf_run targetcli /iscsi/${OCF_RESKEY_target_iqn}/tpg1/luns delete ${OCF_RESKEY_lun} || exit $OCF_ERR_GENERIC ++ if [ -n "${OCF_RESKEY_allowed_initiators}" ]; then ++ for initiator in ${OCF_RESKEY_allowed_initiators}; do ++ if targetcli /iscsi/${OCF_RESKEY_target_iqn}/tpg1/acls/${initiator} status | grep "Mapped LUNs: 0" >/dev/null ; then ++ ocf_run targetcli /iscsi/${OCF_RESKEY_target_iqn}/tpg1/acls/ delete ${initiator} ++ fi ++ done ++ fi ++ ++ ocf_run targetcli /backstores/block delete ${OCF_RESOURCE_INSTANCE} || exit $OCF_ERR_GENERIC + ;; +- lio) +- if [ -n "${OCF_RESKEY_allowed_initiators}" ]; then +- for initiator in ${OCF_RESKEY_allowed_initiators}; do +- ocf_run lio_node --dellunacl=${OCF_RESKEY_target_iqn} 1 \ +- ${initiator} ${OCF_RESKEY_lun} || exit $OCF_ERR_GENERIC +- done +- fi +- ocf_run lio_node --dellun=${OCF_RESKEY_target_iqn} 1 ${OCF_RESKEY_lun} || exit $OCF_ERR_GENERIC +- ocf_run tcm_node --freedev=iblock_${OCF_RESKEY_lio_iblock}/${OCF_RESOURCE_INSTANCE} || exit $OCF_ERR_GENERIC + esac +- fi +- +- return $OCF_SUCCESS ++ ++ return $OCF_SUCCESS + } + + iSCSILogicalUnit_monitor() { +- case $OCF_RESKEY_implementation in ++ case $OCF_RESKEY_implementation in + iet) +- # Figure out and set the target ID +- TID=`sed -ne "s/tid:\([[:digit:]]\+\) name:${OCF_RESKEY_target_iqn}$/\1/p" < /proc/net/iet/volume` +- if [ -z "${TID}" ]; then +- # Our target is not configured, thus we're not +- # running. +- return $OCF_NOT_RUNNING +- fi +- # FIXME: this looks for a matching LUN and path, but does +- # not actually test for the correct target ID. +- grep -E -q "[[:space:]]+lun:${OCF_RESKEY_lun}.*path:${OCF_RESKEY_path}$" /proc/net/iet/volume && return $OCF_SUCCESS +- ;; ++ # Figure out and set the target ID ++ TID=`sed -ne "s/tid:\([[:digit:]]\+\) name:${OCF_RESKEY_target_iqn}$/\1/p" < /proc/net/iet/volume` ++ if [ -z "${TID}" ]; then ++ # Our target is not configured, thus we're not ++ # running. ++ return $OCF_NOT_RUNNING ++ fi ++ # FIXME: this looks for a matching LUN and path, but does ++ # not actually test for the correct target ID. ++ grep -E -q "[[:space:]]+lun:${OCF_RESKEY_lun}.*path:${OCF_RESKEY_path}$" /proc/net/iet/volume && return $OCF_SUCCESS ++ ;; + tgt) +- # Figure out and set the target ID +- TID=`tgtadm --lld iscsi --op show --mode target \ +- | sed -ne "s/^Target \([[:digit:]]\+\): ${OCF_RESKEY_target_iqn}$/\1/p"` +- if [ -z "$TID" ]; then +- # Our target is not configured, thus we're not +- # running. +- return $OCF_NOT_RUNNING +- fi +- # This only looks for the backing store, but does not test +- # for the correct target ID and LUN. +- tgtadm --lld iscsi --op show --mode target \ +- | grep -E -q "[[:space:]]+Backing store.*: ${OCF_RESKEY_path}$" && return $OCF_SUCCESS +- ;; ++ # Figure out and set the target ID ++ TID=`tgtadm --lld iscsi --op show --mode target \ ++ | sed -ne "s/^Target \([[:digit:]]\+\): ${OCF_RESKEY_target_iqn}$/\1/p"` ++ if [ -z "$TID" ]; then ++ # Our target is not configured, thus we're not ++ # running. ++ return $OCF_NOT_RUNNING ++ fi ++ # This only looks for the backing store, but does not test ++ # for the correct target ID and LUN. ++ tgtadm --lld iscsi --op show --mode target \ ++ | grep -E -q "[[:space:]]+Backing store.*: ${OCF_RESKEY_path}$" && return $OCF_SUCCESS ++ ;; + lio) +- configfs_path="/sys/kernel/config/target/iscsi/${OCF_RESKEY_target_iqn}/tpgt_1/lun/lun_${OCF_RESKEY_lun}/${OCF_RESOURCE_INSTANCE}/udev_path" +- [ -e ${configfs_path} ] && [ `cat ${configfs_path}` = "${OCF_RESKEY_path}" ] && return $OCF_SUCCESS +- ;; +- esac +- +- return $OCF_NOT_RUNNING ++ configfs_path="/sys/kernel/config/target/iscsi/${OCF_RESKEY_target_iqn}/tpgt_1/lun/lun_${OCF_RESKEY_lun}/${OCF_RESOURCE_INSTANCE}/udev_path" ++ [ -e ${configfs_path} ] && [ `cat ${configfs_path}` = "${OCF_RESKEY_path}" ] && return $OCF_SUCCESS ++ ++ # if we aren't activated, is a block device still left over? ++ block_configfs_path="/sys/kernel/config/target/core/iblock_${OCF_RESKEY_lio_iblock}/${OCF_RESKEY_INSTANCE}/udev_path" ++ [ -e ${block_configfs_path} ] && ocf_log warn "existing block without an active lun: ${block_configfs_path}" ++ [ -e ${block_configfs_path} ] && return $OCF_ERR_GENERIC ++ ++ ;; ++ lio-t) ++ configfs_path="/sys/kernel/config/target/iscsi/${OCF_RESKEY_target_iqn}/tpgt_1/lun/lun_${OCF_RESKEY_lun}/*/udev_path" ++ [ -e ${configfs_path} ] && [ `cat ${configfs_path}` = "${OCF_RESKEY_path}" ] && return $OCF_SUCCESS ++ ;; ++ esac ++ ++ return $OCF_NOT_RUNNING + } + + iSCSILogicalUnit_validate() { +- # Do we have all required variables? +- for var in target_iqn lun path; do ++ # Do we have all required variables? ++ for var in target_iqn lun path; do + param="OCF_RESKEY_${var}" + if [ -z "${!param}" ]; then +- ocf_log error "Missing resource parameter \"$var\"!" +- exit $OCF_ERR_CONFIGURED ++ ocf_exit_reason "Missing resource parameter \"$var\"!" ++ exit $OCF_ERR_CONFIGURED + fi +- done ++ done + +- # Is the configured implementation supported? +- case "$OCF_RESKEY_implementation" in +- "iet"|"tgt"|"lio") +- ;; ++ # Is the configured implementation supported? ++ case "$OCF_RESKEY_implementation" in ++ "iet"|"tgt"|"lio"|"lio-t") ++ ;; + "") +- # The user didn't specify an implementation, and we were +- # unable to determine one from installed binaries (in +- # other words: no binaries for any supported +- # implementation could be found) +- ocf_log error "Undefined iSCSI target implementation" +- exit $OCF_ERR_INSTALLED +- ;; ++ # The user didn't specify an implementation, and we were ++ # unable to determine one from installed binaries (in ++ # other words: no binaries for any supported ++ # implementation could be found) ++ ocf_exit_reason "Undefined iSCSI target implementation" ++ exit $OCF_ERR_INSTALLED ++ ;; + *) +- ocf_log error "Unsupported iSCSI target implementation \"$OCF_RESKEY_implementation\"!" +- exit $OCF_ERR_CONFIGURED +- ;; +- esac ++ ocf_exit_reason "Unsupported iSCSI target implementation \"$OCF_RESKEY_implementation\"!" ++ exit $OCF_ERR_CONFIGURED ++ ;; ++ esac + +- # Do we have a valid LUN? +- case $OCF_RESKEY_implementation in ++ # Do we have a valid LUN? ++ case $OCF_RESKEY_implementation in + iet) +- # IET allows LUN 0 and up +- [ $OCF_RESKEY_lun -ge 0 ] +- case $? in ++ # IET allows LUN 0 and up ++ [ $OCF_RESKEY_lun -ge 0 ] ++ case $? in + 0) +- # OK +- ;; ++ # OK ++ ;; + 1) +- ocf_log err "Invalid LUN $OCF_RESKEY_lun (must be a non-negative integer)." +- exit $OCF_ERR_CONFIGURED +- ;; ++ ocf_log err "Invalid LUN $OCF_RESKEY_lun (must be a non-negative integer)." ++ exit $OCF_ERR_CONFIGURED ++ ;; + *) +- ocf_log err "Invalid LUN $OCF_RESKEY_lun (must be an integer)." +- exit $OCF_ERR_CONFIGURED +- ;; +- esac +- ;; ++ ocf_log err "Invalid LUN $OCF_RESKEY_lun (must be an integer)." ++ exit $OCF_ERR_CONFIGURED ++ ;; ++ esac ++ ;; + tgt) +- # tgt reserves LUN 0 for its own purposes +- [ $OCF_RESKEY_lun -ge 1 ] +- case $? in ++ # tgt reserves LUN 0 for its own purposes ++ [ $OCF_RESKEY_lun -ge 1 ] ++ case $? in + 0) +- # OK +- ;; ++ # OK ++ ;; + 1) +- ocf_log err "Invalid LUN $OCF_RESKEY_lun (must be greater than 0)." +- exit $OCF_ERR_CONFIGURED +- ;; ++ ocf_log err "Invalid LUN $OCF_RESKEY_lun (must be greater than 0)." ++ exit $OCF_ERR_CONFIGURED ++ ;; + *) +- ocf_log err "Invalid LUN $OCF_RESKEY_lun (must be an integer)." +- exit $OCF_ERR_CONFIGURED +- ;; +- esac +- ;; +- esac +- +- # Do we have any configuration parameters that the current +- # implementation does not support? +- local unsupported_params +- local var +- local envar +- case $OCF_RESKEY_implementation in ++ ocf_log err "Invalid LUN $OCF_RESKEY_lun (must be an integer)." ++ exit $OCF_ERR_CONFIGURED ++ ;; ++ esac ++ ;; ++ esac ++ ++ # Do we have any configuration parameters that the current ++ # implementation does not support? ++ local unsupported_params ++ local var ++ local envar ++ case $OCF_RESKEY_implementation in + iet) +- # IET does not support setting the vendor and product ID +- # (it always uses "IET" and "VIRTUAL-DISK") +- unsupported_params="vendor_id product_id allowed_initiators lio_iblock tgt_bstype tgt_bsoflags tgt_device_type" +- ;; ++ # IET does not support setting the vendor and product ID ++ # (it always uses "IET" and "VIRTUAL-DISK") ++ unsupported_params="vendor_id product_id allowed_initiators lio_iblock tgt_bstype tgt_bsoflags tgt_device_type" ++ ;; + tgt) +- unsupported_params="allowed_initiators lio_iblock" +- ;; ++ unsupported_params="allowed_initiators lio_iblock" ++ ;; + lio) +- unsupported_params="scsi_id vendor_id product_id tgt_bstype tgt_bsoflags tgt_device_type" +- ;; +- esac +- for var in ${unsupported_params}; do +- envar=OCF_RESKEY_${var} +- defvar=OCF_RESKEY_${var}_default +- if [ -n "${!envar}" ]; then +- if [[ "${!envar}" != "${!defvar}" ]];then +- case "$__OCF_ACTION" in +- start|validate-all) +- ocf_log warn "Configuration parameter \"${var}\"" \ +- "is not supported by the iSCSI implementation" \ +- "and will be ignored." ;; +- esac +- fi +- fi +- done ++ unsupported_params="scsi_id vendor_id product_id tgt_bstype tgt_bsoflags tgt_device_type" ++ ;; ++ lio-t) ++ unsupported_params="scsi_id vendor_id product_id tgt_bstype tgt_bsoflags tgt_device_type lio_iblock" ++ ;; ++ esac ++ ++ for var in ${unsupported_params}; do ++ envar=OCF_RESKEY_${var} ++ defvar=OCF_RESKEY_${var}_default ++ if [ -n "${!envar}" ]; then ++ if [[ "${!envar}" != "${!defvar}" ]];then ++ case "$__OCF_ACTION" in ++ start|validate-all) ++ ocf_log warn "Configuration parameter \"${var}\"" \ ++ "is not supported by the iSCSI implementation" \ ++ "and will be ignored." ;; ++ esac ++ fi ++ fi ++ done + +- if ! ocf_is_probe; then +- # Do we have all required binaries? ++ if ! ocf_is_probe; then ++ # Do we have all required binaries? + case $OCF_RESKEY_implementation in +- iet) ++ iet) + check_binary ietadm + ;; +- tgt) ++ tgt) + check_binary tgtadm + ;; +- lio) ++ lio) + check_binary tcm_node + check_binary lio_node + ;; ++ lio-t) ++ check_binary targetcli ++ ;; + esac + +- # Is the required kernel functionality available? ++ # Is the required kernel functionality available? + case $OCF_RESKEY_implementation in +- iet) ++ iet) + [ -d /proc/net/iet ] + if [ $? -ne 0 ]; then +- ocf_log err "/proc/net/iet does not exist or is not a directory -- check if required modules are loaded." +- exit $OCF_ERR_INSTALLED ++ ocf_log err "/proc/net/iet does not exist or is not a directory -- check if required modules are loaded." ++ exit $OCF_ERR_INSTALLED + fi + ;; +- tgt) +- # tgt is userland only ++ tgt) ++ # tgt is userland only + ;; + esac +- fi ++ fi + +- return $OCF_SUCCESS ++ return $OCF_SUCCESS + } + +- + case $1 in +- meta-data) ++meta-data) + meta_data + exit $OCF_SUCCESS + ;; +- usage|help) ++usage|help) + iSCSILogicalUnit_usage + exit $OCF_SUCCESS + ;; +@@ -568,13 +650,14 @@ start) iSCSILogicalUnit_start;; + stop) iSCSILogicalUnit_stop;; + monitor|status) iSCSILogicalUnit_monitor;; + reload) ocf_log err "Reloading..." +- iSCSILogicalUnit_start ++ iSCSILogicalUnit_start + ;; + validate-all) ;; + *) iSCSILogicalUnit_usage + exit $OCF_ERR_UNIMPLEMENTED + ;; + esac ++ + rc=$? + ocf_log debug "${OCF_RESOURCE_INSTANCE} $__OCF_ACTION : $rc" + exit $rc +diff --git a/heartbeat/iSCSITarget b/heartbeat/iSCSITarget +index a988fb2..72ec64a 100755 +--- a/heartbeat/iSCSITarget ++++ b/heartbeat/iSCSITarget +@@ -1,7 +1,7 @@ + #!/bin/bash + # + # +-# iSCSITarget OCF RA. Exports and manages iSCSI targets. ++# iSCSITarget OCF RA. Exports and manages iSCSI targets. + # + # (c) 2009-2010 Florian Haas, Dejan Muhamedagic, + # and Linux-HA contributors +@@ -34,11 +34,13 @@ + # Defaults + # Set a default implementation based on software installed + if have_binary ietadm; then +- OCF_RESKEY_implementation_default="iet" ++ OCF_RESKEY_implementation_default="iet" + elif have_binary tgtadm; then +- OCF_RESKEY_implementation_default="tgt" ++ OCF_RESKEY_implementation_default="tgt" + elif have_binary lio_node; then +- OCF_RESKEY_implementation_default="lio" ++ OCF_RESKEY_implementation_default="lio" ++elif have_binary targetcli; then ++ OCF_RESKEY_implementation_default="lio-t" + fi + : ${OCF_RESKEY_implementation=${OCF_RESKEY_implementation_default}} + +@@ -67,12 +69,12 @@ Units (LUs) exported via a daemon that speaks the iSCSI protocol. + + + The iSCSI target daemon implementation. Must be one of "iet", "tgt", +-or "lio". If unspecified, an implementation is selected based on the ++"lio", or "lio-t". If unspecified, an implementation is selected based on the + availability of management utilities, with "iet" being tried first, +-then "tgt", then "lio". ++then "tgt", then "lio", then "lio-t". + + Specifies the iSCSI target implementation +-("iet", "tgt" or "lio"). ++("iet", "tgt", "lio", or "lio-t"). + + + +@@ -148,11 +150,11 @@ dependent. Neither the name nor the value may contain whitespace. + + + +- +- +- +- +- ++ ++ ++ ++ ++ + + + +@@ -170,182 +172,233 @@ END + } + + iSCSITarget_start() { +- iSCSITarget_monitor +- if [ $? = $OCF_SUCCESS ]; then +- return $OCF_SUCCESS +- fi ++ iSCSITarget_monitor ++ if [ $? = $OCF_SUCCESS ]; then ++ return $OCF_SUCCESS ++ fi + +- local param +- local name +- local value +- local initiator +- local portal ++ local param ++ local name ++ local value ++ local initiator ++ local portal + +- case $OCF_RESKEY_implementation in ++ case $OCF_RESKEY_implementation in + iet) +- local lasttid +- local tid +- if [ "${OCF_RESKEY_tid}" ]; then +- tid="${OCF_RESKEY_tid}" +- else +- # Figure out the last used target ID, add 1 to get the new +- # target ID. +- ocf_take_lock $LOCKFILE +- ocf_release_lock_on_exit $LOCKFILE +- lasttid=`sed -ne "s/tid:\([[:digit:]]\+\) name:.*/\1/p" < /proc/net/iet/volume | sort -n | tail -n1` +- [ -z "${lasttid}" ] && lasttid=0 +- tid=$((++lasttid)) +- fi +- # Create the target. +- ocf_run ietadm --op new \ +- --tid=${tid} \ +- --params Name=${OCF_RESKEY_iqn} || exit $OCF_ERR_GENERIC +- # Set additional parameters. +- for param in ${OCF_RESKEY_additional_parameters}; do +- name=${param%=*} +- value=${param#*=} +- ocf_run ietadm --op update \ +- --tid=${tid} \ +- --params ${name}=${value} || exit $OCF_ERR_GENERIC +- done +- # Legacy versions of IET allow targets by default, current +- # versions deny. To be safe we manage both the .allow and +- # .deny files. +- if [ -n "${OCF_RESKEY_allowed_initiators}" ]; then +- echo "${OCF_RESKEY_iqn} ALL" >> /etc/initiators.deny +- echo "${OCF_RESKEY_iqn} ${OCF_RESKEY_allowed_initiators// /,}" >> /etc/initiators.allow +- else +- echo "${OCF_RESKEY_iqn} ALL" >> /etc/initiators.allow +- fi +- # In iet, adding a new user and assigning it to a target +- # is one operation. +- if [ -n "${OCF_RESKEY_incoming_username}" ]; then +- ocf_run ietadm --op new --user \ +- --tid=${tid} \ +- --params=IncomingUser=${OCF_RESKEY_incoming_username},Password=${OCF_RESKEY_incoming_password} \ +- || exit $OCF_ERR_GENERIC +- fi +- ;; ++ local lasttid ++ local tid ++ if [ "${OCF_RESKEY_tid}" ]; then ++ tid="${OCF_RESKEY_tid}" ++ else ++ # Figure out the last used target ID, add 1 to get the new ++ # target ID. ++ ocf_take_lock $LOCKFILE ++ ocf_release_lock_on_exit $LOCKFILE ++ lasttid=`sed -ne "s/tid:\([[:digit:]]\+\) name:.*/\1/p" < /proc/net/iet/volume | sort -n | tail -n1` ++ [ -z "${lasttid}" ] && lasttid=0 ++ tid=$((++lasttid)) ++ fi ++ ++ # Create the target. ++ ocf_run ietadm --op new \ ++ --tid=${tid} \ ++ --params Name=${OCF_RESKEY_iqn} || exit $OCF_ERR_GENERIC ++ ++ # Set additional parameters. ++ for param in ${OCF_RESKEY_additional_parameters}; do ++ name=${param%=*} ++ value=${param#*=} ++ ocf_run ietadm --op update \ ++ --tid=${tid} \ ++ --params ${name}=${value} || exit $OCF_ERR_GENERIC ++ done ++ ++ # Legacy versions of IET allow targets by default, current ++ # versions deny. To be safe we manage both the .allow and ++ # .deny files. ++ if [ -n "${OCF_RESKEY_allowed_initiators}" ]; then ++ echo "${OCF_RESKEY_iqn} ALL" >> /etc/initiators.deny ++ echo "${OCF_RESKEY_iqn} ${OCF_RESKEY_allowed_initiators// /,}" >> /etc/initiators.allow ++ else ++ echo "${OCF_RESKEY_iqn} ALL" >> /etc/initiators.allow ++ fi ++ # In iet, adding a new user and assigning it to a target ++ # is one operation. ++ if [ -n "${OCF_RESKEY_incoming_username}" ]; then ++ ocf_run ietadm --op new --user \ ++ --tid=${tid} \ ++ --params=IncomingUser=${OCF_RESKEY_incoming_username},Password=${OCF_RESKEY_incoming_password} \ ++ || exit $OCF_ERR_GENERIC ++ fi ++ ;; + tgt) +- local tid +- tid="${OCF_RESKEY_tid}" +- # Create the target. +- ocf_run tgtadm --lld iscsi --op new --mode target \ +- --tid=${tid} \ +- --targetname ${OCF_RESKEY_iqn} || exit $OCF_ERR_GENERIC +- # Set parameters. +- for param in ${OCF_RESKEY_additional_parameters}; do +- name=${param%=*} +- value=${param#*=} +- ocf_run tgtadm --lld iscsi --op update --mode target \ +- --tid=${tid} \ +- --name=${name} --value=${value} || exit $OCF_ERR_GENERIC +- done +- # For tgt, we always have to add access per initiator; +- # access to targets is denied by default. If +- # "allowed_initiators" is unset, we must use the special +- # keyword ALL. +- for initiator in ${OCF_RESKEY_allowed_initiators=ALL}; do +- ocf_run tgtadm --lld iscsi --op bind --mode target \ +- --tid=${tid} \ +- --initiator-address=${initiator} || exit $OCF_ERR_GENERIC +- done +- # In tgt, we must first create a user account, then assign +- # it to a target using the "bind" operation. +- if [ -n "${OCF_RESKEY_incoming_username}" ]; then +- ocf_run tgtadm --lld iscsi --mode account --op new \ +- --user=${OCF_RESKEY_incoming_username} \ +- --password=${OCF_RESKEY_incoming_password} || exit $OCF_ERR_GENERIC +- ocf_run tgtadm --lld iscsi --mode account --op bind \ +- --tid=${tid} \ +- --user=${OCF_RESKEY_incoming_username} || exit $OCF_ERR_GENERIC +- fi +- ;; ++ local tid ++ tid="${OCF_RESKEY_tid}" ++ # Create the target. ++ ocf_run tgtadm --lld iscsi --op new --mode target \ ++ --tid=${tid} \ ++ --targetname ${OCF_RESKEY_iqn} || exit $OCF_ERR_GENERIC ++ ++ # Set parameters. ++ for param in ${OCF_RESKEY_additional_parameters}; do ++ name=${param%=*} ++ value=${param#*=} ++ ocf_run tgtadm --lld iscsi --op update --mode target \ ++ --tid=${tid} \ ++ --name=${name} --value=${value} || exit $OCF_ERR_GENERIC ++ done ++ ++ # For tgt, we always have to add access per initiator; ++ # access to targets is denied by default. If ++ # "allowed_initiators" is unset, we must use the special ++ # keyword ALL. ++ for initiator in ${OCF_RESKEY_allowed_initiators=ALL}; do ++ ocf_run tgtadm --lld iscsi --op bind --mode target \ ++ --tid=${tid} \ ++ --initiator-address=${initiator} || exit $OCF_ERR_GENERIC ++ done ++ ++ # In tgt, we must first create a user account, then assign ++ # it to a target using the "bind" operation. ++ if [ -n "${OCF_RESKEY_incoming_username}" ]; then ++ ocf_run tgtadm --lld iscsi --mode account --op new \ ++ --user=${OCF_RESKEY_incoming_username} \ ++ --password=${OCF_RESKEY_incoming_password} || exit $OCF_ERR_GENERIC ++ ocf_run tgtadm --lld iscsi --mode account --op bind \ ++ --tid=${tid} \ ++ --user=${OCF_RESKEY_incoming_username} || exit $OCF_ERR_GENERIC ++ fi ++ ;; + lio) +- # lio distinguishes between targets and target portal +- # groups (TPGs). We will always create one TPG, with the +- # number 1. In lio, creating a network portal +- # automatically creates the corresponding target if it +- # doesn't already exist. +- for portal in ${OCF_RESKEY_portals}; do +- ocf_run lio_node --addnp ${OCF_RESKEY_iqn} 1 \ +- ${portal} || exit $OCF_ERR_GENERIC +- done +- # in lio, we can set target parameters by manipulating +- # the appropriate configfs entries +- for param in ${OCF_RESKEY_additional_parameters}; do +- name=${param%=*} +- value=${param#*=} +- configfs_path="/sys/kernel/config/target/iscsi/${OCF_RESKEY_iqn}/tpgt_1/param/${name}" +- if [ -e ${configfs_path} ]; then +- echo ${value} > ${configfs_path} || exit $OCF_ERR_GENERIC ++ # lio distinguishes between targets and target portal ++ # groups (TPGs). We will always create one TPG, with the ++ # number 1. In lio, creating a network portal ++ # automatically creates the corresponding target if it ++ # doesn't already exist. ++ for portal in ${OCF_RESKEY_portals}; do ++ ocf_run lio_node --addnp ${OCF_RESKEY_iqn} 1 \ ++ ${portal} || exit $OCF_ERR_GENERIC ++ done ++ ++ # in lio, we can set target parameters by manipulating ++ # the appropriate configfs entries ++ for param in ${OCF_RESKEY_additional_parameters}; do ++ name=${param%=*} ++ value=${param#*=} ++ configfs_path="/sys/kernel/config/target/iscsi/${OCF_RESKEY_iqn}/tpgt_1/param/${name}" ++ if [ -e ${configfs_path} ]; then ++ echo ${value} > ${configfs_path} || exit $OCF_ERR_GENERIC ++ else ++ ocf_log warn "Unsupported iSCSI target parameter ${name}: will be ignored." ++ fi ++ done ++ ++ # lio does per-initiator filtering by default. To disable ++ # this, we need to switch the target to "permissive mode". ++ if [ -n "${OCF_RESKEY_allowed_initiators}" ]; then ++ for initiator in ${OCF_RESKEY_allowed_initiators}; do ++ ocf_run lio_node --addnodeacl ${OCF_RESKEY_iqn} 1 \ ++ ${initiator} || exit $OCF_ERR_GENERIC ++ done + else +- ocf_log warn "Unsupported iSCSI target parameter ${name}: will be ignored." ++ ocf_run lio_node --permissive ${OCF_RESKEY_iqn} 1 || exit $OCF_ERR_GENERIC ++ # permissive mode enables read-only access by default, ++ # so we need to change that to RW to be in line with ++ # the other implementations. ++ echo 0 > "/sys/kernel/config/target/iscsi/${OCF_RESKEY_iqn}/tpgt_1/attrib/demo_mode_write_protect" ++ if [ `cat /sys/kernel/config/target/iscsi/${OCF_RESKEY_iqn}/tpgt_1/attrib/demo_mode_write_protect` -ne 0 ]; then ++ ocf_log err "Failed to disable write protection for target ${OCF_RESKEY_iqn}." ++ exit $OCF_ERR_GENERIC ++ fi + fi +- done +- # lio does per-initiator filtering by default. To disable +- # this, we need to switch the target to "permissive mode". +- if [ -n "${OCF_RESKEY_allowed_initiators}" ]; then +- for initiator in ${OCF_RESKEY_allowed_initiators}; do +- ocf_run lio_node --addnodeacl ${OCF_RESKEY_iqn} 1 \ +- ${initiator} || exit $OCF_ERR_GENERIC ++ ++ # TODO: add CHAP authentication support when it gets added ++ # back into LIO ++ ocf_run lio_node --disableauth ${OCF_RESKEY_iqn} 1 || exit $OCF_ERR_GENERIC ++ # Finally, we need to enable the target to allow ++ # initiators to connect ++ ocf_run lio_node --enabletpg=${OCF_RESKEY_iqn} 1 || exit $OCF_ERR_GENERIC ++ ;; ++ lio-t) ++ # lio distinguishes between targets and target portal ++ # groups (TPGs). We will always create one TPG, with the ++ # number 1. In lio, creating a network portal ++ # automatically creates the corresponding target if it ++ # doesn't already exist. ++ for portal in ${OCF_RESKEY_portals}; do ++ ocf_run targetcli /iscsi create ${OCF_RESKEY_iqn} || exit $OCF_ERR_GENERIC ++ if [ $portal != ${OCF_RESKEY_portals_default} ] ; then ++ IFS=':' read -a sep_portal <<< "$portal" ++ ocf_run targetcli /iscsi/${OCF_RESKEY_iqn}/tpg1/portals create "${sep_portal[0]}" "${sep_portal[1]}" || exit $OCF_ERR_GENERIC ++ fi + done +- else +- ocf_run lio_node --permissive ${OCF_RESKEY_iqn} 1 || exit $OCF_ERR_GENERIC +- # permissive mode enables read-only access by default, +- # so we need to change that to RW to be in line with +- # the other implementations. +- echo 0 > "/sys/kernel/config/target/iscsi/${OCF_RESKEY_iqn}/tpgt_1/attrib/demo_mode_write_protect" +- if [ `cat /sys/kernel/config/target/iscsi/${OCF_RESKEY_iqn}/tpgt_1/attrib/demo_mode_write_protect` -ne 0 ]; then +- ocf_log err "Failed to disable write protection for target ${OCF_RESKEY_iqn}." +- exit $OCF_ERR_GENERIC ++ # in lio, we can set target parameters by manipulating ++ # the appropriate configfs entries ++ for param in ${OCF_RESKEY_additional_parameters}; do ++ name=${param%=*} ++ value=${param#*=} ++ configfs_path="/sys/kernel/config/target/iscsi/${OCF_RESKEY_iqn}/tpgt_1/param/${name}" ++ if [ -e ${configfs_path} ]; then ++ echo ${value} > ${configfs_path} || exit $OCF_ERR_GENERIC ++ else ++ ocf_log warn "Unsupported iSCSI target parameter ${name}: will be ignored." ++ fi ++ done ++ # lio does per-initiator filtering by default. To disable ++ # this, we need to switch the target to "permissive mode". ++ if [ -n "${OCF_RESKEY_allowed_initiators}" ]; then ++ for initiator in ${OCF_RESKEY_allowed_initiators}; do ++ ocf_run targetcli /iscsi/${OCF_RESKEY_iqn}/tpg1/acls create ${initiator} || exit $OCF_ERR_GENERIC ++ done ++ else ++ ocf_run targetcli /iscsi/${OCF_RESKEY_iqn}/tpg1/ set attribute authentication=0 demo_mode_write_protect=0 generate_node_acls=1 cache_dynamic_acls=1 || exit $OCF_ERR_GENERIC + fi +- fi +- # TODO: add CHAP authentication support when it gets added +- # back into LIO +- ocf_run lio_node --disableauth ${OCF_RESKEY_iqn} 1 || exit $OCF_ERR_GENERIC +- # Finally, we need to enable the target to allow +- # initiators to connect +- ocf_run lio_node --enabletpg=${OCF_RESKEY_iqn} 1 || exit $OCF_ERR_GENERIC +- ;; +- esac +- +- return $OCF_SUCCESS ++ # TODO: add CHAP authentication support when it gets added ++ # back into LIO ++ ocf_run targetcli /iscsi/${OCF_RESKEY_iqn}/tpg1/ set attribute authentication=0 || exit $OCF_ERR_GENERIC ++# ocf_run targetcli /iscsi ++ ;; ++ esac ++ ++ iSCSITarget_monitor + } + + iSCSITarget_stop() { +- iSCSITarget_monitor +- if [ $? = $OCF_SUCCESS ]; then ++ iSCSITarget_monitor ++ if [ $? -eq $OCF_NOT_RUNNING ]; then ++ return $OCF_SUCCESS ++ fi ++ + local tid + case $OCF_RESKEY_implementation in +- iet) ++ iet) + # Figure out the target ID + tid=`sed -ne "s/tid:\([[:digit:]]\+\) name:${OCF_RESKEY_iqn}/\1/p" < /proc/net/iet/volume` + if [ -z "${tid}" ]; then +- ocf_log err "Failed to retrieve target ID for IQN ${OCF_RESKEY_iqn}" +- exit $OCF_ERR_GENERIC ++ ocf_log err "Failed to retrieve target ID for IQN ${OCF_RESKEY_iqn}" ++ exit $OCF_ERR_GENERIC + fi + # Close existing connections. There is no other way to + # do this in IET than to parse the contents of + # /proc/net/iet/session. + set -- $(sed -ne '/^tid:'${tid}' /,/^tid/ { +- /^[[:space:]]*sid:\([0-9]\+\)/ { +- s/^[[:space:]]*sid:\([0-9]*\).*/--sid=\1/; h; +- }; +- /^[[:space:]]*cid:\([0-9]\+\)/ { +- s/^[[:space:]]*cid:\([0-9]*\).*/--cid=\1/; G; p; +- }; +- }' < /proc/net/iet/session) ++ /^[[:space:]]*sid:\([0-9]\+\)/ { ++ s/^[[:space:]]*sid:\([0-9]*\).*/--sid=\1/; h; ++ }; ++ /^[[:space:]]*cid:\([0-9]\+\)/ { ++ s/^[[:space:]]*cid:\([0-9]*\).*/--cid=\1/; G; p; ++ }; ++ }' < /proc/net/iet/session) + while [[ -n $2 ]]; do +- # $2 $1 looks like "--sid=X --cid=Y" +- ocf_run ietadm --op delete \ +- --tid=${tid} $2 $1 +- shift 2 ++ # $2 $1 looks like "--sid=X --cid=Y" ++ ocf_run ietadm --op delete \ ++ --tid=${tid} $2 $1 ++ shift 2 + done +- # In iet, unassigning a user from a target and ++ # In iet, unassigning a user from a target and + # deleting the user account is one operation. + if [ -n "${OCF_RESKEY_incoming_username}" ]; then +- ocf_run ietadm --op delete --user \ ++ ocf_run ietadm --op delete --user \ + --tid=${tid} \ + --params=IncomingUser=${OCF_RESKEY_incoming_username} \ + || exit $OCF_ERR_GENERIC +@@ -353,216 +406,226 @@ iSCSITarget_stop() { + # Loop on delete. Keep trying until we time out, if + # necessary. + while true; do +- if ietadm --op delete --tid=${tid}; then +- ocf_log debug "Removed target ${OCF_RESKEY_iqn}." +- break +- else +- ocf_log warn "Failed to remove target ${OCF_RESKEY_iqn}, retrying." +- sleep 1 +- fi ++ if ietadm --op delete --tid=${tid}; then ++ ocf_log debug "Removed target ${OCF_RESKEY_iqn}." ++ break ++ else ++ ocf_log warn "Failed to remove target ${OCF_RESKEY_iqn}, retrying." ++ sleep 1 ++ fi + done + # Avoid stale /etc/initiators.{allow,deny} entries + # for this target + if [ -e /etc/initiators.deny ]; then +- ocf_run sed -e "/^${OCF_RESKEY_iqn}[[:space:]]/d" \ ++ ocf_run sed -e "/^${OCF_RESKEY_iqn}[[:space:]]/d" \ + -i /etc/initiators.deny + fi + if [ -e /etc/initiators.allow ]; then +- ocf_run sed -e "/^${OCF_RESKEY_iqn}[[:space:]]/d" \ ++ ocf_run sed -e "/^${OCF_RESKEY_iqn}[[:space:]]/d" \ + -i /etc/initiators.allow + fi + ;; +- tgt) ++ tgt) + tid="${OCF_RESKEY_tid}" + # Close existing connections. There is no other way to + # do this in tgt than to parse the output of "tgtadm --op + # show". + set -- $(tgtadm --lld iscsi --op show --mode target \ +- | sed -ne '/^Target '${tid}':/,/^Target/ { +- /^[[:space:]]*I_T nexus: \([0-9]\+\)/ { +- s/^.*: \([0-9]*\).*/--sid=\1/; h; +- }; +- /^[[:space:]]*Connection: \([0-9]\+\)/ { +- s/^.*: \([0-9]*\).*/--cid=\1/; G; p; +- }; +- /^[[:space:]]*LUN information:/ q; +- }') ++ | sed -ne '/^Target '${tid}':/,/^Target/ { ++ /^[[:space:]]*I_T nexus: \([0-9]\+\)/ { ++ s/^.*: \([0-9]*\).*/--sid=\1/; h; ++ }; ++ /^[[:space:]]*Connection: \([0-9]\+\)/ { ++ s/^.*: \([0-9]*\).*/--cid=\1/; G; p; ++ }; ++ /^[[:space:]]*LUN information:/ q; ++ }') + while [[ -n $2 ]]; do +- # $2 $1 looks like "--sid=X --cid=Y" +- ocf_run tgtadm --lld iscsi --op delete --mode connection \ ++ # $2 $1 looks like "--sid=X --cid=Y" ++ ocf_run tgtadm --lld iscsi --op delete --mode connection \ + --tid=${tid} $2 $1 +- shift 2 ++ shift 2 + done +- # In tgt, we must first unbind the user account from ++ # In tgt, we must first unbind the user account from + # the target, then remove the account itself. + if [ -n "${OCF_RESKEY_incoming_username}" ]; then +- ocf_run tgtadm --lld iscsi --mode account --op unbind \ +- --tid=${tid} \ +- --user=${OCF_RESKEY_incoming_username} || exit $OCF_ERR_GENERIC +- ocf_run tgtadm --lld iscsi --mode account --op delete \ +- --user=${OCF_RESKEY_incoming_username} || exit $OCF_ERR_GENERIC ++ ocf_run tgtadm --lld iscsi --mode account --op unbind \ ++ --tid=${tid} \ ++ --user=${OCF_RESKEY_incoming_username} || exit $OCF_ERR_GENERIC ++ ocf_run tgtadm --lld iscsi --mode account --op delete \ ++ --user=${OCF_RESKEY_incoming_username} || exit $OCF_ERR_GENERIC + fi + # Loop on delete. Keep trying until we time out, if + # necessary. + while true; do +- if tgtadm --lld iscsi --op delete --mode target --tid=${tid}; then +- ocf_log debug "Removed target ${OCF_RESKEY_iqn}." +- break +- else +- ocf_log warn "Failed to remove target ${OCF_RESKEY_iqn}, retrying." +- sleep 1 +- fi ++ if tgtadm --lld iscsi --op delete --mode target --tid=${tid}; then ++ ocf_log debug "Removed target ${OCF_RESKEY_iqn}." ++ break ++ else ++ ocf_log warn "Failed to remove target ${OCF_RESKEY_iqn}, retrying." ++ sleep 1 ++ fi + done + # In tgt, we don't have to worry about our ACL + # entries. They are automatically removed upon target + # deletion. + ;; +- lio) ++ lio) + # In lio, removing a target automatically removes all + # associated TPGs, network portals, and LUNs. + ocf_run lio_node --deliqn ${OCF_RESKEY_iqn} || exit $OCF_ERR_GENERIC + ;; ++ lio-t) ++ ocf_run targetcli /iscsi delete ${OCF_RESKEY_iqn} || exit $OCF_ERR_GENERIC ++ ;; + esac +- fi + +- return $OCF_SUCCESS ++ return $OCF_SUCCESS + } + + iSCSITarget_monitor() { +- case $OCF_RESKEY_implementation in ++ case $OCF_RESKEY_implementation in + iet) +- grep -Eq "tid:[0-9]+ name:${OCF_RESKEY_iqn}" /proc/net/iet/volume && return $OCF_SUCCESS +- ;; ++ grep -Eq "tid:[0-9]+ name:${OCF_RESKEY_iqn}" /proc/net/iet/volume && return $OCF_SUCCESS ++ ;; + tgt) +- tgtadm --lld iscsi --op show --mode target \ ++ tgtadm --lld iscsi --op show --mode target \ + | grep -Eq "Target [0-9]+: ${OCF_RESKEY_iqn}" && return $OCF_SUCCESS +- ;; +- lio) +- # if we have no configfs entry for the target, it's +- # definitely stopped +- [ -d /sys/kernel/config/target/iscsi/${OCF_RESKEY_iqn} ] || return $OCF_NOT_RUNNING +- # if the target is there, but its TPG is not enabled, then +- # we also consider it stopped +- [ `cat /sys/kernel/config/target/iscsi/${OCF_RESKEY_iqn}/tpgt_1/enable` -eq 1 ] || return $OCF_NOT_RUNNING +- return $OCF_SUCCESS +- ;; +- esac +- +- return $OCF_NOT_RUNNING ++ ;; ++ lio | lio-t) ++ # if we have no configfs entry for the target, it's ++ # definitely stopped ++ [ -d /sys/kernel/config/target/iscsi/${OCF_RESKEY_iqn} ] || return $OCF_NOT_RUNNING ++ # if the target is there, but its TPG is not enabled, then ++ # we also consider it stopped ++ [ `cat /sys/kernel/config/target/iscsi/${OCF_RESKEY_iqn}/tpgt_1/enable` -eq 1 ] || return $OCF_NOT_RUNNING ++ return $OCF_SUCCESS ++ ;; ++ esac ++ ++ return $OCF_NOT_RUNNING + } + + iSCSITarget_validate() { +- # Do we have all required variables? +- local required_vars +- case $OCF_RESKEY_implementation in ++ # Do we have all required variables? ++ local required_vars ++ case $OCF_RESKEY_implementation in + iet) +- required_vars="iqn" +- ;; ++ required_vars="iqn" ++ ;; + tgt) +- required_vars="iqn tid" +- ;; +- esac +- for var in ${required_vars}; do +- param="OCF_RESKEY_${var}" +- if [ -z "${!param}" ]; then +- ocf_log error "Missing resource parameter \"$var\"!" +- exit $OCF_ERR_CONFIGURED +- fi +- done ++ required_vars="iqn tid" ++ ;; ++ esac ++ ++ for var in ${required_vars}; do ++ param="OCF_RESKEY_${var}" ++ if [ -z "${!param}" ]; then ++ ocf_exit_reason "Missing resource parameter \"$var\"!" ++ exit $OCF_ERR_CONFIGURED ++ fi ++ done + +- # Is the configured implementation supported? +- case "$OCF_RESKEY_implementation" in +- "iet"|"tgt"|"lio") +- ;; ++ # Is the configured implementation supported? ++ case "$OCF_RESKEY_implementation" in ++ "iet"|"tgt"|"lio"|"lio-t") ++ ;; + "") +- # The user didn't specify an implementation, and we were +- # unable to determine one from installed binaries (in +- # other words: no binaries for any supported +- # implementation could be found) +- ocf_log error "Undefined iSCSI target implementation" +- exit $OCF_ERR_INSTALLED +- ;; ++ # The user didn't specify an implementation, and we were ++ # unable to determine one from installed binaries (in ++ # other words: no binaries for any supported ++ # implementation could be found) ++ ocf_exit_reason "Undefined iSCSI target implementation" ++ exit $OCF_ERR_INSTALLED ++ ;; + *) +- ocf_log error "Unsupported iSCSI target implementation \"$OCF_RESKEY_implementation\"!" +- exit $OCF_ERR_CONFIGURED +- ;; +- esac +- +- # Do we have any configuration parameters that the current +- # implementation does not support? +- local unsupported_params +- local var +- local envar +- case $OCF_RESKEY_implementation in ++ ocf_exit_reason "Unsupported iSCSI target implementation \"$OCF_RESKEY_implementation\"!" ++ exit $OCF_ERR_CONFIGURED ++ ;; ++ esac ++ ++ # Do we have any configuration parameters that the current ++ # implementation does not support? ++ local unsupported_params ++ local var ++ local envar ++ case $OCF_RESKEY_implementation in + iet|tgt) +- # IET and tgt do not support binding a target portal to a +- # specific IP address. +- unsupported_params="portals" +- ;; +- lio) +- # TODO: Remove incoming_username and incoming_password +- # from this check when LIO 3.0 gets CHAP authentication +- unsupported_params="tid incoming_username incoming_password" +- ;; +- esac +- for var in ${unsupported_params}; do +- envar=OCF_RESKEY_${var} +- defvar=OCF_RESKEY_${var}_default +- if [ -n "${!envar}" ]; then +- if [[ "${!envar}" != "${!defvar}" ]];then +- case "$__OCF_ACTION" in +- start|validate-all) +- ocf_log warn "Configuration parameter \"${var}\"" \ +- "is not supported by the iSCSI implementation" \ +- "and will be ignored." ;; +- esac +- fi +- fi +- done ++ # IET and tgt do not support binding a target portal to a ++ # specific IP address. ++ unsupported_params="portals" ++ ;; ++ lio|lio-t) ++ # TODO: Remove incoming_username and incoming_password ++ # from this check when LIO 3.0 gets CHAP authentication ++ unsupported_params="tid incoming_username incoming_password" ++ ;; ++ esac + +- if ! ocf_is_probe; then +- # Do we have all required binaries? ++ for var in ${unsupported_params}; do ++ envar=OCF_RESKEY_${var} ++ defvar=OCF_RESKEY_${var}_default ++ if [ -n "${!envar}" ]; then ++ if [[ "${!envar}" != "${!defvar}" ]];then ++ case "$__OCF_ACTION" in ++ start|validate-all) ++ ocf_log warn "Configuration parameter \"${var}\"" \ ++ "is not supported by the iSCSI implementation" \ ++ "and will be ignored." ;; ++ esac ++ fi ++ fi ++ done ++ ++ if ! ocf_is_probe; then ++ # Do we have all required binaries? + case $OCF_RESKEY_implementation in +- iet) ++ iet) + check_binary ietadm + ;; +- tgt) ++ tgt) + check_binary tgtadm + ;; +- lio) ++ lio) + check_binary tcm_node + check_binary lio_node + ;; ++ lio-t) ++ check_binary targetcli ++ ;; + esac + +- # Is the required kernel functionality available? ++ # Is the required kernel functionality available? + case $OCF_RESKEY_implementation in +- iet) ++ iet) + [ -d /proc/net/iet ] + if [ $? -ne 0 ]; then +- ocf_log err "/proc/net/iet does not exist or is not a directory -- check if required modules are loaded." +- exit $OCF_ERR_INSTALLED ++ ocf_log err "/proc/net/iet does not exist or is not a directory -- check if required modules are loaded." ++ exit $OCF_ERR_INSTALLED + fi + ;; +- tgt) +- # tgt is userland only ++ tgt) ++ # tgt is userland only + ;; +- lio) +- # lio needs configfs to be mounted ++ lio) ++ # lio needs configfs to be mounted + if ! grep -Eq "^.*/sys/kernel/config[[:space:]]+configfs" /proc/mounts; then +- ocf_log err "configfs not mounted at /sys/kernel/config -- check if required modules are loaded." +- exit $OCF_ERR_INSTALLED ++ ocf_log err "configfs not mounted at /sys/kernel/config -- check if required modules are loaded." ++ exit $OCF_ERR_INSTALLED + fi +- # check for configfs entries created by target_core_mod ++ # check for configfs entries created by target_core_mod + if [ ! -d /sys/kernel/config/target ]; then +- ocf_log err "/sys/kernel/config/target does not exist or is not a directory -- check if required modules are loaded." +- exit $OCF_ERR_INSTALLED ++ ocf_log err "/sys/kernel/config/target does not exist or is not a directory -- check if required modules are loaded." ++ exit $OCF_ERR_INSTALLED + fi + ;; ++ lio-t) ++ #targetcli loads the needed kernel modules ++ ;; + esac +- fi ++ fi + +- return $OCF_SUCCESS ++ return $OCF_SUCCESS + } + + +@@ -585,7 +648,7 @@ start) iSCSITarget_start;; + stop) iSCSITarget_stop;; + monitor|status) iSCSITarget_monitor;; + reload) ocf_log err "Reloading..." +- iSCSITarget_start ++ iSCSITarget_start + ;; + validate-all) ;; + *) iSCSITarget_usage +-- +1.8.4.2 + diff --git a/SOURCES/bz1118029-iscsi-remove-write-back.patch b/SOURCES/bz1118029-iscsi-remove-write-back.patch new file mode 100644 index 00000000..eb600f8f --- /dev/null +++ b/SOURCES/bz1118029-iscsi-remove-write-back.patch @@ -0,0 +1,13 @@ +diff --git a/heartbeat/iSCSILogicalUnit b/heartbeat/iSCSILogicalUnit +index b9c1139..ffd66ff 100755 +--- a/heartbeat/iSCSILogicalUnit ++++ b/heartbeat/iSCSILogicalUnit +@@ -362,7 +362,7 @@ iSCSILogicalUnit_start() { + lio-t) + # For lio, we first have to create a target device, then + # add it to the Target Portal Group as an LU. +- ocf_run targetcli /backstores/block create name=${OCF_RESOURCE_INSTANCE} dev=${OCF_RESKEY_path} write_back=False || exit $OCF_ERR_GENERIC ++ ocf_run targetcli /backstores/block create name=${OCF_RESOURCE_INSTANCE} dev=${OCF_RESKEY_path} || exit $OCF_ERR_GENERIC + if [ -n "${OCF_RESKEY_scsi_sn}" ]; then + echo ${OCF_RESKEY_scsi_sn} > /sys/kernel/config/target/core/iblock_${OCF_RESKEY_lio_iblock}/${OCF_RESOURCE_INSTANCE}/wwn/vpd_unit_serial + fi diff --git a/SOURCES/bz1118029_iscsi_syntax_fix.patch b/SOURCES/bz1118029_iscsi_syntax_fix.patch new file mode 100644 index 00000000..d6369258 --- /dev/null +++ b/SOURCES/bz1118029_iscsi_syntax_fix.patch @@ -0,0 +1,39 @@ +From 3a9d34b37c3959c75b60a3598ed0786e5c48a7b3 Mon Sep 17 00:00:00 2001 +From: jprades +Date: Wed, 17 Sep 2014 17:54:10 -0400 +Subject: [PATCH] High: iSCSILogicalUnit: fixes syntax errors + +--- + heartbeat/iSCSILogicalUnit | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/heartbeat/iSCSILogicalUnit b/heartbeat/iSCSILogicalUnit +index c4cee0d..b9c1139 100755 +--- a/heartbeat/iSCSILogicalUnit ++++ b/heartbeat/iSCSILogicalUnit +@@ -419,11 +419,11 @@ iSCSILogicalUnit_stop() { + ${initiator} ${OCF_RESKEY_lun} || exit $OCF_ERR_GENERIC + fi + done +- lun_configfs_path="/sys/kernel/config/target/iscsi/${OCF_RESKEY_target_iqn}/tpgt_1/lun/lun_#{${OCF_RESKEY_lun}/" ++ lun_configfs_path="/sys/kernel/config/target/iscsi/${OCF_RESKEY_target_iqn}/tpgt_1/lun/lun_${OCF_RESKEY_lun}/" + if [ -e "${lun_configfs_path}" ]; then + ocf_run lio_node --dellun=${OCF_RESKEY_target_iqn} 1 ${OCF_RESKEY_lun} || exit $OCF_ERR_GENERIC + fi +- block_configfs_path="/sys/kernel/config/target/core/iblock_${OCF_RESKEY_lio_iblock}/${OCF_RESKEY_INSTANCE}/udev_path" ++ block_configfs_path="/sys/kernel/config/target/core/iblock_${OCF_RESKEY_lio_iblock}/${OCF_RESOURCE_INSTANCE}/udev_path" + if [ -e "${block_configfs_path}" ]; then + ocf_run tcm_node --freedev=iblock_${OCF_RESKEY_lio_iblock}/${OCF_RESOURCE_INSTANCE} || exit $OCF_ERR_GENERIC + fi +@@ -478,7 +478,7 @@ iSCSILogicalUnit_monitor() { + [ -e ${configfs_path} ] && [ `cat ${configfs_path}` = "${OCF_RESKEY_path}" ] && return $OCF_SUCCESS + + # if we aren't activated, is a block device still left over? +- block_configfs_path="/sys/kernel/config/target/core/iblock_${OCF_RESKEY_lio_iblock}/${OCF_RESKEY_INSTANCE}/udev_path" ++ block_configfs_path="/sys/kernel/config/target/core/iblock_${OCF_RESKEY_lio_iblock}/${OCF_RESOURCE_INSTANCE}/udev_path" + [ -e ${block_configfs_path} ] && ocf_log warn "existing block without an active lun: ${block_configfs_path}" + [ -e ${block_configfs_path} ] && return $OCF_ERR_GENERIC + +-- +1.8.4.2 + diff --git a/SOURCES/bz1122285-ethmonitor-infiniband.patch b/SOURCES/bz1122285-ethmonitor-infiniband.patch new file mode 100644 index 00000000..1c5411aa --- /dev/null +++ b/SOURCES/bz1122285-ethmonitor-infiniband.patch @@ -0,0 +1,466 @@ +From feffc766c48a1010c1bf4f8b1db74795d06dbd50 Mon Sep 17 00:00:00 2001 +From: David Vossel +Date: Mon, 25 Aug 2014 14:57:09 -0500 +Subject: [PATCH 2/4] ethmonitor updates + +--- + heartbeat/ethmonitor | 290 +++++++++++++++++++++++++++++++++------------------ + 1 file changed, 187 insertions(+), 103 deletions(-) + +diff --git a/heartbeat/ethmonitor b/heartbeat/ethmonitor +index b85d7fc..a447391 100755 +--- a/heartbeat/ethmonitor ++++ b/heartbeat/ethmonitor +@@ -1,14 +1,14 @@ + #!/bin/sh + # +-# OCF Resource Agent compliant script. +-# Monitor the vitality of a local network interface. ++# OCF Resource Agent compliant script. ++# Monitor the vitality of a local network interface. + # + # Based on the work by Robert Euhus and Lars Marowsky-Brée. + # + # Transfered from Ipaddr2 into ethmonitor by Alexander Krauth + # + # Copyright (c) 2011 Robert Euhus, Alexander Krauth, Lars Marowsky-Brée +-# All Rights Reserved. ++# All Rights Reserved. + # + # This program is free software; you can redistribute it and/or modify + # it under the terms of version 2 of the GNU General Public License as +@@ -29,12 +29,12 @@ + # along with this program; if not, write the Free Software Foundation, + # Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. + # +-# OCF parameters are as below ++# OCF parameters are as below + # + # OCF_RESKEY_interface + # OCF_RESKEY_multiplicator + # OCF_RESKEY_name +-# OCF_RESKEY_repeat_count ++# OCF_RESKEY_repeat_count + # OCF_RESKEY_repeat_interval + # OCF_RESKEY_pktcnt_timeout + # OCF_RESKEY_arping_count +@@ -70,10 +70,13 @@ The resource configuration requires a monitor operation, because the monitor doe + In addition to the resource configuration, you need to configure some location constraints, based on a CIB attribute value. + The name of the attribute value is configured in the 'name' option of this RA. + +-Example constraint configuration: ++Example constraint configuration using crmsh + location loc_connected_node my_resource_grp \ + rule $id="rule_loc_connected_node" -INF: ethmonitor eq 0 + ++Example constraint configuration using pcs. Only allow 'my_resource' to run on nodes where eth0 ethernet device is available. ++pcs constraint location my_resource rule score=-INFINITY ethmonitor-eth0 ne 1 ++ + The ethmonitor works in 3 different modes to test the interface vitality. + 1. call ip to see if the link status is up (if link is down -> error) + 2. call ip and watch the RX counter (if packages come around in a certain time -> success) +@@ -157,14 +160,30 @@ Maximum number of IPs from ARP cache list to check for ARP REQUEST (arping) answ + + + ++ ++ ++For interfaces that are infiniband devices. ++ ++infiniband device ++ ++ ++ ++ ++ ++For infiniband devices, this is the port to monitor. ++ ++infiniband port ++ ++ ++ + + +- +- +- +- +- +- ++ ++ ++ ++ ++ ++ + + + END +@@ -173,7 +192,7 @@ END + } + + # +-# Return true, if the interface exists ++# Return true, if the interface exists + # + is_interface() { + # +@@ -181,14 +200,25 @@ is_interface() { + # + local iface=`$IP2UTIL -o -f inet addr show | grep " $1 " \ + | cut -d ' ' -f2 | sort -u | grep -v '^ipsec[0-9][0-9]*$'` +- [ "$iface" != "" ] ++ [ "$iface" != "" ] ++} ++ ++infiniband_status() ++{ ++ local device="$OCF_RESKEY_infiniband_device" ++ ++ if [ -n "$OCF_RESKEY_infiniband_port" ]; then ++ device="${OCF_RESKEY_infiniband_device}:${OCF_RESKEY_infiniband_port}" ++ fi ++ ++ ibstatus ${device} | grep -q ACTIVE + } + + if_init() { + local rc + + if [ X"$OCF_RESKEY_interface" = "X" ]; then +- ocf_log err "Interface name (the interface parameter) is mandatory" ++ ocf_exit_reason "Interface name (the interface parameter) is mandatory" + exit $OCF_ERR_CONFIGURED + fi + +@@ -196,60 +226,67 @@ if_init() { + + if is_interface $NIC + then +- case "$NIC" in +- *:*) ocf_log err "Do not specify a virtual interface : $OCF_RESKEY_interface" +- exit $OCF_ERR_CONFIGURED;; +- *) ;; +- esac ++ case "$NIC" in ++ *:*) ocf_exit_reason "Do not specify a virtual interface : $OCF_RESKEY_interface" ++ exit $OCF_ERR_CONFIGURED;; ++ *) ;; ++ esac + else +- case $__OCF_ACTION in +- validate-all) ocf_log err "Interface $NIC does not exist" +- exit $OCF_ERR_CONFIGURED;; +- *) ocf_log warn "Interface $NIC does not exist" +- ## It might be a bond interface which is temporarily not available, therefore we want to continue here +- ;; +- esac ++ case $__OCF_ACTION in ++ validate-all) ++ ocf_exit_reason "Interface $NIC does not exist" ++ exit $OCF_ERR_CONFIGURED;; ++ *) ++ ## It might be a bond interface which is temporarily not available, therefore we want to continue here ++ ocf_log warn "Interface $NIC does not exist" ++ ;; ++ esac + fi + + : ${OCF_RESKEY_multiplier:="1"} + if ! ocf_is_decimal "$OCF_RESKEY_multiplier"; then +- ocf_log err "Invalid OCF_RESKEY_multiplier [$OCF_RESKEY_multiplier]" ++ ocf_exit_reason "Invalid OCF_RESKEY_multiplier [$OCF_RESKEY_multiplier]" + exit $OCF_ERR_CONFIGURED + fi + + ATTRNAME=${OCF_RESKEY_name:-"ethmonitor-$NIC"} + +- REP_COUNT=${OCF_RESKEY_repeat_count:-5} ++ REP_COUNT=${OCF_RESKEY_repeat_count:-5} + if ! ocf_is_decimal "$REP_COUNT" -o [ $REP_COUNT -lt 1 ]; then +- ocf_log err "Invalid OCF_RESKEY_repeat_count [$REP_COUNT]" ++ ocf_exit_reason "Invalid OCF_RESKEY_repeat_count [$REP_COUNT]" + exit $OCF_ERR_CONFIGURED +- fi ++ fi + REP_INTERVAL_S=${OCF_RESKEY_repeat_interval:-10} + if ! ocf_is_decimal "$REP_INTERVAL_S"; then +- ocf_log err "Invalid OCF_RESKEY_repeat_interval [$REP_INTERVAL_S]" ++ ocf_exit_reason "Invalid OCF_RESKEY_repeat_interval [$REP_INTERVAL_S]" + exit $OCF_ERR_CONFIGURED + fi + : ${OCF_RESKEY_pktcnt_timeout:="5"} + if ! ocf_is_decimal "$OCF_RESKEY_pktcnt_timeout"; then +- ocf_log err "Invalid OCF_RESKEY_pktcnt_timeout [$OCF_RESKEY_pktcnt_timeout]" ++ ocf_exit_reason "Invalid OCF_RESKEY_pktcnt_timeout [$OCF_RESKEY_pktcnt_timeout]" + exit $OCF_ERR_CONFIGURED + fi + : ${OCF_RESKEY_arping_count:="1"} + if ! ocf_is_decimal "$OCF_RESKEY_arping_count"; then +- ocf_log err "Invalid OCF_RESKEY_arping_count [$OCF_RESKEY_arping_count]" ++ ocf_exit_reason "Invalid OCF_RESKEY_arping_count [$OCF_RESKEY_arping_count]" + exit $OCF_ERR_CONFIGURED + fi + : ${OCF_RESKEY_arping_timeout:="1"} + if ! ocf_is_decimal "$OCF_RESKEY_arping_timeout"; then +- ocf_log err "Invalid OCF_RESKEY_arping_timeout [$OCF_RESKEY_arping_count]" ++ ocf_exit_reason "Invalid OCF_RESKEY_arping_timeout [$OCF_RESKEY_arping_count]" + exit $OCF_ERR_CONFIGURED + fi + : ${OCF_RESKEY_arping_cache_entries:="5"} + if ! ocf_is_decimal "$OCF_RESKEY_arping_cache_entries"; then +- ocf_log err "Invalid OCF_RESKEY_arping_cache_entries [$OCF_RESKEY_arping_cache_entries]" ++ ocf_exit_reason "Invalid OCF_RESKEY_arping_cache_entries [$OCF_RESKEY_arping_cache_entries]" + exit $OCF_ERR_CONFIGURED + fi +- return $OCF_SUCCESS ++ ++ if [ -n "$OCF_RESKEY_infiniband_device" ]; then ++ #ibstatus is required if an infiniband_device is provided ++ check_binary ibstatus ++ fi ++ return $OCF_SUCCESS + } + + # get the link status on $NIC +@@ -277,7 +314,7 @@ watch_pkt_counter () { + for n in `seq $(( $OCF_RESKEY_pktcnt_timeout * 10 ))`; do + sleep 0.1 + RX_PACKETS_NEW="`get_rx_packets`" +- ocf_log debug "RX_PACKETS_OLD: $RX_PACKETS_OLD RX_PACKETS_NEW: $RX_PACKETS_NEW" ++ ocf_log debug "RX_PACKETS_OLD: $RX_PACKETS_OLD RX_PACKETS_NEW: $RX_PACKETS_NEW" + if [ "$RX_PACKETS_OLD" -ne "$RX_PACKETS_NEW" ]; then + ocf_log debug "we received some packets." + return 0 +@@ -308,7 +345,7 @@ do_arping () { + } + + # +-# Check the interface depending on the level given as parameter: $OCF_RESKEY_check_level ++# Check the interface depending on the level given as parameter: $OCF_RESKEY_check_level + # + # 09: check for nonempty ARP cache + # 10: watch for packet counter changes +@@ -322,21 +359,47 @@ do_arping () { + # the tests for higher check levels are run. + # + if_check () { ++ local arp_list + # always check link status first + link_status="`get_link_status`" + ocf_log debug "link_status: $link_status (1=up, 0=down)" +- [ $link_status -eq 0 ] && return $OCF_NOT_RUNNING ++ ++ if [ $link_status -eq 0 ]; then ++ ocf_log notice "link_status: DOWN" ++ return $OCF_NOT_RUNNING ++ fi ++ ++ # if this is an infiniband device, try ibstatus script ++ if [ -n "$OCF_RESKEY_infiniband_device" ]; then ++ if infiniband_status; then ++ return $OCF_SUCCESS ++ fi ++ ocf_log info "Infiniband device $OCF_RESKEY_infiniband_device is not available, check ibstatus for more information" ++ return $OCF_NOT_RUNNING ++ fi + + # watch for packet counter changes +- ocf_log debug "watch for packet counter changes" +- watch_pkt_counter && return $OCF_SUCCESS ++ ocf_log debug "watch for packet counter changes" ++ watch_pkt_counter ++ if [ $? -eq 0 ]; then ++ return $OCF_SUCCESS ++ else ++ ocf_log debug "No packets received during packet watch timeout" ++ fi + + # check arping ARP cache entries +- ocf_log debug "check arping ARP cache entries" +- for ip in `get_arp_list`; do ++ ocf_log debug "check arping ARP cache entries" ++ arp_list=`get_arp_list` ++ for ip in `echo $arp_list`; do + do_arping $ip && return $OCF_SUCCESS + done + ++ # if we get here, the ethernet device is considered not running. ++ # provide some logging information ++ if [ -z "$arp_list" ]; then ++ ocf_log info "No ARP cache entries found to arping" ++ fi ++ + # watch for packet counter changes in promiscios mode + # ocf_log debug "watch for packet counter changes in promiscios mode" + # be sure switch off promiscios mode in any case +@@ -362,67 +425,89 @@ END + } + + set_cib_value() { +- local score=`expr $1 \* $OCF_RESKEY_multiplier` +- attrd_updater -n $ATTRNAME -v $score -q +- local rc=$? +- case $rc in +- 0) ocf_log debug "attrd_updater: Updated $ATTRNAME = $score" ;; +- *) ocf_log warn "attrd_updater: Could not update $ATTRNAME = $score: rc=$rc";; +- esac +- return $rc ++ local score=`expr $1 \* $OCF_RESKEY_multiplier` ++ attrd_updater -n $ATTRNAME -v $score -q ++ local rc=$? ++ case $rc in ++ 0) ocf_log debug "attrd_updater: Updated $ATTRNAME = $score" ;; ++ *) ocf_log warn "attrd_updater: Could not update $ATTRNAME = $score: rc=$rc";; ++ esac ++ return $rc + } + + if_monitor() { +- ha_pseudo_resource $OCF_RESOURCE_INSTANCE monitor +- local pseudo_status=$? +- if [ $pseudo_status -ne $OCF_SUCCESS ]; then +- exit $pseudo_status +- fi +- +- local mon_rc=$OCF_NOT_RUNNING +- local attr_rc=$OCF_NOT_RUNNING +- local runs=0 +- local start_time +- local end_time +- local sleep_time +- while [ $mon_rc -ne $OCF_SUCCESS -a $REP_COUNT -gt 0 ] +- do +- start_time=`date +%s%N` +- if_check +- mon_rc=$? +- REP_COUNT=$(( $REP_COUNT - 1 )) +- if [ $mon_rc -ne $OCF_SUCCESS -a $REP_COUNT -gt 0 ]; then +- ocf_log warn "Monitoring of $OCF_RESOURCE_INSTANCE failed, $REP_COUNT retries left." +- end_time=`date +%s%N` +- sleep_time=`echo "scale=9; ( $start_time + ( $REP_INTERVAL_S * 1000000000 ) - $end_time ) / 1000000000" | bc -q 2> /dev/null` +- sleep $sleep_time 2> /dev/null +- runs=$(($runs + 1)) +- fi +- +- if [ $mon_rc -eq $OCF_SUCCESS -a $runs -ne 0 ]; then +- ocf_log info "Monitoring of $OCF_RESOURCE_INSTANCE recovered from error" +- fi +- done +- +- ocf_log debug "Monitoring return code: $mon_rc" +- if [ $mon_rc -eq $OCF_SUCCESS ]; then +- set_cib_value 1 +- attr_rc=$? +- else +- ocf_log err "Monitoring of $OCF_RESOURCE_INSTANCE failed." +- set_cib_value 0 +- attr_rc=$? +- fi +- +- ## The resource should not fail, if the interface is down. It should fail, if the update of the CIB variable has errors. +- ## To react on the interface failure you must use constraints based on the CIB variable value, not on the resource itself. +- exit $attr_rc ++ ha_pseudo_resource $OCF_RESOURCE_INSTANCE monitor ++ local pseudo_status=$? ++ if [ $pseudo_status -ne $OCF_SUCCESS ]; then ++ exit $pseudo_status ++ fi ++ ++ local mon_rc=$OCF_NOT_RUNNING ++ local attr_rc=$OCF_NOT_RUNNING ++ local runs=0 ++ local start_time ++ local end_time ++ local sleep_time ++ while [ $mon_rc -ne $OCF_SUCCESS -a $REP_COUNT -gt 0 ] ++ do ++ start_time=`date +%s%N` ++ if_check ++ mon_rc=$? ++ REP_COUNT=$(( $REP_COUNT - 1 )) ++ if [ $mon_rc -ne $OCF_SUCCESS -a $REP_COUNT -gt 0 ]; then ++ ocf_log warn "Monitoring of $OCF_RESOURCE_INSTANCE failed, $REP_COUNT retries left." ++ end_time=`date +%s%N` ++ sleep_time=`echo "scale=9; ( $start_time + ( $REP_INTERVAL_S * 1000000000 ) - $end_time ) / 1000000000" | bc -q 2> /dev/null` ++ sleep $sleep_time 2> /dev/null ++ runs=$(($runs + 1)) ++ fi ++ ++ if [ $mon_rc -eq $OCF_SUCCESS -a $runs -ne 0 ]; then ++ ocf_log info "Monitoring of $OCF_RESOURCE_INSTANCE recovered from error" ++ fi ++ done ++ ++ ocf_log debug "Monitoring return code: $mon_rc" ++ if [ $mon_rc -eq $OCF_SUCCESS ]; then ++ set_cib_value 1 ++ attr_rc=$? ++ else ++ ocf_log err "Monitoring of $OCF_RESOURCE_INSTANCE failed." ++ set_cib_value 0 ++ attr_rc=$? ++ fi ++ ++ ## The resource should not fail, if the interface is down. It should fail, if the update of the CIB variable has errors. ++ ## To react on the interface failure you must use constraints based on the CIB variable value, not on the resource itself. ++ exit $attr_rc ++} ++ ++if_stop() ++{ ++ attrd_updater -D -n $ATTRNAME ++ ha_pseudo_resource $OCF_RESOURCE_INSTANCE stop + } + ++if_start() ++{ ++ local rc ++ ha_pseudo_resource $OCF_RESOURCE_INSTANCE start ++ rc=$? ++ if [ $rc -ne $OCF_SUCCESS ]; then ++ ocf_exit_reason "Failure to create ethmonitor state file" ++ return $rc ++ fi ++ ++ # perform the first monitor during the start operation ++ if_monitor ++ return $? ++} ++ ++ + if_validate() { +- check_binary $IP2UTIL +- check_binary arping +- if_init ++ check_binary $IP2UTIL ++ check_binary arping ++ if_init + } + + case $__OCF_ACTION in +@@ -436,18 +521,17 @@ esac + if_validate + + case $__OCF_ACTION in +-start) ha_pseudo_resource $OCF_RESOURCE_INSTANCE start ++start) if_start + exit $? + ;; +-stop) attrd_updater -D -n $ATTRNAME +- ha_pseudo_resource $OCF_RESOURCE_INSTANCE stop ++stop) if_stop + exit $? + ;; + monitor|status) if_monitor + exit $? + ;; + validate-all) exit $? +- ;; ++ ;; + *) if_usage + exit $OCF_ERR_UNIMPLEMENTED + ;; +-- +1.8.4.2 + diff --git a/SOURCES/bz1126073-1-nfsserver-fix-systemd-status-detection.patch b/SOURCES/bz1126073-1-nfsserver-fix-systemd-status-detection.patch new file mode 100644 index 00000000..7e2d3b9c --- /dev/null +++ b/SOURCES/bz1126073-1-nfsserver-fix-systemd-status-detection.patch @@ -0,0 +1,474 @@ +diff -uNr a/heartbeat/nfsserver b/heartbeat/nfsserver +--- a/heartbeat/nfsserver 2016-02-05 09:04:19.350003826 +0100 ++++ b/heartbeat/nfsserver 2016-02-05 09:04:58.463395839 +0100 +@@ -208,9 +208,9 @@ + + + +- +- +- ++ ++ ++ + + + +@@ -327,11 +327,12 @@ + nfs_exec() + { + local cmd=$1 ++ local svc=$2 + set_exec_mode + + case $EXEC_MODE in + 1) ${OCF_RESKEY_nfs_init_script} $cmd;; +- 2) systemctl $cmd nfs-server.service ;; ++ 2) systemctl $cmd ${svc}.service ;; + esac + } + +@@ -353,21 +354,117 @@ + + nfsserver_monitor () + { ++ # Skip trying to start processes once before failing ++ # when run from nfsserver_start () ++ if [ "$1" == "fromstart" ]; then ++ ocf_log info "fromstart" ++ fromstart=1 ++ else ++ tries=1 ++ fi ++ ++ # systemd ++ if [ "$EXEC_MODE" -eq "2" ]; then ++ ocf_log info "Status: rpcbind" ++ rpcinfo &> /dev/null ++ rc=$? ++ if [ "$rc" -ne "0" ]; then ++ if [ ! "$fromstart" ] && [ "$tries" -gt "0" ]; then ++ nfsserver_start frommonitor ++ rc=$? ++ let tries=$tries-1 ++ fi ++ if [ "$rc" -ne "0" ]; then ++ ocf_exit_reason "rpcbind is not running" ++ return $OCF_NOT_RUNNING ++ fi ++ fi ++ ++ ocf_log info "Status: nfs-mountd" ++ rpcinfo -t localhost 100005 &> /dev/null ++ rc=$? ++ if [ "$rc" -ne "0" ]; then ++ if [ ! "$fromstart" ] && [ "$tries" -gt "0" ]; then ++ nfsserver_start frommonitor ++ rc=$? ++ let tries=$tries-1 ++ fi ++ if [ "$rc" -ne "0" ]; then ++ ocf_exit_reason "nfs-mountd is not running" ++ return $OCF_NOT_RUNNING ++ fi ++ fi ++ ++ ocf_log info "Status: nfs-idmapd" ++ fn=`mktemp` ++ nfs_exec status nfs-idmapd > $fn 2>&1 ++ rc=$? ++ ocf_log debug "$(cat $fn)" ++ rm -f $fn ++ if [ "$rc" -ne "0" ]; then ++ if [ ! "$fromstart" ] && [ "$tries" -gt "0" ]; then ++ nfsserver_start frommonitor ++ rc=$? ++ ocf_log info "Tried to start services: rc: $rc" ++ let tries=$tries-1 ++ fi ++ if [ "$rc" -ne "0" ]; then ++ ocf_exit_reason "nfs-idmapd is not running" ++ return $OCF_NOT_RUNNING ++ fi ++ fi ++ ++ ocf_log info "Status: rpc-statd" ++ rpcinfo -t localhost 100024 &> /dev/null ++ rc=$? ++ if [ "$rc" -ne "0" ]; then ++ if [ ! "$fromstart" ] && [ "$tries" -gt "0" ]; then ++ nfsserver_start frommonitor ++ rc=$? ++ let tries=$tries-1 ++ fi ++ if [ "$rc" -ne "0" ]; then ++ ocf_exit_reason "rpc-statd is not running" ++ return $OCF_NOT_RUNNING ++ fi ++ fi ++ fi ++ + fn=`mktemp` +- nfs_exec status > $fn 2>&1 ++ nfs_exec status nfs-server > $fn 2>&1 + rc=$? + ocf_log debug "$(cat $fn)" + rm -f $fn + +- #Adapte LSB status code to OCF return code ++ tfn="/proc/fs/nfsd/threads" ++ if [ ! -f "$tfn" ] || [ "$(cat $tfn)" -le "0" ]; then ++ if [ ! "$fromstart" ] && [ "$tries" -gt "0" ]; then ++ nfsserver_start frommonitor ++ rc=$? ++ let tries=$tries-1 ++ fi ++ if [ "$rc" -ne "0" ]; then ++ ocf_exit_reason "NFS server not running: /proc/fs/nfsd/threads" ++ return $OCF_NOT_RUNNING ++ fi ++ fi ++ ++ #Adapt LSB status code to OCF return code + if [ $rc -eq 0 ]; then + # don't report success if nfs servers are up + # without locking daemons. + v3locking_exec "status" + rc=$? + if [ $rc -ne 0 ]; then +- ocf_exit_reason "NFS server is up, but the locking daemons are down" +- rc=$OCF_ERR_GENERIC ++ if [ ! "$fromstart" ] && [ $tries -gt "0" ]; then ++ nfsserver_start frommonitor ++ rc=$? ++ let tries=$tries-1 ++ fi ++ if [ "$rc" -ne "0" ]; then ++ ocf_exit_reason "NFS server is up, but the locking daemons are down" ++ rc=$OCF_ERR_GENERIC ++ fi + fi + return $rc + elif [ $rc -eq 3 ]; then +@@ -391,12 +488,7 @@ + # only write to the tmp /etc/sysconfig/nfs if sysconfig exists. + # otherwise this distro does not support setting these options. + if [ -d "/etc/sysconfig" ]; then +- # replace if the value exists, append otherwise +- if grep "^\s*${key}=" $file ; then +- sed -i "s/\s*${key}=.*$/${key}=\"${value}\"/" $file +- else +- echo "${key}=\"${value}\"" >> $file +- fi ++ echo "${key}=\"${value}\"" >> $file + elif [ "$requires_sysconfig" = "true" ]; then + ocf_log warn "/etc/sysconfig/nfs not found, unable to set port and nfsd args." + fi +@@ -409,11 +501,6 @@ + local tmpconfig=$(mktemp ${HA_RSCTMP}/nfsserver-tmp-XXXXX) + local statd_args + +- if [ -f "$NFS_SYSCONFIG" ]; then +- ## Take the $NFS_SYSCONFIG file as our skeleton +- cp $NFS_SYSCONFIG $tmpconfig +- fi +- + # nfsd args + set_arg "RPCNFSDARGS" "$OCF_RESKEY_nfsd_args" "$tmpconfig" "true" + +@@ -444,20 +531,14 @@ + + # override local nfs config. preserve previous local config though. + if [ -s $tmpconfig ]; then +- cat $NFS_SYSCONFIG | grep -q -e "$NFS_SYSCONFIG_AUTOGEN_TAG" > /dev/null 2>&1 ++ cat $NFS_SYSCONFIG | grep -e "$NFS_SYSCONFIG_AUTOGEN_TAG" + if [ $? -ne 0 ]; then + # backup local nfs config if it doesn't have our HA autogen tag in it. + mv -f $NFS_SYSCONFIG $NFS_SYSCONFIG_LOCAL_BACKUP + fi +- +- cat $tmpconfig | grep -q -e "$NFS_SYSCONFIG_AUTOGEN_TAG" > /dev/null 2>&1 +- if [ $? -ne 0 ]; then +- echo "# $NFS_SYSCONFIG_AUTOGEN_TAG" > $NFS_SYSCONFIG +- echo "# local config backup stored here, '$NFS_SYSCONFIG_LOCAL_BACKUP'" >> $NFS_SYSCONFIG +- cat $tmpconfig >> $NFS_SYSCONFIG +- else +- cat $tmpconfig > $NFS_SYSCONFIG +- fi ++ echo "# $NFS_SYSCONFIG_AUTOGEN_TAG" > $NFS_SYSCONFIG ++ echo "# local config backup stored here, '$NFS_SYSCONFIG_LOCAL_BACKUP'" >> $NFS_SYSCONFIG ++ cat $tmpconfig >> $NFS_SYSCONFIG + fi + rm -f $tmpconfig + } +@@ -476,14 +557,13 @@ + [ -d "$fp/$STATD_DIR/sm" ] || mkdir -p "$fp/$STATD_DIR/sm" + [ -d "$fp/$STATD_DIR/sm.ha" ] || mkdir -p "$fp/$STATD_DIR/sm.ha" + [ -d "$fp/$STATD_DIR/sm.bak" ] || mkdir -p "$fp/$STATD_DIR/sm.bak" +- [ -n "`id -u rpcuser 2>/dev/null`" -a "`id -g rpcuser 2>/dev/null`" ] && +- chown -R rpcuser.rpcuser "$fp/$STATD_DIR" ++ [ -n "`id -u rpcuser`" -a "`id -g rpcuser`" ] && chown -R rpcuser.rpcuser "$fp/$STATD_DIR" + + [ -f "$fp/etab" ] || touch "$fp/etab" + [ -f "$fp/xtab" ] || touch "$fp/xtab" + [ -f "$fp/rmtab" ] || touch "$fp/rmtab" + +- dd if=/dev/urandom of=$fp/$STATD_DIR/state bs=1 count=4 >/dev/null 2>&1 ++ dd if=/dev/urandom of=$fp/$STATD_DIR/state bs=1 count=4 &> /dev/null + [ -n "`id -u rpcuser`" -a "`id -g rpcuser`" ] && chown rpcuser.rpcuser "$fp/$STATD_DIR/state" + [ $SELINUX_ENABLED -eq 0 ] && chcon -R "$SELINUX_LABEL" "$fp" + } +@@ -563,15 +643,15 @@ + + terminate() + { +- local pids +- local i=0 ++ declare pids ++ declare i=0 + + while : ; do + pids=$(binary_status $1) + [ -z "$pids" ] && return 0 + kill $pids + sleep 1 +- i=$((i + 1)) ++ ((i++)) + [ $i -gt 3 ] && return 1 + done + } +@@ -579,22 +659,22 @@ + + killkill() + { +- local pids +- local i=0 ++ declare pids ++ declare i=0 + + while : ; do + pids=$(binary_status $1) + [ -z "$pids" ] && return 0 + kill -9 $pids + sleep 1 +- i=$((i + 1)) ++ ((i++)) + [ $i -gt 3 ] && return 1 + done + } + + stop_process() + { +- local process=$1 ++ declare process=$1 + + ocf_log info "Stopping $process" + if terminate $process; then +@@ -665,9 +745,14 @@ + + nfsserver_start () + { ++ # Skip monitor check when run from nfsserver_monitor () ++ if [ "$1" == "frommonitor" ]; then ++ frommonitor=1 ++ fi ++ + local rc; + +- if nfsserver_monitor; then ++ if [ ! "$frommonitor" ] && nfsserver_monitor fromstart; then + ocf_log debug "NFS server is already started" + return $OCF_SUCCESS + fi +@@ -693,11 +778,32 @@ + modprobe nfsd + fi + ++ # systemd ++ if [ "$EXEC_MODE" -eq "2" ]; then ++ nfs_exec start rpcbind ++ local i=10 ++ while [ "$i" -gt 0 ]; do ++ ocf_log info "Start: rpcbind i: $i" ++ rpcinfo &> /dev/null ++ rc=$? ++ if [ "$rc" -eq "0" ]; then ++ break; ++ fi ++ sleep 1 ++ let i=$i-1 ++ done ++ if [ "$i" -eq 0 ]; then ++ ocf_exit_reason "Failed to start rpcbind" ++ return $OCF_ERR_GENERIC ++ fi ++ fi ++ + # check to see if we need to start rpc.statd + v3locking_exec "status" + if [ $? -ne $OCF_SUCCESS ]; then + v3locking_exec "start" + rc=$? ++ ocf_log info "Start: v3locking: $rc" + if [ $rc -ne 0 ]; then + ocf_exit_reason "Failed to start NFS server locking daemons" + return $rc +@@ -706,8 +812,65 @@ + ocf_log info "rpc.statd already up" + fi + ++ # systemd ++ if [ "$EXEC_MODE" -eq "2" ]; then ++ nfs_exec start nfs-mountd ++ local i=10 ++ while [ "$i" -gt 0 ]; do ++ ocf_log info "Start: nfs-mountd i: $i" ++ rpcinfo -t localhost 100005 &> /dev/null ++ rc=$? ++ if [ "$rc" -eq "0" ]; then ++ break; ++ fi ++ sleep 1 ++ let i=$i-1 ++ done ++ if [ "$i" -eq 0 ]; then ++ ocf_exit_reason "Failed to start nfs-mountd" ++ return $OCF_ERR_GENERIC ++ fi ++ ++ nfs_exec start nfs-idmapd ++ local i=10 ++ while [ "$i" -gt 0 ]; do ++ ocf_log info "Start: nfs-idmapd i: $i" ++ fn=`mktemp` ++ nfs_exec status nfs-idmapd > $fn 2>&1 ++ rc=$? ++ ocf_log debug "$(cat $fn)" ++ rm -f $fn ++ if [ "$rc" -eq "0" ]; then ++ break; ++ fi ++ sleep 1 ++ let i=$i-1 ++ done ++ if [ "$i" -eq 0 ]; then ++ ocf_exit_reason "Failed to start nfs-idmapd" ++ return $OCF_ERR_GENERIC ++ fi ++ ++ nfs_exec start rpc-statd ++ local i=10 ++ while [ "$i" -gt 0 ]; do ++ ocf_log info "Start: rpc-statd i: $i" ++ rpcinfo -t localhost 100024 &> /dev/null ++ rc=$? ++ if [ "$rc" -eq "0" ]; then ++ break; ++ fi ++ sleep 1 ++ let i=$i-1 ++ done ++ if [ "$i" -eq 0 ]; then ++ ocf_exit_reason "Failed to start rpc-statd" ++ return $OCF_ERR_GENERIC ++ fi ++ fi ++ + fn=`mktemp` +- nfs_exec start > $fn 2>&1 ++ nfs_exec start nfs-server > $fn 2>&1 + rc=$? + ocf_log debug "$(cat $fn)" + rm -f $fn +@@ -717,6 +880,12 @@ + return $rc + fi + ++ tfn="/proc/fs/nfsd/threads" ++ if [ ! -f "$tfn" ] || [ "$(cat $tfn)" -le "0" ]; then ++ ocf_exit_reason "Failed to start NFS server: /proc/fs/nfsd/threads" ++ return $OCF_ERR_GENERIC ++ fi ++ + notify_locks + + ocf_log info "NFS server started" +@@ -733,24 +902,71 @@ + cp -rpf $STATD_PATH/sm $STATD_PATH/sm.bak /var/lib/nfs/state $STATD_PATH/sm.ha > /dev/null 2>&1 + + fn=`mktemp` +- nfs_exec stop > $fn 2>&1 ++ nfs_exec stop nfs-server > $fn 2>&1 + rc=$? + ocf_log debug "$(cat $fn)" + rm -f $fn + ++ if [ $rc -ne 0 ]; then ++ ocf_exit_reason "Failed to stop NFS server" ++ return $rc ++ fi ++ ++ # systemd ++ if [ "$EXEC_MODE" -eq "2" ]; then ++ ocf_log info "Stop: threads" ++ tfn="/proc/fs/nfsd/threads" ++ if [ -f "$tfn" ] && [ "$(cat $tfn)" -gt "0" ]; then ++ ocf_exit_reason "NFS server failed to stop: /proc/fs/nfsd/threads" ++ return $OCF_ERR_GENERIC ++ fi ++ ++ nfs_exec stop rpc-statd &> /dev/null ++ ocf_log info "Stop: rpc-statd" ++ rpcinfo -t localhost 100024 &> /dev/null ++ rc=$? ++ if [ "$rc" -eq "0" ]; then ++ ocf_exit_reason "Failed to stop rpc-statd" ++ return $OCF_ERR_GENERIC ++ fi ++ ++ nfs_exec stop nfs-idmapd &> /dev/null ++ ocf_log info "Stop: nfs-idmapd" ++ fn=`mktemp` ++ nfs_exec status nfs-idmapd > $fn 2>&1 ++ rc=$? ++ ocf_log debug "$(cat $fn)" ++ rm -f $fn ++ if [ "$rc" -eq "0" ]; then ++ ocf_exit_reason "Failed to stop nfs-idmapd" ++ return $OCF_ERR_GENERIC ++ fi ++ ++ nfs_exec stop nfs-mountd &> /dev/null ++ ocf_log info "Stop: nfs-mountd" ++ rpcinfo -t localhost 100005 &> /dev/null ++ rc=$? ++ if [ "$rc" -eq "0" ]; then ++ ocf_exit_reason "Failed to stop nfs-mountd" ++ return $OCF_ERR_GENERIC ++ fi ++ fi ++ + v3locking_exec "stop" + if [ $? -ne 0 ]; then + ocf_exit_reason "Failed to stop NFS locking daemons" + rc=$OCF_ERR_GENERIC + fi + +- if [ $rc -eq 0 ]; then +- unbind_tree +- ocf_log info "NFS server stopped" +- else +- ocf_exit_reason "Failed to stop NFS server" ++ # systemd ++ if [ "$EXEC_MODE" -eq "2" ]; then ++ nfs_exec stop rpcbind &> /dev/null ++ ocf_log info "Stop: rpcbind" + fi +- return $rc ++ ++ unbind_tree ++ ocf_log info "NFS server stopped" ++ return 0 + } + + nfsserver_validate () diff --git a/SOURCES/bz1126073-2-nfsserver-fix-systemd-status-detection.patch b/SOURCES/bz1126073-2-nfsserver-fix-systemd-status-detection.patch new file mode 100644 index 00000000..74ec4132 --- /dev/null +++ b/SOURCES/bz1126073-2-nfsserver-fix-systemd-status-detection.patch @@ -0,0 +1,337 @@ +diff -uNr a/heartbeat/nfsserver b/heartbeat/nfsserver +--- a/heartbeat/nfsserver 2016-07-21 12:40:55.417326145 +0200 ++++ b/heartbeat/nfsserver 2016-07-21 12:04:49.000000000 +0200 +@@ -352,45 +352,22 @@ + + nfsserver_monitor () + { +- # Skip trying to start processes once before failing +- # when run from nfsserver_start () +- if [ "$1" == "fromstart" ]; then +- ocf_log info "fromstart" +- fromstart=1 +- else +- tries=1 +- fi +- + # systemd + if [ "$EXEC_MODE" -eq "2" ]; then + ocf_log info "Status: rpcbind" +- rpcinfo &> /dev/null ++ rpcinfo > /dev/null 2>&1 + rc=$? + if [ "$rc" -ne "0" ]; then +- if [ ! "$fromstart" ] && [ "$tries" -gt "0" ]; then +- nfsserver_start frommonitor +- rc=$? +- let tries=$tries-1 +- fi +- if [ "$rc" -ne "0" ]; then +- ocf_exit_reason "rpcbind is not running" +- return $OCF_NOT_RUNNING +- fi ++ ocf_exit_reason "rpcbind is not running" ++ return $OCF_NOT_RUNNING + fi + + ocf_log info "Status: nfs-mountd" +- rpcinfo -t localhost 100005 &> /dev/null ++ rpcinfo -t localhost 100005 > /dev/null 2>&1 + rc=$? + if [ "$rc" -ne "0" ]; then +- if [ ! "$fromstart" ] && [ "$tries" -gt "0" ]; then +- nfsserver_start frommonitor +- rc=$? +- let tries=$tries-1 +- fi +- if [ "$rc" -ne "0" ]; then +- ocf_exit_reason "nfs-mountd is not running" +- return $OCF_NOT_RUNNING +- fi ++ ocf_exit_reason "nfs-mountd is not running" ++ return $OCF_NOT_RUNNING + fi + + ocf_log info "Status: nfs-idmapd" +@@ -400,31 +377,16 @@ + ocf_log debug "$(cat $fn)" + rm -f $fn + if [ "$rc" -ne "0" ]; then +- if [ ! "$fromstart" ] && [ "$tries" -gt "0" ]; then +- nfsserver_start frommonitor +- rc=$? +- ocf_log info "Tried to start services: rc: $rc" +- let tries=$tries-1 +- fi +- if [ "$rc" -ne "0" ]; then +- ocf_exit_reason "nfs-idmapd is not running" +- return $OCF_NOT_RUNNING +- fi ++ ocf_exit_reason "nfs-idmapd is not running" ++ return $OCF_NOT_RUNNING + fi + + ocf_log info "Status: rpc-statd" +- rpcinfo -t localhost 100024 &> /dev/null ++ rpcinfo -t localhost 100024 > /dev/null 2>&1 + rc=$? + if [ "$rc" -ne "0" ]; then +- if [ ! "$fromstart" ] && [ "$tries" -gt "0" ]; then +- nfsserver_start frommonitor +- rc=$? +- let tries=$tries-1 +- fi +- if [ "$rc" -ne "0" ]; then +- ocf_exit_reason "rpc-statd is not running" +- return $OCF_NOT_RUNNING +- fi ++ ocf_exit_reason "rpc-statd is not running" ++ return $OCF_NOT_RUNNING + fi + fi + +@@ -436,15 +398,8 @@ + + tfn="/proc/fs/nfsd/threads" + if [ ! -f "$tfn" ] || [ "$(cat $tfn)" -le "0" ]; then +- if [ ! "$fromstart" ] && [ "$tries" -gt "0" ]; then +- nfsserver_start frommonitor +- rc=$? +- let tries=$tries-1 +- fi +- if [ "$rc" -ne "0" ]; then +- ocf_exit_reason "NFS server not running: /proc/fs/nfsd/threads" +- return $OCF_NOT_RUNNING +- fi ++ ocf_exit_reason "NFS server not running: /proc/fs/nfsd/threads" ++ return $OCF_NOT_RUNNING + fi + + #Adapt LSB status code to OCF return code +@@ -454,15 +409,8 @@ + v3locking_exec "status" + rc=$? + if [ $rc -ne 0 ]; then +- if [ ! "$fromstart" ] && [ $tries -gt "0" ]; then +- nfsserver_start frommonitor +- rc=$? +- let tries=$tries-1 +- fi +- if [ "$rc" -ne "0" ]; then +- ocf_exit_reason "NFS server is up, but the locking daemons are down" +- rc=$OCF_ERR_GENERIC +- fi ++ ocf_exit_reason "NFS server is up, but the locking daemons are down" ++ rc=$OCF_ERR_GENERIC + fi + return $rc + elif [ $rc -eq 3 ]; then +@@ -561,7 +509,7 @@ + [ -f "$fp/xtab" ] || touch "$fp/xtab" + [ -f "$fp/rmtab" ] || touch "$fp/rmtab" + +- dd if=/dev/urandom of=$fp/$STATD_DIR/state bs=1 count=4 &> /dev/null ++ dd if=/dev/urandom of=$fp/$STATD_DIR/state bs=1 count=4 > /dev/null 2>&1 + [ -n "`id -u rpcuser`" -a "`id -g rpcuser`" ] && chown rpcuser.rpcuser "$fp/$STATD_DIR/state" + [ $SELINUX_ENABLED -eq 0 ] && chcon -R "$SELINUX_LABEL" "$fp" + } +@@ -656,15 +604,15 @@ + + terminate() + { +- declare pids +- declare i=0 ++ local pids ++ local i=0 + + while : ; do + pids=$(binary_status $1) + [ -z "$pids" ] && return 0 + kill $pids + sleep 1 +- ((i++)) ++ i=$((i + 1)) + [ $i -gt 3 ] && return 1 + done + } +@@ -672,22 +620,22 @@ + + killkill() + { +- declare pids +- declare i=0 ++ local pids ++ local i=0 + + while : ; do + pids=$(binary_status $1) + [ -z "$pids" ] && return 0 + kill -9 $pids + sleep 1 +- ((i++)) ++ i=$((i + 1)) + [ $i -gt 3 ] && return 1 + done + } + + stop_process() + { +- declare process=$1 ++ local process=$1 + + ocf_log info "Stopping $process" + if terminate $process; then +@@ -758,14 +706,9 @@ + + nfsserver_start () + { +- # Skip monitor check when run from nfsserver_monitor () +- if [ "$1" == "frommonitor" ]; then +- frommonitor=1 +- fi +- + local rc; + +- if [ ! "$frommonitor" ] && nfsserver_monitor fromstart; then ++ if nfsserver_monitor; then + ocf_log debug "NFS server is already started" + return $OCF_SUCCESS + fi +@@ -796,21 +739,17 @@ + # systemd + if [ "$EXEC_MODE" -eq "2" ]; then + nfs_exec start rpcbind +- local i=10 +- while [ "$i" -gt 0 ]; do ++ local i=1 ++ while : ; do + ocf_log info "Start: rpcbind i: $i" +- rpcinfo &> /dev/null ++ rpcinfo > /dev/null 2>&1 + rc=$? + if [ "$rc" -eq "0" ]; then + break; + fi + sleep 1 +- let i=$i-1 ++ i=$((i + 1)) + done +- if [ "$i" -eq 0 ]; then +- ocf_exit_reason "Failed to start rpcbind" +- return $OCF_ERR_GENERIC +- fi + fi + + # check to see if we need to start rpc.statd +@@ -830,25 +769,21 @@ + # systemd + if [ "$EXEC_MODE" -eq "2" ]; then + nfs_exec start nfs-mountd +- local i=10 +- while [ "$i" -gt 0 ]; do ++ local i=1 ++ while : ; do + ocf_log info "Start: nfs-mountd i: $i" +- rpcinfo -t localhost 100005 &> /dev/null ++ rpcinfo -t localhost 100005 > /dev/null 2>&1 + rc=$? + if [ "$rc" -eq "0" ]; then + break; + fi + sleep 1 +- let i=$i-1 ++ i=$((i + 1)) + done +- if [ "$i" -eq 0 ]; then +- ocf_exit_reason "Failed to start nfs-mountd" +- return $OCF_ERR_GENERIC +- fi + + nfs_exec start nfs-idmapd +- local i=10 +- while [ "$i" -gt 0 ]; do ++ local i=1 ++ while : ; do + ocf_log info "Start: nfs-idmapd i: $i" + fn=`mktemp` + nfs_exec status nfs-idmapd > $fn 2>&1 +@@ -859,29 +794,21 @@ + break; + fi + sleep 1 +- let i=$i-1 ++ i=$((i + 1)) + done +- if [ "$i" -eq 0 ]; then +- ocf_exit_reason "Failed to start nfs-idmapd" +- return $OCF_ERR_GENERIC +- fi + + nfs_exec start rpc-statd +- local i=10 +- while [ "$i" -gt 0 ]; do ++ local i=1 ++ while : ; do + ocf_log info "Start: rpc-statd i: $i" +- rpcinfo -t localhost 100024 &> /dev/null ++ rpcinfo -t localhost 100024 > /dev/null 2>&1 + rc=$? + if [ "$rc" -eq "0" ]; then + break; + fi + sleep 1 +- let i=$i-1 ++ i=$((i + 1)) + done +- if [ "$i" -eq 0 ]; then +- ocf_exit_reason "Failed to start rpc-statd" +- return $OCF_ERR_GENERIC +- fi + fi + + fn=`mktemp` +@@ -936,16 +863,16 @@ + return $OCF_ERR_GENERIC + fi + +- nfs_exec stop rpc-statd &> /dev/null ++ nfs_exec stop rpc-statd > /dev/null 2>&1 + ocf_log info "Stop: rpc-statd" +- rpcinfo -t localhost 100024 &> /dev/null ++ rpcinfo -t localhost 100024 > /dev/null 2>&1 + rc=$? + if [ "$rc" -eq "0" ]; then + ocf_exit_reason "Failed to stop rpc-statd" + return $OCF_ERR_GENERIC + fi + +- nfs_exec stop nfs-idmapd &> /dev/null ++ nfs_exec stop nfs-idmapd > /dev/null 2>&1 + ocf_log info "Stop: nfs-idmapd" + fn=`mktemp` + nfs_exec status nfs-idmapd > $fn 2>&1 +@@ -957,9 +884,9 @@ + return $OCF_ERR_GENERIC + fi + +- nfs_exec stop nfs-mountd &> /dev/null ++ nfs_exec stop nfs-mountd > /dev/null 2>&1 + ocf_log info "Stop: nfs-mountd" +- rpcinfo -t localhost 100005 &> /dev/null ++ rpcinfo -t localhost 100005 > /dev/null 2>&1 + rc=$? + if [ "$rc" -eq "0" ]; then + ocf_exit_reason "Failed to stop nfs-mountd" +@@ -975,8 +902,11 @@ + + # systemd + if [ "$EXEC_MODE" -eq "2" ]; then +- nfs_exec stop rpcbind &> /dev/null ++ nfs_exec stop rpcbind > /dev/null 2>&1 + ocf_log info "Stop: rpcbind" ++ ++ nfs_exec stop rpc-gssd > /dev/null 2>&1 ++ ocf_log info "Stop: rpc-gssd" + fi + + unbind_tree diff --git a/SOURCES/bz1128933-Fix-ha_log-drop-global-__ha_log_ignore_stderr_once-h.patch b/SOURCES/bz1128933-Fix-ha_log-drop-global-__ha_log_ignore_stderr_once-h.patch new file mode 100644 index 00000000..04d0c9b7 --- /dev/null +++ b/SOURCES/bz1128933-Fix-ha_log-drop-global-__ha_log_ignore_stderr_once-h.patch @@ -0,0 +1,71 @@ +From 2364eff6a6837ae4418f1876f7f29459fdeec3bb Mon Sep 17 00:00:00 2001 +From: Lars Ellenberg +Date: Mon, 22 Sep 2014 15:26:59 +0200 +Subject: [PATCH 4/6] Fix: ha_log: drop global __ha_log_ignore_stderr_once hack + +Use a helper function instead, +which understands --ignore-stderr as first parameter. +--- + heartbeat/ocf-shellfuncs.in | 23 +++++++++-------------- + 1 file changed, 9 insertions(+), 14 deletions(-) + +diff --git a/heartbeat/ocf-shellfuncs.in b/heartbeat/ocf-shellfuncs.in +index c370fca..fd916e7 100644 +--- a/heartbeat/ocf-shellfuncs.in ++++ b/heartbeat/ocf-shellfuncs.in +@@ -43,14 +43,6 @@ unset LANGUAGE; export LANGUAGE + + __SCRIPT_NAME=`basename $0` + +-# This is internal to shellfuncs. +-# When set, ha_log can be used in a way that guarantees +-# that stderr will not be printed to. This allows us to +-# use ocf_exit_reason to print a string to stderr and use +-# ha_log to print the same string to the other log facilities +-# without having duplicate messages sent to stderr. +-__ha_log_ignore_stderr_once="" +- + if [ -z "$OCF_ROOT" ]; then + : ${OCF_ROOT=@OCF_ROOT_DIR@} + fi +@@ -189,12 +181,11 @@ set_logtag() { + fi + } + +-ha_log() { +- local ignore_stderr="$__ha_log_ignore_stderr_once" ++__ha_log() { ++ local ignore_stderr=false + local loglevel + +- # always reset this variable +- __ha_log_ignore_stderr_once="" ++ [ "x$1" = "x--ignore-stderr" ] && ignore_stderr=true && shift + + [ none = "$HA_LOGFACILITY" ] && HA_LOGFACILITY="" + # if we're connected to a tty, then output to stderr +@@ -257,6 +248,11 @@ ha_log() { + fi + } + ++ha_log() ++{ ++ __ha_log "$@" ++} ++ + ha_debug() { + + if [ "x${HA_debug}" = "x0" ] ; then +@@ -383,8 +379,7 @@ ocf_exit_reason() + + msg=$(printf "${fmt}" "$@") + printf >&2 "%s%s\n" "$cookie" "$msg" +- __ha_log_ignore_stderr_once="true" +- ha_log "ERROR: $msg" ++ __ha_log --ignore-stderr "ERROR: $msg" + } + + # +-- +1.8.4.2 + diff --git a/SOURCES/bz1128933-Fix-ocf_exit_reason-implicit-format-string-s-for-sin.patch b/SOURCES/bz1128933-Fix-ocf_exit_reason-implicit-format-string-s-for-sin.patch new file mode 100644 index 00000000..505e2071 --- /dev/null +++ b/SOURCES/bz1128933-Fix-ocf_exit_reason-implicit-format-string-s-for-sin.patch @@ -0,0 +1,77 @@ +From de3c26d6333a00210de8d112cdb90dc8c2e19367 Mon Sep 17 00:00:00 2001 +From: Lars Ellenberg +Date: Mon, 22 Sep 2014 14:58:58 +0200 +Subject: [PATCH 3/6] Fix: ocf_exit_reason: implicit format string "%s" for + single argument version + +Also, don't use the $msg as format string, but via "%s%s" "$cookie" "$msg". +Or, depending on presence of % sequences in $msg, +you'd get different output on stderr and via ha_log. + +Without the patch: + + ( OCF_ROOT=$PWD dash -c '. heartbeat/ocf-shellfuncs.in ; ocf_exit_reason "0.x% Bugs less"' ) + dash: 372: printf: % B: invalid directive + ocf-exit-reason:0.x + ( OCF_ROOT=$PWD dash -c '. heartbeat/ocf-shellfuncs.in ; ocf_exit_reason "0.x% bugs less"' ) + ocf-exit-reason:0.xugs less + +With this patch: + + ( OCF_ROOT=$PWD dash -c '. heartbeat/ocf-shellfuncs.in ; ocf_exit_reason "0.x% Bugs less"' ) + ocf-exit-reason:0.x% Bugs less + ( OCF_ROOT=$PWD dash -c '. heartbeat/ocf-shellfuncs.in ; ocf_exit_reason "0.x% bugs less"' ) + ocf-exit-reason:0.x% bugs less +--- + heartbeat/ocf-shellfuncs.in | 27 +++++++++++++++++++-------- + 1 file changed, 19 insertions(+), 8 deletions(-) + +diff --git a/heartbeat/ocf-shellfuncs.in b/heartbeat/ocf-shellfuncs.in +index 9ba8e26..c370fca 100644 +--- a/heartbeat/ocf-shellfuncs.in ++++ b/heartbeat/ocf-shellfuncs.in +@@ -356,22 +356,33 @@ ocf_log() { + ocf_exit_reason() + { + local cookie="$OCF_EXIT_REASON_PREFIX" +- local fmt="$1" ++ local fmt + local msg + +- if [ $# -lt 1 ]; then +- ocf_log err "Not enough arguments [$#] to ocf_log_exit_msg." +- fi ++ # No argument is likely not intentional. ++ # Just one argument implies a printf format string of just "%s". ++ # "Least surprise" in case some interpolated string from variable ++ # expansion or other contains a percent sign. ++ # More than one argument: first argument is going to be the format string. ++ case $# in ++ 0) ocf_log err "Not enough arguments to ocf_log_exit_msg." ;; ++ 1) fmt="%s" ;; ++ ++ *) fmt=$1 ++ shift ++ case $fmt in ++ *%*) : ;; # ok, does look like a format string ++ *) ocf_log warn "Does not look like format string: [$fmt]" ;; ++ esac ;; ++ esac ++ + if [ -z "$cookie" ]; then + # use a default prefix + cookie="ocf-exit-reason:" + fi + +- shift +- + msg=$(printf "${fmt}" "$@") +- +- printf >&2 "%s${msg}\n" "$cookie" ++ printf >&2 "%s%s\n" "$cookie" "$msg" + __ha_log_ignore_stderr_once="true" + ha_log "ERROR: $msg" + } +-- +1.8.4.2 + diff --git a/SOURCES/bz1128933-Fix-shellfuncs-fix-syntax-error-caused-by-exit_reaso.patch b/SOURCES/bz1128933-Fix-shellfuncs-fix-syntax-error-caused-by-exit_reaso.patch new file mode 100644 index 00000000..10e37bef --- /dev/null +++ b/SOURCES/bz1128933-Fix-shellfuncs-fix-syntax-error-caused-by-exit_reaso.patch @@ -0,0 +1,26 @@ +From da05792dae917d67b529a27b0605166774bb21b9 Mon Sep 17 00:00:00 2001 +From: David Vossel +Date: Sun, 21 Sep 2014 11:19:07 -0400 +Subject: [PATCH 2/6] Fix: shellfuncs: fix syntax error caused by exit_reason + support for dash shell. + +--- + heartbeat/ocf-shellfuncs.in | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/heartbeat/ocf-shellfuncs.in b/heartbeat/ocf-shellfuncs.in +index ff7c32d..9ba8e26 100644 +--- a/heartbeat/ocf-shellfuncs.in ++++ b/heartbeat/ocf-shellfuncs.in +@@ -356,7 +356,7 @@ ocf_log() { + ocf_exit_reason() + { + local cookie="$OCF_EXIT_REASON_PREFIX" +- local fmt=$1 ++ local fmt="$1" + local msg + + if [ $# -lt 1 ]; then +-- +1.8.4.2 + diff --git a/SOURCES/bz1128933-IPaddr2-exit-reason-support.patch b/SOURCES/bz1128933-IPaddr2-exit-reason-support.patch new file mode 100644 index 00000000..fb27adf3 --- /dev/null +++ b/SOURCES/bz1128933-IPaddr2-exit-reason-support.patch @@ -0,0 +1,185 @@ +From a8adbaa0716f0fa39e41293fe81530686f64e2c8 Mon Sep 17 00:00:00 2001 +From: David Vossel +Date: Fri, 1 Aug 2014 15:31:38 -0400 +Subject: [PATCH] High: IPaddr2: support ocf_exit_reason + +--- + heartbeat/IPaddr2 | 40 +++++++++++++++++++++------------------- + 1 file changed, 21 insertions(+), 19 deletions(-) + +diff --git a/heartbeat/IPaddr2 b/heartbeat/IPaddr2 +index b645288..2791ea0 100755 +--- a/heartbeat/IPaddr2 ++++ b/heartbeat/IPaddr2 +@@ -342,12 +342,12 @@ ip_init() { + local rc + + if [ X`uname -s` != "XLinux" ]; then +- ocf_log err "IPaddr2 only supported Linux." ++ ocf_exit_reason "IPaddr2 only supported Linux." + exit $OCF_ERR_INSTALLED + fi + + if [ X"$OCF_RESKEY_ip" = "X" ]; then +- ocf_log err "IP address (the ip parameter) is mandatory" ++ ocf_exit_reason "IP address (the ip parameter) is mandatory" + exit $OCF_ERR_CONFIGURED + fi + +@@ -359,7 +359,7 @@ ip_init() { + then + : YAY! + else +- ocf_log err "You must be root for $__OCF_ACTION operation." ++ ocf_exit_reason "You must be root for $__OCF_ACTION operation." + exit $OCF_ERR_PERM + fi + +@@ -382,14 +382,14 @@ ip_init() { + IP_INC_NO=`expr ${OCF_RESKEY_CRM_meta_clone:-0} + 1` + + if ocf_is_true ${OCF_RESKEY_lvs_support} && [ $IP_INC_GLOBAL -gt 1 ]; then +- ocf_log err "LVS and load sharing do not go together well" ++ ocf_exit_reason "LVS and load sharing do not go together well" + exit $OCF_ERR_CONFIGURED + fi + + if ocf_is_decimal "$IP_INC_GLOBAL" && [ $IP_INC_GLOBAL -gt 0 ]; then + : + else +- ocf_log err "Invalid OCF_RESKEY_incarnations_max_global [$IP_INC_GLOBAL], should be positive integer" ++ ocf_exit_reason "Invalid meta-attribute clone_max [$IP_INC_GLOBAL], should be positive integer" + exit $OCF_ERR_CONFIGURED + fi + +@@ -397,20 +397,20 @@ ip_init() { + if [ $? -ne 0 ];then + FAMILY=inet + if ocf_is_true $OCF_RESKEY_lvs_ipv6_addrlabel ;then +- ocf_log err "IPv4 does not support lvs_ipv6_addrlabel" ++ ocf_exit_reason "IPv4 does not support lvs_ipv6_addrlabel" + exit $OCF_ERR_CONFIGURED + fi + else + FAMILY=inet6 + if ocf_is_true $OCF_RESKEY_lvs_support ;then +- ocf_log err "The IPv6 does not support lvs_support" ++ ocf_exit_reason "The IPv6 does not support lvs_support" + exit $OCF_ERR_CONFIGURED + fi + if ocf_is_true $OCF_RESKEY_lvs_ipv6_addrlabel ;then + if ocf_is_decimal "$OCF_RESKEY_lvs_ipv6_addrlabel_value" && [ $OCF_RESKEY_lvs_ipv6_addrlabel_value -ge 0 ]; then + : + else +- ocf_log err "Invalid lvs_ipv6_addrlabel_value [$OCF_RESKEY_lvs_ipv6_addrlabel_value], should be positive integer" ++ ocf_exit_reason "Invalid lvs_ipv6_addrlabel_value [$OCF_RESKEY_lvs_ipv6_addrlabel_value], should be positive integer" + exit $OCF_ERR_CONFIGURED + fi + fi +@@ -446,7 +446,7 @@ ip_init() { + ocf_log warn "[$FINDIF] failed" + exit $OCF_SUCCESS + else +- ocf_log err "[$FINDIF] failed" ++ ocf_exit_reason "[$FINDIF] failed" + exit $rc + fi + fi +@@ -769,7 +769,8 @@ END + } + + ip_start() { +- if [ -z "$NIC" ]; then # no nic found or specified ++ if [ -z "$NIC" ]; then ++ ocf_exit_reason "No nic found or specified" + exit $OCF_ERR_CONFIGURED + fi + +@@ -799,7 +800,7 @@ ip_start() { + --local-node $IP_INC_NO \ + --hashmode $IP_CIP_HASH + if [ $? -ne 0 ]; then +- ocf_log err "iptables failed" ++ ocf_exit_reason "iptables failed" + exit $OCF_ERR_GENERIC + fi + fi +@@ -822,7 +823,7 @@ ip_start() { + add_interface $OCF_RESKEY_ip $NETMASK ${BRDCAST:-none} $NIC $IFLABEL + + if [ $? -ne 0 ]; then +- ocf_log err "$CMD failed." ++ ocf_exit_reason "$CMD failed." + exit $OCF_ERR_GENERIC + fi + fi +@@ -897,6 +898,7 @@ ip_stop() { + if [ "$ip_del_if" = "yes" ]; then + delete_interface $OCF_RESKEY_ip $NIC $NETMASK + if [ $? -ne 0 ]; then ++ ocf_exit_reason "Unable to remove IP [${OCF_RESKEY_ip} from interface [ $NIC ]" + exit $OCF_ERR_GENERIC + fi + +@@ -940,7 +942,7 @@ set_send_arp_program() { + ARP_SEND_FUN=run_send_ib_arp + ;; + *) +- ocf_log err "unrecognized arp_sender value: $OCF_RESKEY_arp_sender" ++ ocf_exit_reason "unrecognized arp_sender value: $OCF_RESKEY_arp_sender" + exit $OCF_ERR_CONFIGURED + ;; + esac +@@ -975,21 +977,21 @@ ip_validate() { + + if ocf_is_true "$OCF_RESKEY_unique_clone_address" && + ! ocf_is_true "$OCF_RESKEY_CRM_meta_globally_unique"; then +- ocf_log err "unique_clone_address makes sense only with meta globally_unique set" ++ ocf_exit_reason "unique_clone_address makes sense only with meta globally_unique set" + exit $OCF_ERR_CONFIGURED + fi + + if ocf_is_decimal "$OCF_RESKEY_arp_interval" && [ $OCF_RESKEY_arp_interval -gt 0 ]; then + : + else +- ocf_log err "Invalid OCF_RESKEY_arp_interval [$OCF_RESKEY_arp_interval]" ++ ocf_exit_reason "Invalid OCF_RESKEY_arp_interval [$OCF_RESKEY_arp_interval]" + exit $OCF_ERR_CONFIGURED + fi + + if ocf_is_decimal "$OCF_RESKEY_arp_count" && [ $OCF_RESKEY_arp_count -gt 0 ]; then + : + else +- ocf_log err "Invalid OCF_RESKEY_arp_count [$OCF_RESKEY_arp_count]" ++ ocf_exit_reason "Invalid OCF_RESKEY_arp_count [$OCF_RESKEY_arp_count]" + exit $OCF_ERR_CONFIGURED + fi + +@@ -1001,13 +1003,13 @@ ip_validate() { + sourceip|sourceip-sourceport|sourceip-sourceport-destport) + ;; + *) +- ocf_log err "Invalid OCF_RESKEY_clusterip_hash [$IP_CIP_HASH]" ++ ocf_exit_reason "Invalid OCF_RESKEY_clusterip_hash [$IP_CIP_HASH]" + exit $OCF_ERR_CONFIGURED + ;; + esac + + if ocf_is_true ${OCF_RESKEY_lvs_support}; then +- ecf_log err "LVS and load sharing not advised to try" ++ ocf_exit_reason "LVS and load sharing not advised to try" + exit $OCF_ERR_CONFIGURED + fi + +@@ -1020,7 +1022,7 @@ ip_validate() { + esac + + if [ $valid -eq 0 ]; then +- ocf_log err "Invalid IF_MAC [$IF_MAC]" ++ ocf_exit_reason "Invalid IF_MAC [$IF_MAC]" + exit $OCF_ERR_CONFIGURED + fi + +-- +1.8.4.2 + diff --git a/SOURCES/bz1128933-VirtualDomain-exit-reason-support.patch b/SOURCES/bz1128933-VirtualDomain-exit-reason-support.patch new file mode 100644 index 00000000..dd92efb6 --- /dev/null +++ b/SOURCES/bz1128933-VirtualDomain-exit-reason-support.patch @@ -0,0 +1,102 @@ +From 0501ed8086e054d9b076719c5bd131edbc95db5b Mon Sep 17 00:00:00 2001 +From: David Vossel +Date: Fri, 1 Aug 2014 16:06:22 -0400 +Subject: [PATCH] High: VirtualDomain: exit reason support + +--- + heartbeat/VirtualDomain | 19 ++++++++++--------- + 1 file changed, 10 insertions(+), 9 deletions(-) + +diff --git a/heartbeat/VirtualDomain b/heartbeat/VirtualDomain +index 3a6b6a9..c44c090 100755 +--- a/heartbeat/VirtualDomain ++++ b/heartbeat/VirtualDomain +@@ -356,7 +356,7 @@ VirtualDomain_Start() { + rm -f $snapshotimage + return $OCF_SUCCESS + fi +- ocf_log error "Failed to restore ${DOMAIN_NAME} from state file in ${OCF_RESKEY_snapshot} directory." ++ ocf_exit_reason "Failed to restore ${DOMAIN_NAME} from state file in ${OCF_RESKEY_snapshot} directory." + return $OCF_ERR_GENERIC + fi + +@@ -371,7 +371,7 @@ VirtualDomain_Start() { + virsh $VIRSH_OPTIONS create ${OCF_RESKEY_config} + rc=$? + if [ $rc -ne 0 ]; then +- ocf_log error "Failed to start virtual domain ${DOMAIN_NAME}." ++ ocf_exit_reason "Failed to start virtual domain ${DOMAIN_NAME}." + return $OCF_ERR_GENERIC + fi + +@@ -395,6 +395,7 @@ force_stop() + *"error:"*"domain is not running"*|*"error:"*"domain not found"*) + : ;; # unexpected path to the intended outcome, all is well + [!0]*) ++ ocf_exit_reason "forced stop failed" + return $OCF_ERR_GENERIC ;; + 0*) + while [ $status != $OCF_NOT_RUNNING ]; do +@@ -525,14 +526,14 @@ VirtualDomain_Migrate_To() { + virsh ${VIRSH_OPTIONS} migrate --live $DOMAIN_NAME ${remoteuri} ${migrateuri} + rc=$? + if [ $rc -ne 0 ]; then +- ocf_log err "$DOMAIN_NAME: live migration to ${remoteuri} ${migrateuri} failed: $rc" ++ ocf_exit_reason "$DOMAIN_NAME: live migration to ${remoteuri} ${migrateuri} failed: $rc" + return $OCF_ERR_GENERIC + else + ocf_log info "$DOMAIN_NAME: live migration to ${target_node} succeeded." + return $OCF_SUCCESS + fi + else +- ocf_log err "$DOMAIN_NAME: migrate_to: Not active locally!" ++ ocf_exit_reason "$DOMAIN_NAME: migrate_to: Not active locally!" + return $OCF_ERR_GENERIC + fi + } +@@ -560,7 +561,7 @@ VirtualDomain_Monitor() { + # A monitor script returned a non-success exit + # code. Stop iterating over the list of scripts, log a + # warning message, and propagate $OCF_ERR_GENERIC. +- ocf_log warn "Monitor command \"${script}\" for domain ${DOMAIN_NAME} returned ${script_rc} with output: ${script_output}" ++ ocf_exit_reason "Monitor command \"${script}\" for domain ${DOMAIN_NAME} returned ${script_rc} with output: ${script_output}" + rc=$OCF_ERR_GENERIC + break + else +@@ -582,13 +583,13 @@ VirtualDomain_Validate_All() { + done + + if [ -z $OCF_RESKEY_config ]; then +- ocf_log error "Missing configuration parameter \"config\"." ++ ocf_exit_reason "Missing configuration parameter \"config\"." + return $OCF_ERR_CONFIGURED + fi + + if ocf_is_true $OCF_RESKEY_force_stop; then + if [ -n "$OCF_RESKEY_snapshot" ]; then +- ocf_log error "The 'force_stop' and 'snapshot' options can not be used together." ++ ocf_exit_reason "The 'force_stop' and 'snapshot' options can not be used together." + return $OCF_ERR_CONFIGURED + fi + fi +@@ -601,7 +602,7 @@ VirtualDomain_Validate_All() { + elif [ "$__OCF_ACTION" = "stop" ]; then + ocf_log info "Configuration file $OCF_RESKEY_config not readable, resource considered stopped." + else +- ocf_log error "Configuration file $OCF_RESKEY_config does not exist or is not readable." ++ ocf_exit_reason "Configuration file $OCF_RESKEY_config does not exist or is not readable." + return $OCF_ERR_INSTALLED + fi + fi +@@ -644,7 +645,7 @@ fi + # Retrieve the domain name from the xml file. + DOMAIN_NAME=`egrep '[[:space:]]*.*[[:space:]]*$' ${OCF_RESKEY_config} | sed -e 's/[[:space:]]*\(.*\)<\/name>[[:space:]]*$/\1/' 2>/dev/null` + if [ -z $DOMAIN_NAME ]; then +- ocf_log err "This is unexpected. Cannot determine domain name." ++ ocf_exit_reason "Unable to determine domain name." + exit $OCF_ERR_GENERIC + fi + +-- +1.8.4.2 + diff --git a/SOURCES/bz1128933-binary-check-exit-reason-support.patch b/SOURCES/bz1128933-binary-check-exit-reason-support.patch new file mode 100644 index 00000000..3a83c3b9 --- /dev/null +++ b/SOURCES/bz1128933-binary-check-exit-reason-support.patch @@ -0,0 +1,25 @@ +From 6029211e47a83cec4a6c4e44a967e967cb0b92fb Mon Sep 17 00:00:00 2001 +From: David Vossel +Date: Fri, 1 Aug 2014 13:13:05 -0400 +Subject: [PATCH] High: ocf-binaries: have 'check_binary' set exit reason + +--- + heartbeat/ocf-binaries.in | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/heartbeat/ocf-binaries.in b/heartbeat/ocf-binaries.in +index a78a348..cbf70db 100644 +--- a/heartbeat/ocf-binaries.in ++++ b/heartbeat/ocf-binaries.in +@@ -56,7 +56,7 @@ check_binary () { + if ! have_binary "$1"; then + if [ "$OCF_NOT_RUNNING" = 7 ]; then + # Chances are we have a fully setup OCF environment +- ocf_log err "Setup problem: couldn't find command: $1" ++ ocf_exit_reason "Setup problem: couldn't find command: $1" + else + echo "Setup problem: couldn't find command: $1" + fi +-- +1.8.4.2 + diff --git a/SOURCES/bz1128933-exit-reason-string-updates.patch b/SOURCES/bz1128933-exit-reason-string-updates.patch new file mode 100644 index 00000000..112adeef --- /dev/null +++ b/SOURCES/bz1128933-exit-reason-string-updates.patch @@ -0,0 +1,2118 @@ +From 49546dca4dc4e19743d01576a954eac990c0cde1 Mon Sep 17 00:00:00 2001 +From: David Vossel +Date: Mon, 25 Aug 2014 15:35:45 -0500 +Subject: [PATCH 4/4] exit reason string support for the following agents + +CTDB +Delay +Filesystem +IPsrcaddr +LVM +MailTo +Route +SendArp +Squid +Xinetd +apache +clvm +conntrackd +dhcpd +galera +mysql +mysql-common.sh +named +pgsql +postfix +rsyncd +slapd +symlink +tomcat +--- + heartbeat/CTDB | 24 ++++++++--------- + heartbeat/Delay | 2 +- + heartbeat/Filesystem | 32 +++++++++++----------- + heartbeat/IPsrcaddr | 14 +++++----- + heartbeat/LVM | 32 +++++++++++----------- + heartbeat/MailTo | 4 +-- + heartbeat/Route | 16 +++++------ + heartbeat/SendArp | 4 +-- + heartbeat/Squid | 14 +++++----- + heartbeat/Xinetd | 12 ++++----- + heartbeat/apache | 16 +++++------ + heartbeat/clvm | 14 +++++----- + heartbeat/conntrackd | 14 +++++----- + heartbeat/dhcpd | 24 ++++++++--------- + heartbeat/galera | 26 +++++++++--------- + heartbeat/mysql | 26 +++++++++--------- + heartbeat/mysql-common.sh | 16 +++++------ + heartbeat/named | 16 +++++------ + heartbeat/pgsql | 68 +++++++++++++++++++++++------------------------ + heartbeat/postfix | 22 +++++++-------- + heartbeat/rsyncd | 16 +++++------ + heartbeat/slapd | 24 ++++++++--------- + heartbeat/symlink | 12 ++++----- + heartbeat/tomcat | 16 +++++------ + 24 files changed, 232 insertions(+), 232 deletions(-) + mode change 100644 => 100755 heartbeat/clvm + mode change 100644 => 100755 heartbeat/galera + mode change 100644 => 100755 heartbeat/mysql-common.sh + +diff --git a/heartbeat/CTDB b/heartbeat/CTDB +index 18e6d0f..d1e8d03 100755 +--- a/heartbeat/CTDB ++++ b/heartbeat/CTDB +@@ -520,7 +520,7 @@ ctdb_start() { + mkdir -p $persistent_db_dir 2>/dev/null + for pdbase in $(ls $persistent_db_dir/*.tdb.[0-9] 2>/dev/null$) ; do + /usr/bin/tdbdump $pdbase >/dev/null 2>/dev/null || { +- ocf_log err "Persistent database $pdbase is corrupted! CTDB will not start." ++ ocf_exit_reason "Persistent database $pdbase is corrupted! CTDB will not start." + return $OCF_ERR_GENERIC + } + done +@@ -528,7 +528,7 @@ ctdb_start() { + # Add necessary configuration to smb.conf + init_smb_conf + if [ $? -ne 0 ]; then +- ocf_log err "Failed to update $OCF_RESKEY_smb_conf." ++ ocf_exit_reason "Failed to update $OCF_RESKEY_smb_conf." + return $OCF_ERR_GENERIC + fi + +@@ -563,7 +563,7 @@ ctdb_start() { + # cleanup smb.conf + cleanup_smb_conf + +- ocf_log err "Failed to execute $OCF_RESKEY_ctdbd_binary." ++ ocf_exit_reason "Failed to execute $OCF_RESKEY_ctdbd_binary." + return $OCF_ERR_GENERIC + else + # Wait a bit for CTDB to stabilize +@@ -577,7 +577,7 @@ ctdb_start() { + if [ $? -ne 0 ]; then + # CTDB will be running, kill it before returning + ctdb_stop +- ocf_log err "Can't invoke $OCF_RESKEY_ctdb_binary --socket=$OCF_RESKEY_ctdb_socket status" ++ ocf_exit_reason "Can't invoke $OCF_RESKEY_ctdb_binary --socket=$OCF_RESKEY_ctdb_socket status" + return $OCF_ERR_GENERIC + fi + if ! echo $status | grep -qs 'UNHEALTHY (THIS'; then +@@ -593,7 +593,7 @@ ctdb_start() { + # ctdbd will (or can) actually still be running at this point, so kill it + ctdb_stop + +- ocf_log err "Timeout waiting for CTDB to stabilize" ++ ocf_exit_reason "Timeout waiting for CTDB to stabilize" + return $OCF_ERR_GENERIC + } + +@@ -646,7 +646,7 @@ ctdb_monitor() { + if echo $status | grep -qs 'Connection refused'; then + return $OCF_NOT_RUNNING + else +- ocf_log err "CTDB status call failed: $status" ++ ocf_exit_reason "CTDB status call failed: $status" + return $OCF_ERR_GENERIC + fi + fi +@@ -654,7 +654,7 @@ ctdb_monitor() { + return $OCF_SUCCESS + fi + +- ocf_log err "CTDB status is bad: $status" ++ ocf_exit_reason "CTDB status is bad: $status" + return $OCF_ERR_GENERIC + } + +@@ -667,12 +667,12 @@ ctdb_validate() { + done + + if [ -z "$CTDB_SYSCONFIG" ]; then +- ocf_log err "Can't find CTDB config file (expecting /etc/sysconfig/ctdb, /etc/default/ctdb or similar)" ++ ocf_exit_reason "Can't find CTDB config file (expecting /etc/sysconfig/ctdb, /etc/default/ctdb or similar)" + return $OCF_ERR_INSTALLED + fi + + if ocf_is_true "$OCF_RESKEY_ctdb_manages_samba" && [ ! -f "$OCF_RESKEY_smb_conf" ]; then +- ocf_log err "Samba config file '$OCF_RESKEY_smb_conf' does not exist." ++ ocf_exit_reason "Samba config file '$OCF_RESKEY_smb_conf' does not exist." + return $OCF_ERR_INSTALLED + fi + +@@ -681,19 +681,19 @@ ctdb_validate() { + fi + + if [ ! -f "$OCF_RESKEY_ctdb_config_dir/nodes" ]; then +- ocf_log err "$OCF_RESKEY_ctdb_config_dir/nodes does not exist." ++ ocf_exit_reason "$OCF_RESKEY_ctdb_config_dir/nodes does not exist." + return $OCF_ERR_ARGS + fi + + if [ -z "$OCF_RESKEY_ctdb_recovery_lock" ]; then +- ocf_log err "ctdb_recovery_lock not specified." ++ ocf_exit_reason "ctdb_recovery_lock not specified." + return $OCF_ERR_CONFIGURED + fi + + lock_dir=$(dirname "$OCF_RESKEY_ctdb_recovery_lock") + touch "$lock_dir/$$" 2>/dev/null + if [ $? != 0 ]; then +- ocf_log err "Directory for lock file '$OCF_RESKEY_ctdb_recovery_lock' does not exist, or is not writable." ++ ocf_exit_reason "Directory for lock file '$OCF_RESKEY_ctdb_recovery_lock' does not exist, or is not writable." + return $OCF_ERR_ARGS + fi + rm "$lock_dir/$$" +diff --git a/heartbeat/Delay b/heartbeat/Delay +index f505391..9cfa939 100755 +--- a/heartbeat/Delay ++++ b/heartbeat/Delay +@@ -184,7 +184,7 @@ Delay_Validate_All() { + # _Return_ on validation success + return $OCF_SUCCESS + else +- echo "Some of the instance parameters are invalid" ++ ocf_exit_reason "Some of the instance parameters are invalid" + # _Exit_ on validation failure + exit $OCF_ERR_ARGS + fi +diff --git a/heartbeat/Filesystem b/heartbeat/Filesystem +index 9892b39..3559c93 100755 +--- a/heartbeat/Filesystem ++++ b/heartbeat/Filesystem +@@ -480,7 +480,7 @@ fstype_supported() + # check the if the filesystem support exists again. + $MODPROBE $support >/dev/null + if [ $? -ne 0 ]; then +- ocf_log err "Couldn't find filesystem $FSTYPE in /proc/filesystems and failed to load kernal module" ++ ocf_exit_reason "Couldn't find filesystem $FSTYPE in /proc/filesystems and failed to load kernal module" + return $OCF_ERR_INSTALLED + fi + +@@ -497,7 +497,7 @@ fstype_supported() + sleep 1 + done + +- ocf_log err "Couldn't find filesystem $FSTYPE in /proc/filesystems" ++ ocf_exit_reason "Couldn't find filesystem $FSTYPE in /proc/filesystems" + return $OCF_ERR_INSTALLED + } + +@@ -532,7 +532,7 @@ Filesystem_start() + + if [ $blockdevice = "yes" ]; then + if [ "$DEVICE" != "/dev/null" -a ! -b "$DEVICE" ] ; then +- ocf_log err "Couldn't find device [$DEVICE]. Expected /dev/??? to exist" ++ ocf_exit_reason "Couldn't find device [$DEVICE]. Expected /dev/??? to exist" + exit $OCF_ERR_INSTALLED + fi + +@@ -547,7 +547,7 @@ Filesystem_start() + # NOTE: if any errors at all are detected, it returns non-zero + # if the error is >= 4 then there is a big problem + if [ $? -ge 4 ]; then +- ocf_log err "Couldn't sucessfully fsck filesystem for $DEVICE" ++ ocf_exit_reason "Couldn't sucessfully fsck filesystem for $DEVICE" + return $OCF_ERR_GENERIC + fi + fi +@@ -556,7 +556,7 @@ Filesystem_start() + [ -d "$MOUNTPOINT" ] || + ocf_run mkdir -p $MOUNTPOINT + if [ ! -d "$MOUNTPOINT" ] ; then +- ocf_log err "Couldn't find directory [$MOUNTPOINT] to use as a mount point" ++ ocf_exit_reason "Couldn't find directory [$MOUNTPOINT] to use as a mount point" + exit $OCF_ERR_INSTALLED + fi + +@@ -571,7 +571,7 @@ Filesystem_start() + esac + + if [ $? -ne 0 ]; then +- ocf_log err "Couldn't mount filesystem $DEVICE on $MOUNTPOINT" ++ ocf_exit_reason "Couldn't mount filesystem $DEVICE on $MOUNTPOINT" + if [ -n "$OCFS2_SLES10" ]; then + ocfs2_cleanup + fi +@@ -775,7 +775,7 @@ fs_stop() { + while [ $cnt -gt 0 ]; do + try_umount $SUB && + return $OCF_SUCCESS +- ocf_log err "Couldn't unmount $SUB; trying cleanup with $sig" ++ ocf_exit_reason "Couldn't unmount $SUB; trying cleanup with $sig" + signal_processes $SUB $sig + cnt=$((cnt-1)) + sleep 1 +@@ -826,7 +826,7 @@ Filesystem_stop() + fs_stop $SUB $timeout + rc=$? + if [ $rc -ne $OCF_SUCCESS ]; then +- ocf_log err "Couldn't unmount $SUB, giving up!" ++ ocf_exit_reason "Couldn't unmount $SUB, giving up!" + fi + done + fi +@@ -893,7 +893,7 @@ Filesystem_monitor_10() + dd_opts="iflag=direct bs=4k count=1" + err_output=`dd if=$DEVICE $dd_opts 2>&1 >/dev/null` + if [ $? -ne 0 ]; then +- ocf_log err "Failed to read device $DEVICE" ++ ocf_exit_reason "Failed to read device $DEVICE" + ocf_log err "dd said: $err_output" + return $OCF_ERR_GENERIC + fi +@@ -916,18 +916,18 @@ Filesystem_monitor_20() + [ -d "$status_dir" ] || mkdir -p "$status_dir" + err_output=`echo "${OCF_RESOURCE_INSTANCE}" | dd of=${STATUSFILE} $dd_opts 2>&1` + if [ $? -ne 0 ]; then +- ocf_log err "Failed to write status file ${STATUSFILE}" ++ ocf_exit_reason "Failed to write status file ${STATUSFILE}" + ocf_log err "dd said: $err_output" + return $OCF_ERR_GENERIC + fi + test -f ${STATUSFILE} + if [ $? -ne 0 ]; then +- ocf_log err "Cannot stat the status file ${STATUSFILE}" ++ ocf_exit_reason "Cannot stat the status file ${STATUSFILE}" + return $OCF_ERR_GENERIC + fi + cat ${STATUSFILE} > /dev/null + if [ $? -ne 0 ]; then +- ocf_log err "Cannot read the status file ${STATUSFILE}" ++ ocf_exit_reason "Cannot read the status file ${STATUSFILE}" + return $OCF_ERR_GENERIC + fi + return $OCF_SUCCESS +@@ -945,7 +945,7 @@ Filesystem_monitor() + 10) Filesystem_monitor_10; rc=$?;; + 20) Filesystem_monitor_20; rc=$?;; + *) +- ocf_log err "unsupported monitor level $OCF_CHECK_LEVEL" ++ ocf_exit_reason "unsupported monitor level $OCF_CHECK_LEVEL" + rc=$OCF_ERR_CONFIGURED + ;; + esac +@@ -1057,7 +1057,7 @@ case $OP in + esac + + if [ x = x"$DEVICE" ]; then +- ocf_log err "Please set OCF_RESKEY_device to the device to be managed" ++ ocf_exit_reason "Please set OCF_RESKEY_device to the device to be managed" + exit $OCF_ERR_CONFIGURED + fi + +@@ -1069,7 +1069,7 @@ set_blockdevice_var + # But the output of `mount` and /proc/mounts do not. + if [ -z "$OCF_RESKEY_directory" ]; then + if [ X$OP = "Xstart" -o $blockdevice = "no" ]; then +- ocf_log err "Please specify the directory" ++ ocf_exit_reason "Please specify the directory" + exit $OCF_ERR_CONFIGURED + fi + else +@@ -1136,7 +1136,7 @@ esac + if [ -n "$OCF_RESKEY_CRM_meta_clone" ]; then + case $CLUSTERSAFE in + 0) +- ocf_log err "DANGER! $FSTYPE on $DEVICE is NOT cluster-aware!" ++ ocf_exit_reason "DANGER! $FSTYPE on $DEVICE is NOT cluster-aware!" + ocf_log err "DO NOT RUN IT AS A CLONE!" + ocf_log err "Politely refusing to proceed to avoid data corruption." + exit $OCF_ERR_CONFIGURED +diff --git a/heartbeat/IPsrcaddr b/heartbeat/IPsrcaddr +index e8c0f77..8163c0c 100755 +--- a/heartbeat/IPsrcaddr ++++ b/heartbeat/IPsrcaddr +@@ -111,7 +111,7 @@ END + } + + errorexit() { +- ocf_log err "$*" ++ ocf_exit_reason "$*" + exit $OCF_ERR_GENERIC + } + +@@ -253,7 +253,7 @@ CheckIP() { + ( [ $1 -le 254 ] && [ $2 -le 254 ] && [ $3 -le 254 ] && [ $4 -le 254 ] ) + then + if [ $1 -eq 127 ]; then +- ocf_log err "IP address [$ip] is a loopback address, thus can not be preferred source address" ++ ocf_exit_reason "IP address [$ip] is a loopback address, thus can not be preferred source address" + exit $OCF_ERR_CONFIGURED + fi + else +@@ -368,7 +368,7 @@ ip_status() { + + case $IF in + lo*) +- ocf_log err "IP address [$BASEIP] is served by loopback, thus can not be preferred source address" ++ ocf_exit_reason "IP address [$BASEIP] is served by loopback, thus can not be preferred source address" + exit $OCF_ERR_CONFIGURED + ;; + *)return $OCF_SUCCESS;; +@@ -394,7 +394,7 @@ srca_validate_all() { + if CheckIP "$ipaddress"; then + : + else +- ocf_log err "Invalid IP address [$ipaddress]" ++ ocf_exit_reason "Invalid IP address [$ipaddress]" + exit $OCF_ERR_CONFIGURED + fi + +@@ -406,7 +406,7 @@ srca_validate_all() { + if ip_status "$ipaddress"; then + : + else +- ocf_log err "We are not serving [$ipaddress], hence can not make it a preferred source address" ++ ocf_exit_reason "We are not serving [$ipaddress], hence can not make it a preferred source address" + exit $OCF_ERR_INSTALLED + fi + } +@@ -434,7 +434,7 @@ if + [ -z "$OCF_RESKEY_ipaddress" ] + then + # usage +- ocf_log err "Please set OCF_RESKEY_ipaddress to the preferred source IP address!" ++ ocf_exit_reason "Please set OCF_RESKEY_ipaddress to the preferred source IP address!" + exit $OCF_ERR_CONFIGURED + fi + +@@ -447,7 +447,7 @@ fi + findif_out=`$FINDIF -C` + rc=$? + [ $rc -ne 0 ] && { +- ocf_log err "[$FINDIF -C] failed" ++ ocf_exit_reason "[$FINDIF -C] failed" + exit $rc + } + +diff --git a/heartbeat/LVM b/heartbeat/LVM +index 27cdfbd..58cbe83 100755 +--- a/heartbeat/LVM ++++ b/heartbeat/LVM +@@ -183,8 +183,8 @@ verify_tags_environment() + # guarantee our tag will be filtered on startup + ## + if ! lvm dumpconfig activation/volume_list; then +- ocf_log err "LVM: Improper setup detected" +- ocf_log err "The volume_list filter must be initialized in lvm.conf for exclusive activation without clvmd" ++ ocf_log err "LVM: Improper setup detected" ++ ocf_exit_reason "The volume_list filter must be initialized in lvm.conf for exclusive activation without clvmd" + return $OCF_ERR_GENERIC + fi + +@@ -195,7 +195,7 @@ verify_tags_environment() + ## + if lvm dumpconfig activation/volume_list | grep -e "\"@$OUR_TAG\"" -e "\"${OCF_RESKEY_volgrpname}\""; then + ocf_log err "LVM: Improper setup detected" +- ocf_log err "The volume_list in lvm.conf must not contain the cluster tag, \"$OUR_TAG\", or volume group, $OCF_RESKEY_volgrpname" ++ ocf_exit_reason "The volume_list in lvm.conf must not contain the cluster tag, \"$OUR_TAG\", or volume group, $OCF_RESKEY_volgrpname" + return $OCF_ERR_GENERIC + fi + +@@ -283,7 +283,7 @@ strip_tags() + done + + if [ ! -z `vgs -o tags --noheadings $OCF_RESKEY_volgrpname | tr -d ' '` ]; then +- ocf_log err "Failed to remove ownership tags from $OCF_RESKEY_volgrpname" ++ ocf_exit_reason "Failed to remove ownership tags from $OCF_RESKEY_volgrpname" + return $OCF_ERR_GENERIC + fi + +@@ -310,7 +310,7 @@ set_tags() + + vgchange --addtag $OUR_TAG $OCF_RESKEY_volgrpname + if [ $? -ne 0 ]; then +- ocf_log err "Failed to add ownership tag to $OCF_RESKEY_volgrpname" ++ ocf_exit_reason "Failed to add ownership tag to $OCF_RESKEY_volgrpname" + return $OCF_ERR_GENERIC + fi + +@@ -341,7 +341,7 @@ LVM_status() { + test "`cd /dev/$1 && ls`" != "" + rc=$? + if [ $rc -ne 0 ]; then +- ocf_log err "VG $1 with no logical volumes is not supported by this RA!" ++ ocf_exit_reason "VG $1 with no logical volumes is not supported by this RA!" + fi + fi + +@@ -354,7 +354,7 @@ LVM_status() { + # If vg is running, make sure the correct tag is present. Otherwise we + # can not guarantee exclusive activation. + if ! check_tags; then +- ocf_log err "WARNING: $OCF_RESKEY_volgrpname is active without the cluster tag, \"$OUR_TAG\"" ++ ocf_exit_reason "WARNING: $OCF_RESKEY_volgrpname is active without the cluster tag, \"$OUR_TAG\"" + rc=$OCF_ERR_GENERIC + fi + +@@ -423,7 +423,7 @@ retry_exclusive_start() + return $OCF_ERR_GENERIC;; + *) + if ! lvchange -an $OCF_RESKEY_volgrpname/$1; then +- ocf_log err "Unable to perform required deactivation of $OCF_RESKEY_volgrpname/$1 before starting" ++ ocf_exit_reason "Unable to perform required deactivation of $OCF_RESKEY_volgrpname/$1 before starting" + return $OCF_ERR_GENERIC + fi + ;; +@@ -482,7 +482,7 @@ LVM_start() { + : OK Volume $vg activated just fine! + return $OCF_SUCCESS + else +- ocf_log err "LVM: $vg did not activate correctly" ++ ocf_exit_reason "LVM: $vg did not activate correctly" + return $OCF_NOT_RUNNING + fi + } +@@ -511,7 +511,7 @@ LVM_stop() { + ocf_run vgchange $vgchange_options $vg + res=$? + if LVM_status $vg; then +- ocf_log err "LVM: $vg did not stop correctly" ++ ocf_exit_reason "LVM: $vg did not stop correctly" + res=1 + fi + +@@ -568,7 +568,7 @@ LVM_validate_all() { + ## + VGOUT=`vgck ${VOLUME} 2>&1` + if [ $? -ne 0 ]; then +- ocf_log err "Volume group [$VOLUME] does not exist or contains error! ${VGOUT}" ++ ocf_exit_reason "Volume group [$VOLUME] does not exist or contains error! ${VGOUT}" + exit $OCF_ERR_GENERIC + fi + +@@ -581,7 +581,7 @@ LVM_validate_all() { + VGOUT=`vgdisplay -v ${VOLUME} 2>&1` + fi + if [ $? -ne 0 ]; then +- ocf_log err "Volume group [$VOLUME] does not exist or contains error! ${VGOUT}" ++ ocf_exit_reason "Volume group [$VOLUME] does not exist or contains error! ${VGOUT}" + exit $OCF_ERR_GENERIC + fi + +@@ -597,7 +597,7 @@ LVM_validate_all() { + # Having cloned lvm resources with exclusive vg activation makes no sense at all. + ## + if ocf_is_clone; then +- ocf_log_err "cloned lvm resources can not be activated exclusively" ++ ocf_exit_reason "cloned lvm resources can not be activated exclusively" + exit $OCF_ERR_CONFIGURED + fi + +@@ -616,7 +616,7 @@ LVM_validate_all() { + # verify is clvmd running + ## + if ! ps -C clvmd > /dev/null 2>&1; then +- ocf_log err "$OCF_RESKEY_volgrpname has the cluster attribute set, but 'clvmd' is not running" ++ ocf_exit_reason "$OCF_RESKEY_volgrpname has the cluster attribute set, but 'clvmd' is not running" + exit $OCF_ERR_GENERIC + fi + ;; +@@ -653,7 +653,7 @@ esac + if + [ -z "$OCF_RESKEY_volgrpname" ] + then +- ocf_log err "You must identify the volume group name!" ++ ocf_exit_reason "You must identify the volume group name!" + exit $OCF_ERR_CONFIGURED + fi + +@@ -680,7 +680,7 @@ rc=$? + if + ( [ $rc -ne 0 ] || [ -z "$LVM_VERSION" ] ) + then +- ocf_log err "LVM: $1 could not determine LVM version. Try 'vgchange --version' manually and modify $0 ?" ++ ocf_exit_reason "LVM: $1 could not determine LVM version. Try 'vgchange --version' manually and modify $0 ?" + exit $OCF_ERR_INSTALLED + fi + LVM_MAJOR="${LVM_VERSION%%.*}" +diff --git a/heartbeat/MailTo b/heartbeat/MailTo +index acf6730..3936c39 100755 +--- a/heartbeat/MailTo ++++ b/heartbeat/MailTo +@@ -131,7 +131,7 @@ MailToStatus () { + + MailToValidateAll () { + if [ -z "$MAILCMD" ]; then +- ocf_log err "MAILCMD not set: complain to the packager" ++ ocf_exit_reason "MAILCMD not set: complain to the packager" + exit $OCF_ERR_INSTALLED + fi + check_binary "$MAILCMD" +@@ -169,7 +169,7 @@ esac + if + [ -z "$OCF_RESKEY_email" ] + then +- ocf_log err "At least 1 Email address has to be given!" ++ ocf_exit_reason "At least 1 Email address has to be given!" + exit $OCF_ERR_CONFIGURED + fi + +diff --git a/heartbeat/Route b/heartbeat/Route +index 9a49a26..cfed2b0 100755 +--- a/heartbeat/Route ++++ b/heartbeat/Route +@@ -174,7 +174,7 @@ route_start() { + ocf_log info "${OCF_RESOURCE_INSTANCE} Added network route: $route_spec" + return $OCF_SUCCESS + else +- ocf_log error "${OCF_RESOURCE_INSTANCE} Failed to add network route: $route_spec" ++ ocf_exit_reason "${OCF_RESOURCE_INSTANCE} Failed to add network route: $route_spec" + fi + return $OCF_ERR_GENERIC + } +@@ -189,7 +189,7 @@ route_stop() { + ocf_log info "${OCF_RESOURCE_INSTANCE} Removed network route: $route_spec" + return $OCF_SUCCESS + else +- ocf_log error "${OCF_RESOURCE_INSTANCE} Failed to remove network route: $route_spec" ++ ocf_exit_reason "${OCF_RESOURCE_INSTANCE} Failed to remove network route: $route_spec" + fi + ;; + $OCF_NOT_RUNNING) +@@ -224,24 +224,24 @@ route_validate() { + # If we're running as a clone, are the clone meta attrs OK? + if [ "${OCF_RESKEY_CRM_meta_clone}" ]; then + if [ "${OCF_RESKEY_CRM_meta_clone_node_max}" != 1 ]; then +- ocf_log error "Misconfigured clone parameters. Must set meta attribute \"clone_node_max\" to 1, got ${OCF_RESKEY_CRM_meta_clone_node_max}." ++ ocf_exit_reason "Misconfigured clone parameters. Must set meta attribute \"clone_node_max\" to 1, got ${OCF_RESKEY_CRM_meta_clone_node_max}." + return $OCF_ERR_ARGS + fi + fi + # Did we get a destination? + if [ -z "${OCF_RESKEY_destination}" ]; then +- ocf_log error "Missing required parameter \"destination\"." ++ ocf_exit_reason "Missing required parameter \"destination\"." + return $OCF_ERR_ARGS + fi + # Did we get either a device or a gateway address? + if [ -z "${OCF_RESKEY_device}" -a -z "${OCF_RESKEY_gateway}" ]; then +- ocf_log error "Must specifiy either \"device\", or \"gateway\", or both." ++ ocf_exit_reason "Must specifiy either \"device\", or \"gateway\", or both." + return $OCF_ERR_ARGS + fi + # If a device has been configured, is it available on this system? + if [ -n "${OCF_RESKEY_device}" ]; then + if ! ip link show ${OCF_RESKEY_device} >/dev/null 2>&1; then +- ocf_log error "Network device ${OCF_RESKEY_device} appears not to be available on this system." ++ ocf_exit_reason "Network device ${OCF_RESKEY_device} appears not to be available on this system." + # OCF_ERR_ARGS prevents the resource from running anywhere at all, + # maybe another node has the interface? + # OCF_ERR_INSTALLED just prevents starting on this particular node. +@@ -256,7 +256,7 @@ route_validate() { + # this system? + if [ -n "${OCF_RESKEY_source}" ]; then + if ! ip address show | grep -w ${OCF_RESKEY_source} >/dev/null 2>&1; then +- ocf_log error "Source address ${OCF_RESKEY_source} appears not to be available on this system." ++ ocf_exit_reason "Source address ${OCF_RESKEY_source} appears not to be available on this system." + # same reason as with _device: + return $OCF_ERR_INSTALLED + fi +@@ -264,7 +264,7 @@ route_validate() { + # If a gateway address has been configured, is it reachable? + if [ -n "${OCF_RESKEY_gateway}" ]; then + if ! ip route get ${OCF_RESKEY_gateway} >/dev/null 2>&1; then +- ocf_log error "Gateway address ${OCF_RESKEY_gateway} is unreachable." ++ ocf_exit_reason "Gateway address ${OCF_RESKEY_gateway} is unreachable." + # same reason as with _device: + return $OCF_ERR_INSTALLED + fi +diff --git a/heartbeat/SendArp b/heartbeat/SendArp +index 675070c..b67404f 100755 +--- a/heartbeat/SendArp ++++ b/heartbeat/SendArp +@@ -166,10 +166,10 @@ sendarp_start() { + # and wait-ing would be equal to not running in + # background + ($SENDARP $ARGS || +- ocf_log err "Could not send gratuitous arps") & ++ ocf_exit_reason "Could not send gratuitous arps") & + else + $SENDARP $ARGS || { +- ocf_log err "Could not send gratuitous arps" ++ ocf_exit_reason "Could not send gratuitous arps" + rc=$OCF_ERR_GENERIC + } + fi +diff --git a/heartbeat/Squid b/heartbeat/Squid +index 28e2db5..70c7c3d 100755 +--- a/heartbeat/Squid ++++ b/heartbeat/Squid +@@ -216,7 +216,7 @@ are_pids_sane() + if [[ "${SQUID_PIDS[1]}" = "${SQUID_PIDS[2]}" ]]; then + return $OCF_SUCCESS + else +- ocf_log err "$SQUID_NAME:Pid unmatch" ++ ocf_exit_reason "$SQUID_NAME:Pid unmatch" + return $OCF_ERR_GENERIC + fi + } +@@ -253,7 +253,7 @@ monitor_squid() + "${SQUID_PIDS[0]},${SQUID_PIDS[1]},${SQUID_PIDS[2]}" + (( trialcount = trialcount + 1 )) + if (( trialcount > SQUID_CONFIRM_TRIALCOUNT )); then +- ocf_log err "$SQUID_NAME:Inconsistency of processes remains unsolved" ++ ocf_exit_reason "$SQUID_NAME:Inconsistency of processes remains unsolved" + return $OCF_ERR_GENERIC + fi + sleep 1 +@@ -348,7 +348,7 @@ fi + + SQUID_CONF="${OCF_RESKEY_squid_conf}" + if [[ -z "$SQUID_CONF" ]]; then +- ocf_log err "SQUID_CONF is not defined" ++ ocf_exit_reason "SQUID_CONF is not defined" + exit $OCF_ERR_CONFIGURED + fi + +@@ -374,23 +374,23 @@ fi + + SQUID_EXE="${OCF_RESKEY_squid_exe}" + if [[ -z "$SQUID_EXE" ]]; then +- ocf_log err "SQUID_EXE is not defined" ++ ocf_exit_reason "SQUID_EXE is not defined" + exit $OCF_ERR_CONFIGURED + fi + if [[ ! -x "$SQUID_EXE" ]]; then +- ocf_log err "$SQUID_EXE is not found" ++ ocf_exit_reason "$SQUID_EXE is not found" + exit $OCF_ERR_CONFIGURED + fi + + SQUID_PIDFILE="${OCF_RESKEY_squid_pidfile}" + if [[ -z "$SQUID_PIDFILE" ]]; then +- ocf_log err "SQUID_PIDFILE is not defined" ++ ocf_exit_reason "SQUID_PIDFILE is not defined" + exit $OCF_ERR_CONFIGURED + fi + + SQUID_PORT="${OCF_RESKEY_squid_port}" + if [[ -z "$SQUID_PORT" ]]; then +- ocf_log err "SQUID_PORT is not defined" ++ ocf_exit_reason "SQUID_PORT is not defined" + exit $OCF_ERR_CONFIGURED + fi + +diff --git a/heartbeat/Xinetd b/heartbeat/Xinetd +index ee2c4fa..212648e 100755 +--- a/heartbeat/Xinetd ++++ b/heartbeat/Xinetd +@@ -89,11 +89,11 @@ hup_inetd () { + if kill -s HUP $pid; then + ocf_log info "asked xinetd to reload by sending SIGHUP to process $pid!" + else +- ocf_log err "could not send SIGHUP to process $pid!" ++ ocf_exit_reason "could not send SIGHUP to process $pid!" + exit $OCF_ERR_GENERIC + fi + else +- ocf_log err "xinetd process not found!" ++ ocf_exit_reason "xinetd process not found!" + exit $OCF_ERR_GENERIC + fi + } +@@ -161,7 +161,7 @@ xup_usage () { + + xup_validate_all () { + if [ ! -f "$SVCDEF" ]; then +- ocf_log err "service $service missing $SVCDEF" ++ ocf_exit_reason "service $service missing $SVCDEF" + return $OCF_ERR_INSTALLED + fi + return $OCF_SUCCESS +@@ -185,7 +185,7 @@ case "$1" in + esac + + if [ -z "$OCF_RESKEY_service" ]; then +- ocf_log err "please define \"service\" parameter" ++ ocf_exit_reason "please define \"service\" parameter" + if [ "$1" = "start" ]; then + exit $OCF_ERR_CONFIGURED + else +@@ -195,7 +195,7 @@ fi + + # Is xinetd running at all + if [ -z "`get_xinetd_pid`" ]; then +- ocf_log err "xinetd not running, we manage just xinetd services, not the daemon itself" ++ ocf_exit_reason "xinetd not running, we manage just xinetd services, not the daemon itself" + case "$1" in + stop) exit $OCF_SUCCESS;; + start|monitor|status) exit $OCF_ERR_INSTALLED;; +@@ -204,7 +204,7 @@ fi + + # Make sure the OCF_RESKEY_service is a valid xinetd service name + if [ ! -f $SVCDEF ]; then +- ocf_log err "service definition $SVCDEF not found!" ++ ocf_exit_reason "service definition $SVCDEF not found!" + if [ "$1" = "start" ]; then + exit $OCF_ERR_INSTALLED + else +diff --git a/heartbeat/apache b/heartbeat/apache +index bee2f97..e7d570f 100755 +--- a/heartbeat/apache ++++ b/heartbeat/apache +@@ -272,7 +272,7 @@ apache_stop() { + kill_stop $ApachePID + + if ProcessRunning $ApachePID; then +- ocf_log info "$CMD still running ($ApachePID). Killing pid failed." ++ ocf_exit_reason "$CMD still running ($ApachePID). Killing pid failed." + ret=$OCF_ERR_GENERIC + fi + fi +@@ -303,7 +303,7 @@ apache_monitor_10() { + return $OCF_SUCCESS + else + if ! ocf_is_probe; then +- ocf_log err "Failed to access httpd status page." ++ ocf_exit_reason "Failed to access httpd status page." + fi + return $OCF_ERR_GENERIC + fi +@@ -359,7 +359,7 @@ apache_monitor_basic() { + fi + + if ! ocf_is_probe; then +- ocf_log err "Failed to access httpd status page." ++ ocf_exit_reason "Failed to access httpd status page." + fi + return $OCF_ERR_GENERIC + } +@@ -372,7 +372,7 @@ apache_monitor() { + + ourhttpclient=`findhttpclient` # we'll need one + if [ -z "$ourhttpclient" ]; then +- ocf_log err "could not find a http client; make sure that either wget or curl is available" ++ ocf_exit_reason "could not find a http client; make sure that either wget or curl is available" + return $OCF_ERR_INSTALLED + fi + +@@ -574,25 +574,25 @@ apache_validate_all() { + # We are sure to succeed here, since we forced $PORT to be valid in GetParams() + : OK + else +- ocf_log err "Port number $PORT is invalid!" ++ ocf_exit_reason "Port number $PORT is invalid!" + return $OCF_ERR_INSTALLED + fi + + case $STATUSURL in + http://*) ;; + *) +- ocf_log err "Invalid STATUSURL $STATUSURL" ++ ocf_exit_reason "Invalid STATUSURL $STATUSURL" + return $OCF_ERR_CONFIGURED ;; + esac + + if [ ! -x $HTTPD ]; then +- ocf_log err "HTTPD $HTTPD not found or is not an executable!" ++ ocf_exit_reason "HTTPD $HTTPD not found or is not an executable!" + return $OCF_ERR_INSTALLED + fi + + if [ ! -f $CONFIGFILE ]; then + # We are sure to succeed here, since we have parsed $CONFIGFILE before getting here +- ocf_log err "Configuration file $CONFIGFILE not found!" ++ ocf_exit_reason "Configuration file $CONFIGFILE not found!" + return $OCF_ERR_INSTALLED + fi + +diff --git a/heartbeat/clvm b/heartbeat/clvm +old mode 100644 +new mode 100755 +index 20bb40c..bb2b61c +--- a/heartbeat/clvm ++++ b/heartbeat/clvm +@@ -160,7 +160,7 @@ check_process() + return $OCF_NOT_RUNNING;; + *) + rm -f "$pidfile" > /dev/null 2>&1 +- ocf_log err "Error encountered detecting pid status of $binary" ++ ocf_exit_reason "Error encountered detecting pid status of $binary" + return $OCF_ERR_GENERIC;; + esac + } +@@ -171,7 +171,7 @@ clvmd_status() + local mirror_rc + clvmd_validate + if [ $? -ne $OCF_SUCCESS ]; then +- ocf_log error "Unable to monitor, Environment validation failed." ++ ocf_exit_reason "Unable to monitor, Environment validation failed." + return $? + fi + +@@ -251,7 +251,7 @@ clvmd_stop() + ocf_log info "Deactivating clustered VG(s):" + ocf_run ${LVM_VGCHANGE} -anl $LVM_VGS + if [ $? -ne 0 ]; then +- ocf_log error "Failed to deactivate volume groups, cluster vglist = $LVM_VGS" ++ ocf_exit_reason "Failed to deactivate volume groups, cluster vglist = $LVM_VGS" + return $OCF_ERR_GENERIC + fi + fi +@@ -259,14 +259,14 @@ clvmd_stop() + ocf_log info "Signaling $DAEMON to exit" + killall -TERM $DAEMON + if [ $? != 0 ]; then +- ocf_log error "Failed to signal -TERM to $DAEMON" ++ ocf_exit_reason "Failed to signal -TERM to $DAEMON" + return $OCF_ERR_GENERIC + fi + + wait_for_process $DAEMON $CLVMD_TIMEOUT + rc=$? + if [ $rc -ne $OCF_SUCCESS ]; then +- ocf_log error "$DAEMON failed to exit" ++ ocf_exit_reason "$DAEMON failed to exit" + return $rc + fi + +@@ -304,7 +304,7 @@ start_process() + ocf_run $binary_path $opts + rc=$? + if [ $rc -ne 0 ]; then +- ocf_log error "Failed to launch $binary_path, exit code $rc" ++ ocf_exit_reason "Failed to launch $binary_path, exit code $rc" + exit $OCF_ERR_GENERIC + fi + fi +@@ -332,7 +332,7 @@ clvmd_start() + + clvmd_validate + if [ $? -ne $OCF_SUCCESS ]; then +- ocf_log error "Unable to start, Environment validation failed." ++ ocf_exit_reason "Unable to start, Environment validation failed." + return $? + fi + +diff --git a/heartbeat/conntrackd b/heartbeat/conntrackd +index 32eab6b..84ea360 100755 +--- a/heartbeat/conntrackd ++++ b/heartbeat/conntrackd +@@ -98,7 +98,7 @@ meta_expect() + # [, not [[, or it won't work ;) + [ $val $op $expect ] && return + fi +- ocf_log err "meta parameter misconfigured, expected $what $op $expect, but found ${val:-unset}." ++ ocf_exit_reason "meta parameter misconfigured, expected $what $op $expect, but found ${val:-unset}." + exit $OCF_ERR_CONFIGURED + } + +@@ -123,7 +123,7 @@ conntrackd_monitor() { + # now see if it acceppts queries + if ! $OCF_RESKEY_binary -C $OCF_RESKEY_config -s > /dev/null 2>&1; then + rc=$OCF_ERR_GENERIC +- ocf_log err "conntrackd is running but not responding to queries" ++ ocf_exit_reason "conntrackd is running but not responding to queries" + fi + if conntrackd_is_master; then + rc=$OCF_RUNNING_MASTER +@@ -154,7 +154,7 @@ conntrackd_start() { + conntrackd_set_master_score $slave_score + # -n = request resync from the others + if ! $OCF_RESKEY_binary -C $OCF_RESKEY_config -n; then +- ocf_log err "$OCF_RESKEY_binary -C $OCF_RESKEY_config -n failed during start." ++ ocf_exit_reason "$OCF_RESKEY_binary -C $OCF_RESKEY_config -n failed during start." + rc=$OCF_ERR_GENERIC + else + rc=$OCF_SUCCESS +@@ -170,7 +170,7 @@ conntrackd_start() { + ha_pseudo_resource $statefile stop + ;; + $OCF_ERR_GENERIC) +- ocf_log err "conntrackd start failed" ++ ocf_exit_reason "conntrackd start failed" + rc=$OCF_ERR_GENERIC + break + ;; +@@ -208,7 +208,7 @@ conntrackd_stop() { + conntrackd_validate_all() { + check_binary "$OCF_RESKEY_binary" + if ! [ -e "$OCF_RESKEY_config" ]; then +- ocf_log err "Config FILE $OCF_RESKEY_config does not exist" ++ ocf_exit_reason "Config FILE $OCF_RESKEY_config does not exist" + return $OCF_ERR_INSTALLED + fi + meta_expect master-node-max = 1 +@@ -227,7 +227,7 @@ conntrackd_promote() { + # -B = send a bulk update on the line + for parm in c f R B; do + if ! $OCF_RESKEY_binary -C $OCF_RESKEY_config -$parm; then +- ocf_log err "$OCF_RESKEY_binary -C $OCF_RESKEY_config -$parm failed during promote." ++ ocf_exit_reason "$OCF_RESKEY_binary -C $OCF_RESKEY_config -$parm failed during promote." + rc=$OCF_ERR_GENERIC + break + fi +@@ -245,7 +245,7 @@ conntrackd_demote() { + # -n = request a resync from the others + for parm in t n; do + if ! $OCF_RESKEY_binary -C $OCF_RESKEY_config -$parm; then +- ocf_log err "$OCF_RESKEY_binary -C $OCF_RESKEY_config -$parm failed during demote." ++ ocf_exit_reason "$OCF_RESKEY_binary -C $OCF_RESKEY_config -$parm failed during demote." + rc=$OCF_ERR_GENERIC + break + fi +diff --git a/heartbeat/dhcpd b/heartbeat/dhcpd +index 835a788..67b529e 100755 +--- a/heartbeat/dhcpd ++++ b/heartbeat/dhcpd +@@ -189,17 +189,17 @@ dhcpd_validate_all() { + # chroot mode is enabled. + if ocf_is_true $OCF_RESKEY_chrooted ; then + if ! test -e "$OCF_RESKEY_chrooted_path"; then +- ocf_log err "Path $OCF_RESKEY_chrooted_path does not exist." ++ ocf_exit_reason "Path $OCF_RESKEY_chrooted_path does not exist." + return $OCF_ERR_INSTALLED + fi + + if test -n "$OCF_RESKEY_chrooted_path/$OCF_RESKEY_config" -a ! -r "$OCF_RESKEY_chrooted_path/$OCF_RESKEY_config"; then +- ocf_log err "Configuration file $OCF_RESKEY_chrooted_path/$OCF_RESKEY_config doesn't exist" ++ ocf_exit_reason "Configuration file $OCF_RESKEY_chrooted_path/$OCF_RESKEY_config doesn't exist" + return $OCF_ERR_INSTALLED + fi + else + if test -n "$OCF_RESKEY_config" -a ! -r "$OCF_RESKEY_config"; then +- ocf_log err "Configuration file $OCF_RESKEY_config doesn't exist" ++ ocf_exit_reason "Configuration file $OCF_RESKEY_config doesn't exist" + return $OCF_ERR_INSTALLED + fi + fi +@@ -207,7 +207,7 @@ dhcpd_validate_all() { + fi + + if ! getent passwd $OCF_RESKEY_user >/dev/null 2>&1; then +- ocf_log err "User $OCF_RESKEY_user doesn't exist" ++ ocf_exit_reason "User $OCF_RESKEY_user doesn't exist" + return $OCF_ERR_INSTALLED + fi + +@@ -264,7 +264,7 @@ dhcpd_initialize_chroot() { + ## If there is no conf file, we can't initialize the chrooted + ## environment, return with "program not configured" + if ! [ -f $OCF_RESKEY_config ] ; then +- ocf_log err "dhcpd has not been configured." ++ ocf_exit_reason "dhcpd has not been configured." + return $OCF_ERR_CONFIGURED + fi + +@@ -283,7 +283,7 @@ dhcpd_initialize_chroot() { + if [ -e $i ] ; then + DEFAULT_FILE_LIST="$DEFAULT_FILE_LIST $i" + else +- ocf_log err "include file $i does not exist" ++ ocf_exit_reason "include file $i does not exist" + return $OCF_ERR_INSTALLED + fi + done +@@ -299,7 +299,7 @@ dhcpd_initialize_chroot() { + + # Next, we copy the configuration file into place. + cp -aL "$i" "$OCF_RESKEY_chrooted_path/${i%/*}/" > /dev/null 2>&1 || +- { ocf_log err "could not copy $i to chroot jail"; return $OCF_ERR_GENERIC; } ++ { ocf_exit_reason "could not copy $i to chroot jail"; return $OCF_ERR_GENERIC; } + done + + libdir=$(basename $(echo /var/lib/dhcp/lib*)) +@@ -328,7 +328,7 @@ dhcpd_initialize_chroot() { + for i in $cplibs ; do + if [ -s "$i" ]; then + cp -pL "$i" "/var/lib/dhcp/$libdir/" || +- { ocf_log err "could not copy $i to chroot jail"; return $OCF_ERR_GENERIC; } ++ { ocf_exit_reason "could not copy $i to chroot jail"; return $OCF_ERR_GENERIC; } + fi + done + +@@ -339,7 +339,7 @@ dhcpd_initialize_chroot() { + dhcpd_initialize() { + ## If there is no conf file, we can't start a dhcp service. + if ! [ -f $OCF_RESKEY_config ] ; then +- ocf_log err "dhcpd has not been configured." ++ ocf_exit_reason "dhcpd has not been configured." + return $OCF_ERR_CONFIGURED + fi + +@@ -392,10 +392,10 @@ dhcpd_start() { + # Only initialize the chrooted path(s) if chroot mode is enabled. + if ocf_is_true $OCF_RESKEY_chrooted ; then + dhcpd_initialize_chroot || +- { ocf_log err "Could not fully initialize the chroot environment." ; return $OCF_ERR_INSTALLED; } ++ { ocf_exit_reason "Could not fully initialize the chroot environment." ; return $OCF_ERR_INSTALLED; } + else + dhcpd_initialize || +- { ocf_log err "Could not fully initialize the runtime environment." ; return $OCF_ERR_INSTALLED; } ++ { ocf_exit_reason "Could not fully initialize the runtime environment." ; return $OCF_ERR_INSTALLED; } + fi + + dhcpd_validate_all || exit +@@ -501,7 +501,7 @@ dhcpd_stop () { + + #If still up + if dhcpd_monitor 2>&1; then +- ocf_log err "dhcpd is still up! Trying kill -s KILL" ++ ocf_log notice "dhcpd is still up! Trying kill -s KILL" + + kill -s SIGKILL `cat $PIDF` + fi +diff --git a/heartbeat/galera b/heartbeat/galera +old mode 100644 +new mode 100755 +index 6d8cf12..54654f8 +--- a/heartbeat/galera ++++ b/heartbeat/galera +@@ -318,7 +318,7 @@ is_primary() + fi + + if [ -z "$cluster_status" ]; then +- ocf_log err "Unable to retrieve wsrep_cluster_status, verify check_user '$OCF_RESKEY_check_user' has permissions to view status" ++ ocf_exit_reason "Unable to retrieve wsrep_cluster_status, verify check_user '$OCF_RESKEY_check_user' has permissions to view status" + else + ocf_log info "Galera instance wsrep_cluster_status=${cluster_status}" + fi +@@ -441,7 +441,7 @@ galera_promote() + ocf_log info "Node <${NODENAME}> is bootstrapping the cluster" + extra_opts="--wsrep-cluster-address=gcomm://" + else +- ocf_log err "Failure, Attempted to promote Master instance of $OCF_RESOURCE_INSTANCE before bootstrap node has been detected." ++ ocf_exit_reason "Failure, Attempted to promote Master instance of $OCF_RESOURCE_INSTANCE before bootstrap node has been detected." + return $OCF_ERR_GENERIC + fi + +@@ -451,7 +451,7 @@ galera_promote() + mysql_common_stop + rc=$? + if [ $rc -ne $OCF_SUCCESS ] && [ $rc -ne $OCF_NOT_RUNNING ]; then +- ocf_log err "Failed to stop read-only galera instance during promotion to Master" ++ ocf_exit_reason "Failed to stop read-only galera instance during promotion to Master" + return $rc + fi + +@@ -467,19 +467,19 @@ galera_promote() + galera_monitor + rc=$? + if [ $rc != $OCF_SUCCESS -a $rc != $OCF_RUNNING_MASTER ]; then +- ocf_log err "Failed initial monitor action" ++ ocf_exit_reason "Failed initial monitor action" + return $rc + fi + + is_readonly + if [ $? -eq 0 ]; then +- ocf_log err "Failure. Master instance started in read-only mode, check configuration." ++ ocf_exit_reason "Failure. Master instance started in read-only mode, check configuration." + return $OCF_ERR_GENERIC + fi + + is_primary + if [ $? -ne 0 ]; then +- ocf_log err "Failure. Master instance started, but is not in Primary mode." ++ ocf_exit_reason "Failure. Master instance started, but is not in Primary mode." + return $OCF_ERR_GENERIC + fi + +@@ -505,7 +505,7 @@ galera_demote() + mysql_common_stop + rc=$? + if [ $rc -ne $OCF_SUCCESS ] && [ $rc -ne $OCF_NOT_RUNNING ]; then +- ocf_log err "Failed to stop Master galera instance during demotion to Master" ++ ocf_exit_reason "Failed to stop Master galera instance during demotion to Master" + return $rc + fi + +@@ -523,7 +523,7 @@ galera_start() + + echo $OCF_RESKEY_wsrep_cluster_address | grep -q $NODENAME + if [ $? -ne 0 ]; then +- ocf_log err "local node <${NODENAME}> must be a member of the wsrep_cluster_address <${OCF_RESKEY_wsrep_cluster_address}>to start this galera instance" ++ ocf_exit_reason "local node <${NODENAME}> must be a member of the wsrep_cluster_address <${OCF_RESKEY_wsrep_cluster_address}>to start this galera instance" + return $OCF_ERR_CONFIGURED + fi + +@@ -532,7 +532,7 @@ galera_start() + + is_readonly + if [ $? -ne 0 ]; then +- ocf_log err "Failure. Slave instance did not start correctly in read-only mode, Make sure local galera.cnf does not have wsrep_cluster_address set." ++ ocf_exit_reason "Slave instance did not start correctly in read-only mode, Make sure local galera.cnf does not have wsrep_cluster_address set." + return $OCF_ERR_GENERIC + fi + +@@ -579,7 +579,7 @@ galera_monitor() + + echo $OCF_RESKEY_wsrep_cluster_address | grep -q $NODENAME + if [ $? -ne 0 ]; then +- ocf_log err "local node <${NODENAME}> is started, but is not a member of the wsrep_cluster_address <${OCF_RESKEY_wsrep_cluster_address}>" ++ ocf_exit_reason "local node <${NODENAME}> is started, but is not a member of the wsrep_cluster_address <${OCF_RESKEY_wsrep_cluster_address}>" + return $OCF_ERR_GENERIC + fi + +@@ -587,7 +587,7 @@ galera_monitor() + if [ $? -ne 0 ]; then + is_primary + if [ $? -ne 0 ]; then +- ocf_log err "local node <${NODENAME}> is neither in primary mode nor in read_only mode. Unknown state." ++ ocf_exit_reason "local node <${NODENAME}> is neither in primary mode nor in read_only mode. Unknown state." + return $OCF_ERR_GENERIC + fi + +@@ -629,12 +629,12 @@ galera_stop() + galera_validate() + { + if ! ocf_is_ms; then +- ocf_log err "Galera must be configured as a multistate Master/Slave resource." ++ ocf_exit_reason "Galera must be configured as a multistate Master/Slave resource." + return $OCF_ERR_CONFIGURED + fi + + if [ -z "$OCF_RESKEY_wsrep_cluster_address" ]; then +- ocf_log err "Galera must be configured with a wsrep_cluster_address value." ++ ocf_exit_reason "Galera must be configured with a wsrep_cluster_address value." + return $OCF_ERR_CONFIGURED + fi + +diff --git a/heartbeat/mysql b/heartbeat/mysql +index 41287d0..3170065 100755 +--- a/heartbeat/mysql ++++ b/heartbeat/mysql +@@ -394,7 +394,7 @@ get_slave_info() { + else + # Instance produced an empty "SHOW SLAVE STATUS" output -- + # instance is not a slave +- ocf_log err "check_slave invoked on an instance that is not a replication slave." ++ ocf_exit_reason "check_slave invoked on an instance that is not a replication slave." + return $OCF_ERR_GENERIC + fi + +@@ -415,7 +415,7 @@ check_slave() { + # Whoa. Replication ran into an error. This slave has + # diverged from its master. Make sure this resource + # doesn't restart in place. +- ocf_log err "MySQL instance configured for replication, but replication has failed." ++ ocf_exit_reason "MySQL instance configured for replication, but replication has failed." + ocf_log err "See $tmpfile for details" + + # Just pull the reader VIP away, killing MySQL here would be pretty evil +@@ -454,7 +454,7 @@ check_slave() { + # We don't have a replication SQL thread running. Not a + # good thing. Try to recoved by restarting the SQL thread + # and remove reader vip. Prevent MySQL restart. +- ocf_log err "MySQL Slave SQL threads currently not running." ++ ocf_exit_reason "MySQL Slave SQL threads currently not running." + ocf_log err "See $tmpfile for details" + + # Remove reader vip +@@ -472,7 +472,7 @@ check_slave() { + # We're supposed to bail out if we lag too far + # behind. Let's check our lag. + if [ $secs_behind -gt $OCF_RESKEY_max_slave_lag ]; then +- ocf_log err "MySQL Slave is $secs_behind seconds behind master (allowed maximum: $OCF_RESKEY_max_slave_lag)." ++ ocf_exit_reason "MySQL Slave is $secs_behind seconds behind master (allowed maximum: $OCF_RESKEY_max_slave_lag)." + ocf_log err "See $tmpfile for details" + + # Remove reader vip +@@ -507,7 +507,7 @@ check_slave() { + # instance is not a slave + # TODO: Needs to handle when get_slave_info will return too many connections error + rm -f $tmpfile +- ocf_log err "check_slave invoked on an instance that is not a replication slave." ++ ocf_exit_reason "check_slave invoked on an instance that is not a replication slave." + exit $OCF_ERR_GENERIC + fi + } +@@ -596,7 +596,7 @@ unset_master(){ + ocf_run $MYSQL $MYSQL_OPTIONS_REPL \ + -e "STOP SLAVE IO_THREAD" + if [ $? -gt 0 ]; then +- ocf_log err "Error stopping slave IO thread" ++ ocf_exit_reason "Error stopping slave IO thread" + exit $OCF_ERR_GENERIC + fi + +@@ -620,14 +620,14 @@ unset_master(){ + ocf_run $MYSQL $MYSQL_OPTIONS_REPL \ + -e "STOP SLAVE" + if [ $? -gt 0 ]; then +- ocf_log err "Error stopping rest slave threads" ++ ocf_exit_reason "Error stopping rest slave threads" + exit $OCF_ERR_GENERIC + fi + + ocf_run $MYSQL $MYSQL_OPTIONS_REPL \ + -e "RESET SLAVE;" + if [ $? -gt 0 ]; then +- ocf_log err "Failed to reset slave" ++ ocf_exit_reason "Failed to reset slave" + exit $OCF_ERR_GENERIC + fi + } +@@ -737,7 +737,7 @@ mysql_monitor() { + rc=$? + + if [ $rc -ne 0 ]; then +- ocf_log err "Failed to select from $test_table"; ++ ocf_exit_reason "Failed to select from $test_table"; + return $OCF_ERR_GENERIC; + fi + fi +@@ -800,7 +800,7 @@ mysql_start() { + set_master + start_slave + if [ $? -ne 0 ]; then +- ocf_log err "Failed to start slave" ++ ocf_exit_reason "Failed to start slave" + return $OCF_ERR_GENERIC + fi + else +@@ -823,7 +823,7 @@ mysql_start() { + mysql_monitor + rc=$? + if [ $rc != $OCF_SUCCESS -a $rc != $OCF_RUNNING_MASTER ]; then +- ocf_log err "Failed initial monitor action" ++ ocf_exit_reason "Failed initial monitor action" + return $rc + fi + +@@ -921,7 +921,7 @@ mysql_notify() { + + start_slave + if [ $? -ne 0 ]; then +- ocf_log err "Failed to start slave" ++ ocf_exit_reason "Failed to start slave" + return $OCF_ERR_GENERIC + fi + fi +@@ -933,7 +933,7 @@ mysql_notify() { + ocf_log info "post-demote notification for $demote_host" + set_read_only on + if [ $? -ne 0 ]; then +- ocf_log err "Failed to set read-only"; ++ ocf_exit_reason "Failed to set read-only"; + return $OCF_ERR_GENERIC; + fi + +diff --git a/heartbeat/mysql-common.sh b/heartbeat/mysql-common.sh +old mode 100644 +new mode 100755 +index 5b6a991..a02f8cd +--- a/heartbeat/mysql-common.sh ++++ b/heartbeat/mysql-common.sh +@@ -98,24 +98,24 @@ mysql_common_validate() + check_binary $OCF_RESKEY_client_binary + + if [ ! -f $OCF_RESKEY_config ]; then +- ocf_log err "Config $OCF_RESKEY_config doesn't exist"; ++ ocf_exit_reason "Config $OCF_RESKEY_config doesn't exist"; + return $OCF_ERR_INSTALLED; + fi + + if [ ! -d $OCF_RESKEY_datadir ]; then +- ocf_log err "Datadir $OCF_RESKEY_datadir doesn't exist"; ++ ocf_exit_reason "Datadir $OCF_RESKEY_datadir doesn't exist"; + return $OCF_ERR_INSTALLED; + fi + + getent passwd $OCF_RESKEY_user >/dev/null 2>&1 + if [ ! $? -eq 0 ]; then +- ocf_log err "User $OCF_RESKEY_user doesn't exit"; ++ ocf_exit_reason "User $OCF_RESKEY_user doesn't exit"; + return $OCF_ERR_INSTALLED; + fi + + getent group $OCF_RESKEY_group >/dev/null 2>&1 + if [ ! $? -eq 0 ]; then +- ocf_log err "Group $OCF_RESKEY_group doesn't exist"; ++ ocf_exit_reason "Group $OCF_RESKEY_group doesn't exist"; + return $OCF_ERR_INSTALLED; + fi + +@@ -162,7 +162,7 @@ mysql_common_prepare_dirs() + $MYSQL_BINDIR/mysql_install_db --datadir=$OCF_RESKEY_datadir + rc=$? + if [ $rc -ne 0 ] ; then +- ocf_log err "Initialization failed: $rc"; ++ ocf_exit_reason "Initialization failed: $rc"; + exit $OCF_ERR_GENERIC + fi + chown -R $OCF_RESKEY_user:$OCF_RESKEY_group $OCF_RESKEY_datadir +@@ -187,7 +187,7 @@ mysql_common_prepare_dirs() + # user + for dir in $pid_dir $socket_dir; do + if ! su -s /bin/sh - $OCF_RESKEY_user -c "test -w $dir"; then +- ocf_log err "Directory $dir is not writable by $OCF_RESKEY_user" ++ ocf_exit_reason "Directory $dir is not writable by $OCF_RESKEY_user" + exit $OCF_ERR_PERM; + fi + done +@@ -213,7 +213,7 @@ mysql_common_start() + while [ $start_wait = 1 ]; do + if ! ps $pid > /dev/null 2>&1; then + wait $pid +- ocf_log err "MySQL server failed to start (pid=$pid) (rc=$?), please check your installation" ++ ocf_exit_reason "MySQL server failed to start (pid=$pid) (rc=$?), please check your installation" + return $OCF_ERR_GENERIC + fi + mysql_common_status info +@@ -244,7 +244,7 @@ mysql_common_stop() + /bin/kill $pid > /dev/null + rc=$? + if [ $rc != 0 ]; then +- ocf_log err "MySQL couldn't be stopped" ++ ocf_exit_reason "MySQL couldn't be stopped" + return $OCF_ERR_GENERIC + fi + # stop waiting +diff --git a/heartbeat/named b/heartbeat/named +index ede22df..2c34a15 100755 +--- a/heartbeat/named ++++ b/heartbeat/named +@@ -211,21 +211,21 @@ named_validate_all() { + if ocf_is_probe; then + ocf_log info "Configuration file ${OCF_RESKEY_named_rootdir}/${OCF_RESKEY_named_config} not readable during probe." + else +- ocf_log err "Configuration file ${OCF_RESKEY_named_rootdir}/${OCF_RESKEY_named_config} doesn't exist" ++ ocf_exit_reason "Configuration file ${OCF_RESKEY_named_rootdir}/${OCF_RESKEY_named_config} doesn't exist" + return $OCF_ERR_INSTALLED + fi + fi + + getent passwd $OCF_RESKEY_named_user >/dev/null 2>&1 + if [ ! $? -eq 0 ]; then +- ocf_log err "User $OCF_RESKEY_named_user doesn't exist"; ++ ocf_exit_reason "User $OCF_RESKEY_named_user doesn't exist"; + return $OCF_ERR_INSTALLED; + fi + + if [ -z "$OCF_RESKEY_monitor_request" -o \ + -z "$OCF_RESKEY_monitor_response" -o \ + -z "$OCF_RESKEY_monitor_ip" ]; then +- ocf_log err "None of monitor_request, monitor_response, and monitor_ip can be empty" ++ ocf_exit_reason "None of monitor_request, monitor_response, and monitor_ip can be empty" + return $OCF_ERR_CONFIGURED + fi + +@@ -309,7 +309,7 @@ named_monitor() { + + if [ $? -ne 0 ] || ! echo $output | grep -q '.* has .*address '"$OCF_RESKEY_monitor_response" + then +- ocf_log err "named didn't answer properly for $OCF_RESKEY_monitor_request." ++ ocf_exit_reason "named didn't answer properly for $OCF_RESKEY_monitor_request." + ocf_log err "Expected: $OCF_RESKEY_monitor_response." + ocf_log err "Got: $output" + return $OCF_ERR_GENERIC +@@ -356,7 +356,7 @@ named_start() { + + if ! ${OCF_RESKEY_named} -u ${OCF_RESKEY_named_user} $root_dir_opt ${OCF_RESKEY_named_options} + then +- ocf_log err "named failed to start." ++ ocf_exit_reason "named failed to start." + return $OCF_ERR_GENERIC + fi + +@@ -368,7 +368,7 @@ named_start() { + echo $pid > ${OCF_RESKEY_named_pidfile} + fi + else +- ocf_log err "named failed to start. Probably error in configuration." ++ ocf_exit_reason "named failed to start. Probably error in configuration." + return $OCF_ERR_GENERIC + fi + +@@ -420,7 +420,7 @@ named_stop () { + + #If still up + if named_status 2>&1; then +- ocf_log err "named is still up! Killing" ++ ocf_exit_reason "named is still up! Killing" + kill -9 `cat ${OCF_RESKEY_named_pidfile}` + fi + +@@ -460,7 +460,7 @@ then + fi + + if [ `id -u` -ne 0 ]; then +- ocf_log err "$0 must be run as root" ++ ocf_exit_reason "$0 must be run as root" + exit $OCF_ERR_GENERIC + fi + +diff --git a/heartbeat/pgsql b/heartbeat/pgsql +index aea97da..794f85e 100755 +--- a/heartbeat/pgsql ++++ b/heartbeat/pgsql +@@ -495,7 +495,7 @@ pgsql_real_start() { + # Check if we need to create a log file + if ! check_log_file $OCF_RESKEY_logfile + then +- ocf_log err "PostgreSQL can't write to the log file: $OCF_RESKEY_logfile" ++ ocf_exit_reason "PostgreSQL can't write to the log file: $OCF_RESKEY_logfile" + return $OCF_ERR_PERM + fi + +@@ -533,7 +533,7 @@ pgsql_real_start() { + # Probably started..... + ocf_log info "PostgreSQL start command sent." + else +- ocf_log err "Can't start PostgreSQL." ++ ocf_exit_reason "Can't start PostgreSQL." + return $OCF_ERR_GENERIC + fi + +@@ -565,7 +565,7 @@ pgsql_replication_start() { + fi + + if [ -f $PGSQL_LOCK ]; then +- ocf_log err "My data may be inconsistent. You have to remove $PGSQL_LOCK file to force start." ++ ocf_exit_reason "My data may be inconsistent. You have to remove $PGSQL_LOCK file to force start." + return $OCF_ERR_GENERIC + fi + +@@ -595,7 +595,7 @@ pgsql_promote() { + local rc + + if ! is_replication; then +- ocf_log err "Not in a replication mode." ++ ocf_exit_reason "Not in a replication mode." + return $OCF_ERR_CONFIGURED + fi + rm -f ${XLOG_NOTE_FILE}.* +@@ -618,7 +618,7 @@ pgsql_promote() { + pgsql_real_start + rc=$? + if [ $rc -ne $OCF_RUNNING_MASTER ]; then +- ocf_log err "Can't start PostgreSQL as primary on promote." ++ ocf_exit_reason "Can't start PostgreSQL as primary on promote." + if [ $rc -ne $OCF_SUCCESS ]; then + change_pgsql_status "$NODENAME" "STOP" + fi +@@ -629,7 +629,7 @@ pgsql_promote() { + if [ $? -eq 0 ]; then + ocf_log info "PostgreSQL promote command sent." + else +- ocf_log err "Can't promote PostgreSQL." ++ ocf_exit_reason "Can't promote PostgreSQL." + return $OCF_ERR_GENERIC + fi + +@@ -640,7 +640,7 @@ pgsql_promote() { + if [ $rc -eq $OCF_RUNNING_MASTER ]; then + break; + elif [ $rc -eq $OCF_ERR_GENERIC ]; then +- ocf_log err "Can't promote PostgreSQL." ++ ocf_exit_reason "Can't promote PostgreSQL." + return $rc + fi + sleep 1 +@@ -660,7 +660,7 @@ pgsql_demote() { + local rc + + if ! is_replication; then +- ocf_log err "Not in a replication mode." ++ ocf_exit_reason "Not in a replication mode." + return $OCF_ERR_CONFIGURED + fi + +@@ -861,7 +861,7 @@ pgsql_real_monitor() { + t) ocf_log debug "PostgreSQL is running as a hot standby." + return $OCF_SUCCESS;; + +- *) ocf_log err "$CHECK_MS_SQL output is $output" ++ *) ocf_exit_reason "$CHECK_MS_SQL output is $output" + return $OCF_ERR_GENERIC;; + esac + fi +@@ -966,7 +966,7 @@ pgsql_pre_promote() { + cmp_location=`printf "$master_baseline\n$my_master_baseline\n" |\ + sort | head -1` + if [ "$cmp_location" != "$my_master_baseline" ]; then +- ocf_log err "My data is newer than new master's one. New master's location : $master_baseline" ++ ocf_exit_reason "My data is newer than new master's one. New master's location : $master_baseline" + $CRM_FAILCOUNT -r $OCF_RESOURCE_INSTANCE -U $NODENAME -v INFINITY + return $OCF_ERR_GENERIC + fi +@@ -1149,7 +1149,7 @@ have_master_right() { + + show_xlog_location + if [ $? -ne 0 ]; then +- ocf_log err "Failed to show my xlog location." ++ ocf_exit_reason "Failed to show my xlog location." + exit $OCF_ERR_GENERIC + fi + +@@ -1288,7 +1288,7 @@ set_async_mode_all() { + ocf_log info "Set all nodes into async mode." + runasowner -q err "echo \"synchronous_standby_names = ''\" > \"$REP_MODE_CONF\"" + if [ $? -ne 0 ]; then +- ocf_log err "Can't set all nodes into async mode." ++ ocf_exit_reason "Can't set all nodes into async mode." + return 1 + fi + return 0 +@@ -1339,7 +1339,7 @@ reload_conf() { + if [ $? -eq 0 ]; then + ocf_log info "Reload configuration file." + else +- ocf_log err "Can't reload configuration file." ++ ocf_exit_reason "Can't reload configuration file." + return 1 + fi + +@@ -1359,7 +1359,7 @@ user_recovery_conf() { + make_recovery_conf() { + runasowner "touch $RECOVERY_CONF" + if [ $? -ne 0 ]; then +- ocf_log err "Can't create recovery.conf." ++ ocf_exit_reason "Can't create recovery.conf." + return 1 + fi + +@@ -1492,11 +1492,11 @@ report_psql_error() + + ocf_log $loglevel "PostgreSQL $OCF_RESKEY_pgdb isn't running" + if [ $rc -eq 1 ]; then +- ocf_log err "Fatal error (out of memory, file not found, etc.) occurred while executing the psql command." ++ ocf_exit_reason "Fatal error (out of memory, file not found, etc.) occurred while executing the psql command." + elif [ $rc -eq 2 ]; then + ocf_log $loglevel "Connection error (connection to the server went bad and the session was not interactive) occurred while executing the psql command." + elif [ $rc -eq 3 ]; then +- ocf_log err "Script error (the variable ON_ERROR_STOP was set) occurred while executing the psql command." ++ ocf_exit_reason "Script error (the variable ON_ERROR_STOP was set) occurred while executing the psql command." + fi + } + +@@ -1536,7 +1536,7 @@ node_exist() { + + check_binary2() { + if ! have_binary "$1"; then +- ocf_log err "Setup problem: couldn't find command: $1" ++ ocf_exit_reason "Setup problem: couldn't find command: $1" + return 1 + fi + return 0 +@@ -1550,7 +1550,7 @@ check_config() { + ocf_log info "Configuration file is $1 not readable during probe." + rc=1 + else +- ocf_log err "Configuration file $1 doesn't exist" ++ ocf_exit_reason "Configuration file $1 doesn't exist" + rc=2 + fi + fi +@@ -1576,7 +1576,7 @@ pgsql_validate_all() { + + getent passwd $OCF_RESKEY_pgdba >/dev/null 2>&1 + if [ ! $? -eq 0 ]; then +- ocf_log err "User $OCF_RESKEY_pgdba doesn't exist"; ++ ocf_exit_reason "User $OCF_RESKEY_pgdba doesn't exist"; + return $OCF_ERR_INSTALLED; + fi + +@@ -1584,46 +1584,46 @@ pgsql_validate_all() { + ocf_log info "Don't check $OCF_RESKEY_pgdata during probe" + else + if ! runasowner "test -w $OCF_RESKEY_pgdata"; then +- ocf_log err "Directory $OCF_RESKEY_pgdata is not writable by $OCF_RESKEY_pgdba" ++ ocf_exit_reason "Directory $OCF_RESKEY_pgdata is not writable by $OCF_RESKEY_pgdba" + return $OCF_ERR_PERM; + fi + fi + + if [ -n "$OCF_RESKEY_monitor_user" -a ! -n "$OCF_RESKEY_monitor_password" ] + then +- ocf_log err "monitor password can't be empty" ++ ocf_exit_reason "monitor password can't be empty" + return $OCF_ERR_CONFIGURED + fi + + if [ ! -n "$OCF_RESKEY_monitor_user" -a -n "$OCF_RESKEY_monitor_password" ] + then +- ocf_log err "monitor_user has to be set if monitor_password is set" ++ ocf_exit_reason "monitor_user has to be set if monitor_password is set" + return $OCF_ERR_CONFIGURED + fi + + if is_replication || [ "$OCF_RESKEY_rep_mode" = "slave" ]; then + version=`cat $OCF_RESKEY_pgdata/PG_VERSION` + if [ `printf "$version\n9.1" | sort -n | head -1` != "9.1" ]; then +- ocf_log err "Replication mode needs PostgreSQL 9.1 or higher." ++ ocf_exit_reason "Replication mode needs PostgreSQL 9.1 or higher." + return $OCF_ERR_INSTALLED + fi + if [ ! -n "$OCF_RESKEY_master_ip" ]; then +- ocf_log err "master_ip can't be empty." ++ ocf_exit_reason "master_ip can't be empty." + return $OCF_ERR_CONFIGURED + fi + fi + + if is_replication; then + if ! ocf_is_ms; then +- ocf_log err "Replication(rep_mode=async or sync) requires Master/Slave configuration." ++ ocf_exit_reason "Replication(rep_mode=async or sync) requires Master/Slave configuration." + return $OCF_ERR_CONFIGURED + fi + if [ ! "$OCF_RESKEY_rep_mode" = "sync" -a ! "$OCF_RESKEY_rep_mode" = "async" ]; then +- ocf_log err "Invalid rep_mode : $OCF_RESKEY_rep_mode" ++ ocf_exit_reason "Invalid rep_mode : $OCF_RESKEY_rep_mode" + return $OCF_ERR_CONFIGURED + fi + if [ ! -n "$NODE_LIST" ]; then +- ocf_log err "node_list can't be empty." ++ ocf_exit_reason "node_list can't be empty." + return $OCF_ERR_CONFIGURED + fi + if [ $check_config_rc -eq 0 ]; then +@@ -1641,14 +1641,14 @@ pgsql_validate_all() { + fi + fi + if ! mkdir -p $OCF_RESKEY_tmpdir || ! chown $OCF_RESKEY_pgdba $OCF_RESKEY_tmpdir || ! chmod 700 $OCF_RESKEY_tmpdir; then +- ocf_log err "Can't create directory $OCF_RESKEY_tmpdir or it is not readable by $OCF_RESKEY_pgdba" ++ ocf_exit_reason "Can't create directory $OCF_RESKEY_tmpdir or it is not readable by $OCF_RESKEY_pgdba" + return $OCF_ERR_PERM + fi + fi + + if [ "$OCF_RESKEY_rep_mode" = "slave" ]; then + if ocf_is_ms; then +- ocf_log err "Replication(rep_mode=slave) does not support Master/Slave configuration." ++ ocf_exit_reason "Replication(rep_mode=slave) does not support Master/Slave configuration." + return $OCF_ERR_CONFIGURED + fi + fi +@@ -1683,24 +1683,24 @@ check_log_file() { + check_socket_dir() { + if [ ! -d "$OCF_RESKEY_socketdir" ]; then + if ! mkdir "$OCF_RESKEY_socketdir"; then +- ocf_log err "Can't create directory $OCF_RESKEY_socketdir" ++ ocf_exit_reason "Can't create directory $OCF_RESKEY_socketdir" + exit $OCF_ERR_PERM + fi + + if ! chown $OCF_RESKEY_pgdba:`getent passwd \ + $OCF_RESKEY_pgdba | cut -d ":" -f 4` "$OCF_RESKEY_socketdir" + then +- ocf_log err "Can't change ownership for $OCF_RESKEY_socketdir" ++ ocf_exit_reason "Can't change ownership for $OCF_RESKEY_socketdir" + exit $OCF_ERR_PERM + fi + + if ! chmod 2775 "$OCF_RESKEY_socketdir"; then +- ocf_log err "Can't change permissions for $OCF_RESKEY_socketdir" ++ ocf_exit_reason "Can't change permissions for $OCF_RESKEY_socketdir" + exit $OCF_ERR_PERM + fi + else + if ! runasowner "touch $OCF_RESKEY_socketdir/test.$$"; then +- ocf_log err "$OCF_RESKEY_pgdba can't create files in $OCF_RESKEY_socketdir" ++ ocf_exit_reason "$OCF_RESKEY_pgdba can't create files in $OCF_RESKEY_socketdir" + exit $OCF_ERR_PERM + fi + rm $OCF_RESKEY_socketdir/test.$$ +@@ -1782,7 +1782,7 @@ US=`id -u -n` + + if [ $US != root -a $US != $OCF_RESKEY_pgdba ] + then +- ocf_log err "$0 must be run as root or $OCF_RESKEY_pgdba" ++ ocf_exit_reason "$0 must be run as root or $OCF_RESKEY_pgdba" + exit $OCF_ERR_GENERIC + fi + +diff --git a/heartbeat/postfix b/heartbeat/postfix +index 8619af6..72fc371 100755 +--- a/heartbeat/postfix ++++ b/heartbeat/postfix +@@ -134,7 +134,7 @@ postfix_start() + ret=$? + + if [ $ret -ne 0 ]; then +- ocf_log err "Postfix returned error: " $ret ++ ocf_exit_reason "Postfix returned error: " $ret + return $OCF_ERR_GENERIC + fi + +@@ -165,7 +165,7 @@ postfix_stop() + ret=$? + + if [ $ret -ne 0 ]; then +- ocf_log err "Postfix returned an error while stopping: " $ret ++ ocf_exit_reason "Postfix returned an error while stopping: " $ret + return $OCF_ERR_GENERIC + fi + +@@ -181,14 +181,14 @@ postfix_stop() + # escalate to abort if we did not stop by now + # @TODO shall we loop here too? + if postfix_running info; then +- ocf_log err "Postfix failed to stop. Escalating to 'abort'." ++ ocf_exit_reason "Postfix failed to stop. Escalating to 'abort'." + + $binary $OPTIONS abort >/dev/null 2>&1; ret=$? + sleep 5 + + # postfix abort did not succeed + if postfix_running; then +- ocf_log err "Postfix failed to abort." ++ ocf_exit_reason "Postfix failed to abort." + return $OCF_ERR_GENERIC + fi + fi +@@ -238,14 +238,14 @@ postfix_validate_all() + # skip in-depth directory checks if config file isn't readable during probe + dir_check=false + else +- ocf_log err "Postfix configuration directory '$config_dir' does not exist or is not readable." ++ ocf_exit_reason "Postfix configuration directory '$config_dir' does not exist or is not readable." + return $OCF_ERR_INSTALLED + fi + fi + + alternate_config_directories=`postconf -h alternate_config_directories 2>/dev/null | grep "$config_dir/\?"` + if [ "x$alternate_config_directories" = "x" ]; then +- ocf_log err "Postfix main configuration must contain correct 'alternate_config_directories' parameter." ++ ocf_exit_reason "Postfix main configuration must contain correct 'alternate_config_directories' parameter." + return $OCF_ERR_INSTALLED + fi + fi +@@ -257,7 +257,7 @@ postfix_validate_all() + if ocf_is_probe; then + ocf_log info "Postfix queue directory '$queue_dir' not readable during probe." + else +- ocf_log err "Postfix queue directory '$queue_dir' does not exist or is not readable." ++ ocf_exit_reason "Postfix queue directory '$queue_dir' does not exist or is not readable." + return $OCF_ERR_INSTALLED + fi + fi +@@ -266,14 +266,14 @@ postfix_validate_all() + data_dir=`postconf $OPTION_CONFIG_DIR -h data_directory 2>/dev/null` + data_dir_count=`echo "$data_dir" | tr ',' ' ' | wc -w` + if [ $data_dir_count -gt 1 ]; then +- ocf_log err "Postfix data directory '$orig_data_dir' cannot be set to multiple directories." ++ ocf_exit_reason "Postfix data directory '$orig_data_dir' cannot be set to multiple directories." + return $OCF_ERR_INSTALLED + fi + if [ ! -d "$data_dir" ]; then + if ocf_is_probe; then + ocf_log info "Postfix data directory '$data_dir' not readable during probe." + else +- ocf_log err "Postfix data directory '$data_dir' does not exist or is not readable." ++ ocf_exit_reason "Postfix data directory '$data_dir' does not exist or is not readable." + return $OCF_ERR_INSTALLED + fi + fi +@@ -287,7 +287,7 @@ postfix_validate_all() + if ocf_is_probe; then + ocf_log info "Directory '$dir' is not writable by user '$user' during probe." + else +- ocf_log err "Directory '$dir' is not writable by user '$user'." ++ ocf_exit_reason "Directory '$dir' is not writable by user '$user'." + return $OCF_ERR_PERM; + fi + fi +@@ -300,7 +300,7 @@ postfix_validate_all() + $binary $OPTIONS check >/dev/null 2>&1 + ret=$? + if [ $ret -ne 0 ]; then +- ocf_log err "Postfix 'check' failed: " $ret ++ ocf_exit_reason "Postfix 'check' failed: " $ret + return $OCF_ERR_GENERIC + fi + fi +diff --git a/heartbeat/rsyncd b/heartbeat/rsyncd +index b8cdeb7..dfbbea8 100755 +--- a/heartbeat/rsyncd ++++ b/heartbeat/rsyncd +@@ -127,7 +127,7 @@ rsyncd_status() + return $OCF_ERR_GENERIC + fi + else +- ocf_log err "PID file empty!" ++ ocf_exit_reason "PID file empty!" + return $OCF_ERR_GENERIC + fi + fi +@@ -145,7 +145,7 @@ rsyncd_start() + if [ $retVal -eq $OCF_SUCCESS ]; then + exit $OCF_SUCCESS + elif [ $retVal -ne $OCF_NOT_RUNNING ]; then +- ocf_log err "Error. Unknown status." ++ ocf_exit_reason "Error. Unknown status." + exit $OCF_ERR_GENERIC + fi + +@@ -164,11 +164,11 @@ rsyncd_start() + if grep -v "^#" "$CONF_FILE" | grep "pid file" > /dev/null ; then + $COMMAND; + if [ $? -ne 0 ]; then +- ocf_log err "Error. rsycn daemon returned error $?." ++ ocf_exit_reason "Error. rsycn daemon returned error $?." + exit $OCF_ERR_GENERIC + fi + else +- ocf_log err "Error. \"pid file\" entry required in the rsyncd config file by rsyncd OCF RA." ++ ocf_exit_reason "Error. \"pid file\" entry required in the rsyncd config file by rsyncd OCF RA." + return $OCF_ERR_GENERIC + fi + +@@ -186,7 +186,7 @@ rsyncd_stop() + if [ $? -ne 0 ]; then + kill -s KILL $PID + if [ $? -ne 0 ]; then +- ocf_log err "Error. Could not stop rsync daemon." ++ ocf_exit_reason "Error. Could not stop rsync daemon." + return $OCF_ERR_GENERIC + fi + fi +@@ -205,18 +205,18 @@ rsyncd_monitor() + rsyncd_validate_all() + { + if [ -n "$OCF_RESKEY_binpath" -a ! -x "$OCF_RESKEY_binpath" ]; then +- ocf_log err "Binary path $OCF_RESKEY_binpath does not exist." ++ ocf_exit_reason "Binary path $OCF_RESKEY_binpath does not exist." + exit $OCF_ERR_ARGS + fi + if [ -n "$OCF_RESKEY_conffile" -a ! -f "$OCF_RESKEY_conffile" ]; then +- ocf_log err "Config file $OCF_RESKEY_conffile does not exist." ++ ocf_exit_reason "Config file $OCF_RESKEY_conffile does not exist." + exit $OCF_ERR_ARGS + fi + + if grep -v "^#" "$CONF_FILE" | grep "pid file" > /dev/null ; then + : + else +- ocf_log err "Error. \"pid file\" entry required in the rsyncd config file by rsyncd OCF RA." ++ ocf_exit_reason "Error. \"pid file\" entry required in the rsyncd config file by rsyncd OCF RA." + return $OCF_ERR_GENERIC + fi + +diff --git a/heartbeat/slapd b/heartbeat/slapd +index ffb40e8..c26b16f 100755 +--- a/heartbeat/slapd ++++ b/heartbeat/slapd +@@ -268,7 +268,7 @@ slapd_pid() + return $OCF_SUCCESS + fi + +- ocf_log err "slapd pid file '$pid_file' empty." ++ ocf_exit_reason "slapd pid file '$pid_file' empty." + return $OCF_ERR_GENERIC + fi + +@@ -316,7 +316,7 @@ slapd_start() + elif [ -f "$config" ]; then + options="$options -f $config" + else +- ocf_log err "slapd configuration '$config' does not exist." ++ ocf_exit_reason "slapd configuration '$config' does not exist." + return $OCF_ERR_INSTALLED + fi + +@@ -331,7 +331,7 @@ slapd_start() + fi + + if [ $rc -ne 0 ]; then +- ocf_log err "slapd returned error." ++ ocf_exit_reason "slapd returned error." + + return $OCF_ERR_GENERIC + fi +@@ -366,7 +366,7 @@ slapd_stop() + + terminate $pid TERM $OCF_RESKEY_stop_escalate; rc=$? + if [ $rc -ne 0 ]; then +- ocf_log err "slapd failed to stop. Escalating to KILL." ++ ocf_exit_reason "slapd failed to stop. Escalating to KILL." + terminate $pid KILL; rc=$? + fi + +@@ -391,12 +391,12 @@ slapd_monitor() + if [ $state -eq $OCF_NOT_RUNNING ]; then + if [ -z "$1" ];then + if ! ocf_is_probe; then +- ocf_log err "slapd process not found." ++ ocf_exit_reason "slapd process not found." + fi + fi + return $state + elif [ $state -ne $OCF_SUCCESS ]; then +- ocf_log err "slapd returned error." ++ ocf_exit_reason "slapd returned error." + return $state + fi + +@@ -427,7 +427,7 @@ slapd_monitor() + if ocf_is_probe; then + ocf_log info "slapd configuration '$config' does not exist during probe." + else +- ocf_log err "slapd configuration '$config' does not exist." ++ ocf_exit_reason "slapd configuration '$config' does not exist." + return $OCF_ERR_INSTALLED + fi + fi +@@ -447,12 +447,12 @@ slapd_monitor() + ocf_log debug "slapd database with suffix '$suffix' reachable" + ;; + "49") +- ocf_log err "slapd database with suffix '$suffix' unreachable. Invalid credentials." ++ ocf_exit_reason "slapd database with suffix '$suffix' unreachable. Invalid credentials." + return $OCF_ERR_CONFIGURED + ;; + *) + if [ -z "$1" ] || [ -n "$1" -a $rc -ne 1 ]; then +- ocf_log err "slapd database with suffix '$suffix' unreachable. exit code ($rc)" ++ ocf_exit_reason "slapd database with suffix '$suffix' unreachable. exit code ($rc)" + fi + state=$OCF_ERR_GENERIC + ;; +@@ -480,7 +480,7 @@ slapd_validate_all() + if ocf_is_probe; then + ocf_log info "slapd configuration '$config' does not exist during probe." + else +- ocf_log err "slapd configuration '$config' does not exist." ++ ocf_exit_reason "slapd configuration '$config' does not exist." + return $OCF_ERR_INSTALLED + fi + fi +@@ -489,14 +489,14 @@ slapd_validate_all() + if [ -z "$user" ]; then + user=`id -nu 2>/dev/null` + elif ! id "$user" >/dev/null 2>&1; then +- ocf_log err "slapd user '$user' does not exist" ++ ocf_exit_reason "slapd user '$user' does not exist" + return $OCF_ERR_INSTALLED + fi + + if [ -z "$group" ]; then + group=`id -ng 2>/dev/null` + elif ! grep "^$group:" /etc/group >/dev/null 2>&1; then +- ocf_log err "slapd group '$group' does not exist" ++ ocf_exit_reason "slapd group '$group' does not exist" + return $OCF_ERR_INSTALLED + fi + +diff --git a/heartbeat/symlink b/heartbeat/symlink +index 214092d..1e36a9c 100755 +--- a/heartbeat/symlink ++++ b/heartbeat/symlink +@@ -117,7 +117,7 @@ symlink_monitor() { + rc=$OCF_NOT_RUNNING + elif [ ! -L "$OCF_RESKEY_link" ]; then + if [ -z "$OCF_RESKEY_backup_suffix" ]; then +- ocf_log err "$OCF_RESKEY_link exists but is not a symbolic link!" ++ ocf_exit_reason "$OCF_RESKEY_link exists but is not a symbolic link!" + exit $OCF_ERR_INSTALLED + else + ocf_log debug "$OCF_RESKEY_link exists but is not a symbolic link, will be moved to ${OCF_RESKEY_link}${OCF_RESKEY_backup_suffix} on start" +@@ -128,7 +128,7 @@ symlink_monitor() { + rc=$OCF_SUCCESS + else + if [ -z "$OCF_RESKEY_backup_suffix" ]; then +- ocf_log err "$OCF_RESKEY_link does not point to ${OCF_RESKEY_target}!" ++ ocf_exit_reason "$OCF_RESKEY_link does not point to ${OCF_RESKEY_target}!" + exit $OCF_ERR_INSTALLED + else + ocf_log debug "$OCF_RESKEY_link does not point to ${OCF_RESKEY_target}, will be moved to ${OCF_RESKEY_link}${OCF_RESKEY_backup_suffix} on start" +@@ -146,7 +146,7 @@ symlink_start() { + # have errored out. But there is a chance that + # something else put that file there after + # symlink_monitor ran. +- ocf_log err "$OCF_RESKEY_link exists and no backup_suffix is set, won't overwrite." ++ ocf_exit_reason "$OCF_RESKEY_link exists and no backup_suffix is set, won't overwrite." + exit $OCF_ERR_GENERIC + else + ocf_log debug "Found $OCF_RESKEY_link, moving to ${OCF_RESKEY_link}${OCF_RESKEY_backup_suffix}" +@@ -174,7 +174,7 @@ symlink_stop() { + fi + return $OCF_SUCCESS + else +- ocf_log err "Removing $OCF_RESKEY_link failed." ++ ocf_exit_reason "Removing $OCF_RESKEY_link failed." + return $OCF_ERR_GENERIC + fi + else +@@ -184,11 +184,11 @@ symlink_stop() { + + symlink_validate_all() { + if [ "x${OCF_RESKEY_link}" = "x" ]; then +- ocf_log err "Mandatory parameter link is unset" ++ ocf_exit_reason "Mandatory parameter link is unset" + exit $OCF_ERR_CONFIGURED + fi + if [ "x${OCF_RESKEY_target}" = "x" ]; then +- ocf_log err "Mandatory parameter target is unset" ++ ocf_exit_reason "Mandatory parameter target is unset" + exit $OCF_ERR_CONFIGURED + fi + +diff --git a/heartbeat/tomcat b/heartbeat/tomcat +index 23a7e2f..7b67786 100755 +--- a/heartbeat/tomcat ++++ b/heartbeat/tomcat +@@ -157,7 +157,7 @@ rotate_catalina_out() + su - -s /bin/sh $RESOURCE_TOMCAT_USER \ + -c "touch \"$CATALINA_BASE/logs/catalina_$CURRENT_ROTATELOG_SUFFIX.log\"" > /dev/null 2>&1 + if [ $? -ne 0 ]; then +- ocf_log err "$CATALINA_BASE/logs/catalina_$CURRENT_ROTATELOG_SUFFIX.log is not writable." ++ ocf_exit_reason "$CATALINA_BASE/logs/catalina_$CURRENT_ROTATELOG_SUFFIX.log is not writable." + return $OCF_ERR_GENERIC + fi + +@@ -235,7 +235,7 @@ start_tomcat() + if [ $? -eq 0 ]; then + ocf_log debug "Rotate catalina.out succeeded." + else +- ocf_log err "Rotate catalina.out failed. Avoid starting tomcat without catalina.out rotation." ++ ocf_exit_reason "Rotate catalina.out failed. Avoid starting tomcat without catalina.out rotation." + return $OCF_ERR_GENERIC + fi + fi +@@ -534,12 +534,12 @@ validate_all_tomcat() + check_binary $WGET + + if [ -z "${TOMCAT_START_SCRIPT}" ]; then +- ocf_log err "No default tomcat start script detected. Please specify start script location using the 'tomcat_start_script' option" ++ ocf_exit_reason "No default tomcat start script detected. Please specify start script location using the 'tomcat_start_script' option" + rc=$OCF_ERR_CONFIGURED + fi + + if [ -n "$MAX_STOP_TIME" ] && [ "$MAX_STOP_TIME" -lt 0 ]; then +- ocf_log err "max_stop_time must be set to a value greater than 0." ++ ocf_exit_reason "max_stop_time must be set to a value greater than 0." + rc=$OCF_ERR_CONFIGURED + fi + +@@ -550,14 +550,14 @@ validate_all_tomcat() + ocf_log debug "grep port=\"$port\" $CATALINA_BASE/conf/server.xml" + grep "port=\"$port\"" $CATALINA_BASE/conf/server.xml > /dev/null 2>&1 + if [ $? -ne 0 ]; then +- ocf_log err "Your configured status URL specifies a port ($port), but the server does not have a connector listening to that port in $CATALINA_BASE/conf/server.xml" ++ ocf_exit_reason "Your configured status URL specifies a port ($port), but the server does not have a connector listening to that port in $CATALINA_BASE/conf/server.xml" + rc=$OCF_ERR_INSTALLED + fi + fi + + if ocf_is_true ${CATALINA_ROTATE_LOG}; then + if [ ! -x "$ROTATELOGS" ]; then +- ocf_log err "rotatelogs command does not exist." ++ ocf_exit_reason "rotatelogs command does not exist." + rc=$OCF_ERR_INSTALLED + fi + fi +@@ -635,7 +635,7 @@ if [ ! -d "$JAVA_HOME" -o ! -d "$CATALINA_HOME" -o ! -d "$CATALINA_BASE" ]; then + monitor) exit $OCF_NOT_RUNNING;; + status) exit $LSB_STATUS_STOPPED;; + esac +- ocf_log err "JAVA_HOME or CATALINA_HOME or CATALINA_BASE does not exist." ++ ocf_exit_reason "JAVA_HOME or CATALINA_HOME or CATALINA_BASE does not exist." + exit $OCF_ERR_INSTALLED + fi + +@@ -649,7 +649,7 @@ if [ ! -x "$JAVA" ]; then + monitor) exit $OCF_NOT_RUNNING;; + status) exit $LSB_STATUS_STOPPED;; + esac +- ocf_log err "java command does not exist." ++ ocf_exit_reason "java command does not exist." + exit $OCF_ERR_INSTALLED + fi + +-- +1.8.4.2 + diff --git a/SOURCES/bz1128933-exportfs-exit-reason-support.patch b/SOURCES/bz1128933-exportfs-exit-reason-support.patch new file mode 100644 index 00000000..95d298b3 --- /dev/null +++ b/SOURCES/bz1128933-exportfs-exit-reason-support.patch @@ -0,0 +1,43 @@ +From e334f036ab02ec6cdf4cf463e26d4f32e592f15c Mon Sep 17 00:00:00 2001 +From: David Vossel +Date: Fri, 15 Aug 2014 11:03:36 -0500 +Subject: [PATCH] High: exportfs: support exit reason string + +--- + heartbeat/exportfs | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/heartbeat/exportfs b/heartbeat/exportfs +index 471da24..3f91037 100755 +--- a/heartbeat/exportfs ++++ b/heartbeat/exportfs +@@ -239,7 +239,7 @@ exportfs_monitor () + ocf_log info "Directory ${OCF_RESKEY_directory} is not exported to ${OCF_RESKEY_clientspec} (stopped)." + return $OCF_NOT_RUNNING;; + *) +- ocf_log err "Unable to determine export status for ${OCF_RESKEY_directory}." ++ ocf_exit_reason "Unable to determine export status for ${OCF_RESKEY_directory}." + return $OCF_ERR_GENERIC;; + esac + } +@@ -340,7 +340,7 @@ exportfs_stop () + ocf_log info "Un-exported file system" + return $OCF_SUCCESS + else +- ocf_log err "Failed to un-export file system" ++ ocf_exit_reason "Failed to un-export file system" + exit $OCF_ERR_GENERIC + fi + } +@@ -348,7 +348,7 @@ exportfs_stop () + exportfs_validate_all () + { + if [ ! -d $OCF_RESKEY_directory ]; then +- ocf_log err "$OCF_RESKEY_directory does not exist or is not a directory" ++ ocf_exit_reason "$OCF_RESKEY_directory does not exist or is not a directory" + return $OCF_ERR_INSTALLED + fi + } +-- +1.8.4.2 + diff --git a/SOURCES/bz1128933-introducing-exit-reason-support.patch b/SOURCES/bz1128933-introducing-exit-reason-support.patch new file mode 100644 index 00000000..ad2e6cba --- /dev/null +++ b/SOURCES/bz1128933-introducing-exit-reason-support.patch @@ -0,0 +1,98 @@ +From 0dfe07cbd9e74e0f7f3c85a42085972bf24e1d24 Mon Sep 17 00:00:00 2001 +From: David Vossel +Date: Fri, 15 Aug 2014 10:50:06 -0500 +Subject: [PATCH] Introducing exit reason string support + +--- + heartbeat/ocf-shellfuncs.in | 48 ++++++++++++++++++++++++++++++++++++++++++++- + 1 file changed, 47 insertions(+), 1 deletion(-) + +diff --git a/heartbeat/ocf-shellfuncs.in b/heartbeat/ocf-shellfuncs.in +index 254da57..ff7c32d 100644 +--- a/heartbeat/ocf-shellfuncs.in ++++ b/heartbeat/ocf-shellfuncs.in +@@ -43,6 +43,14 @@ unset LANGUAGE; export LANGUAGE + + __SCRIPT_NAME=`basename $0` + ++# This is internal to shellfuncs. ++# When set, ha_log can be used in a way that guarantees ++# that stderr will not be printed to. This allows us to ++# use ocf_exit_reason to print a string to stderr and use ++# ha_log to print the same string to the other log facilities ++# without having duplicate messages sent to stderr. ++__ha_log_ignore_stderr_once="" ++ + if [ -z "$OCF_ROOT" ]; then + : ${OCF_ROOT=@OCF_ROOT_DIR@} + fi +@@ -182,12 +190,20 @@ set_logtag() { + } + + ha_log() { ++ local ignore_stderr="$__ha_log_ignore_stderr_once" + local loglevel ++ ++ # always reset this variable ++ __ha_log_ignore_stderr_once="" ++ + [ none = "$HA_LOGFACILITY" ] && HA_LOGFACILITY="" + # if we're connected to a tty, then output to stderr + if tty >/dev/null; then + if [ "x$HA_debug" = "x0" -a "x$loglevel" = xdebug ] ; then + return 0 ++ elif [ "$ignore_stderr" = "true" ]; then ++ # something already printed this error to stderr, so ignore ++ return 0 + fi + if [ "$HA_LOGTAG" ]; then + echo "$HA_LOGTAG: $*" +@@ -226,7 +242,7 @@ ha_log() { + echo "$HA_LOGTAG: "`hadate`"${*}" >> $HA_LOGFILE + fi + if +- [ -z "$HA_LOGFACILITY" -a -z "$HA_LOGFILE" ] ++ [ -z "$HA_LOGFACILITY" -a -z "$HA_LOGFILE" ] && ! [ "$ignore_stderr" = "true" ] + then + : appending to stderr + echo `hadate`"${*}" >&2 +@@ -331,6 +347,36 @@ ocf_log() { + } + + # ++# ocf_exit_reason: print exit error string to stderr ++# Usage: Allows the OCF script to provide a string ++# describing why the exit code was returned. ++# Arguments: reason - required, The string that represents why the error ++# occured. ++# ++ocf_exit_reason() ++{ ++ local cookie="$OCF_EXIT_REASON_PREFIX" ++ local fmt=$1 ++ local msg ++ ++ if [ $# -lt 1 ]; then ++ ocf_log err "Not enough arguments [$#] to ocf_log_exit_msg." ++ fi ++ if [ -z "$cookie" ]; then ++ # use a default prefix ++ cookie="ocf-exit-reason:" ++ fi ++ ++ shift ++ ++ msg=$(printf "${fmt}" "$@") ++ ++ printf >&2 "%s${msg}\n" "$cookie" ++ __ha_log_ignore_stderr_once="true" ++ ha_log "ERROR: $msg" ++} ++ ++# + # ocf_deprecated: Log a deprecation warning + # Usage: ocf_deprecated [param-name] + # Arguments: param-name optional, name of a boolean resource +-- +1.8.4.2 + diff --git a/SOURCES/bz1128933-nfsnotify-exit-reason-support.patch b/SOURCES/bz1128933-nfsnotify-exit-reason-support.patch new file mode 100644 index 00000000..2696b3a5 --- /dev/null +++ b/SOURCES/bz1128933-nfsnotify-exit-reason-support.patch @@ -0,0 +1,52 @@ +From 566544cb98bc4e373ac75fa8c6281ef031a673ca Mon Sep 17 00:00:00 2001 +From: David Vossel +Date: Fri, 1 Aug 2014 13:13:39 -0400 +Subject: [PATCH] High: nfsnotify: set exit reason strings in nfsnotify agent + +--- + heartbeat/nfsnotify | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/heartbeat/nfsnotify b/heartbeat/nfsnotify +index 2d0bbfc..5f72d58 100755 +--- a/heartbeat/nfsnotify ++++ b/heartbeat/nfsnotify +@@ -152,7 +152,7 @@ check_statd_pidfile() + return $OCF_SUCCESS + fi + +- ocf_log err "$(cat $pidfile) for $binary is no longer running, sm-notify needs to re-notify clients" ++ ocf_exit_reason "$(cat $pidfile) for $binary is no longer running, sm-notify needs to re-notify clients" + return $OCF_ERR_GENERIC + fi + +@@ -179,7 +179,7 @@ write_statd_pid() + return $OCF_NOT_RUNNING;; + *) + rm -f "$pidfile" > /dev/null 2>&1 +- ocf_log err "Error encountered detecting pid status of $binary" ++ ocf_exit_reason "Error encountered detecting pid status of $binary" + return $OCF_ERR_GENERIC;; + esac + } +@@ -243,7 +243,7 @@ v3notify_start() + ocf_log info "sending notifications on default source address." + $SM_NOTIFY_BINARY -f $OCF_RESKEY_notify_args -P $cur_statd + if [ $? -ne 0 ]; then +- ocf_log err "sm-notify failed, view syslog for more information." ++ ocf_exit_reason "sm-notify execution failed, view syslog for more information" + return $OCF_ERR_GENERIC + fi + +@@ -269,7 +269,7 @@ v3notify_start() + ocf_log info "sending notifications with source address $ip" + $SM_NOTIFY_BINARY -f $OCF_RESKEY_notify_args -v $ip -P "$cur_statd" + if [ $? -ne 0 ]; then +- ocf_log err "sm-notify with source host set to, $ip, failed. view syslog for more information" ++ ocf_exit_reason "sm-notify with source host set to [ $ip ] failed. view syslog for more information" + return $OCF_ERR_GENERIC + fi + done +-- +1.8.4.2 + diff --git a/SOURCES/bz1128933-nfssserver-exit-reason-support.patch b/SOURCES/bz1128933-nfssserver-exit-reason-support.patch new file mode 100644 index 00000000..b1b643b4 --- /dev/null +++ b/SOURCES/bz1128933-nfssserver-exit-reason-support.patch @@ -0,0 +1,97 @@ +From dab933121dfff2b4e9c141c141a196ddc40e9d56 Mon Sep 17 00:00:00 2001 +From: David Vossel +Date: Fri, 1 Aug 2014 13:21:11 -0400 +Subject: [PATCH] High: nfsserver: support exit string in nfsserver agent + +--- + heartbeat/nfsserver | 20 ++++++++++---------- + 1 file changed, 10 insertions(+), 10 deletions(-) + +diff --git a/heartbeat/nfsserver b/heartbeat/nfsserver +index ac921f3..de1a802 100755 +--- a/heartbeat/nfsserver ++++ b/heartbeat/nfsserver +@@ -317,7 +317,7 @@ set_exec_mode() + fi + fi + +- ocf_log err "No init script or systemd unit file detected for nfs server" ++ ocf_exit_reason "No init script or systemd unit file detected for nfs server" + exit $OCF_ERR_INSTALLED + } + +@@ -366,7 +366,7 @@ nfsserver_monitor () + v3locking_exec "status" + rc=$? + if [ $rc -ne 0 ]; then +- ocf_log error "NFS server is up, but the locking daemons are down" ++ ocf_exit_reason "NFS server is up, but the locking daemons are down" + rc=$OCF_ERR_GENERIC + fi + return $rc +@@ -682,7 +682,7 @@ nfsserver_start () + v3locking_exec "start" + rc=$? + if [ $rc -ne 0 ]; then +- ocf_log error "Failed to start NFS server locking daemons" ++ ocf_exit_reason "Failed to start NFS server locking daemons" + return $rc + fi + else +@@ -696,7 +696,7 @@ nfsserver_start () + rm -f $fn + + if [ $rc -ne 0 ]; then +- ocf_log err "Failed to start NFS server" ++ ocf_exit_reason "Failed to start NFS server" + return $rc + fi + +@@ -723,16 +723,16 @@ nfsserver_stop () + + v3locking_exec "stop" + if [ $? -ne 0 ]; then +- ocf_log err "Failed to stop NFS locking daemons" ++ ocf_exit_reason "Failed to stop NFS locking daemons" + rc=$OCF_ERR_GENERIC + fi + + if [ $rc -eq 0 ]; then + unbind_tree + ocf_log info "NFS server stopped" +- return $OCF_SUCCESS ++ else ++ ocf_exit_reason "Failed to stop NFS server" + fi +- ocf_log err "Failed to stop NFS server" + return $rc + } + +@@ -746,13 +746,13 @@ nfsserver_validate () + + + if [ -n "$OCF_RESKEY_CRM_meta_clone" ] && [ -n "$OCF_RESKEY_nfs_shared_infodir" ]; then +- ocf_log err "This RA does not support clone mode when a shared info directory is in use." ++ ocf_exit_reason "This RA does not support clone mode when a shared info directory is in use." + exit $OCF_ERR_CONFIGURED + fi + + if [ -n "$OCF_RESKEY_nfs_smnotify_retry_time" ]; then + if ! ocf_is_decimal "$OCF_RESKEY_nfs_smnotify_retry_time"; then +- ocf_log err "Invalid nfs_smnotify_retry_time [$OCF_RESKEY_nfs_smnotify_retry_time]" ++ ocf_exit_reason "Invalid nfs_smnotify_retry_time [$OCF_RESKEY_nfs_smnotify_retry_time]" + exit $OCF_ERR_CONFIGURED + fi + fi +@@ -760,7 +760,7 @@ nfsserver_validate () + case ${OCF_RESKEY_nfs_notify_cmd##*/} in + sm-notify|rpc.statd) ;; + *) +- ocf_log err "Invalid nfs_notify_cmd [$OCF_RESKEY_nfs_notify_cmd]" ++ ocf_exit_reason "Invalid nfs_notify_cmd [$OCF_RESKEY_nfs_notify_cmd]" + exit $OCF_ERR_CONFIGURED + ;; + esac +-- +1.8.4.2 + diff --git a/SOURCES/bz1135026-docker-handle-invalid-monitor-cmd.patch b/SOURCES/bz1135026-docker-handle-invalid-monitor-cmd.patch new file mode 100644 index 00000000..c9e82933 --- /dev/null +++ b/SOURCES/bz1135026-docker-handle-invalid-monitor-cmd.patch @@ -0,0 +1,69 @@ +From c25542d8808640fae7fad39e27e95e83ffde2e31 Mon Sep 17 00:00:00 2001 +From: David Vossel +Date: Mon, 27 Oct 2014 18:22:27 -0400 +Subject: [PATCH] Low: docker: indicate when monitor_cmd is not available after + startup + +--- + heartbeat/docker | 29 ++++++++++++++++++++++------- + 1 file changed, 22 insertions(+), 7 deletions(-) + +diff --git a/heartbeat/docker b/heartbeat/docker +index 929b26b..a0dcee4 100755 +--- a/heartbeat/docker ++++ b/heartbeat/docker +@@ -168,15 +168,28 @@ END + monitor_cmd_exec() + { + local rc=$OCF_SUCCESS +- if [ -n "$OCF_RESKEY_monitor_cmd" ]; then +- out=$(echo "$OCF_RESKEY_monitor_cmd" | nsenter --target $(docker inspect --format {{.State.Pid}} ${CONTAINER}) --mount --uts --ipc --net --pid 2>&1) +- rc=$? +- if [ $rc -ne 0 ]; then +- ocf_log info "monitor cmd failed with exit code $rc" +- ocf_log info "stdout/stderr: $out" +- rc=$OCF_ERR_GENERIC ++ local out ++ ++ if [ -z "$OCF_RESKEY_monitor_cmd" ]; then ++ return $rc ++ fi ++ ++ out=$(echo "$OCF_RESKEY_monitor_cmd" | nsenter --target $(docker inspect --format {{.State.Pid}} ${CONTAINER}) --mount --uts --ipc --net --pid 2>&1) ++ rc=$? ++ if [ $rc -ne 0 ]; then ++ ocf_log info "monitor cmd exit code = $rc" ++ ocf_log info "stdout/stderr: $out" ++ ++ if [ $rc -eq 127 ]; then ++ ocf_exit_reason "monitor_cmd, ${OCF_RESKEY_monitor_cmd} , not found within container." ++ # there is no recovering from this, exit immediately ++ exit $OCF_ERR_ARGS + fi ++ rc=$OCF_ERR_GENERIC ++ else ++ ocf_log info "monitor cmd passed: exit code = $rc" + fi ++ + return $rc + } + +@@ -288,6 +301,7 @@ docker_start() + + monitor_cmd_exec + if [ $? -eq $OCF_SUCCESS ]; then ++ ocf_log notice "Container $CONTAINER started successfully" + return $OCF_SUCCESS + fi + +@@ -365,6 +379,7 @@ docker_validate() + fi + + if [ -n "$OCF_RESKEY_monitor_cmd" ]; then ++ ocf_log info "checking for nsenter, which is required when 'monitor_cmd' is specified" + check_binary nsenter + fi + +-- +1.8.4.2 + diff --git a/SOURCES/bz1135026-docker-monitor_cmd-arg.patch b/SOURCES/bz1135026-docker-monitor_cmd-arg.patch new file mode 100644 index 00000000..6a692c25 --- /dev/null +++ b/SOURCES/bz1135026-docker-monitor_cmd-arg.patch @@ -0,0 +1,145 @@ +From 804b68824372f98e23b858f6284160c1f2b0e19f Mon Sep 17 00:00:00 2001 +From: David Vossel +Date: Sat, 25 Oct 2014 20:54:14 -0400 +Subject: [PATCH 2/2] High: docker: monitor_cmd option for executing status + script within container + +--- + heartbeat/docker | 76 +++++++++++++++++++++++++++++++++++++++++++++++++------- + 1 file changed, 67 insertions(+), 9 deletions(-) + +diff --git a/heartbeat/docker b/heartbeat/docker +index cdf4e82..929b26b 100755 +--- a/heartbeat/docker ++++ b/heartbeat/docker +@@ -106,6 +106,20 @@ it has initialized. + + + ++ ++ ++Specifiy the full path of a command to launch within the container to check ++the health of the container. This command must return 0 to indicate that ++the container is healthy. A non-zero return code will indicate that the ++container has failed and should be recovered. ++ ++The command is executed using nsenter. In the future 'docker exec' will ++be used once it is more widely supported. ++ ++monitor command ++ ++ ++ + + + Kill a container immediately rather than waiting for it to gracefully +@@ -150,6 +164,22 @@ Expects to have a fully populated OCF RA-compliant environment set. + END + } + ++ ++monitor_cmd_exec() ++{ ++ local rc=$OCF_SUCCESS ++ if [ -n "$OCF_RESKEY_monitor_cmd" ]; then ++ out=$(echo "$OCF_RESKEY_monitor_cmd" | nsenter --target $(docker inspect --format {{.State.Pid}} ${CONTAINER}) --mount --uts --ipc --net --pid 2>&1) ++ rc=$? ++ if [ $rc -ne 0 ]; then ++ ocf_log info "monitor cmd failed with exit code $rc" ++ ocf_log info "stdout/stderr: $out" ++ rc=$OCF_ERR_GENERIC ++ fi ++ fi ++ return $rc ++} ++ + container_exists() + { + docker inspect $CONTAINER > /dev/null 2>&1 +@@ -171,7 +201,7 @@ remove_container() + ocf_run docker rm $CONTAINER + } + +-docker_monitor() ++docker_simple_status() + { + local val + +@@ -195,11 +225,25 @@ docker_monitor() + return $OCF_NOT_RUNNING + } + ++docker_monitor() ++{ ++ local rc=0 ++ ++ docker_simple_status ++ rc=$? ++ ++ if [ $rc -ne 0 ]; then ++ return $rc ++ fi ++ ++ monitor_cmd_exec ++} ++ + docker_start() + { + local run_opts="-d --name=${CONTAINER}" + # check to see if the container has already started +- docker_monitor ++ docker_simple_status + if [ $? -eq $OCF_SUCCESS ]; then + return $OCF_SUCCESS + fi +@@ -233,19 +277,29 @@ docker_start() + return $OCF_ERR_GENERIC + fi + +- docker_monitor +- if [ $? -ne $OCF_SUCCESS ]; then +- ocf_exit_reason "Newly created docker container exited after start" +- return $OCF_ERR_GENERIC +- fi + +- return $OCF_SUCCESS ++ # wait for monitor to pass before declaring that the container is started ++ while true; do ++ docker_simple_status ++ if [ $? -ne $OCF_SUCCESS ]; then ++ ocf_exit_reason "Newly created docker container exited after start" ++ return $OCF_ERR_GENERIC ++ fi ++ ++ monitor_cmd_exec ++ if [ $? -eq $OCF_SUCCESS ]; then ++ return $OCF_SUCCESS ++ fi ++ ++ ocf_exit_reason "waiting on monitor_cmd to pass after start" ++ sleep 1 ++ done + } + + docker_stop() + { + local timeout=60 +- docker_monitor ++ docker_simple_status + if [ $? -eq $OCF_NOT_RUNNING ]; then + remove_container + return $OCF_SUCCESS +@@ -310,6 +364,10 @@ docker_validate() + exit $OCF_ERR_CONFIGURED + fi + ++ if [ -n "$OCF_RESKEY_monitor_cmd" ]; then ++ check_binary nsenter ++ fi ++ + image_exists + if [ $? -ne 0 ]; then + ocf_exit_reason "base image, ${OCF_RESKEY_image}, could not be found." +-- +1.8.4.2 + diff --git a/SOURCES/bz1135026-docker-name-arg.patch b/SOURCES/bz1135026-docker-name-arg.patch new file mode 100644 index 00000000..34074142 --- /dev/null +++ b/SOURCES/bz1135026-docker-name-arg.patch @@ -0,0 +1,61 @@ +From 0f1b107a50dd2ba51277f6962dd0c28dfb8976fc Mon Sep 17 00:00:00 2001 +From: David Vossel +Date: Sat, 25 Oct 2014 20:23:55 -0400 +Subject: [PATCH 1/2] High: docker: replace 'container' argument with 'name' + +I realized that the 'container' argument means something special in +pacemaker. In order to avoid confusion, the 'container' argument for +this agent has been changed to 'name'. Anyone using 'container' as +an argument right now will not be affected. The option still works, it +is depreciated now though. +--- + heartbeat/docker | 19 ++++++++++++++++--- + 1 file changed, 16 insertions(+), 3 deletions(-) + +diff --git a/heartbeat/docker b/heartbeat/docker +index 37a449b..cdf4e82 100755 +--- a/heartbeat/docker ++++ b/heartbeat/docker +@@ -59,7 +59,7 @@ The docker image to base this container off of. + + + +- ++ + + The name to give the created container. By default this will + be that resource's instance name. +@@ -87,6 +87,11 @@ users to do things such as setting a custom entry point and injecting + environment variables into the newly created container. Note the '-d' + option is supplied regardless of this value to force containers to run + in the background. ++ ++NOTE: Do not explicitly specify the --name argument in the run_opts. This ++agent will set --name using either the resource's instance or the name ++provided in the 'name' argument of this agent. ++ + + run options + +@@ -314,8 +319,16 @@ docker_validate() + return $OCF_SUCCESS + } + +-: ${OCF_RESKEY_container=${OCF_RESOURCE_INSTANCE}} +-CONTAINER=$OCF_RESKEY_container ++: ${OCF_RESKEY_name=${OCF_RESOURCE_INSTANCE}} ++ ++if [ -n "$OCF_RESKEY_container" ]; then ++ # we'll keep the container attribute around for a bit in order not to break ++ # any existing deployments. The 'name' attribute is prefered now though. ++ CONTAINER=$OCF_RESKEY_container ++ ocf_log warn "The 'container' attribute is depreciated" ++else ++ CONTAINER=$OCF_RESKEY_name ++fi + + case $__OCF_ACTION in + meta-data) meta_data +-- +1.8.4.2 + diff --git a/SOURCES/bz1135026-docker-stop-fix.patch b/SOURCES/bz1135026-docker-stop-fix.patch new file mode 100644 index 00000000..bd4bc8f3 --- /dev/null +++ b/SOURCES/bz1135026-docker-stop-fix.patch @@ -0,0 +1,49 @@ +From 05fb27218f3b8a78bff0b0e668c8d38feeb93dca Mon Sep 17 00:00:00 2001 +From: David Vossel +Date: Thu, 23 Oct 2014 14:20:14 -0400 +Subject: [PATCH] High: docker: properly remove stale container during stop + when 'reuse' is not enabled + +--- + heartbeat/docker | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +diff --git a/heartbeat/docker b/heartbeat/docker +index 546c423..37a449b 100755 +--- a/heartbeat/docker ++++ b/heartbeat/docker +@@ -157,6 +157,11 @@ remove_container() + return 0 + fi + ++ container_exists ++ if [ $? -ne 0 ]; then ++ # don't attempt to remove a container that doesn't exist ++ return 0 ++ fi + ocf_log notice "Cleaning up inactive container, ${CONTAINER}." + ocf_run docker rm $CONTAINER + } +@@ -210,7 +215,10 @@ docker_start() + if ocf_is_true "$OCF_RESKEY_reuse" && container_exists; then + ocf_log info "starting existing container $CONTAINER." + ocf_run docker start $CONTAINER +- else ++ else ++ # make sure any previous container matching our container name is cleaned up first. ++ # we already know at this point it wouldn't be running ++ remove_container + ocf_log info "running container $CONTAINER for the first time" + ocf_run docker run $run_opts $OCF_RESKEY_image $OCF_RESKEY_run_cmd + fi +@@ -234,6 +242,7 @@ docker_stop() + local timeout=60 + docker_monitor + if [ $? -eq $OCF_NOT_RUNNING ]; then ++ remove_container + return $OCF_SUCCESS + fi + +-- +1.8.4.2 + diff --git a/SOURCES/bz1135026-introducing-docker-agent.patch b/SOURCES/bz1135026-introducing-docker-agent.patch new file mode 100644 index 00000000..aa05b7a6 --- /dev/null +++ b/SOURCES/bz1135026-introducing-docker-agent.patch @@ -0,0 +1,375 @@ +From 6d4180b5ed46cda544e008b242f024b2ab143a83 Mon Sep 17 00:00:00 2001 +From: David Vossel +Date: Thu, 23 Oct 2014 09:37:18 -0500 +Subject: [PATCH] introducing docker agent + +--- + doc/man/Makefile.am | 1 + + heartbeat/Makefile.am | 1 + + heartbeat/docker | 330 ++++++++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 332 insertions(+) + create mode 100755 heartbeat/docker + +diff --git a/doc/man/Makefile.am b/doc/man/Makefile.am +index e97c7e9..ee29756 100644 +--- a/doc/man/Makefile.am ++++ b/doc/man/Makefile.am +@@ -98,6 +98,7 @@ man_MANS = ocf_heartbeat_AoEtarget.7 \ + ocf_heartbeat_conntrackd.7 \ + ocf_heartbeat_db2.7 \ + ocf_heartbeat_dhcpd.7 \ ++ ocf_heartbeat_docker.7 \ + ocf_heartbeat_eDir88.7 \ + ocf_heartbeat_ethmonitor.7 \ + ocf_heartbeat_exportfs.7 \ +diff --git a/heartbeat/Makefile.am b/heartbeat/Makefile.am +index aab521f..f763533 100644 +--- a/heartbeat/Makefile.am ++++ b/heartbeat/Makefile.am +@@ -65,6 +65,7 @@ ocf_SCRIPTS = ClusterMon \ + conntrackd \ + db2 \ + dhcpd \ ++ docker \ + Delay \ + eDir88 \ + EvmsSCC \ +diff --git a/heartbeat/docker b/heartbeat/docker +new file mode 100755 +index 0000000..546c423 +--- /dev/null ++++ b/heartbeat/docker +@@ -0,0 +1,330 @@ ++#!/bin/sh ++# ++# The docker HA resource agent creates and launches a docker container ++# based off a supplied docker image. Containers managed by this agent ++# are both created and removed upon the agent's start and stop actions. ++# ++# Copyright (c) 2014 David Vossel ++# All Rights Reserved. ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of version 2 of the GNU General Public License as ++# published by the Free Software Foundation. ++# ++# This program is distributed in the hope that it would be useful, but ++# WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++# ++# Further, this software is distributed without any warranty that it is ++# free of the rightful claim of any third person regarding infringement ++# or the like. Any license provided herein, whether implied or ++# otherwise, applies only to this software file. Patent licenses, if ++# any, provided herein do not apply to combinations of this program with ++# other software, or any other product whatsoever. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write the Free Software Foundation, ++# Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. ++# ++ ++####################################################################### ++# Initialization: ++ ++: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat} ++. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs ++ ++####################################################################### ++ ++meta_data() ++{ ++ cat < ++ ++ ++1.0 ++ ++ ++The docker HA resource agent creates and launches a docker container ++based off a supplied docker image. Containers managed by this agent ++are both created and removed upon the agent's start and stop actions. ++ ++Docker container resource agent. ++ ++ ++ ++ ++The docker image to base this container off of. ++ ++docker image ++ ++ ++ ++ ++ ++The name to give the created container. By default this will ++be that resource's instance name. ++ ++docker container name ++ ++ ++ ++ ++ ++Allow the image to be pulled from the configured docker registry when ++the image does not exist locally. NOTE, this can drastically increase ++the time required to start the container if the image repository is ++pulled over the network. ++ ++Allow pulling non-local images ++ ++ ++ ++ ++ ++Add options to be appended to the 'docker run' command which is used ++when creating the container during the start action. This option allows ++users to do things such as setting a custom entry point and injecting ++environment variables into the newly created container. Note the '-d' ++option is supplied regardless of this value to force containers to run ++in the background. ++ ++run options ++ ++ ++ ++ ++ ++Specifiy a command to launch within the container once ++it has initialized. ++ ++run command ++ ++ ++ ++ ++ ++Kill a container immediately rather than waiting for it to gracefully ++shutdown ++ ++force kill ++ ++ ++ ++ ++ ++Allow the container to be reused after stopping the container. By default ++containers are removed after stop. With the reuse option containers ++will persist after the container stops. ++ ++reuse container ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++END ++} ++ ++####################################################################### ++REQUIRE_IMAGE_PULL=0 ++ ++docker_usage() ++{ ++ cat < /dev/null 2>&1 ++} ++ ++remove_container() ++{ ++ if ocf_is_true "$OCF_RESKEY_reuse"; then ++ # never remove the container if we have reuse enabled. ++ return 0 ++ fi ++ ++ ocf_log notice "Cleaning up inactive container, ${CONTAINER}." ++ ocf_run docker rm $CONTAINER ++} ++ ++docker_monitor() ++{ ++ local val ++ ++ container_exists ++ if [ $? -ne 0 ]; then ++ return $OCF_NOT_RUNNING ++ fi ++ ++ # retrieve the 'Running' attribute for the container ++ val=$(docker inspect --format {{.State.Running}} $CONTAINER 2>/dev/null) ++ if [ $? -ne 0 ]; then ++ #not running as a result of container not being found ++ return $OCF_NOT_RUNNING ++ fi ++ ++ if ocf_is_true "$val"; then ++ # container exists and is running ++ return $OCF_SUCCESS ++ fi ++ ++ return $OCF_NOT_RUNNING ++} ++ ++docker_start() ++{ ++ local run_opts="-d --name=${CONTAINER}" ++ # check to see if the container has already started ++ docker_monitor ++ if [ $? -eq $OCF_SUCCESS ]; then ++ return $OCF_SUCCESS ++ fi ++ ++ if [ -n "$OCF_RESKEY_run_opts" ]; then ++ run_opts="$run_opts $OCF_RESKEY_run_opts" ++ fi ++ ++ if [ $REQUIRE_IMAGE_PULL -eq 1 ]; then ++ ocf_log notice "Beginning pull of image, ${OCF_RESKEY_image}" ++ docker pull "${OCF_RESKEY_image}" ++ if [ $? -ne 0 ]; then ++ ocf_exit_reason "failed to pull image ${OCF_RESKEY_image}" ++ return $OCF_ERR_GENERIC ++ fi ++ fi ++ ++ if ocf_is_true "$OCF_RESKEY_reuse" && container_exists; then ++ ocf_log info "starting existing container $CONTAINER." ++ ocf_run docker start $CONTAINER ++ else ++ ocf_log info "running container $CONTAINER for the first time" ++ ocf_run docker run $run_opts $OCF_RESKEY_image $OCF_RESKEY_run_cmd ++ fi ++ ++ if [ $? -ne 0 ]; then ++ ocf_exit_reason "docker failed to launch container" ++ return $OCF_ERR_GENERIC ++ fi ++ ++ docker_monitor ++ if [ $? -ne $OCF_SUCCESS ]; then ++ ocf_exit_reason "Newly created docker container exited after start" ++ return $OCF_ERR_GENERIC ++ fi ++ ++ return $OCF_SUCCESS ++} ++ ++docker_stop() ++{ ++ local timeout=60 ++ docker_monitor ++ if [ $? -eq $OCF_NOT_RUNNING ]; then ++ return $OCF_SUCCESS ++ fi ++ ++ if [ -n "$OCF_RESKEY_CRM_meta_timeout" ]; then ++ timeout=$((($OCF_RESKEY_CRM_meta_timeout/1000) -10 )) ++ if [ $timeout -lt 10 ]; then ++ timeout=10 ++ fi ++ fi ++ ++ if ocf_is_true "$OCF_RESKEY_force_kill"; then ++ ocf_run docker kill $CONTAINER ++ else ++ ocf_log debug "waiting $timeout second[s] before killing container" ++ ocf_run docker stop -t=$timeout $CONTAINER ++ fi ++ ++ if [ $? -ne 0 ]; then ++ ocf_exit_reason "Failed to stop container, ${CONTAINER}, based on image, ${OCF_RESKEY_image}." ++ return $OCF_ERR_GENERIC ++ fi ++ ++ remove_container ++ if [ $? -ne 0 ]; then ++ ocf_exit_reason "Failed to remove stopped container, ${CONTAINER}, based on image, ${OCF_RESKEY_image}." ++ return $OCF_ERR_GENERIC ++ fi ++ ++ return $OCF_SUCCESS ++} ++ ++image_exists() ++{ ++ local res=1 ++ ++ ++ echo "${OCF_RESKEY_image}" | grep -q ":" ++ if [ $? -eq 0 ]; then ++ docker images | awk '{print $1 ":" $2}' | grep "^${OCF_RESKEY_image}\$" > /dev/null 2>&1 ++ else ++ docker images | awk '{print $1}' | grep "^${OCF_RESKEY_image}\$" > /dev/null 2>&1 ++ fi ++ if [ $? -eq 0 ]; then ++ return 0 ++ fi ++ if ocf_is_true "$OCF_RESKEY_allow_pull"; then ++ REQUIRE_IMAGE_PULL=1 ++ ocf_log notice "Image (${OCF_RESKEY_image}) does not exist locally but will be pulled during start" ++ return 0 ++ fi ++ # image not found. ++ return 1 ++} ++ ++docker_validate() ++{ ++ check_binary docker ++ if [ -z "$OCF_RESKEY_image" ]; then ++ ocf_exit_reason "'image' option is required" ++ exit $OCF_ERR_CONFIGURED ++ fi ++ ++ image_exists ++ if [ $? -ne 0 ]; then ++ ocf_exit_reason "base image, ${OCF_RESKEY_image}, could not be found." ++ exit $OCF_ERR_CONFIGURED ++ fi ++ ++ return $OCF_SUCCESS ++} ++ ++: ${OCF_RESKEY_container=${OCF_RESOURCE_INSTANCE}} ++CONTAINER=$OCF_RESKEY_container ++ ++case $__OCF_ACTION in ++meta-data) meta_data ++ exit $OCF_SUCCESS;; ++start) ++ docker_validate ++ docker_start;; ++stop) docker_stop;; ++monitor) docker_monitor;; ++validate-all) docker_validate;; ++usage|help) docker_usage ++ exit $OCF_SUCCESS ++ ;; ++*) docker_usage ++ exit $OCF_ERR_UNIMPLEMENTED ++ ;; ++esac ++rc=$? ++ocf_log debug "${OCF_RESOURCE_INSTANCE} $__OCF_ACTION : $rc" ++exit $rc ++ +-- +1.8.4.2 + diff --git a/SOURCES/bz1138871-avoid-check-binary-in-validate.patch b/SOURCES/bz1138871-avoid-check-binary-in-validate.patch new file mode 100644 index 00000000..1cc2b620 --- /dev/null +++ b/SOURCES/bz1138871-avoid-check-binary-in-validate.patch @@ -0,0 +1,43 @@ +From 328b228321e71260f9c0ea4b926b43f208aef158 Mon Sep 17 00:00:00 2001 +From: David Vossel +Date: Tue, 7 Oct 2014 16:11:28 -0400 +Subject: [PATCH 2/2] High: mysql-common: avoid use of check_binary in common + validation function. + +Since the environment validation exit code needs to be interpreted +differently now for monitor operations, we need to avoid functions like +'check_binary' that exit the process immediately upon failure. Instead +we should use 'have_binary' in this situation. + +This allows the mysql agent to work properly in a scenario where the entire +mysql install resides on shared storage. +--- + heartbeat/mysql-common.sh | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +diff --git a/heartbeat/mysql-common.sh b/heartbeat/mysql-common.sh +index a02f8cd..310f487 100755 +--- a/heartbeat/mysql-common.sh ++++ b/heartbeat/mysql-common.sh +@@ -94,8 +94,16 @@ CRM_ATTR_REPL_INFO="${HA_SBIN_DIR}/crm_attribute --type crm_config --name ${INST + + mysql_common_validate() + { +- check_binary $OCF_RESKEY_binary +- check_binary $OCF_RESKEY_client_binary ++ ++ if ! have_binary "$OCF_RESKEY_binary"; then ++ ocf_exit_reason "Setup problem: couldn't find command: $OCF_RESKEY_binary" ++ return $OCF_ERR_INSTALLED; ++ fi ++ ++ if ! have_binary "$OCF_RESKEY_client_binary"; then ++ ocf_exit_reason "Setup problem: couldn't find command: $OCF_RESKEY_client_binary" ++ return $OCF_ERR_INSTALLED; ++ fi + + if [ ! -f $OCF_RESKEY_config ]; then + ocf_exit_reason "Config $OCF_RESKEY_config doesn't exist"; +-- +1.8.4.2 + diff --git a/SOURCES/bz1138871-mysql-error-validation-fails-monitor.patch b/SOURCES/bz1138871-mysql-error-validation-fails-monitor.patch new file mode 100644 index 00000000..70901704 --- /dev/null +++ b/SOURCES/bz1138871-mysql-error-validation-fails-monitor.patch @@ -0,0 +1,35 @@ +From 6ac8332d16837a3481341316e61962e6f78694dd Mon Sep 17 00:00:00 2001 +From: David Vossel +Date: Tue, 7 Oct 2014 16:11:19 -0400 +Subject: [PATCH 1/2] High: mysql: report error when validation fails during + monitor yet pid is still active + +--- + heartbeat/mysql | 11 ++++++++++- + 1 file changed, 10 insertions(+), 1 deletion(-) + +diff --git a/heartbeat/mysql b/heartbeat/mysql +index 6cfe0a0..d895369 100755 +--- a/heartbeat/mysql ++++ b/heartbeat/mysql +@@ -1007,7 +1007,16 @@ LSB_STATUS_STOPPED=3 + if [ $rc -ne 0 ]; then + case "$1" in + stop) ;; +- monitor) exit $OCF_NOT_RUNNING;; ++ monitor) ++ mysql_common_status "info" ++ if [ $? -eq $OCF_SUCCESS ]; then ++ # if validatation fails and pid is active, always treat this as an error ++ ocf_exit_reason "environment validation failed, active pid is in unknown state." ++ exit $OCF_ERR_GENERIC ++ fi ++ # validation failed and pid is not active, it's safe to say this instance is inactive. ++ exit $OCF_NOT_RUNNING;; ++ + status) exit $LSB_STATUS_STOPPED;; + *) exit $rc;; + esac +-- +1.8.4.2 + diff --git a/SOURCES/bz1138871_mysql_stop_fix.patch b/SOURCES/bz1138871_mysql_stop_fix.patch new file mode 100644 index 00000000..27878476 --- /dev/null +++ b/SOURCES/bz1138871_mysql_stop_fix.patch @@ -0,0 +1,26 @@ +From 42a016eb56d79f287190f3abe68c2a7e1b3ca50b Mon Sep 17 00:00:00 2001 +From: John Ruemker +Date: Wed, 17 Sep 2014 18:02:03 -0400 +Subject: [PATCH] High: mysql: do not report success on 'stop' if validation + fails + +--- + heartbeat/mysql | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/heartbeat/mysql b/heartbeat/mysql +index dc862f5..6cfe0a0 100755 +--- a/heartbeat/mysql ++++ b/heartbeat/mysql +@@ -1006,7 +1006,7 @@ rc=$? + LSB_STATUS_STOPPED=3 + if [ $rc -ne 0 ]; then + case "$1" in +- stop) exit $OCF_SUCCESS;; ++ stop) ;; + monitor) exit $OCF_NOT_RUNNING;; + status) exit $LSB_STATUS_STOPPED;; + *) exit $rc;; +-- +1.8.4.2 + diff --git a/SOURCES/bz1159328-LVM-check_writethrough.patch b/SOURCES/bz1159328-LVM-check_writethrough.patch new file mode 100644 index 00000000..d059b833 --- /dev/null +++ b/SOURCES/bz1159328-LVM-check_writethrough.patch @@ -0,0 +1,60 @@ +From 8d25da64ab9dee8545a0c52f7db08213a03ea106 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Tue, 28 Feb 2017 15:46:40 +0100 +Subject: [PATCH] LVM: add check_writethrough parameter + +--- + heartbeat/LVM | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) + +diff --git a/heartbeat/LVM b/heartbeat/LVM +index 90a900b..5b265f5 100755 +--- a/heartbeat/LVM ++++ b/heartbeat/LVM +@@ -29,6 +29,8 @@ + : ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat} + . ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs + ++OCF_RESKEY_check_writethrough_default="false" ++ + ####################################################################### + + +@@ -106,6 +108,14 @@ logical volumes. + + + ++ ++ ++If set to true, check if cache_mode is set to writethrough. ++ ++Check if cache_mode is set to writethrough ++ ++ ++ + + + +@@ -583,6 +593,13 @@ LVM_validate_all() { + exit $OCF_ERR_GENERIC + fi + ++ if ocf_is_true "$OCF_RESKEY_check_writethrough"; then ++ if ! lvs --noheadings -o cache_mode "$OCF_RESKEY_volgrpname" | grep -q "writethrough"; then ++ ocf_exit_reason "LVM cache is not in writethrough mode." ++ exit $OCF_ERR_CONFIGURED ++ fi ++ fi ++ + ## + # If exclusive activation is not enabled, then + # further checking of proper setup is not necessary +@@ -690,6 +707,8 @@ if [ -n "$OCF_RESKEY_tag" ]; then + OUR_TAG=$OCF_RESKEY_tag + fi + ++: ${OCF_RESKEY_check_writethrough=${OCF_RESKEY_check_writethrough_default}} ++ + # What kind of method was invoked? + case "$1" in + diff --git a/SOURCES/bz1160365-iface-vlan.patch.patch b/SOURCES/bz1160365-iface-vlan.patch.patch new file mode 100644 index 00000000..f82d06c7 --- /dev/null +++ b/SOURCES/bz1160365-iface-vlan.patch.patch @@ -0,0 +1,520 @@ +From 0305c97abc49d0f7a93b3602a745805f7e8776d3 Mon Sep 17 00:00:00 2001 +From: David Vossel +Date: Thu, 25 Jun 2015 16:23:45 -0500 +Subject: [PATCH 1/3] bz1160365-iface-vlan.patch + +--- + doc/man/Makefile.am | 1 + + heartbeat/Makefile.am | 1 + + heartbeat/iface-vlan | 475 ++++++++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 477 insertions(+) + create mode 100755 heartbeat/iface-vlan + +diff --git a/doc/man/Makefile.am b/doc/man/Makefile.am +index 653e818..091ec24 100644 +--- a/doc/man/Makefile.am ++++ b/doc/man/Makefile.am +@@ -107,6 +107,7 @@ man_MANS = ocf_heartbeat_AoEtarget.7 \ + ocf_heartbeat_iSCSILogicalUnit.7 \ + ocf_heartbeat_iSCSITarget.7 \ + ocf_heartbeat_ids.7 \ ++ ocf_heartbeat_iface-vlan.7 \ + ocf_heartbeat_iscsi.7 \ + ocf_heartbeat_jboss.7 \ + ocf_heartbeat_lxc.7 \ +diff --git a/heartbeat/Makefile.am b/heartbeat/Makefile.am +index e4ed4fd..6df4080 100644 +--- a/heartbeat/Makefile.am ++++ b/heartbeat/Makefile.am +@@ -76,6 +76,7 @@ ocf_SCRIPTS = ClusterMon \ + fio \ + galera \ + ids \ ++ iface-vlan \ + iscsi \ + ICP \ + IPsrcaddr \ +diff --git a/heartbeat/iface-vlan b/heartbeat/iface-vlan +new file mode 100755 +index 0000000..bc8583c +--- /dev/null ++++ b/heartbeat/iface-vlan +@@ -0,0 +1,475 @@ ++#!/bin/sh ++# ++# OCF Resource Agent compliant iface-vlan script. ++# ++# Implements network VLAN interface management ++# ++# Copyright (C) 2013 Red Hat, Inc. All rights reserved. ++# Author: Fabio M. Di Nitto ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of version 2 of the GNU General Public License as ++# published by the Free Software Foundation. ++# ++# This program is distributed in the hope that it would be useful, but ++# WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++# ++# Further, this software is distributed without any warranty that it is ++# free of the rightful claim of any third person regarding infringement ++# or the like. Any license provided herein, whether implied or ++# otherwise, applies only to this software file. Patent licenses, if ++# any, provided herein do not apply to combinations of this program with ++# other software, or any other product whatsoever. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write the Free Software Foundation, ++# Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. ++# ++# ++ ++# TODO: ++# ++# OCF parameters are as below ++# OCF_RESKEY_vlan_interface ++# OCF_RESKEY_vlan_id ++# OCF_RESKEY_vlan_name ++# OCF_RESKEY_vlan_reorder_hdr ++# OCF_RESKEY_vlan_gvrp ++# OCF_RESKEY_vlan_mvrp ++# OCF_RESKEY_vlan_loose_binding ++# ++ ++####################################################################### ++# Initialization: ++ ++: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat} ++. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs ++ ++# Defaults ++OCF_RESKEY_vlan_reorder_hdr_default=1 ++OCF_RESKEY_vlan_gvrp_default=0 ++OCF_RESKEY_vlan_mvrp_default=0 ++OCF_RESKEY_vlan_loose_binding_default=0 ++OCF_RESKEY_vlan_name_default=${OCF_RESKEY_vlan_interface}.${OCF_RESKEY_vlan_id} ++ ++: ${OCF_RESKEY_vlan_name=${OCF_RESKEY_vlan_name_default}} ++: ${OCF_RESKEY_vlan_reorder_hdr=${OCF_RESKEY_vlan_reorder_hdr_default}} ++: ${OCF_RESKEY_vlan_gvrp=${OCF_RESKEY_vlan_gvrp_default}} ++ ++# don't set defaults for mvrp or loose binding since both ++# are rather new kernel features and they might not be supported ++#: ${OCF_RESKEY_vlan_mvrp=${OCF_RESKEY_vlan_mvrp_default}} ++#: ${OCF_RESKEY_vlan_loose_binding=${OCF_RESKEY_vlan_loose_binding_default}} ++ ++####################################################################### ++ ++vlan_usage() { ++ cat < ++ ++ ++ 1.0 ++ ++ ++ This resource manages VLAN network interfaces. ++ It can add, remove, configure VLANs. ++ ++ ++ ++ Manages VLAN network interfaces. ++ ++ ++ ++ ++ ++ Define the interface where VLAN should be attached. ++ ++ ++ Network interface. ++ ++ ++ ++ ++ ++ ++ Define the VLAN ID. It has to be a value between 0 and 4094. ++ ++ ++ Define the VLAN ID. ++ ++ ++ ++ ++ ++ ++ Define the name of the VLAN interface (max 15 charaters). ++ ++ ++ Name of the VLAN. ++ ++ ++ ++ ++ ++ ++ Enable or disable header reordering. ++ ++ ++ Enable or disable header reordering. ++ ++ ++ ++ ++ ++ ++ Enable or disable GARP VLAN registration protocol. ++ ++ ++ Enable or disable gvrp. ++ ++ ++ ++ ++ ++ ++ Enable or disable Multiple VLAN Registration Protocol. ++ Please note that most distributions do not ship a version of iproute2 ++ that supports mvrp yet, even if the kernel has support for it. ++ Check output of $IPADDR2 link add type vlan --help in the FLAG ++ section to verify if mvrp support is available. ++ ++ ++ Enable or disable mvrp. ++ ++ ++ ++ ++ ++ ++ Enable or disable VLAN loose bind. By default the VLAN interface ++ admin status (UP/DOWN) follows the underneath inteface status. ++ Enabling loose bind allows the VLAN to disconnect from the ++ interface status. Be very careful that enabling loose binding ++ could invalidate this agent monitor operations. ++ Please note that most distributions do not ship a version of iproute2 ++ that supports loose_binding yet, even if the kernel has support for it. ++ Check output of $IPADDR2 link add type vlan --help in the FLAG ++ section to verify if loose_binding support is available. ++ ++ ++ Enable or disable loose binding. ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++END ++} ++ ++# check if the interface is admin up/down ++ ++iface_is_up() { ++ if ! $IP2UTIL -o link show $1 | \ ++ sed -e 's#.*<##g' -e 's#>.*##' -e 's#LOWER_UP##g' | \ ++ grep -q UP; then ++ return 1 ++ fi ++ return 0 ++} ++ ++# check if the slaves have link layer up/down ++# see kernel network documentation on meaning of LOWER_UP flag ++# for more in depth explanation on how it works ++# NOTE: this check is not reliable in virt environment ++# since interfaces are always LOWER_UP. There is no way ++# from the guest to know if the host has disconnected somehow ++ ++iface_lower_is_up() { ++ if ! $IP2UTIL -o link show $1 | \ ++ grep -q LOWER_UP; then ++ return 1 ++ fi ++ return 0 ++} ++ ++vlan_validate() { ++ check_binary $IP2UTIL ++ ++ if [ -z "$OCF_RESKEY_vlan_interface" ]; then ++ ocf_log err "Invalid OCF_RESKEY_vlan_interface: value cannot be empty" ++ return 1 ++ fi ++ ++ # the echo .. is the equivalent of strlen in bash ++ # ++ # /usr/include/linux/if.h:#define IFNAMSIZ 16 ++ # needs to include 0 byte end string ++ ++ if [ "${#OCF_RESKEY_vlan_interface}" -gt 15 ]; then ++ ocf_log err "Invalid OCF_RESKEY_vlan_interface: name is too long" ++ return 1 ++ fi ++ ++ if [ ! -d "/sys/class/net" ]; then ++ ocf_log err "Unable to find sysfs network class in /sys" ++ return 1 ++ fi ++ ++ if [ ! -e "/sys/class/net/$OCF_RESKEY_vlan_interface" ]; then ++ ocf_log err "Invalid OCF_RESKEY_vlan_interface: $OCF_RESKEY_vlan_interface does not exists" ++ return 1 ++ fi ++ ++ if [ -z "$OCF_RESKEY_vlan_id" ]; then ++ ocf_log err "Invalid OCF_RESKEY_vlan_id: value cannot be empty" ++ return 1 ++ fi ++ if ! ocf_is_decimal "$OCF_RESKEY_vlan_id" || \ ++ [ "$OCF_RESKEY_vlan_id" -gt "4094" ]; then ++ ocf_log err "Invalid OCF_RESKEY_vlan_id: must be a decimal value (0 to 4094 included)" ++ return 1 ++ fi ++ ++ if [ "${#OCF_RESKEY_vlan_name}" -gt 15 ]; then ++ ocf_log err "Invalid OCF_RESKEY_vlan_name: name is too long" ++ return 1 ++ fi ++ ++ return 0 ++} ++ ++vlan_check() { ++ if [ -e "/sys/class/net/$OCF_RESKEY_vlan_name" ]; then ++ if [ ! -e "$HA_RSCTMP/iface-vlan.$OCF_RESKEY_vlan_name" ]; then ++ return $OCF_ERR_GENERIC ++ fi ++ else ++ if [ -e "$HA_RSCTMP/iface-vlan.$OCF_RESKEY_vlan_name" ]; then ++ error="$(rm -f "$HA_RSCTMP/iface-vlan.$OCF_RESKEY_vlan_name" 2>&1)" ++ if [ "$?" != "0" ]; then ++ ocf_log err "Unable to remove stale lock file for vlan $OCF_RESKEY_vlan_name: $error" ++ return $OCF_ERR_GENERIC ++ fi ++ fi ++ return $OCF_NOT_RUNNING ++ fi ++ ++ if ! iface_is_up $OCF_RESKEY_vlan_interface; then ++ if ocf_is_true "$OCF_RESKEY_vlan_loose_binding"; then ++ ocf_log warn "Interface $OCF_RESKEY_vlan_interface is administratively down" ++ else ++ ocf_log err "Interface $OCF_RESKEY_vlan_interface is administratively down" ++ return $OCF_ERR_GENERIC ++ fi ++ fi ++ ++ if ! iface_is_up $OCF_RESKEY_vlan_name; then ++ ocf_log err "VLAN $OCF_RESKEY_vlan_name is administratively down" ++ return $OCF_ERR_GENERIC ++ fi ++ ++ if ! iface_lower_is_up $OCF_RESKEY_vlan_name; then ++ ocf_log err "VLAN $OCF_RESKEY_vlan_name has no active link-layer" ++ return $OCF_ERR_GENERIC ++ fi ++ ++ return $OCF_SUCCESS ++} ++ ++# we need a simpler stop version to clean after us if start fails ++# without involving any error checking ++# rolling back in case of failure is otherwise complex ++ ++vlan_force_stop() { ++ $IP2UTIL link delete "$OCF_RESKEY_vlan_name" >/dev/null 2>&1 ++ rm -f "$HA_RSCTMP/iface-vlan.$OCF_RESKEY_vlan_name" 2>&1 ++} ++ ++vlan_start() { ++ # check if the vlan already exists ++ vlan_check ++ ret=$? ++ if [ "$ret" != "$OCF_NOT_RUNNING" ]; then ++ return $ret ++ fi ++ ++ # make sure kernel module is loaded ++ if [ ! -e /proc/net/vlan ]; then ++ error="$(modprobe 8021q 2>&1)" ++ if [ "$?" != "0" ]; then ++ ocf_log err "Unable to load kernel 8021q driver: $error" ++ return $OCF_ERR_GENERIC ++ fi ++ fi ++ ++ # generate options ++ VLANOPTS="" ++ ++ if [ -n "$OCF_RESKEY_vlan_reorder_hdr" ]; then ++ if ocf_is_true "$OCF_RESKEY_vlan_reorder_hdr"; then ++ VLANOPTS="reorder_hdr on" ++ else ++ VLANOPTS="reorder_hdr off" ++ fi ++ fi ++ ++ if [ -n "$OCF_RESKEY_vlan_gvrp" ]; then ++ if ocf_is_true "$OCF_RESKEY_vlan_gvrp"; then ++ VLANOPTS="$VLANOPTS gvrp on" ++ else ++ VLANOPTS="$VLANOPTS gvrp off" ++ fi ++ fi ++ ++ if [ -n "$OCF_RESKEY_vlan_mvrp" ]; then ++ if ocf_is_true "$OCF_RESKEY_vlan_mvrp"; then ++ VLANOPTS="$VLANOPTS mvrp on" ++ else ++ VLANOPTS="$VLANOPTS mvrp off" ++ fi ++ fi ++ ++ if [ -n "$OCF_RESKEY_vlan_loose_binding" ]; then ++ if ocf_is_true "$OCF_RESKEY_vlan_loose_binding"; then ++ VLANOPTS="$VLANOPTS loose_binding on" ++ else ++ VLANOPTS="$VLANOPTS loose_binding off" ++ fi ++ fi ++ ++ # create the VLAN ++ error="$($IP2UTIL link add link "$OCF_RESKEY_vlan_interface" name "$OCF_RESKEY_vlan_name" type vlan id "$OCF_RESKEY_vlan_id" $VLANOPTS 2>&1)" ++ if [ "$?" != "0" ]; then ++ ocf_log err "Unable to create VLAN $OCF_RESKEY_vlan_name: $error" ++ return $OCF_ERR_GENERIC ++ fi ++ ++ # set the interface up ++ error="$($IP2UTIL link set dev "$OCF_RESKEY_vlan_interface" up 2>&1)" ++ if [ "$?" != "0" ]; then ++ ocf_log err "Unable to set VLAN $OCF_RESKEY_vlan_interface up: $error" ++ return $OCF_ERR_GENERIC ++ fi ++ ++ # set the vlan up ++ error="$($IP2UTIL link set dev "$OCF_RESKEY_vlan_name" up 2>&1)" ++ if [ "$?" != "0" ]; then ++ ocf_log err "Unable to set VLAN $OCF_RESKEY_vlan_name up: $error" ++ return $OCF_ERR_GENERIC ++ fi ++ ++ error="$(touch "$HA_RSCTMP/iface-vlan.$OCF_RESKEY_vlan_name" 2>&1)" ++ if [ "$?" != "0" ]; then ++ ocf_log err "Unable to create lock file for VLAN $OCF_RESKEY_vlan_name: $error" ++ return $OCF_ERR_GENERIC ++ fi ++ ++ return $OCF_SUCCESS ++} ++ ++vlan_stop() { ++ vlan_check ++ ret=$? ++ if [ "$ret" = "$OCF_NOT_RUNNING" ]; then ++ return $OCF_SUCCESS ++ fi ++ if [ "$ret" != "$OCF_SUCCESS" ]; then ++ return $ret ++ fi ++ ++ # set vlan down ++ error="$($IP2UTIL link set dev "$OCF_RESKEY_vlan_name" down 2>&1)" ++ if [ "$?" != "0" ]; then ++ ocf_log err "Unable to set VLAN $OCF_RESKEY_vlan_name down: $error" ++ return $OCF_ERR_GENERIC ++ fi ++ ++ # delete vlan ++ error="$($IP2UTIL link delete "$OCF_RESKEY_vlan_name" 2>&1)" ++ if [ "$?" != "0" ]; then ++ ocf_log err "Unable to delete VLAN $OCF_RESKEY_vlan_name: $error" ++ return $OCF_ERR_GENERIC ++ fi ++ ++ error="$(rm -f "$HA_RSCTMP/iface-vlan.$OCF_RESKEY_vlan_name" 2>&1)" ++ if [ "$?" != "0" ]; then ++ ocf_log err "Unable to remove lock file for VLAN $OCF_RESKEY_vlan_name: $error" ++ return $OCF_ERR_GENERIC ++ fi ++ ++ return $OCF_SUCCESS ++} ++ ++case $__OCF_ACTION in ++ meta-data) ++ vlan_meta_data ++ exit $OCF_SUCCESS ++ ;; ++ usage|help) ++ vlan_usage ++ exit $OCF_SUCCESS ++ ;; ++esac ++ ++if [ ! -d "$HA_RSCTMP" ]; then ++ ocf_log debug "$HA_RSCTMP not found, we are probably being executed manually" ++ mkdir -p "$HA_RSCTMP" ++fi ++ ++if [ -n "$__OCF_ACTION" ] && ! vlan_validate; then ++ exit $OCF_ERR_CONFIGURED ++fi ++ ++case $__OCF_ACTION in ++ start|stop) ++ if ! ocf_is_root; then ++ ocf_log err "You must be root for $__OCF_ACTION operation." ++ exit $OCF_ERR_PERM ++ fi ++ ;; ++esac ++ ++case $__OCF_ACTION in ++ start) ++ vlan_start ++ ret=$? ++ if [ "$ret" != "$OCF_SUCCESS" ]; then ++ vlan_force_stop ++ fi ++ exit $ret ++ ;; ++ stop) ++ vlan_stop ++ exit $? ++ ;; ++ status|monitor) ++ vlan_check ++ exit $? ++ ;; ++ validate-all) ++ # vlan_validate above does the trick ++ ;; ++ *) ++ vlan_usage ++ exit $OCF_ERR_UNIMPLEMENTED ++ ;; ++esac ++# vi:sw=4:ts=8: +-- +1.8.4.2 + diff --git a/SOURCES/bz1168251-SAPHana-agents-update.patch b/SOURCES/bz1168251-SAPHana-agents-update.patch new file mode 100644 index 00000000..871dbf58 --- /dev/null +++ b/SOURCES/bz1168251-SAPHana-agents-update.patch @@ -0,0 +1,97 @@ +diff --git a/heartbeat/SAPHana b/heartbeat/SAPHana +index f4db17a..412152b 100644 +--- a/heartbeat/SAPHana ++++ b/heartbeat/SAPHana +@@ -137,7 +137,7 @@ function saphana_meta_data() { + Manages two SAP HANA instances in system replication (SR). + + The SAPHanaSR resource agent manages two SAP Hana instances (databases) which are configured +-in system replication. This first version is limitted to the scale-up scenario. Scale-Up is ++in system replication. This first version is limitted to the scale-up scenario. Scale-Out is + not supported in this version. + + Managing the two SAP HANA instances means that the resource agent controls the start/stop of the +@@ -231,7 +231,9 @@ The resource agent uses the following four interfaces provided by SAP: + + Define SAPHana resource agent messages to be printed + Define SAPHana resource agent messages to be printed. +- This parameter should only be set of been requested by SUSE support. The default is sufficient for normal operation. ++ This parameter should only be set if requested by support. The default is sufficient for normal operation. ++ Values: ra-act-lpa-dec-flow ++ You could specify any combination of the above values like "ra-act-flow" + + + +@@ -480,7 +482,7 @@ function get_crm_master() + # globals: sr_name(w), remoteHost(w), otherNodes(w) + # globals: ATTR_NAME_HANA_SYNC_STATUS(w), ATTR_NAME_HANA_CLONE_STATE(w) + # globals: DIR_EXECUTABLE(w), SAPSTARTSRV(w), SAPCONTROL(w), DIR_PROFILE(w), SAPSTARTPROFILE(w), LD_LIBRARY_PATH(w), PATH(w) +-# globals: LPA_DIRECTORY(w), SIDInstanceName(w), remoteNode(w) ++# globals: LPA_DIRECTORY(w), SIDInstanceName(w), remoteNode(w), hdbSrQueryTimeout(w) + # saphana_init : Define global variables with default values, if optional parameters are not set + # + function saphana_init() { +@@ -497,6 +499,8 @@ function saphana_init() { + super_ocf_log debug "DBG: Used new method to get SID ($SID) and InstanceNr ($InstanceNr)" + sid=$(echo "$SID" | tr [:upper:] [:lower:]) + sidadm="${sid}adm" ++ # TODO PRIO3: Do we need a parameter for the RA to be able to adjust hdbSrQueryTimeout? ++ hdbSrQueryTimeout=180 + # DONE: PRIO4: SAPVIRHOST might be different to NODENAME + # DONE: PRIO1: ASK: Is the output format of ListInstances fix? Could we take that as an API? Answer: Yes + # try to catch: Inst Info : LNX - 42 - lv9041 - 740, patch 36, changelist 1444691 +@@ -827,7 +831,7 @@ function analyze_hana_sync_status() + super_ocf_log err "ACT: Secure store users are missing (see best practice manual how to setup the users)" + rc=$OCF_ERR_CONFIGURED + fi +- hana_sync_status=$(timeout 60 $DIR_EXECUTABLE/hdbsql -a -x -U $secUser $query_state); sqlrc=$? ++ hana_sync_status=$(timeout $hdbSrQueryTimeout $DIR_EXECUTABLE/hdbsql -a -x -U $secUser $query_state); sqlrc=$? + hana_sync_status=$(echo $hana_sync_status | dequote) + super_ocf_log debug "DBG: hdbsql rc=$sqlrc hana_sync_status=\"$hana_sync_status\"" + if [ "$sqlrc" -eq 0 -a "$hana_sync_status" != "" ]; then +@@ -846,10 +850,10 @@ function analyze_hana_sync_status() + # TODO: PRIO9: for first we assume there is only ONE secondary site (like ROT) + # TODO: PRIO3: should we loop over all cluster nodes fetching their roles-attribute? To minimize sql-queries? + # +- all_secondary_hosts=$(timeout 60 hdbsql -a -x -U $secUser $query_secondaries ); sqlrc=$? ++ all_secondary_hosts=$(timeout $hdbSrQueryTimeout hdbsql -a -x -U $secUser $query_secondaries ); sqlrc=$? + all_secondary_hosts=$(echo $all_secondary_hosts | dequote); + if [ "$sqlrc" -eq 0 ]; then +- all_broken_secondary_hosts=$(timeout 60 hdbsql -a -x -U $secUser $query_failed_secondaries); sqlrc=$? ++ all_broken_secondary_hosts=$(timeout $hdbSrQueryTimeout hdbsql -a -x -U $secUser $query_failed_secondaries); sqlrc=$? + all_broken_secondary_hosts=$(echo $all_broken_secondary_hosts | dequote); + if [ "$sqlrc" -eq 0 ]; then + if [ -n "$all_broken_secondary_hosts" ]; then +@@ -869,9 +873,9 @@ function analyze_hana_sync_status() + fi + fi + else +- # return codes 19: license error -> set SFAIL! + case "$sqlrc" in + 19 ) ++ # return codes 19: license error -> set SFAIL! + # DONE: PRIO1: We should NOT set SFAIL, if HDB is exactly broken now + # When HDB breaks during monitor this could prevent a prositive remote failover + super_ocf_log warn "ACT: Was not able to fetch HANA SYNC STATUS - set sync status to SFAIL for ALL OTHER cluster hosts" +diff --git a/heartbeat/SAPHanaTopology b/heartbeat/SAPHanaTopology +index 19fbbb4..082ad29 100644 +--- a/heartbeat/SAPHanaTopology ++++ b/heartbeat/SAPHanaTopology +@@ -123,7 +123,7 @@ function sht_meta_data() { + + + +- 0.149.3 ++ 0.149.4 + Analyzes SAP HANA System Replication Topology. + This RA analyzes the SAP HANA topology and "sends" all findings via the node status attributes to + all nodes in the cluster. These attributes are taken by the SAPHana RA to control the SAP Hana Databases. +@@ -172,7 +172,7 @@ SAPHanaTopology scans the output table of landscapeHostConfiguration.py to ident + Define type of SAPHanaTopology RA messages to be printed + Define type of SAPHanaTopology RA messages to be printed. + Define SAPHana resource agent messages to be printed. +- This parameter should only be set of been requested by SUSE support. The default is sufficient for normal operation. ++ This parameter should only be set if requested by support. The default is sufficient for normal operation. + Values: ra-act-lpa-dec-flow + You could specify any combination of the above values like "ra-act-flow" + diff --git a/SOURCES/bz1168251-SAPHana-agents-update2.patch b/SOURCES/bz1168251-SAPHana-agents-update2.patch new file mode 100644 index 00000000..50808f84 --- /dev/null +++ b/SOURCES/bz1168251-SAPHana-agents-update2.patch @@ -0,0 +1,37 @@ +diff --git a/heartbeat/SAPHana b/heartbeat/SAPHana +index 412152b..1ff6a7d 100644 +--- a/heartbeat/SAPHana ++++ b/heartbeat/SAPHana +@@ -356,7 +356,8 @@ function get_hana_attribute() + local attr_node=$1 + local attr_name=$2 + local attr_store=${3:-reboot} # DONE: PRIO5 get this (optional) from parameter +- crm_attribute -N ${attr_node} -G -n "$attr_name" -l $attr_store -q; rc=$? ++ local attr_default=${4:-} ++ crm_attribute -N ${attr_node} -G -n "$attr_name" -l $attr_store -q -d "$attr_default"; rc=$? + super_ocf_log info "FLOW $FUNCNAME rc=$rc" + return $rc + } +@@ -373,9 +374,10 @@ function set_hana_attribute() + local attr_value=$2 + local attr_name=$3 + local attr_store=${4:-reboot} # DONE: PRIO5 get this (optional) from parameter ++ local attr_default=${5:-} + local rc=1 + local attr_old="" +- attr_old=$(get_hana_attribute $attr_node $attr_name $attr_store); get_rc=$? ++ attr_old=$(get_hana_attribute $attr_node $attr_name $attr_store $attr_default); get_rc=$? + if [ "$attr_old" != "$attr_value" ]; then + super_ocf_log debug "DBG: SET attribute $attr_name for node ${attr_node} to ${attr_value} former ($attr_old) get_rc=$get_rc " + crm_attribute -N $attr_node -v $attr_value -n "$attr_name" -l $attr_store; rc=$? +@@ -578,8 +580,8 @@ function saphana_init() { + remoteHost=$(get_hana_attribute ${NODENAME} ${ATTR_NAME_HANA_REMOTEHOST[@]}); + if [ -z "$remoteHost" ]; then + if [ ${#otherNodes[@]} -eq 1 ]; then # we are a 2 node cluster, lets assume the other is the remote-host +- remoteHost=${otherNodes[0]} +- remoteNode=$remoteHost ++ remoteNode=${otherNodes[0]} ++ remoteHost=$(get_hana_attribute $remoteNode ${ATTR_NAME_HANA_VHOST[@]} "$remoteNode"); + super_ocf_log debug "DBG: auto-guess remoteHost=$remoteHost" + else + super_ocf_log debug "DBG: Could not auto-guess remoteHost out of list (${otherNodes[@]})" diff --git a/SOURCES/bz1168251-SAPHana-agents-update3.patch b/SOURCES/bz1168251-SAPHana-agents-update3.patch new file mode 100644 index 00000000..35fc51b9 --- /dev/null +++ b/SOURCES/bz1168251-SAPHana-agents-update3.patch @@ -0,0 +1,13 @@ +--- a/heartbeat/SAPHana 2015-05-07 07:47:41.654914103 -0500 ++++ b/heartbeat/SAPHana 2015-05-07 07:47:06.164755744 -0500 +@@ -1733,8 +1733,8 @@ + analyze_hana_sync_status + ;; + esac +- rem_role=$(get_hana_attribute ${remoteHost} ${ATTR_NAME_HANA_ROLES[@]}) +- rem_clone_status=$(get_hana_attribute ${remoteHost} ${ATTR_NAME_HANA_CLONE_STATE[@]}) ++ rem_role=$(get_hana_attribute ${remoteNode} ${ATTR_NAME_HANA_ROLES[@]}) ++ rem_clone_status=$(get_hana_attribute ${remoteNode} ${ATTR_NAME_HANA_CLONE_STATE[@]}) + if [ "$promote_attr" = "DEMOTED" -a "$rem_clone_status" = "PROMOTED" ]; then + case "$rem_role" in + [234]:P:* ) # dual primary, but other instance marked as PROMOTED by the cluster diff --git a/SOURCES/bz1168251-SAPHana-agents.patch b/SOURCES/bz1168251-SAPHana-agents.patch new file mode 100644 index 00000000..caf09fe1 --- /dev/null +++ b/SOURCES/bz1168251-SAPHana-agents.patch @@ -0,0 +1,3129 @@ +From ef36b33da922b2b8501e80ca840bfb7accc65ff0 Mon Sep 17 00:00:00 2001 +From: David Vossel +Date: Thu, 26 Feb 2015 14:21:20 -0600 +Subject: [PATCH] bz1168251-SAPHana-agents + +--- + doc/man/Makefile.am | 2 + + heartbeat/Makefile.am | 2 + + heartbeat/SAPHana | 2106 +++++++++++++++++++++++++++++++++++++++ + heartbeat/SAPHanaTopology | 813 +++++++++++++++ + tools/Makefile.am | 2 +- + tools/show_SAPHanaSR_attributes | 133 +++ + 6 files changed, 3057 insertions(+), 1 deletion(-) + create mode 100755 heartbeat/SAPHana + create mode 100755 heartbeat/SAPHanaTopology + create mode 100755 tools/show_SAPHanaSR_attributes + +diff --git a/doc/man/Makefile.am b/doc/man/Makefile.am +index 5a1ad4d..31fc1f5 100644 +--- a/doc/man/Makefile.am ++++ b/doc/man/Makefile.am +@@ -78,6 +78,8 @@ man_MANS = ocf_heartbeat_AoEtarget.7 \ + ocf_heartbeat_Route.7 \ + ocf_heartbeat_SAPDatabase.7 \ + ocf_heartbeat_SAPInstance.7 \ ++ ocf_heartbeat_SAPHana.7 \ ++ ocf_heartbeat_SAPHanaTopology.7 \ + ocf_heartbeat_SendArp.7 \ + ocf_heartbeat_ServeRAID.7 \ + ocf_heartbeat_SphinxSearchDaemon.7 \ +diff --git a/heartbeat/Makefile.am b/heartbeat/Makefile.am +index f08dad4..dd5b0a9 100644 +--- a/heartbeat/Makefile.am ++++ b/heartbeat/Makefile.am +@@ -105,6 +105,8 @@ ocf_SCRIPTS = ClusterMon \ + rsyslog \ + SAPDatabase \ + SAPInstance \ ++ SAPHana \ ++ SAPHanaTopology \ + SendArp \ + ServeRAID \ + slapd \ +diff --git a/heartbeat/SAPHana b/heartbeat/SAPHana +new file mode 100755 +index 0000000..f4db17a +--- /dev/null ++++ b/heartbeat/SAPHana +@@ -0,0 +1,2106 @@ ++#!/bin/bash ++# ++# SAPHana ++# ++# Description: Manages two single SAP HANA Instance in System Replication ++# Planned: do also manage scale-up scenarios ++# currently the SAPHana is dependent of the analysis of ++# SAPHanaTopology ++# For supported scenarios please read the README file provided ++# in the same software package (rpm) ++# ++############################################################################## ++# ++# SAPHana ++# Author: Fabian Herschel, November 2013 ++# Support: linux@sap.com ++# License: GNU General Public License (GPL) ++# Copyright: (c) 2013,2014 SUSE Linux Products GmbH ++# ++# An example usage: ++# See usage() function below for more details... ++# ++# OCF instance parameters: ++# OCF_RESKEY_SID ++# OCF_RESKEY_InstanceNumber ++# OCF_RESKEY_DIR_EXECUTABLE (optional, well known directories will be searched by default) ++# OCF_RESKEY_DIR_PROFILE (optional, well known directories will be searched by default) ++# OCF_RESKEY_INSTANCE_PROFILE (optional, well known directories will be searched by default) ++# OCF_RESKEY_PREFER_SITE_TAKEOVER (optional, default is no) ++# OCF_RESKEY_DUPLICATE_PRIMARY_TIMEOUT (optional, time difference needed between two last-primary-tiemstampe (lpt)) ++# OCF_RESKEY_SAPHanaFilter (optional, should only be set if been told by support or for debugging purposes) ++# ++# ++####################################################################### ++# ++# Initialization: ++timeB=$(date '+%s') ++ ++: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat} ++. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs ++ ++# ++####################################################################### ++# ++ ++HANA_STATE_PRIMARY=0 ++HANA_STATE_SECONDARY=1 ++HANA_STATE_STANDALONE=2 ++HANA_STATE_DEFECT=3 ++ ++SH=/bin/sh ++ ++# ++# function: super_ocf_log - wrapper function for ocf log in order catch usual logging into super log ++# params: LOG_MESSAGE ++# globals: SAPHanaFilter ++function super_ocf_log() { ++ local level="$1" ++ local message="$2" ++ local skip=1 ++ local mtype="" ++ local search=0 ++ local shf="${SAPHanaFilter:-all}" ++ # message levels: (dbg)|info|warn|err|error ++ # message types: (ACT|RA|FLOW|DBG|LPA|DEC|DBG2... ++ case "$level" in ++ debug | dbg | warn | err | error ) skip=0 ++ ;; ++ info ) ++ case "$shf" in ++ all) skip=0 ++ ;; ++ none ) ++ skip=1 ++ ;; ++ * ) mtype=${message%% *} ++ mtype=${mtype%:} ++ mtype=${mtype#fh} ++ echo "$shf"| grep -iq ${mtype}; search=$? ++ if [ $search -eq 0 ]; then ++ skip=0 ++ else ++ skip=1 ++ fi ++ ;; ++ esac ++ ;; ++ esac ++ if [ $skip -eq 0 ]; then ++ ocf_log "$level" "$message" ++ fi ++} ++ ++# ++# function: saphana_usage - short usage info ++# params: - ++# globals: $0(r) ++# ++function saphana_usage() { ++ super_ocf_log info "FLOW $FUNCNAME ($*)" ++ local rc=0 ++ methods=$(saphana_methods) ++ methods=$(echo $methods | tr ' ' '|') ++ cat <<-! ++ usage: $0 ($methods) ++ ++ $0 manages a SAP HANA Instance as an HA resource. ++ ++ The 'start' operation starts the HANA instance or bring the "clone instance" to a WAITING status ++ The 'stop' operation stops the HANA instance ++ The 'status' operation reports whether the HANA instance is running ++ The 'monitor' operation reports whether the HANA instance seems to be working in master/slave it also needs to check the system replication status ++ The 'promote' operation either runs a takeover for a secondary or a just-nothing for a primary ++ The 'demote' operation neary does nothing and just mark the instance as demoted ++ The 'notify' operation always returns SUCCESS ++ The 'validate-all' operation reports whether the parameters are valid ++ The 'methods' operation reports on the methods $0 supports ++ ++ ! ++ return $rc ++} ++ ++# ++# function: saphana_meta_data - print resource agent meta-data for cluster ++# params: - ++# globals: - ++# ++function saphana_meta_data() { ++ super_ocf_log info "FLOW $FUNCNAME ($*)" ++ local rc=0 ++ cat < ++ ++ ++0.149.4 ++ ++Manages two SAP HANA instances in system replication (SR). ++ ++The SAPHanaSR resource agent manages two SAP Hana instances (databases) which are configured ++in system replication. This first version is limitted to the scale-up scenario. Scale-Up is ++not supported in this version. ++ ++Managing the two SAP HANA instances means that the resource agent controls the start/stop of the ++instances. In addition the resource agent is able to monitor the SAP HANA databases to check their ++availability on landscape host configuration level. For this monitoring the resource agent relies on interfaces ++provided by SAP. A third task of the resource agent is to also check the synchronisation status ++of the two SAP HANA databases. If the synchronisation is not "SOK", than the cluster avoids to ++failover to the secondary side, if the primary fails. This is to improve the data consistency. ++ ++The resource agent uses the following four interfaces provided by SAP: ++ ++1. sapcontrol/sapstartsrv ++ The interface sapcontrol/sapstartsrv is used to start/stop a HANA database instance/system ++ ++2. landscapeHostConfiguration ++ The interface is used to monitor a HANA system. The python script is named landscapeHostConfiguration.py. ++ landscapeHostConfiguration.py has some detailed output about HANA system status ++ and node roles. For our monitor the overall status is relevant. This overall ++ status is reported by the returncode of the script: ++ 0: Internal Fatal, 1: ERROR, 2: WARNING, 3: INFO, 4: OK ++ The SAPHana resource agent will interpret returncodes 0 as FATAL, 1 as not-running or ERROR and and returncodes 2+3+4 as RUNNING. ++ ++3. hdbnsutil ++ The interface hdbnsutil is used to check the "topology" of the system replication as well as the current configuration ++ (primary/secondary) of a SAP HANA database instance. A second task of the interface is the posibility to run a ++ system replication takeover (sr_takeover) or to register a former primary to a newer one (sr_register). ++ ++4. hdbsql / systemReplicationStatus ++ Interface is SQL query into HANA (system replication table). The hdbsql query will be replaced by a python script ++ "systemReplicationStatus.py" in SAP HANA SPS8 or 9. ++ As long as we need to use hdbsql you need to setup secure store users for linux user root to be able to ++ access the SAP HANA database. You need to configure a secure store user key "SAPHANA${SID}SR" which can connect the SAP ++ HANA database: ++ ++5. saphostctrl ++ The interface saphostctrl uses the function ListInstances to figure out the virtual host name of the ++ SAP HANA instance. This is the hostname used during the HANA installation. ++ ++ ++ ++ ++ SAP System Identifier (SID) like "SLE" or "HAE" ++ SAP System Identifier (SID) ++ ++ ++ ++ SAP instance number like "00" or "07" ++ SAP instance number ++ ++ ++ ++ Should cluster/RA prefer to switchover to slave instance instead of restarting master locally? Default="yes" ++ no: Do prefer restart locally ++ yes: Do prefer takever to remote site ++ ++ Local or site recover preferred? ++ ++ ++ ++ Define, if a former primary should automatically be registered. ++ The parameter AUTOMATED_REGISTER defines, wether a former primary instance should ++ be registered automatically by the resource agent during cluster/resource start, if the DUPLICATE_PRIMARY_TIMEOUT is expired... TDB ++ ++ ++ ++ ++ Time difference needed between to primary time stamps, if a dual-primary situation occurs ++ Time difference needed between to primary time stamps, ++ if a dual-primary situation occurs. If the time difference is ++ less than the time gap, than the cluster hold one or both instances in a "WAITING" status. This is to give a admin ++ a chance to react on a failover. A failed former primary will be registered after the time difference is passed. After ++ this registration to the new primary all data will be overwritten by the system replication. ++ ++ ++ ++ ++ The full qualified path where to find sapstartsrv and sapcontrol. Specify this parameter, if you have changed the SAP kernel directory location after the default SAP installation. ++ Path of sapstartsrv and sapcontrol ++ ++ ++ ++ The full qualified path where to find the SAP START profile. Specify this parameter, if you have changed the SAP profile directory location after the default SAP installation. ++ Path of start profile ++ ++ ++ ++ The name of the SAP HANA instance profile. Specify this parameter, if you have changed the name of the SAP HANA instance profile after the default SAP installation. Normally you do not need to set this parameter. ++ HANA instance profile name ++ ++ ++ ++ Define SAPHana resource agent messages to be printed ++ Define SAPHana resource agent messages to be printed. ++ This parameter should only be set of been requested by SUSE support. The default is sufficient for normal operation. ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++END ++return $rc ++} ++ ++# ++# function: saphana_methods - report supported cluster methods ++# params: - ++# globals: - ++# methods: What methods/operations do we support? ++# ++function saphana_methods() { ++ super_ocf_log info "FLOW $FUNCNAME ($*)" ++ local rc=0 m ++ for m in start stop status monitor promote demote notify validate-all methods meta-data usage; do ++ echo "$m" ++ done ++ return $rc ++} ++ ++# ++# function: dequote - filter: remove quotes (") from stdin ++# params: - ++# globals: - ++function dequote() ++{ ++ local rc=0; tr -d '"'; return $rc ++} ++ ++# ++# function: remoteHost2remoteNode - convert a SAP remoteHost to the cluster node name ++# params: remoteHost ++# globals: ATTR_NAME_HANA_VHOST[*] ++# ++function remoteHost2remoteNode() ++{ ++ super_ocf_log info "FLOW $FUNCNAME ($*)" ++ local -a clusterNodes=() ++ local cl="" ++ local vHost="" ++ local remoteHost="$1" ++ local remoteNode="" ++ local rc=1 ++ for cl in ${otherNodes[@]}; do ++ vHost=$(get_hana_attribute $cl ${ATTR_NAME_HANA_VHOST[@]}) ++ if [ "$vHost" = "$remoteHost" ]; then # we found the correct node ++ remoteNode=$cl ++ rc=0 ++ fi ++ done ++ if [ -n "$remoteNode" ]; then ++ echo "$remoteNode" ++ fi ++ super_ocf_log info "FLOW $FUNCNAME rc=$rc" ++ return $rc ++} ++ ++# ++# function: is_clone - report, if resource is configured as a clone (also master/slave) ++# params: - ++# globals: OCF_*(r) ++# descript: is_clone : find out if we are configured to run in a Master/Slave configuration ++# rc: 0: it is a clone, 1: it is not a clone ++# ++# DONE: PRIO2: For the first shippment (scale-out) we need to limit the clones to 2 ++# ++function is_clone() { ++ super_ocf_log info "FLOW $FUNCNAME ($*)" ++ local rc=0 ++ # ++ # is a clone config? ++ # ++ if [ -n "$OCF_RESKEY_CRM_meta_clone_max" ] \ ++ && [ "$OCF_RESKEY_CRM_meta_clone_max" -gt 0 ]; then ++ # ++ # yes it is a clone config - check, if its configured well ++ # ++ if [ "$OCF_RESKEY_CRM_meta_clone_node_max" -ne 1 ] || \ ++ [ "$OCF_RESKEY_CRM_meta_clone_max" -ne 2 ] || \ ++ [ "$OCF_RESKEY_CRM_meta_master_node_max" -ne 1 ] || \ ++ [ "$OCF_RESKEY_CRM_meta_master_max" -ne 1 ]; then ++ super_ocf_log err "ACT: Clone options misconfigured. (expect: clone_max=2,clone_node_max=1,master_node_max=1,master_max=1)" ++ exit $OCF_ERR_CONFIGURED ++ fi ++ rc=0; ++ else ++ rc=1; ++ fi ++ super_ocf_log info "FLOW $FUNCNAME rc=$rc" ++ return $rc ++} ++ ++# ++# function: get_hana_attribute ++# params: NODE ATTR [STORE] ++# globals: - ++# ++function get_hana_attribute() ++{ ++ super_ocf_log info "FLOW $FUNCNAME ($*)" ++ local rc=0 ++ local attr_node=$1 ++ local attr_name=$2 ++ local attr_store=${3:-reboot} # DONE: PRIO5 get this (optional) from parameter ++ crm_attribute -N ${attr_node} -G -n "$attr_name" -l $attr_store -q; rc=$? ++ super_ocf_log info "FLOW $FUNCNAME rc=$rc" ++ return $rc ++} ++ ++# ++# function: set_hana_attribute - set the multi-state status of a node ++# params: NODE VALUE ATTR [STORE] ++# globals: - ++# ++function set_hana_attribute() ++{ ++ super_ocf_log info "FLOW $FUNCNAME ($*)" ++ local attr_node=$1 ++ local attr_value=$2 ++ local attr_name=$3 ++ local attr_store=${4:-reboot} # DONE: PRIO5 get this (optional) from parameter ++ local rc=1 ++ local attr_old="" ++ attr_old=$(get_hana_attribute $attr_node $attr_name $attr_store); get_rc=$? ++ if [ "$attr_old" != "$attr_value" ]; then ++ super_ocf_log debug "DBG: SET attribute $attr_name for node ${attr_node} to ${attr_value} former ($attr_old) get_rc=$get_rc " ++ crm_attribute -N $attr_node -v $attr_value -n "$attr_name" -l $attr_store; rc=$? ++ else ++ super_ocf_log debug "DBG: LET attribute $attr_name for node ${attr_node} still be ${attr_value}" ++ rc=0 ++ fi ++ super_ocf_log info "FLOW $FUNCNAME rc=$rc" ++ return $rc ++} ++ ++# ++# function: assert - quickly go out of here with minimal error/return code handling and log ++# params: MESSAGE ++# globals: OCF_*(r) ++# ++function assert() { ++ super_ocf_log info "FLOW $FUNCNAME ($*)" ++ local err_msg=$1 local default_rc=$OCF_NOT_RUNNING ++ # DONE: Check, if we need to destinguish between probe and others ++ if ocf_is_probe; then ++ default_exit=$OCF_NOT_RUNNING ++ else ++ default_exit=$OCF_ERR_CONFIGURED ++ fi ++ if [ "$ACTION" = "stop" ]; then ++ cleanup_instance ++ exit $OCF_SUCCESS ++ fi ++ super_ocf_log err "ACT: $err_msg" ++ exit $OCF_NOT_RUNNING ++} ++ ++# ++# function: set_crm_master - set the crm master score of the local node ++# params: SCORE ++# globals: HA_SBIN_DIR(r), OCF_RESOURCE_INSTANCE(r) ++# ++function set_crm_master() ++{ ++ super_ocf_log info "FLOW $FUNCNAME ($*)" ++ local rc=0 ++ local score=0 ++ if [ -n "$1" ]; then ++ score=$1 ++ fi ++ # DONE: PRIO2: Only adjust master if value is really different (try to check that) ++ oldscore=$(${HA_SBIN_DIR}/crm_master -G -q -l reboot) ++ if [ "$oldscore" != "$score" ]; then ++ super_ocf_log debug "DBG: SET crm master: $score (old: $oldscore)" ++ ${HA_SBIN_DIR}/crm_master -v $score -l reboot; rc=$? ++ else ++ super_ocf_log debug "DBG: LET crm master: $score" ++ rc=0 ++ fi ++ #logger -t fhLOG "crm_master with: $OCF_RESOURCE_INSTANCE -v $score -l reboot" ++ return $rc ++} ++ ++# ++# function: scoring_crm_master - score instance due to role ans sync match (table SCORING_TABLE_PREFERRED_SITE_TAKEOVER) ++# params: NODE_ROLES NODE_SYNC_STATUS ++# globals: SCORING_TABLE_PREFERRED_SITE_TAKEOVER[@], ++# ++scoring_crm_master() ++{ ++ super_ocf_log info "FLOW $FUNCNAME ($*)" ++ local roles="$1" ++ local sync="$2" ++ local skip=0 ++ local myScore=-1 ++ for scan in "${SCORING_TABLE_PREFERRED_SITE_TAKEOVER[@]}"; do ++ if [ $skip -eq 0 ]; then ++ read rolePatt syncPatt score <<< $scan ++ if grep "$rolePatt" <<< "$roles"; then ++ if grep "$syncPatt" <<< "$sync"; then ++ skip=1 ++ myScore=$score ++ fi ++ fi ++ fi ++ done ++ super_ocf_log debug "DBG: scoring_crm_master adjust score $myScore" ++ set_crm_master $myScore ++} ++ ++# ++# function: get_crm_master - get the crm master score of the local node ++# params: - ++# globals: HA_SBIN_DIR(r) ++# ++function get_crm_master() ++{ ++ super_ocf_log info "FLOW $FUNCNAME ($*)" ++ local rc=0 ++ ${HA_SBIN_DIR}/crm_master -G -q -l reboot; rc=$? ++ return $rc ++} ++ ++# ++# function: saphana_init - initialize variables for the resource agent ++# params: InstanceName ++# globals: OCF_*(r), SID(w), sid(rw), sidadm(w), InstanceName(w), InstanceNr(w), SAPVIRHOST(w), PreferSiteTakeover(w), ++# globals: sr_name(w), remoteHost(w), otherNodes(w) ++# globals: ATTR_NAME_HANA_SYNC_STATUS(w), ATTR_NAME_HANA_CLONE_STATE(w) ++# globals: DIR_EXECUTABLE(w), SAPSTARTSRV(w), SAPCONTROL(w), DIR_PROFILE(w), SAPSTARTPROFILE(w), LD_LIBRARY_PATH(w), PATH(w) ++# globals: LPA_DIRECTORY(w), SIDInstanceName(w), remoteNode(w) ++# saphana_init : Define global variables with default values, if optional parameters are not set ++# ++function saphana_init() { ++ super_ocf_log info "FLOW $FUNCNAME ($*)" ++ local rc=$OCF_SUCCESS ++ local vName ++ # two parameter models (for transition only) ++ # OLD: InstanceName ++ # NEW: SID InstanceNumber ++ SID=$OCF_RESKEY_SID ++ InstanceNr=$OCF_RESKEY_InstanceNumber ++ SIDInstanceName="${SID}_HDB${InstanceNr}" ++ InstanceName="HDB${InstanceNr}" ++ super_ocf_log debug "DBG: Used new method to get SID ($SID) and InstanceNr ($InstanceNr)" ++ sid=$(echo "$SID" | tr [:upper:] [:lower:]) ++ sidadm="${sid}adm" ++ # DONE: PRIO4: SAPVIRHOST might be different to NODENAME ++ # DONE: PRIO1: ASK: Is the output format of ListInstances fix? Could we take that as an API? Answer: Yes ++ # try to catch: Inst Info : LNX - 42 - lv9041 - 740, patch 36, changelist 1444691 ++ # We rely on the following format: SID is word#4, NR is work#6, vHost is word#8 ++ vName=$(/usr/sap/hostctrl/exe/saphostctrl -function ListInstances \ ++ | awk '$4 == SID && $6=NR { print $8 }' SID=$SID NR=$InstanceNr) ++ if [ -z "$vName" ]; then ++ # ++ # if saphostctrl does not know the answer, try to fallback to attribute provided by SAPHanaTopology ++ # ++ vName=$(get_hana_attribute ${NODENAME} ${ATTR_NAME_HANA_VHOST[@]}); ++ fi ++ SAPVIRHOST=${vName} ++ PreferSiteTakeover="$OCF_RESKEY_PREFER_SITE_TAKEOVER" ++ SAPHanaFilter="${OCF_RESKEY_SAPHanaFilter:-ra-act-dec-lpa}" ++ AUTOMATED_REGISTER="${OCF_RESKEY_AUTOMATED_REGISTER:-false}" ++ LPA_DIRECTORY=/var/lib/SAPHanaRA ++ LPA_ATTR=("lpa_${sid}_lpt" "forever") ++ super_ocf_log debug "DBG: SID=$SID, sid=$sid, SIDInstanceName=$SIDInstanceName, InstanceName=$InstanceName, InstanceNr=$InstanceNr, SAPVIRHOST=$SAPVIRHOST" ++ ocf_env=$(env | grep 'OCF_RESKEY_CRM') ++ super_ocf_log debug "DBG: OCF: $ocf_env" ++ # ++ ATTR_NAME_HANA_SYNC_STATUS=("hana_${sid}_sync_state" "reboot") # SOK, SFAIL, UNKNOWN? ++ ATTR_NAME_HANA_PRIMARY_AT=("hana_${sid}_primary_at" "reboot") # Not used so far ++ ATTR_NAME_HANA_CLONE_STATE=("hana_${sid}_clone_state" "reboot") # UKNOWN?, DEMOTED, PROMOTED ++ ATTR_NAME_HANA_REMOTEHOST=("hana_${sid}_remoteHost" "forever") ++ ATTR_NAME_HANA_SITE=("hana_${sid}_site" "forever") ++ ATTR_NAME_HANA_ROLES=("hana_${sid}_roles" "reboot") ++ ATTR_NAME_HANA_SRMODE=("hana_${sid}_srmode" "forever") ++ ATTR_NAME_HANA_VHOST=("hana_${sid}_vhost" "forever") ++ ATTR_NAME_HANA_STATUS=("hana_${sid}_status" "reboot") ++ # ++ # TODO: PRIO4: Table for non-preferred-site-takeover ++ # ++ SCORING_TABLE_PREFERRED_SITE_TAKEOVER=( ++ "[234]*:P:[^:]*:master .* 150" ++ "[015-9]*:P:[^:]*:master .* 90" ++ "[0-9]*:P:[^:]*:slave .* 60" ++ "[0-9]*:P:[^:]*:\? .* 0" ++ "[0-9]*:P:[^:]*:- .* 0" ++ "[234]*:S:[^:]*:master SOK 100" ++ "[015-9]*:S:[^:]*:master SOK 80" ++ "[0-9]*:S:[^:]*:master SFAIL -INFINITY" ++ "[0-9]*:S:[^:]*:slave SOK 10" ++ "[0-9]*:S:[^:]*:slave SFAIL -INFINITY" ++ "[0-9]*:S:[^:]*:\? .* 0" ++ "[0-9]*:S:[^:]*:- .* 0" ++ ".* .* -1" ++ ) ++ SCORING_TABLE_PREFERRED_LOCAL_RESTART=( ++ "[0-9]*:P:[^:]*:master .* 150" ++ "[0-9]*:P:[^:]*:slave .* 140" ++ "[0-9]*:P:[^:]*:\? .* 0" ++ "[0-9]*:P:[^:]*:- .* 0" ++ "[0-9]*:S:[^:]*:master SOK 100" ++ "[0-9]*:S:[^:]*:master SFAIL -INFINITY" ++ "[0-9]*:S:[^:]*:slave SOK 10" ++ "[0-9]*:S:[^:]*:slave SFAIL -INFINITY" ++ "[0-9]*:S:[^:]*:\? .* 0" ++ "[0-9]*:S:[^:]*:- .* 0" ++ ".* .* -1" ++ ) ++ # ++ DUPLICATE_PRIMARY_TIMEOUT="${OCF_RESKEY_DUPLICATE_PRIMARY_TIMEOUT:-7200}" ++ super_ocf_log debug "DBG: DUPLICATE_PRIMARY_TIMEOUT=$DUPLICATE_PRIMARY_TIMEOUT" ++ # ++ # Determine list of other cluster nodes and store in otherNodes variable ++ otherNodes=() ++ case $(crm_attribute --type crm_config --name cluster-infrastructure -q) in ++ *corosync* ) otherNodes=($(crm_node -l | awk '{ if ($2 != me) { print $2 }}' me=${NODENAME}));; ++ *openais* ) otherNodes=($(crm_node -l | awk '$3 == "member" { if ($2 != me) { print $2 }}' me=${NODENAME}));; ++ *cman* ) otherNodes=($(crm_node -l | awk '{for (i=1; i<=NF; i++) { if ($i != me) { print $i }}}' me=${NODENAME}));; ++ esac ++ ++ remoteHost=$(get_hana_attribute ${NODENAME} ${ATTR_NAME_HANA_REMOTEHOST[@]}); ++ if [ -z "$remoteHost" ]; then ++ if [ ${#otherNodes[@]} -eq 1 ]; then # we are a 2 node cluster, lets assume the other is the remote-host ++ remoteHost=${otherNodes[0]} ++ remoteNode=$remoteHost ++ super_ocf_log debug "DBG: auto-guess remoteHost=$remoteHost" ++ else ++ super_ocf_log debug "DBG: Could not auto-guess remoteHost out of list (${otherNodes[@]})" ++ fi ++ else ++ # ++ # search cluster node which vhost is equal remoteHost ++ # ++ remoteNode=$(remoteHost2remoteNode $remoteHost) ++ # TODO: PRIO5: catch rc!=0 ++ fi ++ # ATTR_NAME_HANA_SITE ++ sr_name=$(get_hana_attribute ${NODENAME} ${ATTR_NAME_HANA_SITE[@]}); ++ sr_mode=$(get_hana_attribute "${NODENAME}" ${ATTR_NAME_HANA_SRMODE[@]}) ++ if [ -z "$sr_mode" ]; then ++ sr_mode="sync" ++ fi ++ super_ocf_log debug "DBG: sr_name=$sr_name, remoteHost=$remoteHost, remoteNode=$remoteNode, sr_mode=$sr_mode" ++ # optional OCF parameters, we try to guess which directories are correct ++ if [ -z "$OCF_RESKEY_DIR_EXECUTABLE" ] ++ then ++ if have_binary /usr/sap/$SID/$InstanceName/exe/sapstartsrv && have_binary /usr/sap/$SID/$InstanceName/exe/sapcontrol ++ then ++ DIR_EXECUTABLE="/usr/sap/$SID/$InstanceName/exe" ++ fi ++ else ++ if have_binary "$OCF_RESKEY_DIR_EXECUTABLE/sapstartsrv" && have_binary "$OCF_RESKEY_DIR_EXECUTABLE/sapcontrol" ++ then ++ DIR_EXECUTABLE="$OCF_RESKEY_DIR_EXECUTABLE" ++ fi ++ fi ++ SAPSTARTSRV="$DIR_EXECUTABLE/sapstartsrv" ++ SAPCONTROL="$DIR_EXECUTABLE/sapcontrol" ++ ++ [ -z "$DIR_EXECUTABLE" ] && assert "Cannot find sapstartsrv and sapcontrol executable, please set DIR_EXECUTABLE parameter!" ++ DIR_PROFILE="${OCF_RESKEY_DIR_PROFILE:-/usr/sap/$SID/SYS/profile}" ++ # check, if the following fall-back is ok, or if there could be multiple profiles matching this pattern ++ if [ -n "${SAPVIRHOST}" ]; then ++ SAPSTARTPROFILE="$DIR_PROFILE/${OCF_RESKEY_INSTANCE_PROFILE:-${SID}_${InstanceName}_${SAPVIRHOST}}" ++ else ++ # check, if the following fall-back is ok, or if there could be multiple profiles matching this pattern ++ # also take profile versions into account - they might break this fall-back ++ # TODO: PRIO4: Check, if it makes sense to implement an additional last fall-back: get the SAPSTARTPROFILE from /usr/sap/sapservices ++ # ++ SAPSTARTPROFILE="$(ls -1 $DIR_PROFILE/${OCF_RESKEY_INSTANCE_PROFILE:-${SID}_${InstanceName}_*})" ++ fi ++ # as root user we need the library path to the SAP kernel to be able to call sapcontrol ++ # check, if we already added DIR_EXECUTABLE at the beginning of LD_LIBRARY_PATH ++ if [ "${LD_LIBRARY_PATH%%*:}" != "$DIR_EXECUTABLE" ] ++ then ++ LD_LIBRARY_PATH=$DIR_EXECUTABLE${LD_LIBRARY_PATH:+:}$LD_LIBRARY_PATH ++ export LD_LIBRARY_PATH ++ fi ++ PATH=${PATH}:${DIR_EXECUTABLE}; export PATH ++ super_ocf_log info "FLOW $FUNCNAME rc=$OCF_SUCCESS" ++ ############################# ++ # TODO: PRIO9: To be able to call landscapeHostConfig.py without su (so as root) ++ # TODO: PRIO9: Research for environment script .htacces or something like that ++ #export SAPSYSTEMNAME=ZLF ++ #export DIR_INSTANCE=/usr/sap/ZLF/HDB02 ++ #export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$DIR_INSTANCE/exe:$DIR_INSTANCE/exe/Python/lib ++ #export PYTHONPATH=$DIR_INSTANCE/$HOST:$DIR_INSTANCE/exe/python_support:$DIR_INSTANCE/exe ++ #export PYTHONHOME=$DIR_INSTANCE/exe/Python ++ #export SAP_RETRIEVAL_PATH=$DIR_INSTANCE/$HOST ++ #export DIR_EXECUTABLE=$DIR_INSTANCE/exe ++ ############################# ++ return $OCF_SUCCESS ++} ++ ++# function: check_secstore_users ++# params: USER ++# globals: DIR_EXECUTABLE(r) ++# ++# TODO: PRIO5: Might be dropped, if we get a script for fetching the sync status ++function check_secstore_users() ++{ ++ super_ocf_log info "FLOW $FUNCNAME ($*)" ++ local user="" ++ local rc=1 ++ while [ $# -gt 0 ]; do ++ user="$1" ++ $DIR_EXECUTABLE/hdbuserstore list | grep -q "KEY $user" && echo "$user" && rc=0 && break ++ shift ++ done ++ super_ocf_log info "FLOW $FUNCNAME rc=$rc" ++ return $rc ++} ++ ++# ++# function: check_sapstartsrv - check for sapstartsrv - optional start ++# params: - ++# globals: DIR_PROFILE(w), SAPSTARTPROFILE(r), SAPCONTROL(r), SID(r), InstanceName(r), InstanceNr(r), OCF_*(r) ++# check_sapstartsrv : Before using sapcontrol we make sure that the sapstartsrv is running. ++# ++function check_sapstartsrv() { ++ super_ocf_log info "FLOW $FUNCNAME ($*)" ++ local restart=0 ++ local runninginst="" ++ local rc=$OCF_SUCCESS ++ local output="" ++ if [ ! -S /tmp/.sapstream5${InstanceNr}13 ]; then ++ super_ocf_log warn "ACT: sapstartsrv is not running for instance $SID-$InstanceName (no UDS), it will be started now" ++ restart=1 ++ else ++ output=$($SAPCONTROL -nr $InstanceNr -function ParameterValue INSTANCE_NAME -format script) ++ if [ $? -eq 0 ] ++ then ++ runninginst=$(echo "$output" | grep '^0 : ' | cut -d' ' -f3) ++ if [ "$runninginst" != "$InstanceName" ] ++ then ++ super_ocf_log warn "ACT: sapstartsrv is running for instance $runninginst, that service will be killed" ++ restart=1 ++ else ++ output=$($SAPCONTROL -nr $InstanceNr -function AccessCheck Start) ++ if [ $? -ne 0 ]; then ++ super_ocf_log warn "ACT: FAILED - sapcontrol -nr $InstanceNr -function AccessCheck Start ($(ls -ld1 /tmp/.sapstream5${InstanceNr}13))" ++ super_ocf_log warn "ACT: sapstartsrv will be restarted to try to solve this situation, otherwise please check sapstsartsrv setup (SAP Note 927637)" ++ restart=1 ++ fi ++ fi ++ else ++ super_ocf_log warn "ACT: sapstartsrv is not running for instance $SID-$InstanceName, it will be started now" ++ restart=1 ++ fi ++ fi ++ if [ -z "$runninginst" ]; then runninginst=$InstanceName; fi ++ if [ $restart -eq 1 ] ++ then ++ if [ -d /usr/sap/$SID/SYS/profile/ ] ++ then ++ DIR_PROFILE="/usr/sap/$SID/SYS/profile" ++ else ++ assert "Expected /usr/sap/$SID/SYS/profile/ to be a directory, please set DIR_PROFILE parameter!" ++ fi ++ [ ! -r $SAPSTARTPROFILE ] && assert "Expected $SAPSTARTPROFILE to be the instance START profile, please set INSTANCE_PROFILE parameter!" ++ pkill -9 -f "sapstartsrv.*$runninginst" ++ # removing the unix domain socket files as they might have wrong permissions ++ # or ownership - they will be recreated by sapstartsrv during next start ++ rm -f /tmp/.sapstream5${InstanceNr}13 ++ rm -f /tmp/.sapstream5${InstanceNr}14 ++ $SAPSTARTSRV pf=$SAPSTARTPROFILE -D -u $sidadm ++ # now make sure the daemon has been started and is able to respond ++ local srvrc=1 ++ while [ $srvrc -eq 1 -a $(pgrep -f "sapstartsrv.*$runninginst" | wc -l) -gt 0 ] ++ do ++ sleep 1 ++ $SAPCONTROL -nr $InstanceNr -function GetProcessList > /dev/null 2>&1 ++ srvrc=$? ++ done ++ if [ $srvrc -ne 1 ] ++ then ++ super_ocf_log info "ACT: sapstartsrv for instance $SID-$InstanceName was restarted!" ++ rc=$OCF_SUCCESS ++ else ++ super_ocf_log error "ACT: sapstartsrv for instance $SID-$InstanceName could not be started!" ++ rc=$OCF_ERR_GENERIC ++ ocf_is_probe && rc=$OCF_NOT_RUNNING ++ fi ++ fi ++ return $rc ++} ++ ++# ++# function: cleanup_instance - remove resources from a crashed instance ++# params: - ++# globals: - ++# ++function cleanup_instance() { ++ super_ocf_log info "FLOW $FUNCNAME ($*)" ++ local rc=0 ++ # TODO: PRIO5: Check, if we need HANA cleanup procedure (processes, ipc obj, pid files); Currently not needed ++ super_ocf_log debug "DBG: cleanup_instance currently not implemented" ++ rc=0 ++ super_ocf_log info "FLOW $FUNCNAME rc=$rc" ++} ++ ++# ++# function: check_for_primary - check if local SAP HANA is configured as primary ++# params: - ++# globals: HANA_STATE_PRIMARY(r), HANA_STATE_SECONDARY(r), HANA_STATE_DEFECT(r) ++# ++function check_for_primary() { ++ super_ocf_log info "FLOW $FUNCNAME ($*)" ++ local rc=$HANA_STATE_DEFECT ++ node_full_status=$(su - ${sidadm} -c "hdbnsutil -sr_state" 2>/dev/null ) ++ node_status=$(echo "$node_full_status" | awk '$1=="mode:" {print $2}') ++ super_ocf_log debug "DBG: check_for_primary: node_status=$node_status" ++ for i in 1 2 3 4 5 6 7 8 9; do ++ case "$node_status" in ++ primary ) ++ super_ocf_log info "FLOW $FUNCNAME rc=HANA_STATE_PRIMARY" ++ return $HANA_STATE_PRIMARY;; ++ syncmem | sync | async ) ++ super_ocf_log info "FLOW $FUNCNAME rc=HANA_STATE_SECONDARY" ++ return $HANA_STATE_SECONDARY;; ++ none ) # have seen that mode on second side BEFEORE we registered it as replica ++ super_ocf_log info "FLOW $FUNCNAME rc=HANA_STATE_STANDALONE" ++ return $HANA_STATE_STANDALONE;; ++ * ) ++ super_ocf_log err "ACT: check_for_primary: we didn't expect node_status to be: <$node_status>" ++ dump=$( echo $node_status | hexdump -C ); ++ super_ocf_log err "ACT: check_for_primary: we didn't expect node_status to be: DUMP <$dump>" ++ node_full_status=$(su - ${sidadm} -c "hdbnsutil -sr_state" 2>/dev/null ) ++ node_status=$(echo "$node_full_status" | awk '$1=="mode:" {print $2}') ++ super_ocf_log debug "DEC: check_for_primary: loop=$i: node_status=$node_status" ++ # TODO: PRIO1: Maybe we need to keep the old value for P/S/N, if hdbnsutil just crashes ++ esac; ++ done ++ super_ocf_log info "FLOW $FUNCNAME rc=$rc" ++ return $rc ++} ++ ++# ++# function: analyze_hana_sync_status - query and check hana system replication status ++# params: - ++# globals: DIR_EXECUTABLE(r), remoteHost(r) ++# get the HANA sync status ++# ++function analyze_hana_sync_status() ++{ ++ super_ocf_log info "FLOW $FUNCNAME ($*)" ++ local -a clusterNodes=() ++ local cl="" ++ local vHost="" ++ local n="" ++ local hana_sync_status="" what_does_the_chamelion_say="" ++ local secUser="SLEHALOC" ++ local chkusr; ++ local rc=0 ++ local sqlrc=0 ++# local query_state='select distinct REPLICATION_STATUS from SYS.M_SERVICE_REPLICATION' ++# select distinct REPLICATION_STATUS from SYS.M_SERVICE_REPLICATION where SITE_NAME='"SITE1"'" ++ local query_state="select distinct REPLICATION_STATUS from SYS.M_SERVICE_REPLICATION where SITE_NAME='"${sr_name}"'" ++ local query_secondaries='select distinct SECONDARY_HOST from SYS.M_SERVICE_REPLICATION' ++ local query_failed_secondaries="select distinct SECONDARY_HOST from SYS.M_SERVICE_REPLICATION where SECONDARY_SITE_NAME = (select distinct SECONDARY_SITE_NAME from SYS.M_SERVICE_REPLICATION WHERE REPLICATION_STATUS != 'ACTIVE')" ++ local all_cluster_hosts all_secondary_hosts all_broken_secondaries ++# ++##################################################################################################### ++# ++# select distinct SITE_NAME, HOST, REPLICATION_STATUS, SECONDARY_SITE_NAME, SECONDARY_HOST from SYS.M_SERVICE_REPLICATION ++# ++# ===> "Walldorf", "sap-app-8" "ACTIVE", "Rot", "sap-app-5" ++# "Rot", "sap-app-5", "ACTIVE", "oslo", "sap-app-7" ++# ++##################################################################################################### ++# ++ secUser=$(check_secstore_users SAPHANA${SID}SR SLEHALOC RHELHALOC) ; chkusr=$? ++ if [ $chkusr -ne 0 ]; then ++ super_ocf_log err "ACT: Secure store users are missing (see best practice manual how to setup the users)" ++ rc=$OCF_ERR_CONFIGURED ++ fi ++ hana_sync_status=$(timeout 60 $DIR_EXECUTABLE/hdbsql -a -x -U $secUser $query_state); sqlrc=$? ++ hana_sync_status=$(echo $hana_sync_status | dequote) ++ super_ocf_log debug "DBG: hdbsql rc=$sqlrc hana_sync_status=\"$hana_sync_status\"" ++ if [ "$sqlrc" -eq 0 -a "$hana_sync_status" != "" ]; then ++ # ++ # UNKNOWN, ACTIVE, ERROR, INITIALIZING ++ # ++ if [ "${hana_sync_status}" == "ACTIVE" ]; then ++ # TODO PRIO1: REMOVE remoteNode dependency - set SOK ++ set_hana_attribute "$remoteNode" "SOK" ${ATTR_NAME_HANA_SYNC_STATUS[@]} ++ else ++ super_ocf_log warn "ACT: HANA SYNC STATUS is: ${hana_sync_status}" ++ # TODO PRIO1: REMOVE remoteNode dependency - set SFAIL ++ set_hana_attribute "$remoteNode" "SFAIL" ${ATTR_NAME_HANA_SYNC_STATUS[@]} ++ fi ++ # first get a list of all secondary hosts, than a list of all secondary hosts, if the is ANY failure at this site ++ # TODO: PRIO9: for first we assume there is only ONE secondary site (like ROT) ++ # TODO: PRIO3: should we loop over all cluster nodes fetching their roles-attribute? To minimize sql-queries? ++ # ++ all_secondary_hosts=$(timeout 60 hdbsql -a -x -U $secUser $query_secondaries ); sqlrc=$? ++ all_secondary_hosts=$(echo $all_secondary_hosts | dequote); ++ if [ "$sqlrc" -eq 0 ]; then ++ all_broken_secondary_hosts=$(timeout 60 hdbsql -a -x -U $secUser $query_failed_secondaries); sqlrc=$? ++ all_broken_secondary_hosts=$(echo $all_broken_secondary_hosts | dequote); ++ if [ "$sqlrc" -eq 0 ]; then ++ if [ -n "$all_broken_secondary_hosts" ]; then ++ # ++ # we have a broken secondary site - set all hosts to "SFAIL" ++ # ++ # Note: since HANA hostname can be different from nodename we need to check all vhost attributes ++ for n in $all_broken_secondary_hosts; do ++ for cl in ${otherNodes[@]}; do ++ vHost=$(get_hana_attribute $cl ${ATTR_NAME_HANA_VHOST[@]}) ++ if [ "$vHost" = "$n" ]; then # we found the correct node ++ set_hana_attribute $cl "SFAIL" ${ATTR_NAME_HANA_SYNC_STATUS[@]} ++ fi ++ done ++ done ++ fi ++ fi ++ fi ++ else ++ # return codes 19: license error -> set SFAIL! ++ case "$sqlrc" in ++ 19 ) ++ # DONE: PRIO1: We should NOT set SFAIL, if HDB is exactly broken now ++ # When HDB breaks during monitor this could prevent a prositive remote failover ++ super_ocf_log warn "ACT: Was not able to fetch HANA SYNC STATUS - set sync status to SFAIL for ALL OTHER cluster hosts" ++ for n in $otherNodes; do ++ set_hana_attribute "$n" "SFAIL" ${ATTR_NAME_HANA_SYNC_STATUS[@]} ++ done ++ ;; ++ esac ++ fi ++ return $rc ++} ++ ++# ++# function: get_hana_landscape_status - figure out hana ladscape status ++# params: - ++# globals: sidadm(r), DIR_EXECUTABLE(r) ++# ++function get_hana_landscape_status() ++{ ++ super_ocf_log info "FLOW $FUNCNAME ($*)" ++ local rc=0 ++ # ++ su - $sidadm -c "python $DIR_EXECUTABLE/python_support/landscapeHostConfiguration.py" 1>/dev/null 2>/dev/null; rc=$? ++ return $rc; ++} ++ ++# ++# function: register_hana_secondary - register local hana as secondary to the other site ++# params: - ++# globals: sidadm(r), remoteHost(r), InstanceNr(r), sr_mode(r), sr_name(r) ++# register_hana_secondary ++# ++function register_hana_secondary() ++{ ++ super_ocf_log info "FLOW $FUNCNAME ($*)" ++ local rc=2; ++ local remoteInstance=""; ++ remoteInstance=$InstanceNr ++ if ocf_is_true ${AUTOMATED_REGISTER}; then ++ super_ocf_log info "ACT: REGISTER: hdbnsutil -sr_register --remoteHost=$remoteHost --remoteInstance=$remoteInstance --mode=$sr_mode --name=$sr_name" ++ su - $sidadm -c "hdbnsutil -sr_register --remoteHost=$remoteHost --remoteInstance=$remoteInstance --mode=$sr_mode --name=$sr_name"; rc=$? ++ else ++ super_ocf_log info "ACT: IGNORE REGISTER because AUTOMATED_REGISTER is set to FALSE" ++ rc=1 ++ fi ++ super_ocf_log info "FLOW $FUNCNAME rc=$rc" ++ return $rc; ++} ++ ++# ++# function: saphana_status - pure status check ++# params: - ++# globals: SIDInstanceName, OCF_*, ++function saphana_status() { ++ local binDeam="hdb.sap${SIDInstanceName}" rc=0 ++ binDeam=${binDeam:0:15} # Process name is limited to the first 15 characters ++ if pgrep $binDeam 1>/dev/null; then rc=$OCF_SUCCESS; else rc=$OCF_NOT_RUNNING; fi ++ return $rc ++} ++ ++# ++# function: saphana_start - start a hana instance ++# params: - ++# globals: OCF_*, SAPCONTROL, InstanceNr, SID, InstanceName, ++# ++function saphana_start() { ++ super_ocf_log info "FLOW $FUNCNAME ($*)" ++ local rc=$OCF_NOT_RUNNING ++ local output="" ++ local loopcount=0 ++ check_sapstartsrv ++ rc=$? ++ # ++ # TODO: ASK: PRIO5: For SCALE-OUT - do we need to use an other call like StartSystem? Or better to use the HDB command? ++ # ++ if [ $rc -eq $OCF_SUCCESS ]; then ++ output=$($SAPCONTROL -nr $InstanceNr -function Start) ++ rc=$? ++ super_ocf_log info "ACT: Starting SAPHANA Instance $SID-$InstanceName: $output" ++ fi ++ if [ $rc -eq 0 ] ++ then ++ # TODO: PRIO9: something more dynamic than 3600 seconds in WaitforStarted ++ output=$($SAPCONTROL -nr $InstanceNr -function WaitforStarted 3600 1) ++ if [ $? -eq 0 ] ++ then ++ super_ocf_log info "ACT: SAPHANA Instance $SID-$InstanceName started: $output" ++ rc=$OCF_SUCCESS ++ else ++ super_ocf_log err "ACT: SAPHANA Instance $SID-$InstanceName start failed: $output" ++ rc=$OCF_ERR_GENERIC ++ fi ++ else ++ super_ocf_log err "ACT: SAPHANA Instance $SID-$InstanceName start failed: $output" ++ rc=$OCF_ERR_GENERIC ++ fi ++ super_ocf_log info "FLOW $FUNCNAME rc=$rc" ++ return $rc ++} ++ ++# ++# function: saphana_stop - stop a hana instance ++# params: - ++# globals: OCF_*(r), SAPCONTROL(r), SID(r), InstanceName(r) ++# saphana_stop: Stop the SAP instance ++# ++function saphana_stop() { ++ super_ocf_log info "FLOW $FUNCNAME ($*)" ++ local output="" ++ local rc=0 ++ check_sapstartsrv; rc=$? ++ if [ $rc -eq $OCF_SUCCESS ]; then ++ output=$($SAPCONTROL -nr $InstanceNr -function Stop) ++ rc=$? ++ super_ocf_log info "ACT: Stopping SAP Instance $SID-$InstanceName: $output" ++ fi ++ if [ $rc -eq 0 ] ++ then ++ output=$($SAPCONTROL -nr $InstanceNr -function WaitforStopped 3600 1) ++ if [ $? -eq 0 ] ++ then ++ super_ocf_log info "ACT: SAP Instance $SID-$InstanceName stopped: $output" ++ rc=$OCF_SUCCESS ++ else ++ super_ocf_log err "ACT: SAP Instance $SID-$InstanceName stop failed: $output" ++ rc=$OCF_ERR_GENERIC ++ fi ++ else ++ super_ocf_log err "ACT: SAP Instance $SID-$InstanceName stop failed: $output" ++ rc=$OCF_ERR_GENERIC ++ fi ++ super_ocf_log info "FLOW $FUNCNAME rc=$rc" ++ return $rc ++} ++ ++# ++# function: saphana_validate - validation of (some) variables/parameters ++# params: - ++# globals: OCF_*(r), SID(r), InstanceName(r), InstanceNr(r), SAPVIRHOST(r) ++# saphana_validate: Check the symantic of the input parameters ++# ++function saphana_validate() { ++ super_ocf_log info "FLOW $FUNCNAME ($*)" ++ local rc=$OCF_SUCCESS ++ # ++ # SID is Alpha-AlphaNumeric-Alphanumeric? ++ # ++ if [ $(echo "$SID" | grep -c '^[A-Z][A-Z0-9][A-Z0-9]$') -ne 1 ] ++ then ++ super_ocf_log err "ACT: Parsing instance profile name: '$SID' is not a valid SID!" ++ rc=$OCF_ERR_ARGS ++ fi ++ # ++ # InstanceNr is a two-Digit? ++ # ++ if [ $(echo "$InstanceNr" | grep -c '^[0-9][0-9]$') -ne 1 ] ++ then ++ super_ocf_log err "ACT: Parsing instance profile name: '$InstanceNr' is not a valid instance number!" ++ rc=$OCF_ERR_ARGS ++ fi ++ super_ocf_log info "FLOW $FUNCNAME rc=$rc" ++ return $rc ++} ++ ++# ++# function: saphana_start_primary - handle startup of PRIMARY in M/S ++# params: ++# globals: OCF_*(r), NODENAME, ATTR_NAME_*, HANA_STATE_*, ++# ++function saphana_start_primary() ++{ ++ super_ocf_log info "FLOW $FUNCNAME ($*)" ++ local primary_status sync_attr score_master rc=$OCF_NOT_RUNNING ++ local lss sqlrc; ++ local rc=0 ++ local lpa_dec=4 ++ local lpa_advice="" ++ # ++ # we will be a master (PRIMARY) so checking, if the is an OTHER master ++ # ++ super_ocf_log debug "DBG: saphana_primary - check_for_primary reports HANA_STATE_PRIMARY" ++ # ++ lpa_init_lpt $HANA_STATE_PRIMARY ++ lpa_check_lpt_status; lpa_dec=$? ++ get_hana_landscape_status; lss=$? ++ my_role=$(get_hana_attribute ${NODENAME} ${ATTR_NAME_HANA_ROLES[@]}) ++ my_sync=$(get_hana_attribute ${NODENAME} ${ATTR_NAME_HANA_SYNC_STATUS[@]}) ++ case "$lpa_dec" in ++ 0 ) # LPA says start-up ++ lpa_advice="start" ++ ;; ++ 1) # LPA says register! ++ lpa_advice="register" ++ ;; ++ 2) # LPA says wait for second LPT ++ lpa_advice="wait" ++ ;; ++ 3 | 4 ) # LPA says something is completely wrong - FAIL resource ++ lpa_advice="fail" ++ ;; ++ * ) # LPA failed with an unkonown status - FAIL resource ++ lpa_advice="fail" ++ ;; ++ esac ++ ++ # DONE: PRIO2: Do we need to differ 0 and 1 here? While 0 is a fatal SAP error, 1 for down/error ++ if [ $lss -eq 0 ]; then ++ super_ocf_log err "ACT: get_hana_landscape_status reports FATAL" ++ # DONE: PRIO1: what to do for lss=0? ++ # TODO: PRIO3: Check, if OCF_ERR_GENERIC is best reaction ++ lpa_advice="skip" ++ rc=$OCF_ERR_GENERIC ++ fi ++ case "$lpa_advice" in ++ start ) # process a normal START ++ case "$lss" in ++ 2 | 3 | 4 ) # as landcape says we are up - just set the scores and return code ++ super_ocf_log info "LPA: landcape: UP, LPA: start ==> keep running" ++ LPTloc=$(date '+%s') ++ lpa_set_lpt $LPTloc ++ rc=$OCF_SUCCSESS ++ ;; ++ 1 ) # landcape says we are down, lets start and adjust scores and return code ++ super_ocf_log info "LPA: landcape: DOWN, LPA: start ==> start instance" ++ saphana_start ++ rc=$? ++ LPTloc=$(date '+%s') ++ lpa_set_lpt $LPTloc ++ ;; ++ esac ++ scoring_crm_master "$my_role" "$my_sync" ++ ;; ++ register ) # process a REGISTER ++ case "$lss" in ++ 2 | 3 | 4 ) # upps we are up - but shoudn't? - we could not register with started HDB ++ # DONE: PRIO3: check if this reaction is correct - tell cluster about failed start ++ super_ocf_log info "LPA: landcape: UP, LPA: register ==> take down" ++ set_crm_master -inf ++ rc=$OCF_NOT_RUNNING ++ ;; ++ 1 ) # lets try to register ++ # DONE: PRIO2: Like Action in start_secondary ++ super_ocf_log info "LPA: landcape: DOWN, LPA: register ==> try to register" ++ super_ocf_log info "DEC: AN OTHER HANA IS AVAILABLE ==> LETS REGISTER" ++ set_crm_master 0 ++ if wait_for_primary_master 1; then ++ register_hana_secondary ++ check_for_primary; primary_status=$? ++ if [ $primary_status -eq $HANA_STATE_SECONDARY ]; then ++ super_ocf_log info "ACT: Register successful" ++ lpa_push_lpt 10 ++ lpa_set_lpt 10 ++ set_crm_master 0 ++ saphana_start_secondary ++ rc=$? ++ lpa_set_lpt 30 ++ else ++ super_ocf_log err "ACT: Register failed" ++ rc=$OCF_NOT_RUNNING ++ fi ++ else ++ # lets check next monitor, if we can register ++ rc=$OCF_SUCCESS ++ fi ++ ;; ++ esac ++ ;; ++ wait ) # process a WAIT ++ case "$lss" in ++ 2 | 3 | 4 ) # as we ARE up we just keep it up ++ # TODO: PRIO3: I now change from "just keep it up to take that down" ++ # TODO: PRIO3: OCF_SUCCSESS, OCF_NOT_RUNNING or OCF_ERR_xxxx ? ++ set_crm_master -9000 ++ #scoring_crm_master "$my_role" "$my_sync" ++ rc=$OCF_ERR_GENERIC ++ ;; ++ 1 ) # we are down, so we should wait --> followup in next monitor ++ super_ocf_log info "LPA: landcape: DOWN, LPA: wait ==> keep waiting" ++ # TODO: PRIO3: Check, if WAITING is correct here ++ set_hana_attribute ${NODENAME} "WAITING" ${ATTR_NAME_HANA_CLONE_STATE[@]} ++ set_crm_master -9000 ++ rc=$OCF_SUCCSESS ++ ;; ++ esac ++ ;; ++ fail ) # process a lpa FAIL ++ super_ocf_log info "LPA: LPA reports FAIL" ++ set_crm_master -inf ++ rc=$OCF_NOT_RUNNING ++ ;; ++ esac ++ super_ocf_log info "FLOW $FUNCNAME rc=$rc" ++ return $rc ++} ++ ++# ++# check_for_primary_master ++# params: - ++# globals: ATTR_NAME_HANA_ROLES[@], NODENAME ++# ++check_for_primary_master() ++{ ++ super_ocf_log info "FLOW $FUNCNAME ($*)" ++ local rc=1 ++ local ch ch_role ++ # ++ # get actual list of cluster members ++ # ++ if [ -n "$otherNodes" ]; then ++ for ch in ${otherNodes[@]}; do ++ if [ $rc -eq 1 ]; then ++ ch_role=$(get_hana_attribute ${ch} ${ATTR_NAME_HANA_ROLES[@]}) ++# TODO: PRIO3: check if [0-9], [234] or [34] is correct ++# TODO: PRIO4: Do we need different checks like "any-primary-master" or "running-primary-master" ? ++# grep '[0-9]*:P:[^:]*:master:' <<< $ch_role && rc=0 ++# grep '[34]:P:[^:]*:master:' <<< $ch_role && rc=0 ++# Match "Running+Available Primary" Master -> Match field 1: 3/4, 2: P, 4: master ++ awk -F: 'BEGIN { rc=1 } ++ $1 ~ "[34]" && $2 ="P" && $4="master" { rc=0 } ++ END { exit rc }' <<< $ch_role ; rc=$? ++ fi ++ done ++ fi ++ super_ocf_log info "FLOW $FUNCNAME rc=$rc" ++ return $rc ++} ++ ++# ++# wait_for_primary_master: wait some time till a running primary master is shown in attributes ++# params: optional: loop count - currently time in 10s waiting loop ++# globals: - ++# ++wait_for_primary_master() ++{ ++ local wait=1 ++ local rc=1 ++ local loops=${1:-0} ++ local count=0 ++ super_ocf_log info "FLOW $FUNCNAME ($*)" ++ # ++ # hana_ndb_roles=primary:master1:master:worker:master ++ # ++ while [ "$wait" -eq 1 ]; do ++ if check_for_primary_master; then ++ wait=0 ++ rc=0 ++ else ++ if [ $loops -gt 0 ]; then ++ (( count++ )) ++ if [ $count -gt $loops ]; then ++ wait=0 ++ rc=1 ++ fi ++ fi ++ sleep 10 ++ fi ++ done ++ super_ocf_log info "FLOW $FUNCNAME rc=$rc" ++ return $rc ++} ++ ++# ++# function: saphana_start_secondary - handle startup of PRIMARY in M/S ++# params: ++# globals: OCF_*(r), NODENAME, ATTR_NAME_*, ++# ++function saphana_start_secondary() ++{ ++ super_ocf_log info "FLOW $FUNCNAME ($*)" ++ local primary_status sync_attr score_master rc=$OCF_NOT_RUNNING ++ local sqlrc; ++ set_crm_master 0 ++ # ++ ####### LPA - begin ++ # ++ lpa_push_lpt 10 ++ lpa_set_lpt 10 ++ # ++ ####### LPA - end ++ # ++ # ++ # we would be slave (secondary) ++ # we first need to check, if there are Master Nodes, because the Scecondary only starts ++ # successfuly, if the Primary is available. Thatfore we mark the Secondary as "WAITING" ++ # DONE: PRIO3: wait_for_primary_master 10 is just a test value: 10 loops x10 seconds than go to WAITING ++ # DONE: PRIO3: rename 'wait_for_primary_master' to match better the use case ("wait_some_time") ++ # ++ super_ocf_log debug "DBG: wait for promoted side" ++ # TODO: PRIO3: Check if setting SFAIL during secondary start is ok ++ set_hana_attribute "${NODENAME}" "SFAIL" ${ATTR_NAME_HANA_SYNC_STATUS[@]} ++ if wait_for_primary_master 10; then ++ saphana_start; rc=$? ++ if [ $rc -ne $OCF_SUCCESS ]; then ++ if ! wait_for_primary_master 1; then ++ # It seams the stating secondary could not start because of stopping primary ++ # so this is a WAITING situation ++ super_ocf_log info "ACT: PRIMARY seams to be down now ==> WAITING" ++ set_hana_attribute ${NODENAME} "WAITING" ${ATTR_NAME_HANA_CLONE_STATE[@]} ++ set_crm_master -INFINITY ++ rc=$OCF_SUCCSESS ++ fi ++ else ++ lpa_set_lpt 30 ++ fi ++ else ++ super_ocf_log info "ACT: wait_for_primary_master ==> WAITING" ++ set_hana_attribute ${NODENAME} "WAITING" ${ATTR_NAME_HANA_CLONE_STATE[@]} ++ set_crm_master -INFINITY ++ rc=$OCF_SUCCSESS ++ fi ++ super_ocf_log info "FLOW $FUNCNAME rc=$rc" ++ return $rc ++} ++ ++# ++# function: lpa_get_lpt - get lpt from cluster ++# params: NODE ++# output: LPT ++# rc: rc=0: OK, rc=1: InternalERROR, rc=2: ERROR ++# globals: LPA_ATTR_*, ++# ++function lpa_get_lpt() { ++ super_ocf_log info "FLOW $FUNCNAME ($*)" ++ local rc=1 ++ local node=$1 ++ local lpt="" ++ lpt=$(get_hana_attribute ${node} ${LPA_ATTR[@]}) ++ if [ -n "$lpt" ]; then ++ rc=0 ++ echo $lpt ++ else ++ rc=2 ++ fi ++ super_ocf_log info "FLOW $FUNCNAME rc=$rc" ++ return $rc ++} ++ ++# ++# function: lpa_set_lpt - set lpt in cluster ++# params: LPT [node] ++# globals: LPA_ATTR(r), NODENAME(r), ++# rc: rc=0: OK, rc=1: InternalERROR, rc=2: ERROR ++# ++function lpa_set_lpt() { ++ super_ocf_log info "FLOW $FUNCNAME ($*)" ++ local rc=1 ++ local crm_rc=1 ++ local lpt=$1 ++ local clpt=-1 ++ local node=${2:-${NODENAME}} ++ set_hana_attribute ${node} "$lpt" ${LPA_ATTR[@]}; crm_rc=$? ++ clpt=$(lpa_get_lpt $NODENAME) ++ if [ "$lpt" != "$clpt" ]; then ++ rc=2 ++ else ++ rc=0 ++ fi ++ super_ocf_log info "FLOW $FUNCNAME rc=$rc" ++ return $rc ++} ++ ++# ++# function: lpa_pull_lpt - fetch lpt from file ++# params: - ++# globals: LPA_DIRECTORY(r), sid, NODENAME ++# output: LPT ++# rc: rc=0: OK, rc=1: InternalERROR, rc=2: ERROR ++# ++function lpa_pull_lpt() { ++ super_ocf_log info "FLOW $FUNCNAME ($*)" ++ local rc=1 ++ local lpt="" ++ local readrest=0 ++ local lpa_file=$LPA_DIRECTORY/lpa_${sid}_${NODENAME} ++ if [ -f $lpa_file ]; then ++ read lpt readrest <<<$(cat $lpa_file) # exactly load first word from file to lpt ++ fi ++ if [ -n "$lpt" ]; then ++ rc=0 ++ echo $lpt ++ else ++ rc=2 ++ fi ++ super_ocf_log info "FLOW $FUNCNAME rc=$rc" ++ return $rc ++} ++ ++# ++# function: lpa_push_lpt - put lpt to file ++# params: LPT ++# globals: LPA_DIRECTORY(r), sid, NODENAME ++# output: -- ++# rc: rc=0: OK, rc=1: InternalERROR, rc=2: ERROR ++# ++function lpa_push_lpt() { ++ super_ocf_log info "FLOW $FUNCNAME ($*)" ++ local lpt=$1 ++ local clpt=-1 ++ local rc=1 ++ local lpa_file=$LPA_DIRECTORY/lpa_${sid}_${NODENAME} ++ # ++ mkdir -p $LPA_DIRECTORY ++ echo "$lpt" > $lpa_file ++ clpt=$(lpa_pull_lpt); lpt_rc=$? ++ if [ "$clpt" != "$lpt" -o "$lpt_rc" -ne 0 ]; then ++ rc=2 ++ else ++ rc=0 ++ fi ++ super_ocf_log info "FLOW $FUNCNAME rc=$rc" ++ return $rc ++} ++ ++# ++# function: lpa_init_lpt - initialize local lpt, if needed ++# params: HANA_STATE ++# globals: HANA_STATE_*(r), LPA_DIRECTORY(r), sid(r), NODENAME(r), ++# lpa_init_lpt ++# ++# Returncodes: ++# rc=0: OK, rc=1 InternalERROR, rc=2: ERROR ++# ++# Initializing (if NO local LPT-file): ++# SECONDARY sets to 0 ++# PRIMARY sets to 1 ++# ++function lpa_init_lpt() { ++ super_ocf_log info "FLOW $FUNCNAME ($*)" ++ local rc=1 ++ local LPTloc=-1 ++ local LPTrem=-1 ++ local hana_state=$1 ++ local lpa_file=$LPA_DIRECTORY/lpa_${sid}_${NODENAME} ++ mkdir -p $LPA_DIRECTORY ++ LPTloc=$(lpa_get_lpt ${NODENAME}) || LPTloc=$(lpa_pull_lpt) || \ ++ if [ "$hana_state" -eq "$HANA_STATE_PRIMARY" ]; then # Initialize for Primary ++ # init primary ++ LPTloc=20 ++ lpa_push_lpt "20"; rc=$? ++ elif [ "$hana_state" -eq "$HANA_STATE_SECONDARY" ]; then # Initialize for Secondary ++ # init secondary ++ LPTloc=10 ++ lpa_push_lpt "10"; rc=$? ++ else ++ rc=2 ++ fi ++ lpa_set_lpt $LPTloc ++ super_ocf_log info "FLOW $FUNCNAME rc=$rc" ++ return $rc ++} ++ ++# ++# function: lpa_check_lpt_status - start a hana clone instance ++# params: - ++# globals: DUPLICATE_PRIMARY_TIMEOUT, NODENAME, remoteNode ++# lpa_check_lpt_status ++# ++# Returncodes: ++# ++# Initializing (if NO local LPT-file): ++# SECONDARY sets to 10 ++# PRIMARY sets to 20 ++# ++# LPRlocal OR LPTremore ARE real lpt (>1000) ++# THEN: ++# Bigger LPR wins, if delta-gab is OK ++# LPTlocal >> LPTremore ===> rc=0 (start) ++# LPTRemote >> LPTlocal ===> rc=1 (register) ++# Stalemate in all other cases ==> STALEMATE-HANDLING ===> rc=2 (wait) ++# LPRlocal AND LPTremore ARE NOT real lpt (<=1000) ++# THEN: ++# Bigger LPT wins ++# LPTlocal > LPTremore ===> rc=0 (start) ++# LPTRemote > LPTlocal ===> rc=1 (register) ++# Stalemate in all other cases ==> STALEMATE-HANDLING ===> rc=2 (wait) ++# LPTRemote is not initialized (0) ++# THEN: ++# WAIT ==> like STALEMATE-HANDLING ===> rc=2 (wait) ++# ++function lpa_check_lpt_status() { ++ super_ocf_log info "FLOW $FUNCNAME ($*)" ++ local rc=0 ++ local LPTloc=-1 ++ local LPTrem=-1 ++ local LPTMark=1000 ++ local delta=0 ++ # ++ # First GET LPT from ATTR-FILE-DEFAULT ++ # ++ LPTloc=$(lpa_get_lpt $NODENAME); lparc=$? # ATTR ++ if [ "$lparc" -ne 0 ]; then ++ # as a fallback try to fetch the value from external status file ++ LPTloc=$(lpa_pull_lpt); # FILE ++ lparc=$? ++ if [ -z "$LPTloc" -o "$LPTloc" -eq -1 -o "$lparc" -ne 0 ]; then ++ # last option - try to initialize as PRIMARY ++ lpa_push_lpt 20 ++ lpa_set_lpt 20 ++ LPTloc=20 # DEFAULT ++ fi ++ fi ++ # TODO PRIO1: REMOVE remoteNode dependency - lpa_get_lpt ++ LPTrem=$(lpa_get_lpt $remoteNode); lparc=$? ++ if [ $lparc -ne 0 ]; then ++ # LPT of the other node could not be evaluated - LPA says WAIT ++ super_ocf_log debug "DBG: LPA: LPTloc=$LPTloc, LPTrem undefined ==> WAIT" ++ rc=2 ++ else ++ super_ocf_log debug "DBG: LPA: LPTloc ($LPTloc) LPTrem ($LPTrem) delta ($delta)" ++ if [ $LPTloc -lt $LPTMark -a $LPTrem -lt $LPTMark ]; then ++ delta=0 # both lpts are not a real timestamp so just take the greater one ++ else ++ delta=$DUPLICATE_PRIMARY_TIMEOUT # at least one of the lpts is a real timestamp so include delta-gap ++ fi ++ if (( delta < LPTloc - LPTrem )); then ++ # We are the winner - LPA says STARTUP ++ super_ocf_log debug "DBG: LPA: LPTloc wins $LPTloc > $LPTrem + $delta ==> START" ++ rc=0 ++ elif (( delta < LPTrem - LPTloc )); then ++ if ocf_is_true "$AUTOMATED_REGISTER" ; then ++ # The other one has won - LPA says REGISTER ++ super_ocf_log debug "DBG: LPA: LPTrem wins $LPTrem > $LPTloc + $delta ==> REGISTER" ++ rc=1 ++ else ++ super_ocf_log debug "DBG: LPA: LPTrem wins $LPTrem > $LPTloc + $delta BUT AUTOMATED_REGISTER='false' ==> WAIT" ++ rc=2 ++ fi ++ ++ else ++ super_ocf_log debug "DBG: LPA: Difference between LPTloc and LPTrem is less than delta ($delta) ==> WAIT" ++ # TODO: PRIO3: ADD STALEMATE-HANDLING HERE; currently admin should set one of the lpa to 20 ++ rc=2 ++ fi ++ fi ++ super_ocf_log info "FLOW $FUNCNAME rc=$rc" ++ return $rc ++} ++ ++# ++# function: saphana_start_clone - start a hana clone instance ++# params: - ++# globals: OCF_*, ATTR_NAME_*, HANA_STATE_*, NODENAME ++# saphana_start_clone ++# ++function saphana_start_clone() { ++ super_ocf_log info "FLOW $FUNCNAME ($*)" ++ local primary_status sync_attr score_master rc=$OCF_NOT_RUNNING ++ local sqlrc; ++ local chkusr; ++ # TODO: PRIO4: remove check_secstore_users later ++ secUser=$(check_secstore_users SAPHANA${SID}SR SLEHALOC RHELHALOC) ; chkusr=$? ++ if [ $chkusr -ne 0 ]; then ++ super_ocf_log err "ACT: Secure store users are missing (see best practice manual how to setup the users)" ++ rc=$OCF_ERR_CONFIGURED ++ else ++ set_hana_attribute ${NODENAME} "DEMOTED" ${ATTR_NAME_HANA_CLONE_STATE[@]} ++ check_for_primary; primary_status=$? ++ if [ $primary_status -eq $HANA_STATE_PRIMARY ]; then ++ saphana_start_primary; rc=$? ++ else ++ saphana_start_secondary; rc=$? ++ lpa_set_lpt 30 ++ fi ++ fi ++ return $rc ++} ++ ++# ++# function: saphana_stop_clone - stop a hana clone instance ++# params: - ++# globals: NODENAME(r), HANA_STATE_*(r) ++# saphana_stop_clone ++# ++function saphana_stop_clone() { ++ super_ocf_log info "FLOW $FUNCNAME ($*)" ++ local rc=0 ++ local primary_status="x" ++ set_hana_attribute ${NODENAME} "UNDEFINED" ${ATTR_NAME_HANA_CLONE_STATE[@]} ++ check_for_primary; primary_status=$? ++ if [ $primary_status -eq $HANA_STATE_SECONDARY ]; then ++ lpa_set_lpt 10 ++ fi ++ saphana_stop; rc=$? ++ return $rc ++} ++ ++# ++# function: saphana_monitor_primary - monitor a hana clone instance ++# params: - ++# globals: HANA_STATE_*(r), remoteHost, NODENAME, ATTR_NAME_*, OCF_*, PreferSiteTakeover ++# ++function saphana_monitor_primary() ++{ ++ super_ocf_log info "FLOW $FUNCNAME ($*)" ++ local rc=$OCF_ERR_GENERIC ++ local promoted=0 ++ local init_attribute=0 ++ local LPTloc=-1 ++ local lparc=4 ++ local lss ++ local remoreSync="" ++ local my_role="" ++ # ++ # OK, we are running/are configured as HANA PRIMARY ++ # ++ super_ocf_log debug "DBG: saphana_monitor_clone: HANA_STATE_PRIMARY" ++ # ++ ##### CHECK, IF WE ARE DEMOTED (CLUSTER NODE ATTRIBUTE) ++ # ++ promote_attr=$(get_hana_attribute ${NODENAME} ${ATTR_NAME_HANA_CLONE_STATE[@]}) ++ super_ocf_log debug "DBG: saphana_monitor_clone: $ATTR_NAME_HANA_CLONE_STATE=$promote_attr" ++ if [ -z "$promote_attr" ]; then ++ init_attribute=1 ++ promoted=0; ++ else ++ case "$promote_attr" in ++ PROMOTED ) ++ promoted=1; ++ ;; ++ DEMOTED ) ++ promoted=0; ++ ;; ++ WAITING ) ++ # DONE: lpa_check_lpt_status to come out of here :) ++ # DONE: PRIO2: CHECK IF THE FIX FOR COMING OUT OF WAITING IS CORRECT ++ get_hana_landscape_status; lss=$? ++ if [ $lss -ge 2 ]; then ++ # seems admin already decided that for us? -> we are running - set DEMOTED ++ promoted=0; ++ LPTloc=$(date '+%s') ++ lpa_set_lpt $LPTloc ++ fi ++ lpa_check_lpt_status; lparc=$? ++ if [ $lparc -ne 2 ]; then ++ # lpa - no need to wait any longer - lets try a new start ++ saphana_start_clone ++ rc=$? ++ super_ocf_log info "FLOW $FUNCNAME rc=$rc" ++ return $rc ++ else ++ lpa_init_lpt $HANA_STATE_PRIMARY ++ # still waiting for second site to report lpa-lpt ++ if ocf_is_true "$AUTOMATED_REGISTER" ; then ++ super_ocf_log info "LPA: Still waiting for remote site to report LPA status" ++ else ++ super_ocf_log info "LPA: Dual primary detected and AUTOMATED_REGISTER='false' ==> WAITING" ++ fi ++ ++ return $OCF_SUCCESS ++ fi ++ promoted=0; ++ ;; ++ UNDEFINED ) ++ if ocf_is_probe; then ++ promoted=0; ++ else ++ set_hana_attribute ${NODENAME} "DEMOTED" ${ATTR_NAME_HANA_CLONE_STATE[@]} ++ promoted=0; ++ fi ++ ;; ++ * ) ++ promoted=0; ++ ;; ++ esac ++ fi ++ get_hana_landscape_status; lss=$? ++ super_ocf_log debug "DBG: saphana_monitor_clone: get_hana_landscape_status=$lss" ++ case "$lss" in ++ 0 ) # FATAL or ERROR ++ rc=$OCF_ERR_GENERIC ++ ;; ++ 1 ) # DOWN or ERROR ++ # DONE: PRIO2: Maybe we need to differ between 0 and 1. While 0 is a fatal sap error, 1 is down/error ++ if ocf_is_probe; then ++ # ++ # leave master score untouched, only set return code ++ # ++ rc=$OCF_NOT_RUNNING ++ else ++ if [ "$promoted" -eq 1 ]; then ++ # INSTANCE IS FAILED PRIMARY IN PROMOTED STATE ++ # DONE: PRIO2: Adjust with set_crm_master? ++ # For Migration it would be good to decrease master score ++ # For Reload locally we should NOT adjust the master score ++ # ===> Should we rely on the migration threshold? ++ # set_crm_master ++ if ocf_is_true "${PreferSiteTakeover}" ; then ++ # ++ # DONE: PRIO1: first check, if remote site is already (and still) in sync ++ # TODO: PRIO4: Decide if penality (-9000) or weak (5) is better here to cover situations where other clone is gone ++ # ++ # TODO PRIO1: REMOVE remoteNode dependency - get_sync_status ++ remoteSync=$(get_hana_attribute $remoteNode ${ATTR_NAME_HANA_SYNC_STATUS[@]}) ++ case "$remoteSync" in ++ SOK ) ++ super_ocf_log info "DEC: PreferSiteTakeover selected so decrease promotion score here (and reset lpa)" ++ set_crm_master 5 ++ if check_for_primary_master; then ++ lpa_set_lpt 20 ++ fi ++ ;; ++ SFAIL ) ++ super_ocf_log info "DEC: PreferSiteTakeover selected BUT remoteHost is not in sync (SFAIL) ==> local restart preferred" ++ ;; ++ * ) ++ super_ocf_log info "DEC: PreferSiteTakeover selected BUT remoteHost is not in sync ($remoteSync) ==> local restart preferred" ++ ;; ++ esac ++ else ++ # TODO: PRIO5: SCALE-OUT ONLY? Implement for local restart ++ # It maybe that for the local restart we only need to decrease the secondaries promotion score ++ #super_ocf_log info "DEC: PreferSiteTakeover selected so decrease promotion score here" ++ my_role=$(get_hana_attribute ${NODENAME} ${ATTR_NAME_HANA_ROLES[@]}) ++ my_sync=$(get_hana_attribute ${NODENAME} ${ATTR_NAME_HANA_SYNC_STATUS[@]}) ++ scoring_crm_master "$my_role" "$my_sync" ++ rc=$OCF_FAILED_MASTER ++ fi ++ rc=$OCF_FAILED_MASTER ++ else ++ # INSTANCE IS FAILED PRIMARY IN DEMOTED STATE ++ # TODO: PRIO3: Adjust with set_crm_master? ++ # Current decission: Do NOT adjust master score now as other ++ # steps should already have done that ++ # ++ rc=$OCF_NOT_RUNNING ++ fi ++ fi ++ ;; ++ 2 | 3 | 4 ) # WARN, INFO or OK ++ if ocf_is_probe; then ++ rc=$OCF_SUCCESS ++ else ++ LPTloc=$(date '+%s') ++ lpa_set_lpt $LPTloc ++ lpa_push_lpt $LPTloc ++ if [ "$promoted" -eq 1 ]; then ++ set_hana_attribute "$NODENAME" "PRIM" ${ATTR_NAME_HANA_SYNC_STATUS[@]} ++ rc=$OCF_RUNNING_MASTER ++ else ++ if [ "$init_attribute" -eq 1 ]; then ++ set_hana_attribute ${NODENAME} "DEMOTED" ${ATTR_NAME_HANA_CLONE_STATE[@]} ++ rc=$OCF_RUNNING_MASTER ++ else ++ rc=$OCF_SUCCESS ++ fi ++ fi ++ my_sync=$(get_hana_attribute ${NODENAME} ${ATTR_NAME_HANA_SYNC_STATUS[@]}) ++ my_role=$(get_hana_attribute ${NODENAME} ${ATTR_NAME_HANA_ROLES[@]}) ++ case "$my_role" in ++ [12]:P:*:master:* ) # primary is down or may not anser hdbsql query so drop analyze_hana_sync_status ++ ;; ++ [34]:P:*:master:* ) # primary is up and should now be able to anser hdbsql query ++ analyze_hana_sync_status ++ ;; ++ esac ++ rem_role=$(get_hana_attribute ${remoteHost} ${ATTR_NAME_HANA_ROLES[@]}) ++ rem_clone_status=$(get_hana_attribute ${remoteHost} ${ATTR_NAME_HANA_CLONE_STATE[@]}) ++ if [ "$promote_attr" = "DEMOTED" -a "$rem_clone_status" = "PROMOTED" ]; then ++ case "$rem_role" in ++ [234]:P:* ) # dual primary, but other instance marked as PROMOTED by the cluster ++ lpa_check_lpt_status; again_lpa_rc=$? ++ if [ $again_lpa_rc -eq 2 ]; then ++ super_ocf_log info "DEC: Dual primary detected, other instance is PROMOTED and lpa stalemate ==> local restart" ++ lpa_set_lpt 10 ++ lpa_push_lpt 10 ++ rc=$OCF_NOT_RUNNING ++ fi ++ ;; ++ esac ++ fi ++ scoring_crm_master "$my_role" "$my_sync" ++ fi ++ ;; ++ * ) # UNDEFINED STATUS ++ if ocf_is_probe; then ++ rc=$OCF_NOT_RUNNING ++ else ++ if [ "$promoted" -eq 1 ]; then ++ rc=$OCF_FAILED_MASTER ++ else ++ rc=$OCF_NOT_RUNNING ++ fi ++ fi ++ ;; ++ esac ++ super_ocf_log info "FLOW $FUNCNAME rc=$rc" ++ return $rc ++} ++ ++# ++# function: saphana_monitor_secondary - monitor a hana clone instance ++# params: - ++# globals: OCF_*, ATTR_NAME_*, NODENAME ++# saphana_monitor_secondary ++# ++function saphana_monitor_secondary() ++{ ++ super_ocf_log info "FLOW $FUNCNAME ($*)" ++ local rc=$OCF_ERR_GENERIC ++ local promoted=0 ++ local init_attribute=0 ++ local lss ++ # ++ # OK, we are running as HANA SECONDARY ++ # ++ if ! lpa_get_lpt ${NODENAME}; then ++ lpa_set_lpt 10 ++ lpa_push_lpt 10 ++ fi ++ promote_attr=$(get_hana_attribute ${NODENAME} ${ATTR_NAME_HANA_CLONE_STATE[@]}) ++ super_ocf_log debug "DBG: saphana_monitor_clone: $ATTR_NAME_HANA_CLONE_STATE=$promote_attr" ++ if [ -z "$promote_attr" ]; then ++ init_attribute=1 ++ # DONE: PRIO3: do we need to inizialize also the DEMOTED attribute value? ++ set_hana_attribute ${NODENAME} "DEMOTED" ${ATTR_NAME_HANA_CLONE_STATE[@]} ++ promoted=0; ++ else ++ case "$promote_attr" in ++ PROMOTED ) # However - PROMOTED should never happen for a SECONDARY ++ promoted=1; ++ ;; ++ DEMOTED ) # This is the status we expect ++ promoted=0; ++ ;; ++ WAITING* ) # We are WAITING for PRIMARY so not testing the HANA engine now but check for a new start ++ if check_for_primary_master; then ++ super_ocf_log info "ACT: SECONDARY still in status WAITING - Primary now available - try a new start" ++ saphana_start_clone ++ rc=$? ++ else ++ super_ocf_log info "ACT: saphana_monitor_clone: SECONDARY still in status WAITING - Primary is still missing" ++ return $OCF_SUCCESS ++ fi ++ promoted=0; ++ ;; ++ UNDEFINED | * ) ++ if ocf_is_probe; then ++ promoted=0; ++ else ++ set_hana_attribute ${NODENAME} "DEMOTED" ${ATTR_NAME_HANA_CLONE_STATE[@]} ++ promoted=0; ++ fi ++ ;; ++ esac ++ fi ++ # ++ super_ocf_log debug "DBG: saphana_monitor_clone: HANA_STATE_SECONDARY" ++ # ++ # old method was: saphana_monitor - new method is get_hana_landscape_status ++ get_hana_landscape_status; lss=$? ++ super_ocf_log debug "DBG: saphana_monitor_clone: get_hana_landscape_status=$lss" ++ case "$lss" in ++ 0 ) # FATAL ++ # DONE: PRIO1: Maybe we need to differ between 0 and 1. While 0 is a fatal sap error, 1 is down/error ++ # TODO: PRIO3: is OCF_ERR_GENERIC best option? ++ lpa_set_lpt 10 ++ rc=$OCF_ERR_GENERIC ++ ;; ++ 1 ) # ERROR ++ lpa_set_lpt 10 ++ rc=$OCF_NOT_RUNNING ++ ;; ++ 2 | 3 | 4 ) # WARN INFO OK ++ rc=$OCF_SUCCESS ++ lpa_set_lpt 30 ++ sync_attr=$(get_hana_attribute ${NODENAME} ${ATTR_NAME_HANA_SYNC_STATUS[@]}) ++ super_ocf_log debug "DBG: sync_attr=$sync_attr" ++ case "$sync_attr" in ++ "SOK" ) # This is a possible node to promote, when primary is missing ++ super_ocf_log info "DEC: secondary with sync status SOK ==> possible takeover node" ++ my_role=$(get_hana_attribute ${NODENAME} ${ATTR_NAME_HANA_ROLES[@]}) ++ my_sync=$(get_hana_attribute ${NODENAME} ${ATTR_NAME_HANA_SYNC_STATUS[@]}) ++ scoring_crm_master "$my_role" "$my_sync" ++ ;; ++ "SFAIL" ) # This is currently NOT a possible node to promote ++ super_ocf_log info "DEC: secondary with sync status FAILED ==> EXCLUDE as posible takeover node" ++ set_crm_master -INFINITY ++ ;; ++ "*" ) # Unknown sync status ++ super_ocf_log info "DEC: secondary with sync status UKNOWN/UNDEFINED ==> EXCLUDE as posible takeover node" ++ set_crm_master -INFINITY ++ ;; ++ esac ++ ;; ++ * ) # UNDEFINED STATUS ++ rc=$OCF_NOT_RUNNING ++ ;; ++ esac ++ super_ocf_log info "FLOW $FUNCNAME rc=$rc" ++ return $rc ++} ++ ++# ++# function: saphana_monitor_clone - monitor a hana clone instance ++# params: - ++# globals: OCF_*, ATTR_NAME_*, HOSTNANE, HANA_STATE_* ++# saphana_monitor_clone ++# ++function saphana_monitor_clone() { ++ super_ocf_log info "FLOW $FUNCNAME ($*)" ++ # ++ # TODO: PRIO3: For the secondary, which is missing the primary (so in status WAITING) what is better: ++ # a) returning 7 here and force cluster a restart of the slave ++ # b) starting the instance here inside the monitor -> may result in longer runtime, timeouts ++ # ++ # first check with the status function (OS tools) if there could be something like a SAP instance running ++ # as we do not know here, if we are in master or slave state we do not want to start our monitoring ++ # agents (sapstartsrv) on the wrong host ++ local rc=$OCF_ERR_GENERIC ++ local promoted=0 ++ local init_attribute=0 ++ ++ my_role=$(get_hana_attribute ${NODENAME} ${ATTR_NAME_HANA_ROLES[@]}) ++ my_sync=$(get_hana_attribute ${NODENAME} ${ATTR_NAME_HANA_SYNC_STATUS[@]}) ++ lpa_check_lpt_status # TODO: PRIO3 : remove that line later - its only to call lpa_check_lpt_status much more often for checking ++ ++ if ocf_is_probe; then ++ super_ocf_log debug "DBG: PROBE ONLY" ++ else ++ super_ocf_log debug "DBG: REGULAR MONITOR" ++ fi ++ # ++ # First check, if we are PRIMARY or SECONDARY ++ # ++ check_for_primary; primary_status=$? ++ if [ $primary_status -eq $HANA_STATE_PRIMARY ]; then ++ saphana_monitor_primary; rc=$? ++ else ++ if [ $primary_status -eq $HANA_STATE_SECONDARY ]; then ++ saphana_monitor_secondary; rc=$? ++ else ++ # ++ # OK, we are neither HANA PRIMARY nor HANA SECONDARY ++ # ++ super_ocf_log warn "ACT: saphana_monitor_clone: HANA_STATE_DEFECT" ++ # TODO: PRIO2: Or only set_crm_master -INFINITY ? ++ rc=$OCF_ERR_GENERIC ++ fi ++ fi ++ super_ocf_log info "FLOW $FUNCNAME rc=$rc" ++ return $rc ++} ++ ++# ++# function: saphana_promote_clone - promote a hana clone ++# params: - ++# globals: OCF_*(r), NODENAME(r), HANA_STATE_*, SID(r), InstanceName(r), ++# saphana_promote_clone: ++# In a Master/Slave configuration get Master being the primary OR by running hana takeover ++# ++function saphana_promote_clone() { ++ super_ocf_log info "FLOW $FUNCNAME ($*)" ++ local rc=$OCF_ERR_GENERIC; ++ local hana_sync; ++ local primary_status; ++ # ++ # first check, if we WILL be PRIMARY (checking HANA status) ++ # ++ set_hana_attribute ${NODENAME} "PROMOTED" ${ATTR_NAME_HANA_CLONE_STATE[@]} ++ check_for_primary; primary_status=$? ++ # ++ if [ $primary_status -eq $HANA_STATE_PRIMARY ]; then ++ # ++ # as we are already planned to be PRIMARY we only mark the node as PROMOTED ++ # ++ super_ocf_log info "ACT: Promoted $SID-$InstanceName as master (no hdbnsutil action needed)." ++ rc=$OCF_SUCCESS; ++ else ++ if [ $primary_status -eq $HANA_STATE_SECONDARY ]; then ++ # ++ # we are SECONDARY/SLAVE and need to takepover ... ++ # promote on the replica side... ++ # ++ hana_sync=$(get_hana_attribute ${NODENAME} ${ATTR_NAME_HANA_SYNC_STATUS[@]}) ++ case "$hana_sync" in ++ SOK ) ++ super_ocf_log info "ACT: !!!!!!! Promote REPLICA $SID-$InstanceName to be primary. !!!!!!" ++ LPTloc=$(date '+%s') ++ # lpa_set_lpt 20 $remoteNode ++ lpa_set_lpt $LPTloc ++ lpa_push_lpt $LPTloc ++ su - $sidadm -c "hdbnsutil -sr_takeover" ++ # ++ # now gain check, if we are primary NOW ++ # ++ # TODO: PRIO3: check, if we need to destinguish between HANA_STATE_PRIMARY, HANA_STATE_SECONDARY, HANA_STATE_DEFECT ++ # ++ if check_for_primary; then ++ rc=$OCF_SUCCESS; ++ else ++ rc=$OCF_FAILED_MASTER ++ fi ++ ;; ++ * ) ++ super_ocf_log err "ACT: HANA SYNC STATUS IS NOT 'SOK' SO THIS HANA SITE COULD NOT BE PROMOTED" ++ rc=$OCF_ERR_GENERIC ++ ;; ++ esac ++ else ++ # ++ # neither MASTER nor SLAVE - This clone instance seams to be broken!! ++ # ++ rc=$OCF_ERR_GENERIC ++ fi ++ fi ++ rc=$? ++ super_ocf_log info "FLOW $FUNCNAME rc=$rc" ++ return $rc ++} ++ ++# ++# function: saphana_demote_clone - demote a hana clone instance ++# params: - ++# globals: OCF_*(r), NODENAME(r), ++# saphana_demote_clone ++# the HANA System Replication (SR) runs in a Master/Slave ++# While we could not change a HANA instance to be really demoted, we only mark the status for ++# correct monitor return codes ++# ++function saphana_demote_clone() { ++ super_ocf_log info "FLOW $FUNCNAME ($*)" ++ local rc=$OCF_ERR_GENERIC; ++ set_hana_attribute ${NODENAME} "DEMOTED" ${ATTR_NAME_HANA_CLONE_STATE[@]} ++ rc=$OCF_SUCCESS; ++ super_ocf_log info "ACT: Demoted $SID-$InstanceName." ++ super_ocf_log info "FLOW $FUNCNAME rc=$rc" ++ return $rc ++} ++ ++# ++# function: main - main function to operate ++# params: ACTION ++# globals: OCF_*(r), SID(w), sidadm(w), InstanceName(w), SAPVIRHOST(w), DIR_EXECUTABLE(w), ++# globals: SAPSTARTSRV(w), SAPCONTROL(w), DIR_PROFILE(w), SAPSTARTPROFILE(w), ACTION(w), CLACT(w), ra_rc(rw), $0(r), %ENV(r) ++# ++ ++## GLOBALS ++SID="" ++sidadm="" ++InstanceName="" ++InstanceNr="" ++SAPVIRHOST="" ++DIR_EXECUTABLE="" ++SAPSTARTSRV="" ++SAPCONTROL="" ++DIR_PROFILE="" ++SAPSTARTPROFILE="" ++SAPHanaFilter="${OCF_RESKEY_SAPHanaFilter:-ra-act-dec-lpa}" ++ ++NODENAME=$(crm_node -n) ++ ++ ++if [ $# -ne 1 ] ++then ++ saphana_usage ++ exit $OCF_ERR_ARGS ++fi ++ ++ACTION=$1 ++if [ "$ACTION" = "status" ]; then ++ ACTION=monitor ++fi ++ ++# These operations don't require OCF parameters to be set ++# TODO: PRIO5: check, if notify is still not needing OCF parameters ++case "$ACTION" in ++ usage|methods) saphana_$ACTION ++ exit $OCF_SUCCESS;; ++ meta-data) saphana_meta_data ++ exit $OCF_SUCCESS;; ++ notify) #saphana_notify ++ exit $OCF_SUCCESS;; ++ *);; ++esac ++saphana_init ++ ++if ! ocf_is_root ++then ++ super_ocf_log err "ACT: $0 must be run as root" ++ exit $OCF_ERR_PERM ++fi ++ ++# parameter check ++if [ -z "$OCF_RESKEY_SID" ] ++then ++ super_ocf_log err "ACT: Please set parameter SID!" ++ exit $OCF_ERR_ARGS ++fi ++ ++if [ -z "$OCF_RESKEY_InstanceNumber" ] ++then ++ super_ocf_log err "ACT: Please set parameter InstanceNumber!" ++ exit $OCF_ERR_ARGS ++fi ++ ++if is_clone ++then ++ CLACT=_clone ++else ++ if [ "$ACTION" = "promote" -o "$ACTION" = "demote" ] ++ then ++ super_ocf_log err "ACT: $ACTION called in a non master/slave environment" ++ exit $OCF_ERR_ARGS ++ fi ++fi ++ ++# What kind of method was invoked? ++THE_VERSION=$(saphana_meta_data | grep ' ++ ++ ++ 0.149.3 ++ Analyzes SAP HANA System Replication Topology. ++ This RA analyzes the SAP HANA topology and "sends" all findings via the node status attributes to ++ all nodes in the cluster. These attributes are taken by the SAPHana RA to control the SAP Hana Databases. ++ In addition it starts and monitors the local saphostagent. ++ ++1. Interface to monitor a HANA system: landscapeHostConfiguration.py ++landscapeHostConfiguration.py has some detailed output about HANA system status ++and node roles. For our monitor the overall status is relevant. This overall ++status is reported by the returncode of the script: ++0: Internal Fatal ++1: ERROR ++2: WARNING ++3: INFO (maybe a switch of the resource running) ++4: OK ++The SAPHanaTopology resource agent will interpret returncodes 1 as NOT-RUNNING (or 1 failure) and returncodes 2+3+4 as RUNNING. ++SAPHanaTopology scans the output table of landscapeHostConfiguration.py to identify the roles of the cluster node. Roles means configured and current role of the nameserver as well as the indexserver. ++ ++2. Interface is hdbnsutil ++ The interface hdbnsutil is used to check the "topology" of the system replication as well as the current configuration ++ (primary/secondary) of a SAP HANA database instance. A second task of the interface is the posibility to run a ++ system replication takeover (sr_takeover) or to register a former primary to a newer one (sr_register). ++ ++3. saphostctrl ++ The interface saphostctrl uses the function ListInstances to figure out the virtual host name of the ++ SAP HANA instance. This is the hostname used during the HANA installation. ++ ++ ++ ++ The SAP System Identifier (SID) ++ The SAP System Identifier (SID) ++ ++ ++ ++ The SAP Instance Number ++ The SAP Instance Number ++ ++ ++ ++ Path to the SAP Hana Instance executable directory. If not set the RA tries /usr/sap/\$SID/\$InstanceName/exe. ++ While InstanceName is the string of "HDB" and \$InstanceNumber for SAP Hana databases. ++ ++ Path to the SAP Hana Instance executable directory. ++ ++ ++ ++ Define type of SAPHanaTopology RA messages to be printed ++ Define type of SAPHanaTopology RA messages to be printed. ++Define SAPHana resource agent messages to be printed. ++ This parameter should only be set of been requested by SUSE support. The default is sufficient for normal operation. ++ Values: ra-act-lpa-dec-flow ++ You could specify any combination of the above values like "ra-act-flow" ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++END ++return $rc ++} ++ ++# ++# function: get_hana_attribute ++# params: NODE ATTR [STORE] ++# globals: - ++# ++function get_hana_attribute() ++{ ++ super_ocf_log info "FLOW $FUNCNAME ($*)" ++ local rc=0 ++ local attr_node=$1 ++ local attr_name=$2 ++ local attr_store=${3:-reboot} # DONE: PRIO5 get this (optional) from parameter ++ crm_attribute -N ${attr_node} -G -n "$attr_name" -l $attr_store -q; rc=$? ++ if [ $rc -ne 0 ]; then ++ super_ocf_log debug "DBG: ATTRIBUTE-FAILURE: crm_attribute -N $attr_node -G -n "$attr_name" -l $attr_store -q" ++ fi ++ super_ocf_log info "FLOW $FUNCNAME rc=$rc" ++ return $rc ++} ++ ++# ++# function: set_hana_attribute - set the multi-state status of a node ++# params: NODE VALUE ATTR [STORE] ++# globals: - ++# ++function set_hana_attribute() ++{ ++ super_ocf_log info "FLOW $FUNCNAME ($*)" ++ local attr_node=$1 ++ local attr_value=$2 ++ local attr_name=$3 ++ local attr_store=${4:-reboot} # DONE: PRIO5 get this (optional) from parameter ++ local rc=1 ++ local attr_old ++ attr_old=$(get_hana_attribute $attr_node $attr_name $attr_store); get_rc=$? ++ if [ "$attr_old" != "$attr_value" ]; then ++ super_ocf_log debug "DBG: SET attribute $attr_name for node ${attr_node} to ${attr_value} former ($attr_old) get_rc=$get_rc " ++ crm_attribute -N $attr_node -v "$attr_value" -n "$attr_name" -l $attr_store; rc=$? ++ if [ $rc -ne 0 ]; then ++ super_ocf_log debug "DBG: ATTRIBUTE-FAILURE: crm_attribute -N $attr_node -v $attr_value -n "$attr_name" -l $attr_store" ++ fi ++ else ++ super_ocf_log debug "DBG: LET attribute $attr_name for node ${attr_node} still be ${attr_value}" ++ rc=0 ++ fi ++ super_ocf_log info "FLOW $FUNCNAME rc=$rc" ++ return $rc ++} ++ ++# ++# function: sht_methods - report supported cluster methods ++# params: - ++# globals: - ++# methods: What methods/operations do we support? ++# ++function sht_methods() { ++ super_ocf_log info "FLOW $FUNCNAME ($*)" ++ local rc=0 ++ cat <<-! ++ start ++ stop ++ status ++ monitor ++ notify ++ validate-all ++ methods ++ meta-data ++ usage ++ admin-setup ++ ! ++ return $rc ++} ++ ++# ++# function: is_clone - report, if resource is configured as a clone (also master/slave) ++# params: - ++# globals: OCF_*(r) ++# descript: is_clone : find out if we are configured to run in a Master/Slave configuration ++# rc: 0: it is a clone ++# 1: it is not a clone ++# Special EXIT of RA, if clone is missconfigured ++# ++function is_clone() { ++ super_ocf_log info "FLOW $FUNCNAME ($*)" ++ local rc=0 ++ # ++ # is a clone config? ++ # ++ if [ -n "$OCF_RESKEY_CRM_meta_clone_max" ] \ ++ && [ "$OCF_RESKEY_CRM_meta_clone_max" -gt 0 ]; then ++ # ++ # yes it is a clone config - check, if its configured well ++ # ++ if [ "$OCF_RESKEY_CRM_meta_clone_node_max" -ne 1 ] ; then ++ super_ocf_log err "ACT: Clone options misconfigured. (expect: clone_node_max=1)" ++ exit $OCF_ERR_CONFIGURED ++ fi ++ rc=0; ++ else ++ rc=1; ++ fi ++ super_ocf_log info "FLOW $FUNCNAME rc=$rc" ++ return $rc ++} ++ ++# ++# function: sht_init - initialize variables for the resource agent ++# params: - ++# globals: OCF_*(r), SID(w), sid(rw), sidadm(w), InstanceName(w), InstanceNr(w), ++# globals: meta_notify_master_uname(w), HANA_SR_TOLOPOGY(w), sr_name(w), remoteHost(w) ++# globals: ATTR_NAME_HANA_SYNC_STATUS(w), ATTR_NAME_HANA_PRIMARY_AT(w), ATTR_NAME_HANA_CLONE_STATE(w) ++# globals: DIR_EXECUTABLE(w), SAPSTARTSRV(w), SAPCONTROL(w), DIR_PROFILE(w), SAPSTARTPROFILE(w), LD_LIBRARY_PATH(w), PATH(w), nodelist(w) ++# sht_init : Define global variables with default values, if optional parameters are not set ++# ++# ++ ++function sht_init() { ++ super_ocf_log info "FLOW $FUNCNAME ($*)" ++ local myInstanceName="" ++ local rc=$OCF_SUCCESS ++ local hdbANSWER="" ++ HOSTEXECNAME=saphostexec ++ USRSAP=/usr/sap ++ SAPSERVICE_PATH=${USRSAP}/sapservices ++ SAPHOSTCTRL_PATH=${USRSAP}/hostctrl/exe ++ HOSTEXEC_PATH=${SAPHOSTCTRL_PATH}/${HOSTEXECNAME} ++ HOSTEXEC_PROFILE_PATH=${SAPHOSTCTRL_PATH}/host_profile ++ SID=$OCF_RESKEY_SID ++ InstanceNr=$OCF_RESKEY_InstanceNumber ++ myInstanceName="${SID}_HDB${InstanceNr}" ++ InstanceName="HDB${InstanceNr}" ++ super_ocf_log debug "DBG2: Used new method to get SID ($SID) and InstanceNr ($InstanceNr)" ++ sid=$(echo "$SID" | tr [:upper:] [:lower:]) ++ sidadm="${sid}adm" ++ SAPHanaFilter="${OCF_RESKEY_SAPHanaFilter:-ra-act-dec-lpa}" ++ ocf_env=$(env | grep 'OCF_RESKEY_CRM') ++ super_ocf_log debug "DBG3: OCF: $ocf_env" ++ ATTR_NAME_HANA_SYNC_STATUS=("hana_${sid}_sync_state" "reboot") # SOK, SFAIL, UNKNOWN? ++ ATTR_NAME_HANA_PRIMARY_AT=("hana_${sid}_primary_at" "reboot") # Not really used ++ ATTR_NAME_HANA_CLONE_STATE=("hana_${sid}_clone_state" "reboot") # UKNOWN?, DEMOTED, PROMOTED ++ ATTR_NAME_HANA_REMOTEHOST=("hana_${sid}_remoteHost" "forever") ++ ATTR_NAME_HANA_SITE=("hana_${sid}_site" "forever") ++ ATTR_NAME_HANA_ROLES=("hana_${sid}_roles" "reboot") ++ ATTR_NAME_HANA_SRMODE=("hana_${sid}_srmode" "forever") ++ ATTR_NAME_HANA_VHOST=("hana_${sid}_vhost" "forever") ++ ATTR_NAME_HANA_STATUS=("hana_${sid}_status" "reboot") ++ ++ # optional OCF parameters, we try to guess which directories are correct ++ if [ -z "$OCF_RESKEY_DIR_EXECUTABLE" ] ++ then ++ DIR_EXECUTABLE="/usr/sap/$SID/$InstanceName/exe" ++ else ++ DIR_EXECUTABLE="$OCF_RESKEY_DIR_EXECUTABLE" ++ fi ++ ++ if [ -z "$DIR_EXECUTABLE" ]; then ++ super_ocf_log err "DEC: Can not determine DIR_EXECUTABLE. Please set this parameter. -> OCF_ERR_CONFIGURED" ++ rc=$OCF_ERR_CONFIGURED ++ fi ++ ++ if [ -z "$OCF_RESKEY_DIR_PROFILE" ] ++ then ++ DIR_PROFILE="/usr/sap/$SID/SYS/profile" ++ else ++ DIR_PROFILE="$OCF_RESKEY_DIR_PROFILE" ++ fi ++ ++ # as root user we need the library path to the SAP kernel to be able to call sapcontrol ++ # check, if we already added DIR_EXECUTABLE at the beginning of LD_LIBRARY_PATH ++ if [ "${LD_LIBRARY_PATH%%*:}" != "$DIR_EXECUTABLE" ] ++ then ++ LD_LIBRARY_PATH=$DIR_EXECUTABLE${LD_LIBRARY_PATH:+:}$LD_LIBRARY_PATH ++ export LD_LIBRARY_PATH ++ fi ++ ++ PATH=${PATH}:${DIR_EXECUTABLE} ++ # ++ # figure-out all needed values from system replication status with ONE call ++ # we need: mode=primary|sync|syncmem|...; site name=; mapping/=/ (multiple lines) ++ case $(crm_attribute --type crm_config --name cluster-infrastructure -q) in ++ *corosync* ) nodelist=$(crm_node -l | awk '{ print $2 }');; ++ *openais* ) nodelist=$(crm_node -l | awk '/member/ {print $2}');; ++ *cman* ) nodelist=$(crm_node -l);; ++ esac ++ hdbANSWER=$(su - ${sidadm} -c "hdbnsutil -sr_state --sapcontrol=1" 2>/dev/null) ++ super_ocf_log debug "DBG2: hdbANSWER=\$\(su - ${sidadm} -c \"hdbnsutil -sr_state --sapcontrol=1\"\)" ++ site=$(echo "$hdbANSWER" | awk -F= '/site name/ {print $2}') ++ srmode=$(echo "$hdbANSWER" | awk -F= '/mode/ {print $2}') ++ MAPPING=$(echo "$hdbANSWER" | awk -F[=/] '$1 ~ "mapping" && $3 !~ site { print $4 }' site=$site) ++ super_ocf_log debug "DBG: site=$site, mode=$srmode, MAPPING=$MAPPING" ++ # ++ # filter all non-cluster mappings ++ # ++ hanaRemoteHost=$(for n1 in $nodelist; do for n2 in $MAPPING; do if [ "$n1" == "$n2" ]; then echo $n1; fi; done; done ) ++ super_ocf_log info "DEC: site=$site, mode=$srmode, MAPPING=$MAPPING, hanaRemoteHost=$hanaRemoteHost" ++ super_ocf_log debug "DBG: site=$site, mode=$srmode, MAPPING=$MAPPING, hanaRemoteHost=$hanaRemoteHost" ++ super_ocf_log info "FLOW $FUNCNAME rc=$OCF_SUCCESS" ++ return $OCF_SUCCESS ++} ++ ++# ++# function: check_for_primary - check if local SAP HANA is configured as primary ++# params: - ++# globals: HANA_STATE_PRIMARY(r), HANA_STATE_SECONDARY(r), HANA_STATE_DEFECT(r), HANA_STATE_STANDALONE(r) ++# ++function check_for_primary() { ++ super_ocf_log info "FLOW $FUNCNAME ($*)" ++ local rc=0 ++ # DONE: Change stderr location!! ++ #sidadm=lnxadm ++ #node_status=$(check_for_primary_single) ++ node_status=$srmode ++ super_ocf_log debug "DBG2: check_for_primary: node_status=$node_status" ++ super_ocf_log debug "DBG: check_for_primary: node_status=$node_status" ++ for i in 1 2 3 4 5 6 7 8 9; do ++ case "$node_status" in ++ primary ) ++ super_ocf_log info "FLOW $FUNCNAME rc=HANA_STATE_PRIMARY" ++ return $HANA_STATE_PRIMARY;; ++ syncmem | sync | async ) ++ super_ocf_log info "FLOW $FUNCNAME rc=HANA_STATE_SECONDARY" ++ return $HANA_STATE_SECONDARY;; ++ none ) # have seen that mode on second side BEFEORE we registered it as replica ++ super_ocf_log info "FLOW $FUNCNAME rc=HANA_STATE_STANDALONE" ++ return $HANA_STATE_STANDALONE;; ++ * ) ++ super_ocf_log err "ACT: check_for_primary: we didn't expect node_status to be: <$node_status>" ++ dump=$( echo $node_status | hexdump -C ); ++ super_ocf_log err "ACT: check_for_primary: we didn't expect node_status to be: DUMP <$dump>" ++ node_full_status=$(su - ${sidadm} -c "hdbnsutil -sr_state" 2>/dev/null ) ++ node_status=$(echo "$node_full_status" | awk '$1=="mode:" {print $2}') ++ super_ocf_log info "DEC: check_for_primary: loop=$i: node_status=$node_status" ++ # TODO: PRIO1: Maybe we need to keep the old value for P/S/N, if hdbnsutil just crashes ++ esac; ++ done ++ super_ocf_log info "FLOW $FUNCNAME rc=HANA_STATE_DEFECT" ++ return $HANA_STATE_DEFECT ++} ++ ++ ++# ++# function: start_saphostagent ++# params: - ++# globals: ++# ++function start_saphostagent() ++{ ++ if [ -x "${HOSTEXEC_PATH}" ]; then ++ ${HOSTEXEC_PATH} pf=${HOSTEXEC_PROFILE_PATH} ++ fi ++ return 0 ++} ++ ++# ++# function: stop_saphostagent ++# params: - ++# globals: ++# ++function stop_saphostagent() ++{ ++ if [ -x "${HOSTEXEC_PATH}" ]; then ++ ${HOSTEXEC_PATH} -stop ++ fi ++} ++ ++# ++# function: check_saphostagent ++# params: - ++# globals: ++# ++function check_saphostagent() ++{ ++ local rc=1 ++ pgrep -f /usr/sap/hostctrl/exe/saphostexec; rc=$? ++ return $rc ++} ++ ++# ++############################################################################# ++# ++# function: sht_start - start a hana instance ++# params: - ++# globals: OCF_* ++# sht_start : Start the SAP HANA instance ++# ++function sht_start() { ++ ++ super_ocf_log info "FLOW $FUNCNAME ($*)" ++ ++ local rc=$OCF_NOT_RUNNING ++ local output="" ++ local loopcount=0 ++ ++ mkdir -p /var/lib/SAPHana ++ touch /var/lib/SAPHana/SAPTopologyON ++ if ! check_saphostagent; then ++ start_saphostagent ++ fi ++ ++ rc=$OCF_SUCCESS ++ ++ super_ocf_log info "FLOW $FUNCNAME rc=$rc" ++ return $rc ++} ++ ++# ++# function: sht_stop - stop a hana instance ++# params: - ++# globals: OCF_*(r), SAPCONTROL(r), SID(r), InstanceName(r) ++# sht_stop: Stop the SAP instance ++# ++function sht_stop() { ++ super_ocf_log info "FLOW $FUNCNAME ($*)" ++ local output="" ++ local rc=0 ++ ++ rm /var/lib/SAPHana/SAPTopologyON ++ rc=$OCF_SUCCESS ++ ++ super_ocf_log info "FLOW $FUNCNAME rc=$rc" ++ return $rc ++} ++ ++ ++# ++# function: sht_monitor - monitor a hana topology instance ++# params: -- ++# globals: OCF_*(r), SAPCONTROL(r), InstanveNr(r) ++# sht_monitor: Can the given SAP instance do anything useful? ++# ++function sht_monitor() { ++ super_ocf_log info "FLOW $FUNCNAME ($*)" ++ local rc=0 ++ ++ if [ -f /var/lib/SAPHana/SAPTopologyON ]; then ++ rc=$OCF_SUCCESS ++ else ++ rc=$OCF_NOT_RUNNING ++ fi ++ ++ super_ocf_log info "FLOW $FUNCNAME rc=$rc" ++ return $rc ++} ++ ++ ++# ++# function: sht_status - get status of a hana instance (os tools only) ++# params: - ++# globals: SID(r), InstanceName(r), OCF_*(r), sidarm(r) ++# sht_status: Lightweight check of SAP instance only with OS tools ++# ++function sht_status() { ++ super_ocf_log info "FLOW $FUNCNAME ($*)" ++ local rc=0 ++ ++ sht_monitor; rc=$? ++ return $rc ++} ++ ++ ++# ++# function: sht_validate - validation of (some) variables/parameters ++# params: - ++# globals: OCF_*(r), SID(r), InstanceName(r), InstanceNr(r), ++# sht_validate: Check the symantic of the input parameters ++# ++function sht_validate() { ++ super_ocf_log info "FLOW $FUNCNAME ($*)" ++ local rc=$OCF_SUCCESS ++ if [ $(echo "$SID" | grep -c '^[A-Z][A-Z0-9][A-Z0-9]$') -ne 1 ] ++ then ++ super_ocf_log err "ACT: Parsing instance profile name: '$SID' is not a valid SID!" ++ rc=$OCF_ERR_ARGS ++ fi ++ ++ if [ $(echo "$InstanceNr" | grep -c '^[0-9][0-9]$') -ne 1 ] ++ then ++ super_ocf_log err "ACT: Parsing instance profile name: '$InstanceNr' is not a valid instance number!" ++ rc=$OCF_ERR_ARGS ++ fi ++ ++ super_ocf_log info "FLOW $FUNCNAME rc=$rc" ++ return $rc ++} ++ ++# ++# function: sht_start_clone - start a hana clone instance ++# params: - ++# globals: OCF_*(r), ++# sht_start_clone ++# ++function sht_start_clone() { ++ super_ocf_log info "FLOW $FUNCNAME ($*)" ++ local rc=$OCF_NOT_RUNNING ++ sht_start; rc=$? ++ return $rc ++} ++ ++# ++# function: sht_stop_clone - stop a hana clone instance ++# params: - ++# globals: NODENAME(r), HANA_STATE_*, ATTR_NAME_* ++# sht_stop_clone ++# ++function sht_stop_clone() { ++ super_ocf_log info "FLOW $FUNCNAME ($*)" ++ local rc=0 ++ check_for_primary; primary_status=$? ++ if [ $primary_status -eq $HANA_STATE_PRIMARY ]; then ++ hanaPrim="P" ++ elif [ $primary_status -eq $HANA_STATE_SECONDARY ]; then ++ hanaPrim="S" ++ elif [ $primary_status -eq $HANA_STATE_STANDALONE ]; then ++ hanaPrim="N" ++ else ++ hanaPrim="-" ++ fi ++ set_hana_attribute "${NODENAME}" "1:$hanaPrim:-:-:-:-" ${ATTR_NAME_HANA_ROLES[@]} ++ sht_stop; rc=$? ++ return $rc ++} ++ ++# ++# function: sht_monitor_clone - monitor a hana clone instance ++# params: - ++# globals: OCF_*, SID, InstanceNr, InstanceName, MAPPING(r) ++# sht_monitor_clone ++# ++function sht_monitor_clone() { ++ super_ocf_log info "FLOW $FUNCNAME ($*)" ++ # ++ local rc=$OCF_ERR_GENERIC ++ local promoted=0 ++ local init_attribute=0 ++ ++ ++ if ocf_is_probe; then ++ super_ocf_log debug "DBG2: PROBE ONLY" ++ else ++ super_ocf_log debug "DBG2: REGULAR MONITOR" ++ if ! check_saphostagent; then ++ start_saphostagent ++ fi ++ fi ++ # ++ # First check, if we are PRIMARY or SECONDARY ++ # ++ super_ocf_log debug "DBG2: HANA SID $SID" ++ super_ocf_log debug "DBG2: HANA InstanceName $InstanceName" ++ super_ocf_log debug "DBG2: HANA InstanceNr $InstanceNr" ++ check_for_primary; primary_status=$? ++ if [ $primary_status -eq $HANA_STATE_PRIMARY ]; then ++ hanaPrim="P" ++ super_ocf_log debug "DBG2: HANA IS PRIMARY" ++ sht_monitor; rc=$? ++ else ++ if [ $primary_status -eq $HANA_STATE_SECONDARY ]; then ++ hanaPrim="S" ++ super_ocf_log debug "DBG2: HANA IS SECONDARY" ++ sht_monitor; rc=$? ++ elif [ $primary_status -eq $HANA_STATE_STANDALONE ]; then ++ hanaPrim="N" ++ super_ocf_log debug "DBG2: HANA IS STANDALONE" ++ sht_monitor; rc=$? ++ else ++ hanaPrim="-" ++ super_ocf_log warn "ACT: sht_monitor_clone: HANA_STATE_DEFECT" ++ rc=$OCF_ERR_CONFIGURED ++ fi ++ fi ++ # DONE: PRIO1: ASK: Is the output format of ListInstances fix? Could we take that as an API? ++ # try to catch: Inst Info : LNX - 42 - lv9041 - 740, patch 36, changelist 1444691 ++ # We rely on the following format: SID is word#4, NR is work#6, vHost is word#8 ++ vName=$(/usr/sap/hostctrl/exe/saphostctrl -function ListInstances \ ++ | awk '$4 == SID && $6=NR { print $8 }' SID=$SID NR=$InstanceNr 2>/dev/null ) ++ super_ocf_log debug "DBG: ListInstances: $(/usr/sap/hostctrl/exe/saphostctrl -function ListInstances)" ++ if [ -n "$vName" ]; then ++ set_hana_attribute ${NODENAME} "$vName" ${ATTR_NAME_HANA_VHOST[@]} ++ else ++ vName=$(get_hana_attribute ${NODENAME} ${ATTR_NAME_HANA_VHOST[@]}) ++ fi ++ #site=$(get_site_name) ++ hanaANSWER=$(su - $sidadm -c "python exe/python_support/landscapeHostConfiguration.py" 2>/dev/null); hanalrc="$?" ++ hanarole=$(echo "$hanaANSWER" | tr -d ' ' | awk -F'|' '$2 == host { printf "%s:%s:%s:%s\n",$10,$11,$12,$13 } ' host=${vName}) ++ #if [ -z "$MAPPING" ]; then ++ # super_ocf_log info "ACT: Did not find remote Host at this moment" ++ #fi ++ # FH TODO PRIO1: TRY TO GET RID OF "ATTR_NAME_HANA_REMOTEHOST" ++ if [ -n "$hanaRemoteHost" ]; then ++ set_hana_attribute ${NODENAME} "$hanaRemoteHost" ${ATTR_NAME_HANA_REMOTEHOST[@]} ++ fi ++ set_hana_attribute ${NODENAME} "$hanalrc:$hanaPrim:$hanarole" ${ATTR_NAME_HANA_ROLES[@]} ++ set_hana_attribute ${NODENAME} "$site" ${ATTR_NAME_HANA_SITE[@]} ++ set_hana_attribute ${NODENAME} "$vName" ${ATTR_NAME_HANA_VHOST[@]} ++ case "$hanaPrim" in ++ P ) ;; ++ S ) # only secondary may propargate its sync status ++ case $(crm_attribute --type crm_config --name cluster-infrastructure -q) in ++ *corosync* ) nodelist=$(crm_node -l | awk '{ print $2 }');; ++ *openais* ) nodelist=$(crm_node -l | awk '/member/ {print $2}');; ++ *cman* ) nodelist=$(crm_node -l);; ++ esac ++ ++ for n in ${nodelist}; do ++ set_hana_attribute ${n} "$srmode" ${ATTR_NAME_HANA_SRMODE[@]} ++ done ++ ;; ++ esac ++ #ATTR_NAME_HANA_STATUS # TODO: PRIO5: For SCALE-OUT: Fill that attribute later ++ super_ocf_log info "FLOW $FUNCNAME rc=$rc" ++ return $rc ++} ++ ++# ++# function: sht_notify - notify action ++# params: - ++# globals: OCF_*(r), ACTION(r), CLACT(r), NODENAME(r) ++# sht_notify: Handle master scoring - to make sure a slave gets the next master ++# ++function sht_notify() { ++ super_ocf_log info "FLOW $FUNCNAME ($*)" ++ local rc=0 ++ super_ocf_log info "RA ==== end action $ACTION$CLACT (${n_type}/${n_op})====" ++ return $rc ++} ++ ++# ++# function: main - main function to operate ++# params: ACTION ++# globals: OCF_*(r), SID(w), sidadm(w), InstanceName(w), DIR_EXECUTABLE(w), ACTION(w), CLACT(w), ra_rc(rw), $0(r), %ENV(r) ++# ++ ++## GLOBALS ++SID="" ++sidadm="" ++InstanceName="" ++InstanceNr="" ++DIR_EXECUTABLE="" ++SAPHanaFilter="${OCF_RESKEY_SAPHanaFilter:-ra-act-dec-lpa}" ++NODENAME=$(crm_node -n) ++ ++if [ $# -ne 1 ] ++then ++ sht_usage ++ exit $OCF_ERR_ARGS ++fi ++ ++ACTION=$1 ++if [ "$ACTION" = "status" ]; then ++ ACTION=monitor ++fi ++ ++# These operations don't require OCF parameters to be set ++case "$ACTION" in ++ usage|methods) sht_$ACTION ++ exit $OCF_SUCCESS;; ++ meta-data) sht_meta_data ++ exit $OCF_SUCCESS;; ++ notify) sht_notify ++ exit $OCF_SUCCESS;; ++ admin-setup) admin-setup ++ exit $OCF_SUCCESS;; ++ *);; ++esac ++sht_init ++ ++if ! ocf_is_root ++then ++ super_ocf_log err "ACT: $0 must be run as root" ++ exit $OCF_ERR_PERM ++fi ++ ++# parameter check ++if [ -z "$OCF_RESKEY_SID" ] ++then ++ super_ocf_log err "ACT: Please set parameter SID!" ++ exit $OCF_ERR_ARGS ++fi ++ ++if [ -z "$OCF_RESKEY_InstanceNumber" ] ++then ++ super_ocf_log err "ACT: Please set parameter InstanceNumber!" ++ exit $OCF_ERR_ARGS ++fi ++ ++ ++if is_clone ++then ++ CLACT=_clone ++else ++ if [ "$ACTION" = "promote" -o "$ACTION" = "demote" ] ++ then ++ super_ocf_log err "ACT: $ACTION called in a non clone environment" ++ exit $OCF_ERR_ARGS ++ fi ++fi ++ ++THE_VERSION=$(sht_meta_data | grep ' $b ? $a : $b; ++} ++ ++sub print_attr_host() ++{ ++ my ($HKey, $AKey); ++ printf "%-22s", "Attribute \\ Host"; ++ foreach $HKey (sort keys %Host) { ++ printf "%-16s ", $HKey; ++ } ++ printf "\n"; ++ ++ printf "%s\n", "-" x 120 ; ++ ++ foreach $AKey (sort keys %Name) { ++ printf "%-22s", $AKey; ++ foreach $HKey (sort keys %Host) { ++ printf "%-16.16s ", $Host{$HKey} -> {$AKey}; ++ } ++ ++ printf "\n"; ++ } ++ return 0; ++} ++ ++sub print_host_attr() ++{ ++ my ($AKey, $HKey, $len, $line_len, $hclen); ++ $hclen=$Name{_hosts}->{_length}; ++ $line_len=$hclen+1; ++ printf "%-$hclen.${hclen}s ", "$table_title"; ++ foreach $AKey (sort keys %Name) { ++ if ($AKey ne "_hosts") { ++ $len = $Name{$AKey}->{_length}; ++ $line_len=$line_len+$len+1; ++ printf "%-$len.${len}s ", $Name{$AKey}->{_title}; ++ } ++ } ++ printf "\n"; ++ printf "%s\n", "-" x $line_len ; ++ foreach $HKey (sort keys %Host) { ++ printf "%-$hclen.${hclen}s ", $HKey; ++ foreach $AKey (sort keys %Name) { ++ if ($AKey ne "_hosts") { ++ $len = $Name{$AKey}->{_length}; ++ printf "%-$len.${len}s ", $Host{$HKey} -> {$AKey}; ++ } ++ } ++ printf "\n"; ++ } ++ return 0; ++} ++ ++open ListInstances, "/usr/sap/hostctrl/exe/saphostctrl -function ListInstances|"; ++while () { ++ # try to catch: Inst Info : LNX - 42 - lv9041 - 740, patch 36, changelist 1444691 ++ chomp; ++ if ( $_ =~ /:\s+([A-Z][A-Z0-9][A-Z0-9])\s+-/ ) { ++ $sid=tolower("$1"); ++ } ++} ++close ListInstances; ++ ++ ++open CIB, "cibadmin -Ql |"; ++while () { ++ chomp; ++ my ($host, $name, $value); ++ my $found=0; ++ if ( $_ =~ /nvpair.*name="(\w+_${sid}_\w+)"/ ) { ++ $name=$1; ++ # find attribute in forever and reboot store :) ++ if ( $_ =~ /id="(status|nodes)-([a-zA-Z0-9\_\-]+)-/ ) { ++ $host=$2; ++ } ++ if ( $_ =~ /value="([^"]+)"/ ) { ++ $value=$1; ++ $found=1; ++ } ++ } ++ if ( $found == 1 ) { ++ # ++ # handle the hosts name and table-title ++ # ++ $Host{$host}->{$name}=${value}; ++ if ( defined ($Name{_hosts}->{_length})) { ++ $Name{_hosts}->{_length} = max($Name{_hosts}->{_length}, length($host )); ++ } else { ++ $Name{_hosts}->{_length} = length($host ); ++ } ++ $Name{_hosts}->{_length} = max($Name{_hosts}->{_length}, length( $table_title)); ++ # ++ # now handle the attributes name and value ++ # ++ $Name{$name}->{$host}=${value}; ++ if ( defined ($Name{$name}->{_length})) { ++ $Name{$name}->{_length} = max($Name{$name}->{_length}, length($value )); ++ } else { ++ $Name{$name}->{_length} = length($value ); ++ } ++ if ( $name =~ /hana_${sid}_(.*)/ ) { ++ $Name{$name}->{_title} = $1; ++ } else { ++ $Name{$name}->{_title} = $name; ++ } ++ $Name{$name}->{_length} = max($Name{$name}->{_length}, length( $Name{$name}->{_title})); ++ # printf "%-8s %-20s %-30s\n", $1, $2, $3; ++ } ++} ++close CIB; ++ ++#print_attr_host; ++print_host_attr; +-- +1.8.4.2 + diff --git a/SOURCES/bz1168251-SAPHana-agents_update4.patch b/SOURCES/bz1168251-SAPHana-agents_update4.patch new file mode 100644 index 00000000..9cf860ad --- /dev/null +++ b/SOURCES/bz1168251-SAPHana-agents_update4.patch @@ -0,0 +1,441 @@ +diff --git a/heartbeat/SAPHana b/heartbeat/SAPHana +index 1913dc3..ed0443b 100644 +--- a/heartbeat/SAPHana ++++ b/heartbeat/SAPHana +@@ -48,6 +48,8 @@ HANA_STATE_SECONDARY=1 + HANA_STATE_STANDALONE=2 + HANA_STATE_DEFECT=3 + ++debug_attributes=0 ++ + SH=/bin/sh + + # +@@ -132,19 +134,19 @@ function saphana_meta_data() { + + + +-0.149.4 ++0.149.7 + + Manages two SAP HANA instances in system replication (SR). + + The SAPHanaSR resource agent manages two SAP Hana instances (databases) which are configured +-in system replication. This first version is limitted to the scale-up scenario. Scale-Out is ++in system replication. This first version is limited to the scale-up scenario. Scale-Out is + not supported in this version. + + Managing the two SAP HANA instances means that the resource agent controls the start/stop of the + instances. In addition the resource agent is able to monitor the SAP HANA databases to check their + availability on landscape host configuration level. For this monitoring the resource agent relies on interfaces + provided by SAP. A third task of the resource agent is to also check the synchronisation status +-of the two SAP HANA databases. If the synchronisation is not "SOK", than the cluster avoids to ++of the two SAP HANA databases. If the synchronisation is not "SOK", then the cluster avoids to + failover to the secondary side, if the primary fails. This is to improve the data consistency. + + The resource agent uses the following four interfaces provided by SAP: +@@ -162,7 +164,7 @@ The resource agent uses the following four interfaces provided by SAP: + + 3. hdbnsutil + The interface hdbnsutil is used to check the "topology" of the system replication as well as the current configuration +- (primary/secondary) of a SAP HANA database instance. A second task of the interface is the posibility to run a ++ (primary/secondary) of a SAP HANA database instance. A second task of the interface is the possibility to run a + system replication takeover (sr_takeover) or to register a former primary to a newer one (sr_register). + + 4. hdbsql / systemReplicationStatus +@@ -198,7 +200,7 @@ The resource agent uses the following four interfaces provided by SAP: + + + Define, if a former primary should automatically be registered. +- The parameter AUTOMATED_REGISTER defines, wether a former primary instance should ++ The parameter AUTOMATED_REGISTER defines, whether a former primary instance should + be registered automatically by the resource agent during cluster/resource start, if the DUPLICATE_PRIMARY_TIMEOUT is expired... TDB + + +@@ -207,7 +209,7 @@ The resource agent uses the following four interfaces provided by SAP: + Time difference needed between to primary time stamps, if a dual-primary situation occurs + Time difference needed between to primary time stamps, + if a dual-primary situation occurs. If the time difference is +- less than the time gap, than the cluster hold one or both instances in a "WAITING" status. This is to give a admin ++ less than the time gap, then the cluster hold one or both instances in a "WAITING" status. This is to give an admin + a chance to react on a failover. A failed former primary will be registered after the time difference is passed. After + this registration to the new primary all data will be overwritten by the system replication. + +@@ -316,7 +318,7 @@ function remoteHost2remoteNode() + # descript: is_clone : find out if we are configured to run in a Master/Slave configuration + # rc: 0: it is a clone, 1: it is not a clone + # +-# DONE: PRIO2: For the first shippment (scale-out) we need to limit the clones to 2 ++# DONE: PRIO2: For the first shipment (scale-out) we need to limit the clones to 2 + # + function is_clone() { + super_ocf_log info "FLOW $FUNCNAME ($*)" +@@ -356,8 +358,14 @@ function get_hana_attribute() + local attr_node=$1 + local attr_name=$2 + local attr_store=${3:-reboot} # DONE: PRIO5 get this (optional) from parameter +- local attr_default=${4:-} +- crm_attribute -N ${attr_node} -G -n "$attr_name" -l $attr_store -q -d "$attr_default"; rc=$? ++ local attr_default=${5:-} ++ local attr_val="" ++ attr_val=$(crm_attribute -N ${attr_node} -G -n "$attr_name" -l $attr_store -q -d "$attr_default"); rc=$? ++ if [ $debug_attributes -eq 1 ]; then ++ dstr=$(date) ++ echo "$dstr: SAPHana: crm_attribute -N ${attr_node} -G -n \"$attr_name\" -l $attr_store -q --> $attr_val" >> /var/log/fhATTRIBUTE ++ fi ++ echo "$attr_val" + super_ocf_log info "FLOW $FUNCNAME rc=$rc" + return $rc + } +@@ -381,6 +389,10 @@ function set_hana_attribute() + if [ "$attr_old" != "$attr_value" ]; then + super_ocf_log debug "DBG: SET attribute $attr_name for node ${attr_node} to ${attr_value} former ($attr_old) get_rc=$get_rc " + crm_attribute -N $attr_node -v $attr_value -n "$attr_name" -l $attr_store; rc=$? ++ if [ $debug_attributes -eq 1 ]; then ++ dstr=$(date) ++ echo "$dstr: SAPHana: crm_attribute -N $attr_node -v $attr_value -n \"$attr_name\" -l $attr_store" >> /var/log/fhATTRIBUTE ++ fi + else + super_ocf_log debug "DBG: LET attribute $attr_name for node ${attr_node} still be ${attr_value}" + rc=0 +@@ -448,7 +460,7 @@ scoring_crm_master() + local roles="$1" + local sync="$2" + local skip=0 +- local myScore=-1 ++ local myScore="" + for scan in "${SCORING_TABLE_PREFERRED_SITE_TAKEOVER[@]}"; do + if [ $skip -eq 0 ]; then + read rolePatt syncPatt score <<< $scan +@@ -461,7 +473,10 @@ scoring_crm_master() + fi + done + super_ocf_log debug "DBG: scoring_crm_master adjust score $myScore" +- set_crm_master $myScore ++ # TODO: PRIO1: DO Not Score, If we did not found our role/sync at this moment - bsc#919925 ++ if [ -n "$myScore" ]; then ++ set_crm_master $myScore ++ fi + } + + # +@@ -1068,6 +1083,27 @@ function saphana_start_primary() + case "$lpa_dec" in + 0 ) # LPA says start-up + lpa_advice="start" ++ # TODO: PRIO1: We need to do a special handling for remote being a 234-Secondary in SR Status SOK ++ # if ( remote_role like [234]:S ) && ( remote_sync_status is SOK|PRIM ) && ( PreferSiteTakeover ) ++ # then lpa_advice="wait" ++ remoteRole=$(get_hana_attribute $remoteNode ${ATTR_NAME_HANA_ROLES[@]}) ++ remoteSync=$(get_hana_attribute $remoteNode ${ATTR_NAME_HANA_SYNC_STATUS[@]}) ++ super_ocf_log info "DEC: saphana_primary - checking remoteStatus" ++ if ocf_is_true "${PreferSiteTakeover}"; then ++ remoteStatus="$remoteRole:$remoteSync" ++ case "$remoteStatus" in ++ [234]:S:*:SOK | [234]:S:*:PRIM ) ++ lpa_advice="wait" ++ # TODO: PRIO3: Split WAIT into WAIT4TAKEOVER ++ super_ocf_log info "DEC: saphana_primary - waiting for secondary to takeover (SOK, PreferSiteTakover)" ++ ;; ++ * ) ++ super_ocf_log info "DEC: saphana_primary - remoteStatus is: $remoteStatus" ++ ;; ++ esac ++ else ++ super_ocf_log info "DEC: saphana_primary - PreferSiteTakeover set to false" ++ fi + ;; + 1) # LPA says register! + lpa_advice="register" +@@ -1075,7 +1111,7 @@ function saphana_start_primary() + 2) # LPA says wait for second LPT + lpa_advice="wait" + ;; +- 3 | 4 ) # LPA says something is completely wrong - FAIL resource ++ 3 | 4 ) # LPA says something is completely wrong - FAIL resource # TODO: PRIO1: RC3 for waiting remote side to report lss + lpa_advice="fail" + ;; + * ) # LPA failed with an unkonown status - FAIL resource +@@ -1098,7 +1134,7 @@ function saphana_start_primary() + super_ocf_log info "LPA: landcape: UP, LPA: start ==> keep running" + LPTloc=$(date '+%s') + lpa_set_lpt $LPTloc +- rc=$OCF_SUCCSESS ++ rc=$OCF_SUCCESS + ;; + 1 ) # landcape says we are down, lets start and adjust scores and return code + super_ocf_log info "LPA: landcape: DOWN, LPA: start ==> start instance" +@@ -1149,7 +1185,7 @@ function saphana_start_primary() + case "$lss" in + 2 | 3 | 4 ) # as we ARE up we just keep it up + # TODO: PRIO3: I now change from "just keep it up to take that down" +- # TODO: PRIO3: OCF_SUCCSESS, OCF_NOT_RUNNING or OCF_ERR_xxxx ? ++ # TODO: PRIO3: OCF_SUCCESS, OCF_NOT_RUNNING or OCF_ERR_xxxx ? + set_crm_master -9000 + #scoring_crm_master "$my_role" "$my_sync" + rc=$OCF_ERR_GENERIC +@@ -1159,7 +1195,7 @@ function saphana_start_primary() + # TODO: PRIO3: Check, if WAITING is correct here + set_hana_attribute ${NODENAME} "WAITING" ${ATTR_NAME_HANA_CLONE_STATE[@]} + set_crm_master -9000 +- rc=$OCF_SUCCSESS ++ rc=$OCF_SUCCESS + ;; + esac + ;; +@@ -1277,7 +1313,7 @@ function saphana_start_secondary() + super_ocf_log info "ACT: PRIMARY seams to be down now ==> WAITING" + set_hana_attribute ${NODENAME} "WAITING" ${ATTR_NAME_HANA_CLONE_STATE[@]} + set_crm_master -INFINITY +- rc=$OCF_SUCCSESS ++ rc=$OCF_SUCCESS + fi + else + lpa_set_lpt 30 +@@ -1286,7 +1322,7 @@ function saphana_start_secondary() + super_ocf_log info "ACT: wait_for_primary_master ==> WAITING" + set_hana_attribute ${NODENAME} "WAITING" ${ATTR_NAME_HANA_CLONE_STATE[@]} + set_crm_master -INFINITY +- rc=$OCF_SUCCSESS ++ rc=$OCF_SUCCESS + fi + super_ocf_log info "FLOW $FUNCNAME rc=$rc" + return $rc +@@ -1453,7 +1489,8 @@ function lpa_init_lpt() { + # LPTlocal > LPTremore ===> rc=0 (start) + # LPTRemote > LPTlocal ===> rc=1 (register) + # Stalemate in all other cases ==> STALEMATE-HANDLING ===> rc=2 (wait) +-# LPTRemote is not initialized (0) ++# LPTRemote is not initialized or node not kown in cluster (crm_mon -l) (0) ++# TODO: PRIO1: Need to introduce a return-code 3 for remote sides lpa not ready + # THEN: + # WAIT ==> like STALEMATE-HANDLING ===> rc=2 (wait) + # +@@ -1625,7 +1662,6 @@ function saphana_monitor_primary() + else + super_ocf_log info "LPA: Dual primary detected and AUTOMATED_REGISTER='false' ==> WAITING" + fi +- + return $OCF_SUCCESS + fi + promoted=0; +@@ -1853,11 +1889,11 @@ function saphana_monitor_secondary() + scoring_crm_master "$my_role" "$my_sync" + ;; + "SFAIL" ) # This is currently NOT a possible node to promote +- super_ocf_log info "DEC: secondary with sync status FAILED ==> EXCLUDE as posible takeover node" ++ super_ocf_log info "DEC: secondary with sync status FAILED ==> EXCLUDE as possible takeover node" + set_crm_master -INFINITY + ;; + "*" ) # Unknown sync status +- super_ocf_log info "DEC: secondary with sync status UKNOWN/UNDEFINED ==> EXCLUDE as posible takeover node" ++ super_ocf_log info "DEC: secondary with sync status UKNOWN/UNDEFINED ==> EXCLUDE as possible takeover node" + set_crm_master -INFINITY + ;; + esac +@@ -1889,10 +1925,12 @@ function saphana_monitor_clone() { + local rc=$OCF_ERR_GENERIC + local promoted=0 + local init_attribute=0 ++ local lpaRc=0 ++ local mRc=0 ++ local myMaster=-1 + + my_role=$(get_hana_attribute ${NODENAME} ${ATTR_NAME_HANA_ROLES[@]}) + my_sync=$(get_hana_attribute ${NODENAME} ${ATTR_NAME_HANA_SYNC_STATUS[@]}) +- lpa_check_lpt_status # TODO: PRIO3 : remove that line later - its only to call lpa_check_lpt_status much more often for checking + + if ocf_is_probe; then + super_ocf_log debug "DBG: PROBE ONLY" +@@ -1904,6 +1942,16 @@ function saphana_monitor_clone() { + # + check_for_primary; primary_status=$? + if [ $primary_status -eq $HANA_STATE_PRIMARY ]; then ++ # FIX: bsc#919925 Leaving Node Maintenance stops HANA Resource Agent ++ # TODO: PRIO1: Maybe we need a lpa-check here to ++ if ocf_is_probe; then ++ myMaster=$(get_crm_master); mRc=$? ++ if [ $mRc -ne 0 ]; then ++ set_crm_master 5 ++ elif [ $myMaster -eq -1 ]; then ++ set_crm_master 5 ++ fi ++ fi + saphana_monitor_primary; rc=$? + else + if [ $primary_status -eq $HANA_STATE_SECONDARY ]; then +diff --git a/heartbeat/SAPHanaTopology b/heartbeat/SAPHanaTopology +index 082ad29..1d4887f 100644 +--- a/heartbeat/SAPHanaTopology ++++ b/heartbeat/SAPHanaTopology +@@ -14,6 +14,7 @@ + # Support: linux@sap.com + # License: GNU General Public License (GPL) + # Copyright: (c) 2014 SUSE Linux Products GmbH ++# (c) 2015 SUSE Linux GmbH + # + # An example usage: + # See usage() function below for more details... +@@ -39,6 +40,8 @@ HANA_STATE_SECONDARY=1 + HANA_STATE_STANDALONE=2 + HANA_STATE_DEFECT=3 + ++debug_attributes=0 ++ + SH=/bin/sh + + # +@@ -123,7 +126,7 @@ function sht_meta_data() { + + + +- 0.149.4 ++ 0.149.6 + Analyzes SAP HANA System Replication Topology. + This RA analyzes the SAP HANA topology and "sends" all findings via the node status attributes to + all nodes in the cluster. These attributes are taken by the SAPHana RA to control the SAP Hana Databases. +@@ -205,7 +208,13 @@ function get_hana_attribute() + local attr_node=$1 + local attr_name=$2 + local attr_store=${3:-reboot} # DONE: PRIO5 get this (optional) from parameter +- crm_attribute -N ${attr_node} -G -n "$attr_name" -l $attr_store -q; rc=$? ++ local attr_val="" ++ attr_val=$(crm_attribute -N ${attr_node} -G -n "$attr_name" -l $attr_store -q); rc=$? ++ if [ $debug_attributes -eq 1 ]; then ++ dstr=$(date) ++ echo "$dstr: SAPHanaTopology: crm_attribute -N ${attr_node} -G -n \"$attr_name\" -l $attr_store -q --> $attr_val" >> /var/log/fhATTRIBUTE ++ fi ++ echo "$attr_val" + if [ $rc -ne 0 ]; then + super_ocf_log debug "DBG: ATTRIBUTE-FAILURE: crm_attribute -N $attr_node -G -n "$attr_name" -l $attr_store -q" + fi +@@ -230,6 +239,10 @@ function set_hana_attribute() + attr_old=$(get_hana_attribute $attr_node $attr_name $attr_store); get_rc=$? + if [ "$attr_old" != "$attr_value" ]; then + super_ocf_log debug "DBG: SET attribute $attr_name for node ${attr_node} to ${attr_value} former ($attr_old) get_rc=$get_rc " ++ if [ $debug_attributes -eq 1 ]; then ++ dstr=$(date) ++ echo "$dstr: SAPHanaTopology: crm_attribute -N $attr_node -v $attr_value -n \"$attr_name\" -l $attr_store" >> /var/log/fhATTRIBUTE ++ fi + crm_attribute -N $attr_node -v "$attr_value" -n "$attr_name" -l $attr_store; rc=$? + if [ $rc -ne 0 ]; then + super_ocf_log debug "DBG: ATTRIBUTE-FAILURE: crm_attribute -N $attr_node -v $attr_value -n "$attr_name" -l $attr_store" +@@ -377,18 +390,32 @@ function sht_init() { + *openais* ) nodelist=$(crm_node -l | awk '/member/ {print $2}');; + *cman* ) nodelist=$(crm_node -l);; + esac ++ #### SAP-CALL + hdbANSWER=$(su - ${sidadm} -c "hdbnsutil -sr_state --sapcontrol=1" 2>/dev/null) + super_ocf_log debug "DBG2: hdbANSWER=\$\(su - ${sidadm} -c \"hdbnsutil -sr_state --sapcontrol=1\"\)" + site=$(echo "$hdbANSWER" | awk -F= '/site name/ {print $2}') + srmode=$(echo "$hdbANSWER" | awk -F= '/mode/ {print $2}') +- MAPPING=$(echo "$hdbANSWER" | awk -F[=/] '$1 ~ "mapping" && $3 !~ site { print $4 }' site=$site) ++ if [ $debug_attributes -eq 1 ]; then ++ dstr=$(date) ++ echo "$dstr: SAPHanaTopology: srmode=$srmode" >> /var/log/fhATTRIBUTE ++ fi ++ MAPPING=$(echo "$hdbANSWER" | awk -F[=/] '$1 == "mapping" && $3 != site { print $4 }' site=$site) + super_ocf_log debug "DBG: site=$site, mode=$srmode, MAPPING=$MAPPING" + # + # filter all non-cluster mappings + # +- hanaRemoteHost=$(for n1 in $nodelist; do for n2 in $MAPPING; do if [ "$n1" == "$n2" ]; then echo $n1; fi; done; done ) +- super_ocf_log info "DEC: site=$site, mode=$srmode, MAPPING=$MAPPING, hanaRemoteHost=$hanaRemoteHost" +- super_ocf_log debug "DBG: site=$site, mode=$srmode, MAPPING=$MAPPING, hanaRemoteHost=$hanaRemoteHost" ++ # DONE: PRIO2: Need mapping between HANA HOSTS not cluster NODES ++ local hanaVHost ++ hanaRemoteHost=$(for n1 in $nodelist; do ++ hanaVHost=$(get_hana_attribute ${n1} ${ATTR_NAME_HANA_VHOST[@]}) ++ for n2 in $MAPPING; do ++ if [ "$hanaVHost" == "$n2" ]; then ++ echo $hanaVHost; ++ fi; ++ done; ++ done ) ++ super_ocf_log info "DEC: site=$site, mode=$srmode, MAPPING=$MAPPING, hanaRemoteHost=$hanaRemoteHost" ++ super_ocf_log debug "DBG: site=$site, mode=$srmode, MAPPING=$MAPPING, hanaRemoteHost=$hanaRemoteHost" + super_ocf_log info "FLOW $FUNCNAME rc=$OCF_SUCCESS" + return $OCF_SUCCESS + } +@@ -422,6 +449,7 @@ function check_for_primary() { + super_ocf_log err "ACT: check_for_primary: we didn't expect node_status to be: <$node_status>" + dump=$( echo $node_status | hexdump -C ); + super_ocf_log err "ACT: check_for_primary: we didn't expect node_status to be: DUMP <$dump>" ++ #### SAP-CALL + node_full_status=$(su - ${sidadm} -c "hdbnsutil -sr_state" 2>/dev/null ) + node_status=$(echo "$node_full_status" | awk '$1=="mode:" {print $2}') + super_ocf_log info "DEC: check_for_primary: loop=$i: node_status=$node_status" +@@ -440,6 +468,7 @@ function check_for_primary() { + # + function start_saphostagent() + { ++ ### SAP-CALL + if [ -x "${HOSTEXEC_PATH}" ]; then + ${HOSTEXEC_PATH} pf=${HOSTEXEC_PROFILE_PATH} + fi +@@ -453,9 +482,10 @@ function start_saphostagent() + # + function stop_saphostagent() + { +- if [ -x "${HOSTEXEC_PATH}" ]; then +- ${HOSTEXEC_PATH} -stop +- fi ++ ### SAP-CALL ++ if [ -x "${HOSTEXEC_PATH}" ]; then ++ ${HOSTEXEC_PATH} -stop ++ fi + } + + # +@@ -586,7 +616,7 @@ function sht_validate() { + # + function sht_start_clone() { + super_ocf_log info "FLOW $FUNCNAME ($*)" +- local rc=$OCF_NOT_RUNNING ++ local rc=$OCF_NOT_RUNNING + sht_start; rc=$? + return $rc + } +@@ -666,27 +696,30 @@ function sht_monitor_clone() { + # DONE: PRIO1: ASK: Is the output format of ListInstances fix? Could we take that as an API? + # try to catch: Inst Info : LNX - 42 - lv9041 - 740, patch 36, changelist 1444691 + # We rely on the following format: SID is word#4, NR is work#6, vHost is word#8 ++ #### SAP-CALL + vName=$(/usr/sap/hostctrl/exe/saphostctrl -function ListInstances \ + | awk '$4 == SID && $6=NR { print $8 }' SID=$SID NR=$InstanceNr 2>/dev/null ) +- super_ocf_log debug "DBG: ListInstances: $(/usr/sap/hostctrl/exe/saphostctrl -function ListInstances)" ++ # super_ocf_log debug "DBG: ListInstances: $(/usr/sap/hostctrl/exe/saphostctrl -function ListInstances)" + if [ -n "$vName" ]; then + set_hana_attribute ${NODENAME} "$vName" ${ATTR_NAME_HANA_VHOST[@]} + else + vName=$(get_hana_attribute ${NODENAME} ${ATTR_NAME_HANA_VHOST[@]}) + fi + #site=$(get_site_name) ++ #### SAP-CALL + hanaANSWER=$(su - $sidadm -c "python exe/python_support/landscapeHostConfiguration.py" 2>/dev/null); hanalrc="$?" + hanarole=$(echo "$hanaANSWER" | tr -d ' ' | awk -F'|' '$2 == host { printf "%s:%s:%s:%s\n",$10,$11,$12,$13 } ' host=${vName}) + #if [ -z "$MAPPING" ]; then + # super_ocf_log info "ACT: Did not find remote Host at this moment" + #fi +- # FH TODO PRIO1: TRY TO GET RID OF "ATTR_NAME_HANA_REMOTEHOST" ++ # FH TODO PRIO3: TRY TO GET RID OF "ATTR_NAME_HANA_REMOTEHOST" + if [ -n "$hanaRemoteHost" ]; then + set_hana_attribute ${NODENAME} "$hanaRemoteHost" ${ATTR_NAME_HANA_REMOTEHOST[@]} + fi + set_hana_attribute ${NODENAME} "$hanalrc:$hanaPrim:$hanarole" ${ATTR_NAME_HANA_ROLES[@]} +- set_hana_attribute ${NODENAME} "$site" ${ATTR_NAME_HANA_SITE[@]} +- set_hana_attribute ${NODENAME} "$vName" ${ATTR_NAME_HANA_VHOST[@]} ++ if [ -n "$site" ]; then ++ set_hana_attribute ${NODENAME} "$site" ${ATTR_NAME_HANA_SITE[@]} ++ fi + case "$hanaPrim" in + P ) ;; + S ) # only secondary may propargate its sync status +@@ -701,7 +734,6 @@ function sht_monitor_clone() { + done + ;; + esac +- #ATTR_NAME_HANA_STATUS # TODO: PRIO5: For SCALE-OUT: Fill that attribute later + super_ocf_log info "FLOW $FUNCNAME rc=$rc" + return $rc + } diff --git a/SOURCES/bz1170376-galera-no-readonly.patch b/SOURCES/bz1170376-galera-no-readonly.patch new file mode 100644 index 00000000..e96196ce --- /dev/null +++ b/SOURCES/bz1170376-galera-no-readonly.patch @@ -0,0 +1,204 @@ +diff --git a/heartbeat/galera b/heartbeat/galera +index 994aad0..d74a70d 100755 +--- a/heartbeat/galera ++++ b/heartbeat/galera +@@ -342,6 +342,14 @@ is_readonly() + + master_exists() + { ++ if [ "$__OCF_ACTION" = "demote" ]; then ++ # We don't want to detect master instances during demote. ++ # 1. we could be detecting ourselves as being master, which is no longer the case. ++ # 2. we could be detecting other master instances that are in the process of shutting down. ++ # by not detecting other master instances in "demote" we are deferring this check ++ # to the next recurring monitor operation which will be much more accurate ++ return 1 ++ fi + # determine if a master instance is already up and is healthy + crm_mon --as-xml | grep "resource.*id=\"${OCF_RESOURCE_INSTANCE}\".*role=\"Master\".*active=\"true\".*orphaned=\"false\".*failed=\"false\"" > /dev/null 2>&1 + return $? +@@ -441,20 +449,24 @@ galera_promote() + extra_opts="--wsrep-cluster-address=gcomm://" + else + ocf_exit_reason "Failure, Attempted to promote Master instance of $OCF_RESOURCE_INSTANCE before bootstrap node has been detected." ++ clear_last_commit + return $OCF_ERR_GENERIC + fi +- + fi + +- # make sure the read only instance is stopped +- mysql_common_stop +- rc=$? +- if [ $rc -ne $OCF_SUCCESS ] && [ $rc -ne $OCF_NOT_RUNNING ]; then +- ocf_exit_reason "Failed to stop read-only galera instance during promotion to Master" +- return $rc ++ galera_monitor ++ if [ $? -eq $OCF_RUNNING_MASTER ]; then ++ if ocf_is_true $bootstrap; then ++ promote_everyone ++ clear_bootstrap_node ++ ocf_log info "boostrap node already up, promoting the rest of the galera instances." ++ fi ++ clear_last_commit ++ return $OCF_SUCCESS + fi + +- sleep 4 ++ # last commit is no longer relevant once promoted ++ clear_last_commit + + mysql_common_prepare_dirs + mysql_common_start "$extra_opts" +@@ -492,9 +504,6 @@ galera_promote() + wait_for_sync + fi + +- # last commit is no longer relevant once promoted +- clear_last_commit +- + ocf_log info "Galera started" + return $OCF_SUCCESS + } +@@ -510,14 +519,14 @@ galera_demote() + + # if this node was previously a bootstrap node, that is no longer the case. + clear_bootstrap_node ++ clear_last_commit + +- # start again in slave mode so the new last commit is recorded ++ # record last commit by "starting" galera. start is just detection of the last sequence number + galera_start + } + + galera_start() + { +- local extra_opts='--read-only=true' + local last_commit + + echo $OCF_RESKEY_wsrep_cluster_address | grep -q $NODENAME +@@ -526,22 +535,39 @@ galera_start() + return $OCF_ERR_CONFIGURED + fi + +- mysql_common_prepare_dirs +- mysql_common_start "$extra_opts" +- +- is_readonly +- if [ $? -ne 0 ]; then +- ocf_exit_reason "Slave instance did not start correctly in read-only mode, Make sure local galera.cnf does not have wsrep_cluster_address set." ++ galera_monitor ++ if [ $? -eq $OCF_RUNNING_MASTER ]; then ++ ocf_exit_reason "master galera instance started outside of the cluster's control" + return $OCF_ERR_GENERIC + fi + +- ocf_log info "attempting to detect last commit version" +- while [ -z "$last_commit" ]; do +- last_commit=$(get_status_variable "wsrep_last_committed") +- if [ -z "$last_commit" ]; then +- sleep 1 ++ mysql_common_prepare_dirs ++ ++ ocf_log info "attempting to detect last commit version by reading ${OCF_RESKEY_datadir}/grastate.dat" ++ last_commit="$(cat ${OCF_RESKEY_datadir}/grastate.dat | sed -n 's/^seqno.\s*\(.*\)\s*$/\1/p')" ++ if [ -z "$last_commit" ] || [ "$last_commit" = "-1" ]; then ++ ocf_log info "now attempting to detect last commit version using 'mysqld_safe --wsrep-recover'" ++ local tmp=$(mktemp) ++ ${OCF_RESKEY_binary} --defaults-file=$OCF_RESKEY_config \ ++ --pid-file=$OCF_RESKEY_pid \ ++ --socket=$OCF_RESKEY_socket \ ++ --datadir=$OCF_RESKEY_datadir \ ++ --user=$OCF_RESKEY_user \ ++ --wsrep-recover > $tmp 2>&1 ++ ++ last_commit="$(cat $tmp | sed -n 's/.*WSREP\:\s*[R|r]ecovered\s*position.*\:\(.*\)\s*$/\1/p')" ++ rm -f $tmp ++ ++ if [ "$last_commit" = "-1" ]; then ++ last_commit="0" + fi +- done ++ fi ++ ++ if [ -z "$last_commit" ]; then ++ ocf_exit_reason "Unable to detect last known write sequence number" ++ clear_last_commit ++ return $OCF_ERR_GENERIC ++ fi + ocf_log info "Last commit version found: $last_commit" + + set_last_commit $last_commit +@@ -567,28 +593,40 @@ galera_monitor() + if ocf_is_probe; then + status_loglevel="info" + fi +- ++ + mysql_common_status $status_loglevel + rc=$? + +- # If status returned an error, return that immediately +- if [ $rc -ne $OCF_SUCCESS ]; then ++ if [ $rc -eq $OCF_NOT_RUNNING ]; then ++ last_commit=$(get_last_commit $node) ++ if [ -n "$last_commit" ]; then ++ # if last commit is set, this instance is considered started in slave mode ++ rc=$OCF_SUCCESS ++ master_exists ++ if [ $? -ne 0 ]; then ++ detect_first_master ++ else ++ # a master instance exists and is healthy, promote this ++ # local read only instance ++ # so it can join the master galera cluster. ++ set_master_score ++ fi ++ fi ++ return $rc ++ elif [ $rc -ne $OCF_SUCCESS ]; then + return $rc + fi + ++ # if we make it here, mysql is running. Check cluster status now. ++ + echo $OCF_RESKEY_wsrep_cluster_address | grep -q $NODENAME + if [ $? -ne 0 ]; then + ocf_exit_reason "local node <${NODENAME}> is started, but is not a member of the wsrep_cluster_address <${OCF_RESKEY_wsrep_cluster_address}>" + return $OCF_ERR_GENERIC + fi + +- is_readonly +- if [ $? -ne 0 ]; then +- is_primary +- if [ $? -ne 0 ]; then +- ocf_exit_reason "local node <${NODENAME}> is neither in primary mode nor in read_only mode. Unknown state." +- return $OCF_ERR_GENERIC +- fi ++ is_primary ++ if [ $? -eq 0 ]; then + + if ocf_is_probe; then + # restore master score during probe +@@ -596,18 +634,10 @@ galera_monitor() + set_master_score + fi + rc=$OCF_RUNNING_MASTER +- else +- master_exists +- if [ $? -ne 0 ]; then +- detect_first_master +- else +- # a master instance exists and is healthy, promote this +- # local read only instance +- # so it can join the master galera cluster. +- set_master_score +- fi ++ else ++ ocf_exit_reason "local node <${NODENAME}> is started, but not in primary mode. Unknown state." ++ rc=$OCF_ERR_GENERIC + fi +- # TODO look at what is done in the wait script + + return $rc + } diff --git a/SOURCES/bz1171162-clvmd-opt-fix.patch b/SOURCES/bz1171162-clvmd-opt-fix.patch new file mode 100644 index 00000000..2a46addc --- /dev/null +++ b/SOURCES/bz1171162-clvmd-opt-fix.patch @@ -0,0 +1,25 @@ +From e0f3e2190cfef76b9d7383a0009b678ed2ef4b17 Mon Sep 17 00:00:00 2001 +From: David Vossel +Date: Wed, 29 Apr 2015 11:08:55 -0500 +Subject: [PATCH 1/6] bz1171162-clvmd-opt-fix + +--- + heartbeat/clvm | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/heartbeat/clvm b/heartbeat/clvm +index dcefcca..a1e2bc4 100755 +--- a/heartbeat/clvm ++++ b/heartbeat/clvm +@@ -370,7 +370,7 @@ clvmd_start() + if ocf_is_true $OCF_RESKEY_with_cmirrord; then + start_process $CMIRROR_PATH + fi +- start_process $DAEMON_PATH $CLVMDOPTS ++ start_process $DAEMON_PATH "$CLVMDOPTS" + + # Refresh local cache. + # +-- +1.8.4.2 + diff --git a/SOURCES/bz1183136-nginx-support.patch b/SOURCES/bz1183136-nginx-support.patch new file mode 100644 index 00000000..b85c9482 --- /dev/null +++ b/SOURCES/bz1183136-nginx-support.patch @@ -0,0 +1,113 @@ +From d828c825c58f2da4b4edd6548c5fd254842a0add Mon Sep 17 00:00:00 2001 +From: David Vossel +Date: Wed, 29 Apr 2015 11:15:18 -0500 +Subject: [PATCH 4/6] nginx agent support + +--- + heartbeat/nginx | 27 ++++++++++++--------------- + 1 file changed, 12 insertions(+), 15 deletions(-) + +diff --git a/heartbeat/nginx b/heartbeat/nginx +index 65fd8f2..fadc545 100755 +--- a/heartbeat/nginx ++++ b/heartbeat/nginx +@@ -31,7 +31,7 @@ + # OCF_RESKEY_status10regex + # OCF_RESKEY_status10url + # OCF_RESKEY_client +-# OCF_RESKEY_testurl ++# OCF_RESKEY_test20url + # OCF_RESKEY_test20regex + # OCF_RESKEY_test20conffile + # OCF_RESKEY_test20name +@@ -416,7 +416,7 @@ start_nginx() { + return $OCF_SUCCESS + fi + if +- ocf_run $NGINXD -t -c $CONFIGFILE ++ ocf_run $NGINXD $OPTIONS -t -c $CONFIGFILE + then + : Configuration file $CONFIGFILE looks OK + else +@@ -442,7 +442,7 @@ start_nginx() { + [ $ec -eq $OCF_NOT_RUNNING ] + then + tries=`expr $tries + 1` +- ocf_log info "Waiting for $NGINXD -c $CONFIGFILE to come up (try $tries)" ++ ocf_log info "Waiting for $NGINXD $OPTIONS -c $CONFIGFILE to come up (try $tries)" + true + else + false +@@ -727,25 +727,25 @@ For example, you can set this paramter to "wget" if you prefer that to curl. + + + +- ++ + + URL to test. If it does not start with "http", then it's + considered to be relative to the document root address. + +-Level 10 monitor url ++Level 20 monitor url + + + + + +-Regular expression to match in the output of testurl. ++Regular expression to match in the output of test20url. + Case insensitive. + + Level 20 monitor regular expression + + + +- ++ + + A file which contains a more complex test configuration. Could be useful if + you have to check more than one web application or in case sensitive +@@ -785,14 +785,11 @@ Extra options to apply when starting nginx. + + + +- ++ + + + +- +- +- +- ++ + + + +@@ -838,11 +835,11 @@ validate_all_nginx() { + exit $OCF_ERR_CONFIGURED + fi + if +- ocf_run $NGINXD -t -c $CONFIGFILE ++ ocf_run $NGINXD $OPTIONS -t -c $CONFIGFILE + then + : Cool $NGINXD likes $CONFIGFILE + else +- ocf_log err "$NGINXD -t -c $CONFIGFILE reported a configuration error." ++ ocf_log err "$NGINXD $OPTIONS -t -c $CONFIGFILE reported a configuration error." + return $OCF_ERR_CONFIGURED + fi + return $OCF_SUCCESS +@@ -859,7 +856,7 @@ then + OPTIONS="$OCF_RESKEY_options" + CLIENT=${OCF_RESKEY_client} + TESTREGEX=${OCF_RESKEY_status10regex:-'Reading: [0-9]+ Writing: [0-9]+ Waiting: [0-9]+'} +- TESTURL="$OCF_RESKEY_status10url" ++ TESTURL="$OCF_RESKEY_test20url" + TESTREGEX20=${OCF_RESKEY_test20regex} + TESTCONFFILE="$OCF_RESKEY_test20conffile" + TESTNAME="$OCF_RESKEY_test20name" +-- +1.8.4.2 + diff --git a/SOURCES/bz1189187-redis-agent.patch b/SOURCES/bz1189187-redis-agent.patch new file mode 100644 index 00000000..4ec372df --- /dev/null +++ b/SOURCES/bz1189187-redis-agent.patch @@ -0,0 +1,564 @@ +From d83b9a9394ef69ca2801c84dee46094a224ca654 Mon Sep 17 00:00:00 2001 +From: David Vossel +Date: Thu, 5 Mar 2015 13:47:58 -0600 +Subject: [PATCH] redis agent support + +--- + doc/man/Makefile.am | 1 + + heartbeat/Makefile.am | 1 + + heartbeat/redis | 519 ++++++++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 521 insertions(+) + create mode 100644 heartbeat/redis + +diff --git a/doc/man/Makefile.am b/doc/man/Makefile.am +index 43d60d9..653e818 100644 +--- a/doc/man/Makefile.am ++++ b/doc/man/Makefile.am +@@ -125,6 +125,7 @@ man_MANS = ocf_heartbeat_AoEtarget.7 \ + ocf_heartbeat_pound.7 \ + ocf_heartbeat_proftpd.7 \ + ocf_heartbeat_rabbitmq-cluster.7 \ ++ ocf_heartbeat_redis.7 \ + ocf_heartbeat_rsyncd.7 \ + ocf_heartbeat_rsyslog.7 \ + ocf_heartbeat_scsi2reservation.7 \ +diff --git a/heartbeat/Makefile.am b/heartbeat/Makefile.am +index 3bcf2d9..e4ed4fd 100644 +--- a/heartbeat/Makefile.am ++++ b/heartbeat/Makefile.am +@@ -105,6 +105,7 @@ ocf_SCRIPTS = ClusterMon \ + rabbitmq-cluster \ + Raid1 \ + Route \ ++ redis \ + rsyncd \ + rsyslog \ + SAPDatabase \ +diff --git a/heartbeat/redis b/heartbeat/redis +new file mode 100644 +index 0000000..6b479b2 +--- /dev/null ++++ b/heartbeat/redis +@@ -0,0 +1,519 @@ ++#!/bin/bash ++ ++. ${OCF_ROOT}/resource.d/heartbeat/.ocf-shellfuncs ++ ++: ${OCF_RESKEY_bin:=/usr/bin/redis-server} ++: ${OCF_RESKEY_client_bin:=/usr/bin/redis-cli} ++: ${OCF_RESKEY_user:=redis} ++: ${OCF_RESKEY_rundir:=/var/run/redis} ++: ${OCF_RESKEY_pidfile_name:=redis-server.pid} ++: ${OCF_RESKEY_socket_name:=redis.sock} ++: ${OCF_RESKEY_port:=6379} ++ ++if [ -z "$OCF_RESKEY_config" ]; then ++ if [ -f "/etc/redis.conf" ]; then ++ OCF_RESKEY_config="/etc/redis.conf" ++ else ++ OCF_RESKEY_config="/etc/redis/redis.conf" ++ fi ++fi ++ ++CHECK_SLAVE_STATE=0 ++ ++REDIS_SERVER="$OCF_RESKEY_bin" ++REDIS_CLIENT="$OCF_RESKEY_client_bin" ++REDIS_CONFIG="$OCF_RESKEY_config" ++REDIS_USER="$OCF_RESKEY_user" ++REDIS_RUNDIR="$OCF_RESKEY_rundir" ++REDIS_PIDFILE="$OCF_RESKEY_rundir/$OCF_RESKEY_pidfile_name" ++REDIS_SOCKET="$OCF_RESKEY_rundir/$OCF_RESKEY_socket_name" ++REDIS_REPLICATION_PORT="$OCF_RESKEY_port" ++ ++function meta_data() { ++ cat < ++ ++ ++1.0 ++ ++ ++Resource agent script for redis server. ++ ++This resource fully supports master/slave replication. The master preference of a node is determined by the 'slave_priority' parameter of the redis config. ++When taking the resource from 'unmanaged' to 'managed', the currently active master will be given a priority of 1000 (plus 1 for each active connection). The default 'slave_priority' is 100, so the master will stay master. For a slave to become master after converting the resource to managed, set a slave_priority greater than 1000. ++ ++ ++Redis server ++ ++ ++ ++ ++Path to \`redis-server\` ++ ++Path to \`redis-server\` ++ ++ ++ ++ ++ ++Path to \`redis-cli\` ++ ++Path to \`redis-cli\` ++ ++ ++ ++ ++ ++Path to 'redis.conf' ++ ++Path to 'redis.conf' ++ ++ ++ ++ ++ ++User to run redis as ++ ++Redis user ++ ++ ++ ++ ++ ++Directory to store socket and pid file in ++ ++Redis var/run dir ++ ++ ++ ++ ++ ++The filename to use for the pidfile. Will be created in the rundir. ++Should only be a basename, not a full path. ++ ++Redis pidfile name ++ ++ ++ ++ ++ ++The filename to use for the socket. Will be crated in the rundir. ++Should only be a basename, not a full path. ++ ++Redis socket name ++ ++ ++ ++ ++ ++Port for replication client to connect to on remote server ++ ++Replication port ++ ++ ++ ++ ++ ++During redis cluster bootstrap, wait for the last known master to be ++promoted before allowing any other instances in the cluster to be ++promoted. This lessens the risk of data loss when persistent data ++is in use. ++ ++Wait for last known master ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++EOI ++} ++ ++INSTANCE_ATTR_NAME=`echo ${OCF_RESOURCE_INSTANCE}| awk -F : '{print $1}'` ++CRM_ATTR_REPL_INFO="${HA_SBIN_DIR}/crm_attribute --type crm_config --name ${INSTANCE_ATTR_NAME}_REPL_INFO -s redis_replication" ++MASTER_HOST="" ++MASTER_ACTIVE_CACHED="" ++MASTER_ACTIVE="" ++ ++master_is_active() ++{ ++ if [ -z "$MASTER_ACTIVE_CACHED" ]; then ++ # determine if a master instance is already up and is healthy ++ crm_mon --as-xml | grep "resource.*id=\"${OCF_RESOURCE_INSTANCE}\".*role=\"Master\".*active=\"true\".*orphaned=\"false\".*failed=\"false\"" > /dev/null 2>&1 ++ MASTER_ACTIVE=$? ++ MASTER_ACTIVE_CACHED="true" ++ fi ++ return $MASTER_ACTIVE ++} ++ ++function set_master() ++{ ++ MASTER_HOST="$1" ++ ${CRM_ATTR_REPL_INFO} -v "$1" -q ++} ++ ++function last_known_master() ++{ ++ if [ -z "$MASTER_HOST" ]; then ++ MASTER_HOST="$(${CRM_ATTR_REPL_INFO} --query -q 2>/dev/null)" ++ fi ++ echo "$MASTER_HOST" ++} ++ ++function crm_master_reboot() { ++ "${HA_SBIN_DIR}/crm_master" -l reboot "$@" ++} ++ ++function calculate_score() ++{ ++ perf_score="$1" ++ connected_clients="$2" ++ ++ if ocf_is_true "$OCF_RESKEY_wait_last_known_master"; then ++ # only set perferred score by slave_priority if ++ # we are not waiting for the last known master. Otherwise ++ # we want the agent to have complete control over the scoring. ++ perf_score="" ++ connected_clients="0" ++ fi ++ ++ if [[ -z "$perf_score" ]]; then ++ if [[ "$(last_known_master)" == "$NODENAME" ]]; then ++ perf_score=1000 ++ else ++ perf_score=1 ++ fi ++ fi ++ perf_score=$(( perf_score + connected_clients )) ++ echo "$perf_score" ++} ++ ++function set_score() ++{ ++ local score="$1" ++ ++ if ocf_is_true "$OCF_RESKEY_wait_last_known_master" && ! master_is_active; then ++ local last_master="$(last_known_master)" ++ if [ -n "$last_master" ] && [[ "$last_master" != "$NODENAME" ]]; then ++ ocf_log info "Postponing setting master score for ${NODENAME} until last known master instance [${last_master}] is promoted" ++ return ++ fi ++ fi ++ ++ ocf_log debug "monitor: Setting master score to '$score'" ++ crm_master_reboot -v "$score" ++} ++ ++function redis_client() { ++ ocf_log debug "redis_client: '$REDIS_CLIENT' -s '$REDIS_SOCKET' $@" ++ "$REDIS_CLIENT" -s "$REDIS_SOCKET" "$@" | sed 's/\r//' ++} ++ ++function simple_status() { ++ local pid ++ ++ if ! [ -f "$REDIS_PIDFILE" ]; then ++ return $OCF_NOT_RUNNING ++ fi ++ ++ pid="$(<"$REDIS_PIDFILE")" ++ pidof "$REDIS_SERVER" | grep -q "\<$pid\>" || return $OCF_NOT_RUNNING ++ ++ ocf_log debug "monitor: redis-server running under pid $pid" ++ ++ return $OCF_SUCCESS ++} ++ ++function monitor() { ++ local res ++ ++ simple_status ++ res=$? ++ if (( res != OCF_SUCCESS )); then ++ return $res ++ fi ++ ++ typeset -A info ++ while read line; do ++ [[ "$line" == "#"* ]] && continue ++ [[ "$line" != *":"* ]] && continue ++ IFS=':' read -r key value <<< "$line" ++ info[$key]="$value" ++ done < <(redis_client info) ++ if [[ -z "${info[role]}" ]]; then ++ ocf_log err "monitor: Could not get role from \`$REDIS_CLIENT -s $REDIS_SOCKET info\`" ++ return $OCF_ERR_GENERIC ++ fi ++ ++ if ocf_is_ms; then ++ # Here we see if a score has already been set. ++ # If score isn't set we the redis setting 'slave_priority'. ++ # If that isn't set, we default to 1000 for a master, and 1 for slave. ++ # We then add 1 for each connected client ++ score="$(crm_master_reboot --get-value --quiet 2>/dev/null)" ++ if [[ -z "$score" ]]; then ++ score=$(calculate_score "${info[slave_priority]}" "${info[connected_clients]}") ++ set_score "$score" ++ fi ++ ++ if [[ "${info[role]}" == "master" ]]; then ++ if ocf_is_probe; then ++ set_master "$NODENAME" ++ fi ++ return $OCF_RUNNING_MASTER ++ fi ++ ++ if [ "$CHECK_SLAVE_STATE" -eq 1 ]; then ++ if [[ "${info[master_link_status]}" != "up" ]]; then ++ ocf_log info "monitor: Slave mode link has not yet been established (link=${info[master_link_status]})" ++ return $OCF_ERR_GENERIC ++ fi ++ if [[ "${info[master_host]}" != "$(last_known_master)" ]]; then ++ ocf_log err "monitor: Slave mode current master does not match running master. current=${info[master_host]}, running=$(last_known_master)" ++ return $OCF_ERR_GENERIC ++ fi ++ fi ++ fi ++ return $OCF_SUCCESS ++} ++ ++function start() { ++ monitor ++ status=$? ++ ++ if (( status == OCF_SUCCESS )) || (( status == OCF_RUNNING_MASTER )); then ++ ocf_log info "start: redis is already running" ++ return $OCF_SUCCESS ++ fi ++ ++ [[ ! -d "$REDIS_RUNDIR" ]] && mkdir -p "$REDIS_RUNDIR" ++ chown -R "$REDIS_USER" "$REDIS_RUNDIR" ++ ++ ocf_log info "start: $REDIS_SERVER --daemonize yes --unixsocket '$REDIS_SOCKET' --pidfile '$REDIS_PIDFILE'" ++ output="$(su "$REDIS_USER" -s /bin/sh -c "cd '$REDIS_RUNDIR'; exec '$REDIS_SERVER' '$REDIS_CONFIG' --daemonize yes --unixsocket '$REDIS_SOCKET' --pidfile '$REDIS_PIDFILE'" 2>&1)" ++ ++ while true; do ++ # wait for redis to start ++ typeset -A info ++ while read line; do ++ [[ "$line" == "#"* ]] && continue ++ [[ "$line" != *":"* ]] && continue ++ IFS=':' read -r key value <<< "$line" ++ info[$key]="$value" ++ done < <(redis_client info) ++ ++ if (( info[loading] == 0 )); then ++ break ++ elif (( info[loading] == 1 )); then ++ sleep "${info[loading_eta_seconds]}" ++ elif pidof "$REDIS_SERVER" >/dev/null; then ++ # unknown error, but the process still exists. ++ # This check is mainly because redis daemonizes before it starts listening, causing `redis-cli` to fail ++ # See https://github.com/antirez/redis/issues/2368 ++ # It's possible that the `pidof` will pick up a different redis, but in that case, the start operation will just time out ++ sleep 1 ++ else ++ ocf_log err "start: Unknown error waiting for redis to start" ++ return $OCF_ERR_GENERIC ++ fi ++ done ++ ++ ocf_is_ms && demote # pacemaker expects resources to start in slave mode ++ ++ monitor ++ status=$? ++ if (( status == OCF_SUCCESS )) || (( status == OCF_RUNNING_MASTER )); then ++ return $OCF_SUCCESS ++ fi ++ ++ ocf_log err "start: Unknown error starting redis. output=${output//$'\n'/; }" ++ return $status ++} ++ ++function stop() { ++ monitor ++ status=$? ++ ++ if (( status == OCF_NOT_RUNNING )); then ++ ocf_log info "stop: redis is already stopped" ++ crm_master_reboot -D ++ return $OCF_SUCCESS ++ fi ++ ++ pid="$(<"$REDIS_PIDFILE")" ++ kill -TERM "$pid" ++ ++ while true; do ++ simple_status ++ status=$? ++ if (( status == OCF_NOT_RUNNING )); then ++ crm_master_reboot -D ++ return $OCF_SUCCESS ++ fi ++ sleep 1 ++ done ++} ++ ++function promote() { ++ monitor ++ status=$? ++ ++ if (( status == OCF_RUNNING_MASTER )); then ++ ocf_log info "promote: Already running as master" ++ set_master "$NODENAME" ++ return $OCF_SUCCESS ++ elif (( status != OCF_SUCCESS )); then ++ ocf_log err "promote: Node is not running as a slave" ++ return $OCF_ERR_GENERIC ++ fi ++ ++ redis_client slaveof no one ++ ++ monitor ++ status=$? ++ if (( status == OCF_RUNNING_MASTER )); then ++ set_master "$NODENAME" ++ return $OCF_SUCCESS ++ fi ++ ++ ocf_log err "promote: Unknown error while promoting to master (status=$status)" ++ return $OCF_ERR_GENERIC ++} ++ ++function demote() { ++ local master_host ++ local master_port ++ ++ CHECK_SLAVE_STATE=1 ++ monitor ++ status=$? ++ ++ if (( status == OCF_SUCCESS )); then ++ ocf_log info "demote: Already running as slave" ++ return $OCF_SUCCESS ++ elif (( status == OCF_NOT_RUNNING )); then ++ ocf_log err "demote: Failed to demote, redis not running." ++ return $OCF_NOT_RUNNING ++ fi ++ ++ master_host="$(last_known_master)" ++ master_port="${REDIS_REPLICATION_PORT}" ++ ++ # The elected master has to remain a slave during startup. ++ # During this period a placeholder master host is assigned. ++ if [ -z "$master_host" ] || [[ "$master_host" == "$NODENAME" ]]; then ++ CHECK_SLAVE_STATE=0 ++ master_host="no-such-master" ++ elif ! master_is_active; then ++ # no master has been promoted yet. we'll be notified when the ++ # master starts. ++ CHECK_SLAVE_STATE=0 ++ master_host="no-such-master" ++ fi ++ ++ ocf_log info "demote: Setting master to '$master_host'" ++ ++ redis_client slaveof "$master_host" "$master_port" ++ ++ # wait briefly for the slave to connect to the master ++ for (( c=1; c <= 20; c++ )) ++ do ++ monitor ++ status=$? ++ if (( status == OCF_SUCCESS )); then ++ return $OCF_SUCCESS ++ fi ++ sleep 1 ++ done ++ ++ ocf_log err "demote: Unexpected error setting slave mode (status=$status)" ++ return $OCF_ERR_GENERIC ++} ++ ++function notify() { ++ mode="${OCF_RESKEY_CRM_meta_notify_type}-${OCF_RESKEY_CRM_meta_notify_operation}" ++ case "$mode" in ++ post-demote|post-promote) # change the master ++ monitor ++ status=$? ++ if (( status == OCF_SUCCESS )); then # were a slave ++ # calling demote updates the slave's connection ++ # to the newly appointed Master instance. ++ demote ++ fi ++ ;; ++ esac ++ return $OCF_SUCCESS ++} ++ ++function validate() { ++ if [[ -x "$REDIS_SERVER" ]]; then ++ ocf_log err "validate: $REDIS_SERVER does not exist or is not executable" ++ return $OCF_ERR_INSTALLED ++ fi ++ if [[ -x "$REDIS_CLIENT" ]]; then ++ ocf_log err "validate: $REDIS_CLIENT does not exist or is not executable" ++ return $OCF_ERR_INSTALLED ++ fi ++ if [[ -f "$REDIS_CONFIG" ]]; then ++ ocf_log err "validate: $REDIS_CONFIG does not exist" ++ return $OCF_ERR_CONFIGURED ++ fi ++ if ! getent passwd "$REDIS_USER" &>/dev/null; then ++ ocf_log err "validate: $REDIS_USER is not a valid user" ++ return $OCF_ERR_CONFIGURED ++ fi ++} ++ ++NODENAME=$(ocf_local_nodename) ++ ++ocf_log debug "action=${1:-$__OCF_ACTION} notify_type=${OCF_RESKEY_CRM_meta_notify_type} notify_operation=${OCF_RESKEY_CRM_meta_notify_operation} master_host=${OCF_RESKEY_CRM_meta_notify_master_uname} slave_host=${OCF_RESKEY_CRM_meta_notify_slave_uname} promote_host=${OCF_RESKEY_CRM_meta_notify_promote_uname} demote_host=${OCF_RESKEY_CRM_meta_notify_demote_uname}; params: bin=${OCF_RESKEY_bin} client_bin=${OCF_RESKEY_client_bin} config=${OCF_RESKEY_config} user=${OCF_RESKEY_user} rundir=${OCF_RESKEY_rundir} port=${OCF_RESKEY_port}" ++ ++case "${1:-$__OCF_ACTION}" in ++ status|monitor) ++ monitor ++ ;; ++ start) ++ start ++ ;; ++ stop) ++ stop ++ ;; ++ restart) ++ stop && start ++ ;; ++ promote) ++ promote ++ ;; ++ demote) ++ demote ++ ;; ++ notify) ++ notify ++ ;; ++ meta-data) ++ meta_data ++ ;; ++ validate-all) ++ validate ++ ;; ++ *) ++ echo "Usage: $0 {monitor|start|stop|restart|promote|demote|notify|validate-all|meta-data}" ++ exit $OCF_ERR_UNIMPLEMENTED ++ ;; ++esac ++status=$? ++ocf_log debug "exit_status=$status" ++exit $status +-- +1.8.4.2 + diff --git a/SOURCES/bz1198681-clvm-activate-vgs-option.patch b/SOURCES/bz1198681-clvm-activate-vgs-option.patch new file mode 100644 index 00000000..c3f84558 --- /dev/null +++ b/SOURCES/bz1198681-clvm-activate-vgs-option.patch @@ -0,0 +1,56 @@ +From b5ac7d0e49bb3b967c3865438067a95606db959a Mon Sep 17 00:00:00 2001 +From: David Vossel +Date: Mon, 27 Apr 2015 16:35:03 -0400 +Subject: [PATCH] High: clvm: activate_vgs option for enable/disable of + automatic vg activation + +--- + heartbeat/clvm | 18 ++++++++++++++++++ + 1 file changed, 18 insertions(+) + +diff --git a/heartbeat/clvm b/heartbeat/clvm +index 9d312cc..23e6f9f 100755 +--- a/heartbeat/clvm ++++ b/heartbeat/clvm +@@ -60,6 +60,18 @@ Options to clvmd. Refer to clvmd.8 for detailed descriptions. + Daemon Options + + ++ ++ ++ ++Whether or not to activate all cluster volume groups after starting ++the clvmd or not. Note that clustered volume groups will always be ++deactivated before the clvmd stops regardless of what this option ++is set to. ++ ++Activate volume groups ++ ++ ++ + + + +@@ -77,6 +89,7 @@ END + ####################################################################### + + : ${OCF_RESKEY_daemon_options:="-d0"} ++: ${OCF_RESKEY_activate_vgs:="true"} + + sbindir=$HA_SBIN_DIR + if [ -z $sbindir ]; then +@@ -322,6 +335,11 @@ start_process() + + clvmd_activate_all() + { ++ ++ if ! ocf_is_true "$OCF_RESKEY_activate_vgs"; then ++ ocf_log info "skipping vg activation, activate_vgs is set to $OCF_RESKEY_activate_vgs" ++ return $OCF_SUCCESS ++ fi + # Activate all volume groups by leaving the + # "volume group name" parameter empty + ocf_run ${LVM_VGCHANGE} -aay +-- +1.8.4.2 + diff --git a/SOURCES/bz1200756-ipsrcaddr-misconfig.patch b/SOURCES/bz1200756-ipsrcaddr-misconfig.patch new file mode 100644 index 00000000..d69d1e2b --- /dev/null +++ b/SOURCES/bz1200756-ipsrcaddr-misconfig.patch @@ -0,0 +1,92 @@ +From 3c383f3dbb3b5351b25d33aa6e516ab8fc04a26a Mon Sep 17 00:00:00 2001 +From: David Vossel +Date: Tue, 28 Apr 2015 11:47:21 -0500 +Subject: [PATCH] High: IPsrcaddr: return correct error code during stop when + misconfigured + +--- + heartbeat/IPsrcaddr | 45 +++++++++++++++++++++++++++++++-------------- + 1 file changed, 31 insertions(+), 14 deletions(-) + +diff --git a/heartbeat/IPsrcaddr b/heartbeat/IPsrcaddr +index 8163c0c..33c5be6 100755 +--- a/heartbeat/IPsrcaddr ++++ b/heartbeat/IPsrcaddr +@@ -387,15 +387,27 @@ ip_status() { + + srca_validate_all() { + +- check_binary $AWK +- check_binary $IFCONFIG ++ if [ -z "$OCF_RESKEY_ipaddress" ]; then ++ # usage ++ ocf_exit_reason "Please set OCF_RESKEY_ipaddress to the preferred source IP address!" ++ return $OCF_ERR_CONFIGURED ++ fi ++ ++ ++ if ! [ "x$SYSTYPE" = "xLinux" ]; then ++ # checks after this point are only relevant for linux. ++ return $OCF_SUCCESS ++ fi ++ ++ check_binary $AWK ++ check_binary $IFCONFIG + + # The IP address should be in good shape + if CheckIP "$ipaddress"; then + : + else + ocf_exit_reason "Invalid IP address [$ipaddress]" +- exit $OCF_ERR_CONFIGURED ++ return $OCF_ERR_CONFIGURED + fi + + if ocf_is_probe; then +@@ -407,8 +419,9 @@ srca_validate_all() { + : + else + ocf_exit_reason "We are not serving [$ipaddress], hence can not make it a preferred source address" +- exit $OCF_ERR_INSTALLED ++ return $OCF_ERR_INSTALLED + fi ++ return $OCF_SUCCESS + } + + if +@@ -430,18 +443,22 @@ case $1 in + ;; + esac + +-if +- [ -z "$OCF_RESKEY_ipaddress" ] +-then +-# usage +- ocf_exit_reason "Please set OCF_RESKEY_ipaddress to the preferred source IP address!" +- exit $OCF_ERR_CONFIGURED +-fi +- + ipaddress="$OCF_RESKEY_ipaddress" + +-if [ "x$SYSTYPE" = "xLinux" ]; then +- srca_validate_all ++srca_validate_all ++rc=$? ++if [ $rc -ne $OCF_SUCCESS ]; then ++ case $1 in ++ # if we can't validate the configuration during a stop, that ++ # means the resources isn't configured correctly. There's no way ++ # to actually stop the resource in this situation because there's ++ # no way it could have even started. Return success here ++ # to indicate that the resource is not running, otherwise the ++ # stop action will fail causing the node to be fenced just because ++ # of a mis configuration. ++ stop) exit $OCF_SUCCESS;; ++ *) exit $rc;; ++ esac + fi + + findif_out=`$FINDIF -C` +-- +1.8.4.2 + diff --git a/SOURCES/bz1212632-nagios.patch b/SOURCES/bz1212632-nagios.patch new file mode 100644 index 00000000..82a1eecf --- /dev/null +++ b/SOURCES/bz1212632-nagios.patch @@ -0,0 +1,272 @@ +diff -uNr a/doc/man/Makefile.am b/doc/man/Makefile.am +--- a/doc/man/Makefile.am 2016-06-06 10:32:26.889194520 +0200 ++++ b/doc/man/Makefile.am 2016-06-06 10:33:28.850643243 +0200 +@@ -118,6 +118,7 @@ + ocf_heartbeat_lxc.7 \ + ocf_heartbeat_mysql.7 \ + ocf_heartbeat_mysql-proxy.7 \ ++ ocf_heartbeat_nagios.7 \ + ocf_heartbeat_named.7 \ + ocf_heartbeat_nfsnotify.7 \ + ocf_heartbeat_nfsserver.7 \ +diff -uNr a/heartbeat/Makefile.am b/heartbeat/Makefile.am +--- a/heartbeat/Makefile.am 2016-06-06 10:32:26.889194520 +0200 ++++ b/heartbeat/Makefile.am 2016-06-06 10:33:02.418878409 +0200 +@@ -97,6 +97,7 @@ + ManageVE \ + mysql \ + mysql-proxy \ ++ nagios \ + named \ + nfsnotify \ + nfsserver \ +diff -uNr a/heartbeat/nagios b/heartbeat/nagios +--- a/heartbeat/nagios 1970-01-01 01:00:00.000000000 +0100 ++++ b/heartbeat/nagios 2016-06-06 10:33:02.418878409 +0200 +@@ -0,0 +1,246 @@ ++#!/bin/sh ++# ++# License: GNU General Public License (GPL) ++# (c) 2015 T.J. Yang, O. Albrigtsen ++# and Linux-HA contributors ++# ++# ----------------------------------------------------------------------------- ++# O C F R E S O U R C E S C R I P T S P E C I F I C A T I O N ++# ----------------------------------------------------------------------------- ++# ++# NAME ++# nagios : OCF resource agent script for Nagios Server ++# ++ ++# Initialization: ++: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat} ++. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs ++ ++# Defaults ++OCF_RESKEY_user_default="nagios" ++OCF_RESKEY_group_default="nagios" ++OCF_RESKEY_binary_default="/usr/sbin/nagios" ++OCF_RESKEY_config_default="/etc/nagios/nagios.cfg" ++OCF_RESKEY_log_default="/var/log/nagios/nagios.log" ++OCF_RESKEY_retention_default="/var/log/nagios/retention.dat" ++OCF_RESKEY_command_default="/var/log/nagios/rw/nagios.cmd" ++OCF_RESKEY_pid_default="/var/run/nagios.pid" ++ ++: ${OCF_RESKEY_user=${OCF_RESKEY_user_default}} ++: ${OCF_RESKEY_group=${OCF_RESKEY_group_default}} ++: ${OCF_RESKEY_binary=${OCF_RESKEY_binary_default}} ++: ${OCF_RESKEY_config=${OCF_RESKEY_config_default}} ++: ${OCF_RESKEY_log=${OCF_RESKEY_log_default}} ++: ${OCF_RESKEY_retention=${OCF_RESKEY_retention_default}} ++: ${OCF_RESKEY_command=${OCF_RESKEY_command_default}} ++: ${OCF_RESKEY_pid=${OCF_RESKEY_pid_default}} ++ ++ ++nagios_usage() { ++ cat < ++ ++ ++0.75 ++ ++OCF Resource script for Nagios 3.x or 4.x. It manages a Nagios instance as a HA resource. ++Nagios resource agent ++ ++ ++ ++ ++ User running Nagios daemon (for file permissions) ++ Nagios user ++ ++ ++ ++ ++ Group running Nagios daemon (for file permissions) ++ Nagios group ++ ++ ++ ++ ++ Location of the Nagios binary ++ Nagios binary ++ ++ ++ ++ ++ Configuration file ++ Nagios config ++ ++ ++ ++ ++ Location of the Nagios log ++ Nagios log ++ ++ ++ ++ ++ Location of the Nagios retention file ++ Nagios retention file ++ ++ ++ ++ ++ Location of the Nagios external command file ++ Nagios command file ++ ++ ++ ++ ++ Location of the Nagios pid/lock ++ Nagios pid file ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++END ++} ++ ++ ++nagios_start() { ++ nagios_validate_all ++ rc=$? ++ if [ $rc -ne 0 ]; then ++ return $rc ++ fi ++ ++ ++ # if resource is already running,no need to continue code after this. ++ if nagios_monitor; then ++ ocf_log info "Nagios is already running" ++ return $OCF_SUCCESS ++ fi ++ ++ # Remove ${OCF_RESKEY_pid} if it exists ++ rm -f ${OCF_RESKEY_pid} ++ ++ ocf_run -q touch ${OCF_RESKEY_log} ${OCF_RESKEY_retention} ${OCF_RESKEY_pid} ++ chown ${OCF_RESKEY_user}:${OCF_RESKEY_group} ${OCF_RESKEY_log} ${OCF_RESKEY_retention} ${OCF_RESKEY_pid} ++ rm -f ${OCF_RESKEY_command} ++ [ -x /sbin/restorecon ] && /sbin/restorecon ${OCF_RESKEY_pid} ++ ocf_run -q ${OCF_RESKEY_binary} -d ${OCF_RESKEY_config} ++ ++ while ! nagios_monitor; do ++ sleep 1 ++ done ++ ++ if [ $? -eq "0" ]; then ++ ocf_log info "Nagios started" ++ return ${OCF_SUCCESS} ++ fi ++ ++ return $OCF_SUCCESS ++} ++ ++nagios_stop() { ++ nagios_monitor ++ if [ "$?" -ne "$OCF_SUCCESS" ]; then ++ # Currently not running. Nothing to do. ++ ocf_log info "Resource is already stopped" ++ rm -f ${OCF_RESKEY_pid} ++ ++ return $OCF_SUCCESS ++ fi ++ ++ kill `cat ${OCF_RESKEY_pid}` ++ ++ # Wait for process to stop ++ while nagios_monitor; do ++ sleep 1 ++ done ++ ++ return $OCF_SUCCESS ++} ++ ++nagios_monitor(){ ++ ocf_pidfile_status ${OCF_RESKEY_pid} > /dev/null 2>&1 ++ case "$?" in ++ 0) ++ rc=$OCF_SUCCESS ++ ;; ++ 1|2) ++ rc=$OCF_NOT_RUNNING ++ ;; ++ *) ++ rc=$OCF_ERR_GENERIC ++ ;; ++ esac ++ return $rc ++} ++ ++nagios_validate_all(){ ++ check_binary ${OCF_RESKEY_binary} ++ ++ if [ ! -f ${OCF_RESKEY_config} ]; then ++ ocf_exit_reason "Configuration file ${OCF_RESKEY_config} not found" ++ return ${OCF_ERR_INSTALLED} ++ fi ++ ++ ${OCF_RESKEY_binary} -v ${OCF_RESKEY_config} > /dev/null 2>&1; ++ if [ $? -ne "0" ]; then ++ ocf_exit_reason "Configuration check failed" ++ return ${OCF_ERR_INSTALLED} ++ fi ++} ++ ++ ++# **************************** MAIN SCRIPT ************************************ ++ ++# Make sure meta-data and usage always succeed ++case $__OCF_ACTION in ++meta-data) nagios_meta_data ++ exit $OCF_SUCCESS ++ ;; ++usage|help) nagios_usage ++ exit $OCF_SUCCESS ++ ;; ++esac ++ ++# This OCF agent script need to be run as root user. ++if ! ocf_is_root; then ++ echo "$0 agent script need to be run as root user." ++ ocf_log debug "$0 agent script need to be run as root user." ++ exit $OCF_ERR_GENERIC ++fi ++ ++# Translate each action into the appropriate function call ++case $__OCF_ACTION in ++start) nagios_start;; ++stop) nagios_stop;; ++status|monitor) nagios_monitor;; ++validate-all) nagios_validate_all;; ++*) nagios_usage ++ exit $OCF_ERR_UNIMPLEMENTED ++ ;; ++esac ++rc=$? ++ ++exit $rc ++ ++# End of this script diff --git a/SOURCES/bz1213971-ethmon-opt.patch b/SOURCES/bz1213971-ethmon-opt.patch new file mode 100644 index 00000000..5a1f346b --- /dev/null +++ b/SOURCES/bz1213971-ethmon-opt.patch @@ -0,0 +1,43 @@ +From 3e969507468bea12e1d126b31b222ad248780a80 Mon Sep 17 00:00:00 2001 +From: David Vossel +Date: Wed, 29 Apr 2015 11:13:26 -0500 +Subject: [PATCH 3/6] ethmonitor link_statys_only option + +--- + heartbeat/ethmonitor | 13 +++++++++++++ + 1 file changed, 13 insertions(+) + +diff --git a/heartbeat/ethmonitor b/heartbeat/ethmonitor +index a447391..d0ec4ef 100755 +--- a/heartbeat/ethmonitor ++++ b/heartbeat/ethmonitor +@@ -176,6 +176,14 @@ For infiniband devices, this is the port to monitor. + + + ++ ++ ++Only report success based on link status. Do not perform RX counter or arping related connectivity tests. ++ ++link status check only ++ ++ ++ + + + +@@ -378,6 +386,11 @@ if_check () { + return $OCF_NOT_RUNNING + fi + ++ # if using link_status_only, skip RX count and arping related tests ++ if ocf_is_true "$OCF_RESKEY_link_status_only"; then ++ return $OCF_SUCCESS ++ fi ++ + # watch for packet counter changes + ocf_log debug "watch for packet counter changes" + watch_pkt_counter +-- +1.8.4.2 + diff --git a/SOURCES/bz1214360-NovaCompute-update1.patch.patch b/SOURCES/bz1214360-NovaCompute-update1.patch.patch new file mode 100644 index 00000000..2dabe0be --- /dev/null +++ b/SOURCES/bz1214360-NovaCompute-update1.patch.patch @@ -0,0 +1,494 @@ +From 8c92227bce9cc4fe177eea5b2f7c9016e96434f9 Mon Sep 17 00:00:00 2001 +From: David Vossel +Date: Mon, 29 Jun 2015 13:03:17 -0500 +Subject: [PATCH 1/3] bz1214360-NovaCompute-update1.patch + +--- + doc/man/Makefile.am | 1 + + heartbeat/Makefile.am | 3 +- + heartbeat/NovaCompute | 73 ++++++------ + heartbeat/NovaEvacuate | 311 +++++++++++++++++++++++++++++++++++++++++++++++++ + 4 files changed, 352 insertions(+), 36 deletions(-) + create mode 100755 heartbeat/NovaEvacuate + +diff --git a/doc/man/Makefile.am b/doc/man/Makefile.am +index 42a57fe..d32426b 100644 +--- a/doc/man/Makefile.am ++++ b/doc/man/Makefile.am +@@ -74,6 +74,7 @@ man_MANS = ocf_heartbeat_AoEtarget.7 \ + ocf_heartbeat_ManageRAID.7 \ + ocf_heartbeat_ManageVE.7 \ + ocf_heartbeat_NovaCompute.7 \ ++ ocf_heartbeat_NovaEvacuate.7 \ + ocf_heartbeat_Pure-FTPd.7 \ + ocf_heartbeat_Raid1.7 \ + ocf_heartbeat_Route.7 \ +diff --git a/heartbeat/Makefile.am b/heartbeat/Makefile.am +index 0bebf97..1034632 100644 +--- a/heartbeat/Makefile.am ++++ b/heartbeat/Makefile.am +@@ -52,7 +52,8 @@ send_ua_SOURCES = send_ua.c IPv6addr_utils.c + IPv6addr_LDADD = -lplumb $(LIBNETLIBS) + send_ua_LDADD = $(LIBNETLIBS) + +-osp_SCRIPTS = NovaCompute ++osp_SCRIPTS = NovaCompute \ ++ NovaEvacuate + + ocf_SCRIPTS = ClusterMon \ + CTDB \ +diff --git a/heartbeat/NovaCompute b/heartbeat/NovaCompute +index f71abeb..09eee38 100644 +--- a/heartbeat/NovaCompute ++++ b/heartbeat/NovaCompute +@@ -107,15 +107,26 @@ Disable shared storage recovery for instances. Use at your own risk! + + + ++ ++ ++How long to wait for nova to finish evacuating instances elsewhere ++before starting nova-compute. Only used when the agent detects ++evacuations might be in progress. ++ ++You may need to increase the start timeout when increasing this value. ++ ++Delay to allow evacuations time to complete ++ ++ ++ + + + +- ++ + + + + +- + + + END +@@ -132,7 +143,7 @@ sigterm_handler() { + + nova_usage() { + cat < ++ ++ ++1.0 ++ ++ ++Facility for tacking a list of compute nodes and reliably evacuating the ones that fence_evacuate has flagged. ++ ++Evacuator for OpenStack Nova Compute Server ++ ++ ++ ++ ++ ++Authorization URL for connecting to keystone in admin context ++ ++Authorization URL ++ ++ ++ ++ ++ ++Username for connecting to keystone in admin context ++ ++Username ++ ++ ++ ++ ++Password for connecting to keystone in admin context ++ ++Password ++ ++ ++ ++ ++ ++Tenant name for connecting to keystone in admin context. ++Note that with Keystone V3 tenant names are only unique within a domain. ++ ++Tenant name ++ ++ ++ ++ ++ ++Nova API location (internal, public or admin URL) ++ ++Nova API location (internal, public or admin URL) ++ ++ ++ ++ ++ ++Disable shared storage recovery for instances. Use at your own risk! ++ ++Disable shared storage recovery for instances ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++END ++} ++ ++####################################################################### ++ ++# don't exit on TERM, to test that lrmd makes sure that we do exit ++trap sigterm_handler TERM ++sigterm_handler() { ++ ocf_log info "They use TERM to bring us down. No such luck." ++ return ++} ++ ++evacuate_usage() { ++ cat < +Date: Thu, 25 Jun 2015 16:27:47 -0500 +Subject: [PATCH 2/3] bz1214781-lvm-partial-activation-fix.patch + +--- + heartbeat/LVM | 26 ++++++++++++++++++++++++-- + 1 file changed, 24 insertions(+), 2 deletions(-) + +diff --git a/heartbeat/LVM b/heartbeat/LVM +index 58cbe83..4b9c167 100755 +--- a/heartbeat/LVM ++++ b/heartbeat/LVM +@@ -568,8 +568,30 @@ LVM_validate_all() { + ## + VGOUT=`vgck ${VOLUME} 2>&1` + if [ $? -ne 0 ]; then +- ocf_exit_reason "Volume group [$VOLUME] does not exist or contains error! ${VGOUT}" +- exit $OCF_ERR_GENERIC ++ # Inconsistency might be due to missing physical volumes, which doesn't ++ # automatically mean we should fail. If partial_activation=true then ++ # we should let start try to handle it, or if no PVs are listed as ++ # "unknown device" then another node may have marked a device missing ++ # where we have access to all of them and can start without issue. ++ if vgs -o pv_attr --noheadings $OCF_RESKEY_volgrpname 2>/dev/null | grep 'm' > /dev/null 2>&1; then ++ if vgs -o pv_name --noheadings $OCF_RESKEY_volgrpname 2>/dev/null | grep 'unknown device' > /dev/null 2>&1; then ++ if ! ocf_is_true "$OCF_RESKEY_partial_activation" ; then ++ # We are missing devices and cannot activate partially ++ ocf_exit_reason "Volume group [$VOLUME] has devices missing. Consider partial_activation=true to attempt to activate partially" ++ exit $OCF_ERR_GENERIC ++ else ++ # We are missing devices but are allowed to activate partially. ++ # Assume that caused the vgck failure and carry on ++ ocf_log warn "Volume group inconsistency detected with missing device(s) and partial_activation enabled. Proceeding with requested action." ++ fi ++ fi ++ # else the vg is partial but all devices are accounted for, so another ++ # node must have marked the device missing. Proceed. ++ else ++ # vgck failure was for something other than missing devices ++ ocf_exit_reason "Volume group [$VOLUME] does not exist or contains error! ${VGOUT}" ++ exit $OCF_ERR_GENERIC ++ fi + fi + + ## +-- +1.8.4.2 + diff --git a/SOURCES/bz1223615-apache-includes-fix.patch.patch b/SOURCES/bz1223615-apache-includes-fix.patch.patch new file mode 100644 index 00000000..22105ee0 --- /dev/null +++ b/SOURCES/bz1223615-apache-includes-fix.patch.patch @@ -0,0 +1,27 @@ +From 72482ca1e117f426378a700a8b1e01443e0fb597 Mon Sep 17 00:00:00 2001 +From: David Vossel +Date: Thu, 25 Jun 2015 16:30:20 -0500 +Subject: [PATCH 3/3] bz1223615-apache-includes-fix.patch + +--- + heartbeat/apache-conf.sh | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/heartbeat/apache-conf.sh b/heartbeat/apache-conf.sh +index dc3426f..a3c8930 100644 +--- a/heartbeat/apache-conf.sh ++++ b/heartbeat/apache-conf.sh +@@ -24,7 +24,9 @@ apachecat() { + function procline() { + split($0,a); + if( a[1]~/^[Ii]nclude$/ ) { +- procinclude(a[2]); ++ includedir=a[2]; ++ gsub("\"","",includedir); ++ procinclude(includedir); + } else { + if( a[1]=="ServerRoot" ) { + rootdir=a[2]; +-- +1.8.4.2 + diff --git a/SOURCES/bz1227293-dhcpd-chroot-fix.patch.patch b/SOURCES/bz1227293-dhcpd-chroot-fix.patch.patch new file mode 100644 index 00000000..7435dd2a --- /dev/null +++ b/SOURCES/bz1227293-dhcpd-chroot-fix.patch.patch @@ -0,0 +1,49 @@ +From 6f8a0aa5c0f6c1e4965e4ce10d62ba83ae9f834e Mon Sep 17 00:00:00 2001 +From: David Vossel +Date: Mon, 29 Jun 2015 13:10:42 -0500 +Subject: [PATCH 3/3] bz1227293-dhcpd-chroot-fix.patch + +--- + heartbeat/dhcpd | 12 ++++++++++-- + 1 file changed, 10 insertions(+), 2 deletions(-) + +diff --git a/heartbeat/dhcpd b/heartbeat/dhcpd +index 67b529e..89a9578 100755 +--- a/heartbeat/dhcpd ++++ b/heartbeat/dhcpd +@@ -38,6 +38,14 @@ OCF_RESKEY_leases_default="/db/dhcpd.leases" + OCF_RESKEY_interface_default="" + OCF_RESKEY_includes_default="" + ++# On some systems, the chrooted default is slightly different. ++# Lets do our best to support both by default. ++if [ ! -d "$OCF_RESKEY_chrooted_path_default" ]; then ++ if [ -d "/var/lib/dhcpd" ]; then ++ OCF_RESKEY_chrooted_path_default="/var/lib/dhcpd" ++ fi ++fi ++ + : ${OCF_RESKEY_binary=${OCF_RESKEY_binary_default}} + : ${OCF_RESKEY_pid=${OCF_RESKEY_pid_default}} + : ${OCF_RESKEY_user=${OCF_RESKEY_user_default}} +@@ -302,7 +310,7 @@ dhcpd_initialize_chroot() { + { ocf_exit_reason "could not copy $i to chroot jail"; return $OCF_ERR_GENERIC; } + done + +- libdir=$(basename $(echo /var/lib/dhcp/lib*)) ++ libdir=$(basename $(echo ${OCF_RESKEY_chrooted_path}/lib*)) + if test -x /usr/bin/ldd ; then + get_ldd_deps() + { +@@ -327,7 +335,7 @@ dhcpd_initialize_chroot() { + done | sort -u` + for i in $cplibs ; do + if [ -s "$i" ]; then +- cp -pL "$i" "/var/lib/dhcp/$libdir/" || ++ cp -pL "$i" "${OCF_RESKEY_chrooted_path}/$libdir/" || + { ocf_exit_reason "could not copy $i to chroot jail"; return $OCF_ERR_GENERIC; } + fi + done +-- +1.8.4.2 + diff --git a/SOURCES/bz1231032-redis-update.patch.patch b/SOURCES/bz1231032-redis-update.patch.patch new file mode 100644 index 00000000..03ddf4b9 --- /dev/null +++ b/SOURCES/bz1231032-redis-update.patch.patch @@ -0,0 +1,121 @@ +From c982683ac8c2de64f69c5f47727242c65e00df90 Mon Sep 17 00:00:00 2001 +From: David Vossel +Date: Mon, 29 Jun 2015 13:07:14 -0500 +Subject: [PATCH 2/3] bz1231032-redis-update.patch + +--- + heartbeat/redis | 51 ++++++++++++++++++++++++++++++++++++++++++++++----- + 1 file changed, 46 insertions(+), 5 deletions(-) + +diff --git a/heartbeat/redis b/heartbeat/redis +index 6b479b2..b63a2b9 100644 +--- a/heartbeat/redis ++++ b/heartbeat/redis +@@ -20,6 +20,7 @@ fi + + CHECK_SLAVE_STATE=0 + ++REDIS_CHECK_DUMP="/usr/bin/redis-check-dump" + REDIS_SERVER="$OCF_RESKEY_bin" + REDIS_CLIENT="$OCF_RESKEY_client_bin" + REDIS_CONFIG="$OCF_RESKEY_config" +@@ -29,6 +30,17 @@ REDIS_PIDFILE="$OCF_RESKEY_rundir/$OCF_RESKEY_pidfile_name" + REDIS_SOCKET="$OCF_RESKEY_rundir/$OCF_RESKEY_socket_name" + REDIS_REPLICATION_PORT="$OCF_RESKEY_port" + ++if ! [ -f $REDIS_CHECK_DUMP ]; then ++ REDIS_CHECK_DUMP="$(which redis-check-dump 2>/dev/null)" ++fi ++ ++if [ -f "$REDIS_CONFIG" ]; then ++ REDIS_DUMP_DIR="$(cat $REDIS_CONFIG | grep "^\s*dir\s" | awk '{ print $2 }' 2>/dev/null)" ++ REDIS_DUMP_FILE="$(cat $REDIS_CONFIG | grep "^\s*dbfilename\s" | awk '{ print $2 }' 2>/dev/null)" ++fi ++: ${REDIS_DUMP_DIR:=/var/lib/redis/} ++: ${REDIS_DUMP_FILE:=dump.rdb} ++ + function meta_data() { + cat < +@@ -289,6 +301,14 @@ function monitor() { + return $OCF_SUCCESS + } + ++function check_dump_file() ++{ ++ if ! have_binary "$REDIS_CHECK_DUMP"; then ++ return 0 ++ fi ++ $REDIS_CHECK_DUMP ${REDIS_DUMP_DIR}/${REDIS_DUMP_FILE} 2>&1 ++} ++ + function start() { + monitor + status=$? +@@ -301,6 +321,16 @@ function start() { + [[ ! -d "$REDIS_RUNDIR" ]] && mkdir -p "$REDIS_RUNDIR" + chown -R "$REDIS_USER" "$REDIS_RUNDIR" + ++ # check for 0 byte database dump file. This is an unrecoverable start ++ # condition that we can avoid by deleting the 0 byte database file. ++ if [ -f "${REDIS_DUMP_DIR}/${REDIS_DUMP_FILE}" ]; then ++ local size="$(stat --format "%s" ${REDIS_DUMP_DIR}/${REDIS_DUMP_FILE})" ++ if [ "$?" -eq "0" ] && [ "$size" -eq "0" ]; then ++ ocf_log notice "Detected 0 byte ${REDIS_DUMP_FILE}, deleting zero length file to avoid start failure." ++ rm -f ${REDIS_DUMP_DIR}/${REDIS_DUMP_FILE} ++ fi ++ fi ++ + ocf_log info "start: $REDIS_SERVER --daemonize yes --unixsocket '$REDIS_SOCKET' --pidfile '$REDIS_PIDFILE'" + output="$(su "$REDIS_USER" -s /bin/sh -c "cd '$REDIS_RUNDIR'; exec '$REDIS_SERVER' '$REDIS_CONFIG' --daemonize yes --unixsocket '$REDIS_SOCKET' --pidfile '$REDIS_PIDFILE'" 2>&1)" + +@@ -325,7 +355,8 @@ function start() { + # It's possible that the `pidof` will pick up a different redis, but in that case, the start operation will just time out + sleep 1 + else +- ocf_log err "start: Unknown error waiting for redis to start" ++ check_output="$(check_dump_file)" ++ ocf_log err "start: Unknown error waiting for redis to start. redis-check-dump output=${check_output//$'\n'/; }" + return $OCF_ERR_GENERIC + fi + done +@@ -338,7 +369,8 @@ function start() { + return $OCF_SUCCESS + fi + +- ocf_log err "start: Unknown error starting redis. output=${output//$'\n'/; }" ++ check_output="$(check_dump_file)" ++ ocf_log err "start: Unknown error starting redis. redis-server output=${output//$'\n'/; } redis-check-dump output=${check_output//$'\n'/; }" + return $status + } + +@@ -427,14 +459,23 @@ function demote() { + + redis_client slaveof "$master_host" "$master_port" + +- # wait briefly for the slave to connect to the master +- for (( c=1; c <= 20; c++ )) +- do ++ # Wait forever for the slave to connect to the master and finish the ++ # sync. Timeout is controlled by Pacemaker "op start timeout=XX". ++ # ++ # hint: redis master_link_status will only come "up" when ++ # the SYNC with the master has completed. ++ # This can take an arbitraty time (data) and should ++ # only be parametrized by the start operation timeout ++ # by the administrator, not by this resource agent code ++ while true; do ++ # Wait infinite if replication is syncing ++ # Then start/demote operation timeout determines timeout + monitor + status=$? + if (( status == OCF_SUCCESS )); then + return $OCF_SUCCESS + fi ++ + sleep 1 + done + +-- +1.8.4.2 + diff --git a/SOURCES/bz1232376-oracle-agent-update.diff b/SOURCES/bz1232376-oracle-agent-update.diff new file mode 100644 index 00000000..3a8eb120 --- /dev/null +++ b/SOURCES/bz1232376-oracle-agent-update.diff @@ -0,0 +1,246 @@ +diff --git a/heartbeat/oracle b/heartbeat/oracle +index 5ecc2f3..c629eb6 100755 +--- a/heartbeat/oracle ++++ b/heartbeat/oracle +@@ -27,6 +27,9 @@ + # OCF_RESKEY_ipcrm (optional; defaults to "instance") + # OCF_RESKEY_clear_backupmode (optional; default to "false") + # OCF_RESKEY_shutdown_method (optional; default to "checkpoint/abort") ++# OCF_RESKEY_monuser (optional; defaults to "OCFMON") ++# OCF_RESKEY_monpassword (optional; defaults to "OCFMON") ++# OCF_RESKEY_monprofile (optional; defaults to "OCFMONPROFILE") + # + # Initialization: + +@@ -56,6 +59,11 @@ oracle_usage() { + ! + } + ++# Defaults ++OCF_RESKEY_monuser_default="OCFMON" ++OCF_RESKEY_monpassword_default="OCFMON" ++OCF_RESKEY_monprofile_default="OCFMONPROFILE" ++ + oracle_meta_data() { + cat < +@@ -100,6 +108,39 @@ If this does not work for you, just set it explicitely. + + + ++ ++ ++Monitoring user name. Every connection as ++sysdba is logged in an audit log. This can ++result in a large number of new files created. ++A new user is created (if it doesn't exist) in ++the start action and subsequently used in monitor. ++It should have very limited rights. Make sure ++that the password for this user does not expire. ++ ++monuser ++ ++ ++ ++ ++ ++Password for the monitoring user. Make sure ++that the password for this user does not expire. ++ ++monpassword ++ ++ ++ ++ ++ ++Profile used by the monitoring user. If the ++profile does not exist, it will be created ++with a non-expiring password. ++ ++monprofile ++ ++ ++ + + + Sometimes IPC objects (shared memory segments and semaphores) +@@ -216,7 +257,7 @@ execsql() { + if [ "$US" = "$ORACLE_OWNER" ]; then + sqlplus -S /nolog + else +- su - $ORACLE_OWNER -c ". $ORA_ENVF; sqlplus -S /nolog" ++ su - $ORACLE_OWNER -s /bin/sh -c ". $ORA_ENVF; sqlplus -S /nolog" + fi + } + +@@ -250,7 +291,7 @@ dbasql() { + runsql "connect / as sysdba" $* + } + monsql() { +- runsql "connect $MONUSR/$MONUSR" $* ++ runsql "connect $MONUSR/\"$MONPWD\"" $* + } + # use dbasql_one if the query should result in a single line output + # at times people stuff commands in oracle .profile +@@ -325,22 +366,73 @@ getipc() { + echo "oradebug tracefile_name" + echo "oradebug ipc" + } ++show_mon_profile() { ++ echo "select PROFILE from dba_profiles where PROFILE='$MONPROFILE';" ++} ++mk_mon_profile() { ++ cat</dev/null && ++ output=`dbasql show_mon_profile` ++ if echo "$output" | grep -iw "^$MONPROFILE" >/dev/null; then + return 0 ++ fi ++ output=`dbasql mk_mon_profile show_mon_profile` ++ if echo "$output" | grep -iw "^$MONPROFILE" >/dev/null; then ++ return 0 ++ else ++ ocf_log err "could not create $MONPROFILE oracle profile" ++ ocf_log err "sqlplus output: $output" ++ return 1 ++ fi ++} ++check_mon_user() { ++ local output ++ local output2 ++ ++ output=`dbasql show_mon_user` ++ if echo "$output" | grep -iw "^$MONUSR" >/dev/null; then ++ if echo "$output" | grep -w "EXPIRED" >/dev/null; then ++ dbasql reset_mon_user_password ++ fi ++ output=`dbasql show_mon_user_profile` ++ if echo "$output" | grep -iw "^$MONPROFILE" >/dev/null; then ++ return 0 ++ else ++ output=`dbasql set_mon_user_profile` ++ output2=`dbasql show_mon_user_profile` ++ if echo "$output2" | grep -iw "^$MONPROFILE" >/dev/null; then ++ return 0 ++ fi ++ ocf_log err "could not set profile for $MONUSR oracle user" ++ ocf_log err "sqlplus output: $output( $output2 )" ++ return 1 ++ fi ++ fi + output=`dbasql mk_mon_user show_mon_user` +- if echo "$output" | grep -w "^$MONUSR" >/dev/null; then ++ if echo "$output" | grep -iw "^$MONUSR" >/dev/null; then + return 0 + else + ocf_log err "could not create $MONUSR oracle user" +@@ -417,7 +509,7 @@ ipcdesc() { + } + rmipc() { + local what=$1 id=$2 +- ipcs -$what | filteroraipc | grep -w $id >/dev/null 2>&1 || ++ ipcs -$what | filteroraipc | grep -iw $id >/dev/null 2>&1 || + return + ocf_log info "Removing `ipcdesc $what` $id." + ipcrm -$what $id +@@ -447,6 +539,8 @@ is_proc_running() { + # instance in OPEN state? + instance_live() { + local status=`monsql_one dbstat` ++ [ "$status" = OPEN ] && return 0 ++ status=`dbasql_one dbstat` + if [ "$status" = OPEN ]; then + return 0 + else +@@ -473,7 +567,7 @@ ora_cleanup() { + } + + oracle_getconfig() { +- ora_common_getconfig "$OCF_RESKEY_sid" "$OCF_RESKEY_home" "$OCF_RESKEY_user" "$OCF_RESKEY_tns_admin" ++ ora_common_getconfig "$OCF_RESKEY_sid" "$OCF_RESKEY_home" "$OCF_RESKEY_user" + + clear_backupmode=${OCF_RESKEY_clear_backupmode:-"false"} + shutdown_method=${OCF_RESKEY_shutdown_method:-"checkpoint/abort"} +@@ -493,7 +587,7 @@ oracle_getconfig() { + oracle_start() { + local status output + if is_proc_running; then +- status="`monsql_one dbstat`" ++ status="`dbasql_one dbstat`" + case "$status" in + "OPEN") + : nothing to be done, we can leave right now +@@ -541,6 +635,11 @@ oracle_start() { + fi + output=`dbasql dbopen` + ++ # check/create the monitor profile ++ if ! check_mon_profile; then ++ return $OCF_ERR_GENERIC ++ fi ++ + # check/create the monitor user + if ! check_mon_user; then + return $OCF_ERR_GENERIC +@@ -650,7 +749,12 @@ show_procs() { + proc_pids() { show_procs | awk '{print $1}'; } + PROCS_CLEANUP_TIME="30" + +-MONUSR="OCFMON" ++MONUSR=${OCF_RESKEY_monuser:-$OCF_RESKEY_monuser_default} ++MONPWD=${OCF_RESKEY_monpassword:-$OCF_RESKEY_monpassword_default} ++MONPROFILE=${OCF_RESKEY_monprofile_default:-$OCF_RESKEY_monprofile_default} ++ ++MONUSR=$(echo $MONUSR | awk '{print toupper($0)}') ++MONPROFILE=$(echo $MONPROFILE | awk '{print toupper($0)}') + OCF_REQUIRED_PARAMS="sid" + OCF_REQUIRED_BINARIES="sqlplus" + ocf_rarun $* +diff --git a/heartbeat/oralsnr b/heartbeat/oralsnr +index 2409017..a91eeab 100755 +--- a/heartbeat/oralsnr ++++ b/heartbeat/oralsnr +@@ -158,7 +158,7 @@ runasdba() { + ( + echo ". $ORA_ENVF" + cat +- ) | su - $ORACLE_OWNER ++ ) | su -s $SH - $ORACLE_OWNER + fi + } + +@@ -268,7 +268,7 @@ oralsnr_validate_all() { + # used in ora-common.sh + show_procs() { + ps -e -o pid,user,args | +- grep '[t]nslsnr' | grep -w "$listener" | grep -w "$ORACLE_OWNER" ++ grep '[t]nslsnr' | grep -i -w "$listener" | grep -w "$ORACLE_OWNER" + } + proc_pids() { show_procs | awk '{print $1}'; } + PROCS_CLEANUP_TIME="10" diff --git a/SOURCES/bz1242181-virtualdomain-migrate_options.patch b/SOURCES/bz1242181-virtualdomain-migrate_options.patch new file mode 100644 index 00000000..a13b6b41 --- /dev/null +++ b/SOURCES/bz1242181-virtualdomain-migrate_options.patch @@ -0,0 +1,133 @@ +diff -uNr a/heartbeat/VirtualDomain b/heartbeat/VirtualDomain +--- a/heartbeat/VirtualDomain 2016-02-29 10:54:21.870787072 +0100 ++++ b/heartbeat/VirtualDomain 2016-02-29 14:02:23.260696550 +0100 +@@ -106,11 +106,28 @@ + + Note: Be sure this composed host name is locally resolveable and the + associated IP is reachable through the favored network. ++ ++See also the migrate_options parameter below. + + Migration network host name suffix + + + ++ ++ ++Extra virsh options for the guest live migration. You can also specify ++here --migrateuri if the calculated migrate URI is unsuitable for your ++environment. If --migrateuri is set then migration_network_suffix ++and migrateport are effectively ignored. Use "%n" as the placeholder ++for the target node name. ++ ++Please refer to the libvirt documentation for details on guest ++migration. ++ ++live migrate options ++ ++ ++ + + + To additionally monitor services within the virtual domain, add this +@@ -485,14 +502,45 @@ + force_stop + } + ++mk_migrateuri() { ++ local target_node ++ local migrate_target ++ local hypervisor ++ ++ target_node="$OCF_RESKEY_CRM_meta_migrate_target" ++ ++ # A typical migration URI via a special migration network looks ++ # like "tcp://bar-mig:49152". The port would be randomly chosen ++ # by libvirt from the range 49152-49215 if omitted, at least since ++ # version 0.7.4 ... ++ if [ -n "${OCF_RESKEY_migration_network_suffix}" ]; then ++ hypervisor="${OCF_RESKEY_hypervisor%%[+:]*}" ++ # Hostname might be a FQDN ++ migrate_target=$(echo ${target_node} | sed -e "s,^\([^.]\+\),\1${OCF_RESKEY_migration_network_suffix},") ++ case $hypervisor in ++ qemu) ++ # For quiet ancient libvirt versions a migration port is needed ++ # and the URI must not contain the "//". Newer versions can handle ++ # the "bad" URI. ++ echo "tcp:${migrate_target}:${OCF_RESKEY_migrateport}" ++ ;; ++ xen) ++ echo "xenmigr://${migrate_target}" ++ ;; ++ *) ++ ocf_log warn "$DOMAIN_NAME: Migration via dedicated network currently not supported for ${hypervisor}." ++ ;; ++ esac ++ fi ++} ++ + VirtualDomain_Migrate_To() { ++ local rc + local target_node + local remoteuri + local transport_suffix + local migrateuri +- local migrateport +- local migrate_target +- local hypervisor ++ local migrate_opts + + target_node="$OCF_RESKEY_CRM_meta_migrate_target" + +@@ -503,38 +551,26 @@ + if [ -n "${OCF_RESKEY_migration_transport}" ]; then + transport_suffix="+${OCF_RESKEY_migration_transport}" + fi +- # A typical migration URI via a special migration network looks +- # like "tcp://bar-mig:49152". The port would be randomly chosen +- # by libvirt from the range 49152-49215 if omitted, at least since +- # version 0.7.4 ... +- if [ -n "${OCF_RESKEY_migration_network_suffix}" ]; then +- hypervisor="${OCF_RESKEY_hypervisor%%[+:]*}" +- # Hostname might be a FQDN +- migrate_target=$(echo ${target_node} | sed -e "s,^\([^.]\+\),\1${OCF_RESKEY_migration_network_suffix},") +- case $hypervisor in +- qemu) +- # For quiet ancient libvirt versions a migration port is needed +- # and the URI must not contain the "//". Newer versions can handle +- # the "bad" URI. +- migrateuri="tcp:${migrate_target}:${OCF_RESKEY_migrateport}" +- ;; +- xen) +- migrateuri="xenmigr://${migrate_target}" +- ;; +- *) +- ocf_log warn "$DOMAIN_NAME: Migration via dedicated network currently not supported for ${hypervisor}." +- ;; +- esac ++ ++ # User defined migrateuri or do we make one? ++ migrate_opts="$OCF_RESKEY_migrate_options" ++ if echo "$migrate_opts" | fgrep -qs -- "--migrateuri="; then ++ migrateuri=`echo "$migrate_opts" | ++ sed "s/.*--migrateuri=\([^ ]*\).*/\1/;s/%n/$target_node/g"` ++ migrate_opts=`echo "$migrate_opts" | ++ sed "s/\(.*\)--migrateuri=[^ ]*\(.*\)/\1\3/"` ++ else ++ migrateuri=`mk_migrateuri` + fi + # Scared of that sed expression? So am I. :-) + remoteuri=$(echo ${OCF_RESKEY_hypervisor} | sed -e "s,\(.*\)://[^/:]*\(:\?[0-9]*\)/\(.*\),\1${transport_suffix}://${target_node}\2/\3,") + + # OK, we know where to connect to. Now do the actual migration. +- ocf_log info "$DOMAIN_NAME: Starting live migration to ${target_node} (using remote hypervisor URI ${remoteuri} ${migrateuri})." +- virsh ${VIRSH_OPTIONS} migrate --live $DOMAIN_NAME ${remoteuri} ${migrateuri} ++ ocf_log info "$DOMAIN_NAME: Starting live migration to ${target_node} (using virsh ${VIRSH_OPTIONS} migrate --live $migrate_opts $DOMAIN_NAME $remoteuri $migrateuri)." ++ virsh ${VIRSH_OPTIONS} migrate --live $migrate_opts $DOMAIN_NAME $remoteuri $migrateuri + rc=$? + if [ $rc -ne 0 ]; then +- ocf_exit_reason "$DOMAIN_NAME: live migration to ${remoteuri} ${migrateuri} failed: $rc" ++ ocf_exit_reason "$DOMAIN_NAME: live migration to ${target_node} failed: $rc" + return $OCF_ERR_GENERIC + else + ocf_log info "$DOMAIN_NAME: live migration to ${target_node} succeeded." diff --git a/SOURCES/bz1242558-virtualdomain-may-remove-config-file.patch b/SOURCES/bz1242558-virtualdomain-may-remove-config-file.patch new file mode 100644 index 00000000..3a9871bb --- /dev/null +++ b/SOURCES/bz1242558-virtualdomain-may-remove-config-file.patch @@ -0,0 +1,40 @@ +diff -uNr a/heartbeat/VirtualDomain b/heartbeat/VirtualDomain +--- a/heartbeat/VirtualDomain 2015-11-20 11:52:58.314263831 +0100 ++++ b/heartbeat/VirtualDomain 2015-11-20 11:53:55.247196256 +0100 +@@ -340,13 +340,32 @@ + return $rc + } + ++# virsh undefine removes configuration files if they are in ++# directories which are managed by libvirt. such directories ++# include also subdirectories of /etc (for instance ++# /etc/libvirt/*) which may be surprising. VirtualDomain didn't ++# include the undefine call before, hence this wasn't an issue ++# before. ++# ++# There seems to be no way to find out which directories are ++# managed by libvirt. ++# + verify_undefined() { +- for dom in `virsh --connect=${OCF_RESKEY_hypervisor} list --all --name 2>/dev/null`; do +- if [ "$dom" = "$DOMAIN_NAME" ]; then ++ local tmpf ++ if virsh --connect=${OCF_RESKEY_hypervisor} list --all --name 2>/dev/null | grep -wqs "$DOMAIN_NAME" ++ then ++ tmpf=$(mktemp -t vmcfgsave.XXXXXX) ++ if [ ! -r "$tmpf" ]; then ++ ocf_log warn "unable to create temp file, disk full?" ++ # we must undefine the domain + virsh $VIRSH_OPTIONS undefine $DOMAIN_NAME > /dev/null 2>&1 +- return ++ else ++ cp -p $OCF_RESKEY_config $tmpf ++ virsh $VIRSH_OPTIONS undefine $DOMAIN_NAME > /dev/null 2>&1 ++ [ -f $OCF_RESKEY_config ] || cp -f $tmpf $OCF_RESKEY_config ++ rm -f $tmpf + fi +- done ++ fi + } + + VirtualDomain_Start() { diff --git a/SOURCES/bz1247303-rabbitmq-cluster-forget-stopped-cluster-nodes.patch b/SOURCES/bz1247303-rabbitmq-cluster-forget-stopped-cluster-nodes.patch new file mode 100644 index 00000000..585b8b30 --- /dev/null +++ b/SOURCES/bz1247303-rabbitmq-cluster-forget-stopped-cluster-nodes.patch @@ -0,0 +1,92 @@ +diff -uNr a/heartbeat/rabbitmq-cluster b/heartbeat/rabbitmq-cluster +--- a/heartbeat/rabbitmq-cluster 2016-02-22 11:09:48.989128414 +0100 ++++ b/heartbeat/rabbitmq-cluster 2016-02-22 11:10:12.011835745 +0100 +@@ -39,7 +39,14 @@ + RMQ_LOG_DIR="/var/log/rabbitmq" + NODENAME=$(ocf_local_nodename) + ++# this attr represents the current active local rmq node name. ++# when rmq stops or the node is fenced, this attr disappears + RMQ_CRM_ATTR_COOKIE="rmq-node-attr-${OCF_RESOURCE_INSTANCE}" ++# this attr represents the last known active local rmq node name ++# when rmp stops or the node is fenced, the attr stays forever so ++# we can continue to map an offline pcmk node to it's rmq node name ++# equivalent. ++RMQ_CRM_ATTR_COOKIE_LAST_KNOWN="rmq-node-attr-last-known-${OCF_RESOURCE_INSTANCE}" + + meta_data() { + cat < /dev/null 2>&1 & + } +@@ -154,7 +161,7 @@ rotate_catalina_out() + { + # Check catalina_%F.log is writable or not. + CURRENT_ROTATELOG_SUFFIX=`date +"%F"` +- su - -s /bin/sh $RESOURCE_TOMCAT_USER \ ++ $SU - -s /bin/sh $RESOURCE_TOMCAT_USER \ + -c "touch \"$CATALINA_BASE/logs/catalina_$CURRENT_ROTATELOG_SUFFIX.log\"" > /dev/null 2>&1 + if [ $? -ne 0 ]; then + ocf_exit_reason "$CATALINA_BASE/logs/catalina_$CURRENT_ROTATELOG_SUFFIX.log is not writable." +@@ -205,7 +212,7 @@ attemptTomcatCommand() + if [ "$RESOURCE_TOMCAT_USER" = root ]; then + "$TOMCAT_START_SCRIPT" $@ >> "$TOMCAT_CONSOLE" 2>&1 + else +- tomcatCommand $@ | su - -s /bin/sh "$RESOURCE_TOMCAT_USER" >> "$TOMCAT_CONSOLE" 2>&1 ++ tomcatCommand $@ | $SU - -s /bin/sh "$RESOURCE_TOMCAT_USER" >> "$TOMCAT_CONSOLE" 2>&1 + fi + + if [ -n "$REDIRECT_DEFAULT_CONFIG" ]; then diff --git a/SOURCES/bz1249430-2-tomcat-fix-selinux-enforced.patch b/SOURCES/bz1249430-2-tomcat-fix-selinux-enforced.patch new file mode 100644 index 00000000..3d4750bc --- /dev/null +++ b/SOURCES/bz1249430-2-tomcat-fix-selinux-enforced.patch @@ -0,0 +1,112 @@ +From a1860a5bbe5c63c6a34d9160a8aacffc61a89dcf Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Fri, 16 Sep 2016 14:25:28 +0200 +Subject: [PATCH] tomcat: use systemd where available due to newer versions not + generating PID-file + +--- + heartbeat/tomcat | 44 ++++++++++++++++++++++++++++++++++++++++---- + 1 file changed, 40 insertions(+), 4 deletions(-) + +diff --git a/heartbeat/tomcat b/heartbeat/tomcat +index 07a7ce4..813d280 100755 +--- a/heartbeat/tomcat ++++ b/heartbeat/tomcat +@@ -56,6 +56,10 @@ else + SU=su + fi + ++if which systemctl > /dev/null 2>&1; then ++ SYSTEMD=1 ++fi ++ + ############################################################################ + # Usage + usage() +@@ -90,6 +94,10 @@ isrunning_tomcat() + # + isalive_tomcat() + { ++ if ocf_is_true $SYSTEMD; then ++ systemctl is-active tomcat@${TOMCAT_NAME} > /dev/null 2>&1 ++ return $? ++ fi + # As the server stops, the PID file disappears. To avoid race conditions, + # we will have remembered the PID of a running instance on script entry. + local pid=$rememberedPID +@@ -184,9 +192,31 @@ rotate_catalina_out() + } + + ############################################################################ ++# Create systemd configuration ++create_systemd_config() ++{ ++cat<<-EOF > /etc/sysconfig/tomcat@${TOMCAT_NAME} ++JAVA_HOME=${JAVA_HOME} ++JAVA_OPTS="${JAVA_OPTS}" ++CATALINA_HOME=${CATALINA_HOME} ++CATALINA_BASE=${CATALINA_BASE} ++CATALINA_OUT=${CATALINA_OUT} ++CATALINA_OPTS="${CATALINA_OPTS}" ++CATALINA_TMPDIR="${CATALINA_TMPDIR}" ++JAVA_ENDORSED_DIRS="${JAVA_ENDORSED_DIRS}" ++LOGGING_CONFIG="${LOGGING_CONFIG}" ++LOGGING_MANAGER="${LOGGING_MANAGER}" ++TOMCAT_CFG=${TOMCAT_CFG} ++EOF ++} ++ ++############################################################################ + # Tomcat Command + tomcatCommand() + { ++ if ocf_is_true $SYSTEMD; then ++ systemctl $@ tomcat@${TOMCAT_NAME} ++ else + cat<<-END_TOMCAT_COMMAND + export JAVA_HOME=${JAVA_HOME} + export JAVA_OPTS="${JAVA_OPTS}" +@@ -202,6 +232,7 @@ cat<<-END_TOMCAT_COMMAND + export TOMCAT_CFG=${TOMCAT_CFG} + $TOMCAT_START_SCRIPT $@ + END_TOMCAT_COMMAND ++ fi + } + attemptTomcatCommand() + { +@@ -209,7 +240,9 @@ attemptTomcatCommand() + export TOMCAT_CFG=$(mktemp ${HA_RSCTMP}/tomcat-tmp-XXXXX.cfg) + fi + +- if [ "$RESOURCE_TOMCAT_USER" = root ]; then ++ if ocf_is_true $SYSTEMD; then ++ tomcatCommand $@ ++ elif [ "$RESOURCE_TOMCAT_USER" = root ]; then + "$TOMCAT_START_SCRIPT" $@ >> "$TOMCAT_CONSOLE" 2>&1 + else + tomcatCommand $@ | $SU - -s /bin/sh "$RESOURCE_TOMCAT_USER" >> "$TOMCAT_CONSOLE" 2>&1 +@@ -224,6 +257,9 @@ attemptTomcatCommand() + # Start Tomcat + start_tomcat() + { ++ if ocf_is_true $SYSTEMD; then ++ create_systemd_config ++ fi + cd "$CATALINA_HOME/bin" + + validate_all_tomcat || exit $? +@@ -334,11 +370,11 @@ Resource script for Tomcat. It manages a Tomcat instance as a cluster resource. + + + +- + The name of the resource, added as a Java parameter in JAVA_OPTS: +--Dname= to Tomcat process on start. Used to ensure ++-Dname=<tomcat_name> to Tomcat process on start. Used to ensure + process is still running and must be unique. +-]]> ++ + The name of the resource + + diff --git a/SOURCES/bz1250728-send_arp-fix-buffer-overflow-on-infiniband.patch b/SOURCES/bz1250728-send_arp-fix-buffer-overflow-on-infiniband.patch new file mode 100644 index 00000000..a7b9bd5d --- /dev/null +++ b/SOURCES/bz1250728-send_arp-fix-buffer-overflow-on-infiniband.patch @@ -0,0 +1,1188 @@ +diff --git a/tools/send_arp.linux.c b/tools/send_arp.linux.c +index e1c1960..477100a 100644 +--- a/tools/send_arp.linux.c ++++ b/tools/send_arp.linux.c +@@ -7,6 +7,23 @@ + * 2 of the License, or (at your option) any later version. + * + * Authors: Alexey Kuznetsov, ++ * YOSHIFUJI Hideaki ++ */ ++ ++/* Andrew Beekhof, Lars Ellenberg: ++ * Based on arping from iputils, ++ * adapted to the command line conventions established by the libnet based ++ * send_arp tool as used by the IPaddr and IPaddr2 resource agents. ++ * The libnet based send_arp, and its command line argument convention, ++ * was first added to the heartbeat project by Matt Soffen. ++ * ++ * Latest "resync" with iputils as of: ++ * git://git.linux-ipv6.org/gitroot/iputils.git ++ * 511f8356e22615479c3cc16bca64d72d204f6df3 ++ * Fri Jul 24 10:48:47 2015 ++ * To get various bugfixes and support for infiniband and other link layer ++ * addresses which do not fit into plain "sockaddr_ll", and broadcast addresses ++ * that may be different from memset(,0xff,). + */ + + #include +@@ -16,12 +33,17 @@ + #include + #include + #include ++#include + #include +-#include ++#include + #include + #include + #include + #include ++#ifdef CAPABILITIES ++#include ++#include ++#endif + + #include + #include +@@ -32,40 +54,85 @@ + #include + #include + +-static void usage(void) __attribute__((noreturn)); ++#ifdef USE_SYSFS ++#include ++struct sysfs_devattr_values; ++#endif + +-static int quit_on_reply; +-static char *device; +-static int ifindex; +-static char *source; +-static struct in_addr src, dst; +-static char *target; +-static int dad = 0, unsolicited = 0, advert = 0; +-static int quiet = 0; +-static int count = -1; +-static int timeout = 0; +-static int unicasting = 0; +-static int s = 0; +-static int broadcast_only = 0; ++#ifndef WITHOUT_IFADDRS ++#include ++#endif + +-static struct sockaddr_ll me; +-static struct sockaddr_ll he; ++#ifdef USE_IDN ++#include ++#include ++#endif + +-static struct timeval start, last; ++static char SNAPSHOT[] = "s20121221"; + +-static int sent, brd_sent; +-static int received, brd_recv, req_recv; ++static void usage(void) __attribute__((noreturn)); ++ ++#ifndef DEFAULT_DEVICE ++#define DEFAULT_DEVICE "eth0" ++#endif ++#ifdef DEFAULT_DEVICE ++# define DEFAULT_DEVICE_STR DEFAULT_DEVICE ++#else ++# define DEFAULT_DEVICE NULL ++#endif ++ ++struct device { ++ const char *name; ++ int ifindex; ++#ifndef WITHOUT_IFADDRS ++ struct ifaddrs *ifa; ++#endif ++#ifdef USE_SYSFS ++ struct sysfs_devattr_values *sysfs; ++#endif ++}; ++ ++int quit_on_reply=0; ++struct device device = { ++ .name = DEFAULT_DEVICE, ++}; ++char *source; ++struct in_addr src, dst; ++char *target; ++int dad, unsolicited, advert; ++int quiet; ++int count=-1; ++int timeout; ++int unicasting; ++int s; ++int broadcast_only; ++ ++struct sockaddr_storage me; ++struct sockaddr_storage he; ++ ++struct timeval start, last; ++ ++int sent, brd_sent; ++int received, brd_recv, req_recv; ++ ++#ifndef CAPABILITIES ++static uid_t euid; ++#endif + + #define MS_TDIFF(tv1,tv2) ( ((tv1).tv_sec-(tv2).tv_sec)*1000 + \ + ((tv1).tv_usec-(tv2).tv_usec)/1000 ) + +-static void print_hex(unsigned char *p, int len); +-static int recv_pack(unsigned char *buf, int len, struct sockaddr_ll *FROM); +-static void set_signal(int signo, void (*handler)(void)); +-static int send_pack(int s, struct in_addr src, struct in_addr dst, +- struct sockaddr_ll *ME, struct sockaddr_ll *HE); +-static void finish(void); +-static void catcher(void); ++#define OFFSET_OF(name,ele) ((size_t)&((name *)0)->ele) ++ ++static socklen_t sll_len(size_t halen) ++{ ++ socklen_t len = OFFSET_OF(struct sockaddr_ll, sll_addr) + halen; ++ if (len < sizeof(struct sockaddr_ll)) ++ len = sizeof(struct sockaddr_ll); ++ return len; ++} ++ ++#define SLL_LEN(hln) sll_len(hln) + + void usage(void) + { +@@ -80,14 +147,18 @@ void usage(void) + " -V : print version and exit\n" + " -c count : how many packets to send\n" + " -w timeout : how long to wait for a reply\n" +- " -I device : which ethernet device to use (eth0)\n" ++ " -I device : which ethernet device to use" ++#ifdef DEFAULT_DEVICE_STR ++ " (" DEFAULT_DEVICE_STR ")" ++#endif ++ "\n" + " -s source : source ip address\n" + " destination : ask for what ip address\n" + ); + exit(2); + } + +-void set_signal(int signo, void (*handler)(void)) ++static void set_signal(int signo, void (*handler)(void)) + { + struct sigaction sa; + +@@ -97,7 +168,126 @@ void set_signal(int signo, void (*handler)(void)) + sigaction(signo, &sa, NULL); + } + +-int send_pack(int s, struct in_addr src, struct in_addr dst, ++#ifdef CAPABILITIES ++static const cap_value_t caps[] = { CAP_NET_RAW, }; ++static cap_flag_value_t cap_raw = CAP_CLEAR; ++#endif ++ ++static void limit_capabilities(void) ++{ ++#ifdef CAPABILITIES ++ cap_t cap_p; ++ ++ cap_p = cap_get_proc(); ++ if (!cap_p) { ++ perror("arping: cap_get_proc"); ++ exit(-1); ++ } ++ ++ cap_get_flag(cap_p, CAP_NET_RAW, CAP_PERMITTED, &cap_raw); ++ ++ if (cap_raw != CAP_CLEAR) { ++ if (cap_clear(cap_p) < 0) { ++ perror("arping: cap_clear"); ++ exit(-1); ++ } ++ ++ cap_set_flag(cap_p, CAP_PERMITTED, 1, caps, CAP_SET); ++ ++ if (cap_set_proc(cap_p) < 0) { ++ perror("arping: cap_set_proc"); ++ if (errno != EPERM) ++ exit(-1); ++ } ++ } ++ ++ if (prctl(PR_SET_KEEPCAPS, 1) < 0) { ++ perror("arping: prctl"); ++ exit(-1); ++ } ++ ++ if (setuid(getuid()) < 0) { ++ perror("arping: setuid"); ++ exit(-1); ++ } ++ ++ if (prctl(PR_SET_KEEPCAPS, 0) < 0) { ++ perror("arping: prctl"); ++ exit(-1); ++ } ++ ++ cap_free(cap_p); ++#else ++ euid = geteuid(); ++#endif ++} ++ ++static int modify_capability_raw(int on) ++{ ++#ifdef CAPABILITIES ++ cap_t cap_p; ++ ++ if (cap_raw != CAP_SET) ++ return on ? -1 : 0; ++ ++ cap_p = cap_get_proc(); ++ if (!cap_p) { ++ perror("arping: cap_get_proc"); ++ return -1; ++ } ++ ++ cap_set_flag(cap_p, CAP_EFFECTIVE, 1, caps, on ? CAP_SET : CAP_CLEAR); ++ ++ if (cap_set_proc(cap_p) < 0) { ++ perror("arping: cap_set_proc"); ++ return -1; ++ } ++ ++ cap_free(cap_p); ++#else ++ if (setuid(on ? euid : getuid())) { ++ perror("arping: setuid"); ++ return -1; ++ } ++#endif ++ return 0; ++} ++ ++static int enable_capability_raw(void) ++{ ++ return modify_capability_raw(1); ++} ++ ++static int disable_capability_raw(void) ++{ ++ return modify_capability_raw(0); ++} ++ ++static void drop_capabilities(void) ++{ ++#ifdef CAPABILITIES ++ cap_t cap_p = cap_init(); ++ ++ if (!cap_p) { ++ perror("arping: cap_init"); ++ exit(-1); ++ } ++ ++ if (cap_set_proc(cap_p) < 0) { ++ perror("arping: cap_set_proc"); ++ exit(-1); ++ } ++ ++ cap_free(cap_p); ++#else ++ if (setuid(getuid()) < 0) { ++ perror("arping: setuid"); ++ exit(-1); ++ } ++#endif ++} ++ ++static int send_pack(int s, struct in_addr src, struct in_addr dst, + struct sockaddr_ll *ME, struct sockaddr_ll *HE) + { + int err; +@@ -130,7 +320,7 @@ int send_pack(int s, struct in_addr src, struct in_addr dst, + p+=4; + + gettimeofday(&now, NULL); +- err = sendto(s, buf, p-buf, 0, (struct sockaddr*)HE, sizeof(*HE)); ++ err = sendto(s, buf, p-buf, 0, (struct sockaddr*)HE, SLL_LEN(ah->ar_hln)); + if (err == p-buf) { + last = now; + sent++; +@@ -140,7 +330,7 @@ int send_pack(int s, struct in_addr src, struct in_addr dst, + return err; + } + +-void finish(void) ++static void finish(void) + { + if (!quiet) { + printf("Sent %d probes (%d broadcast(s))\n", sent, brd_sent); +@@ -158,40 +348,43 @@ void finish(void) + printf("\n"); + fflush(stdout); + } +- +- if (dad) { +- fflush(stdout); +- exit(!!received); +- } +- ++ fflush(stdout); ++ if (dad) ++ exit(!!received); + if (unsolicited) + exit(0); +- +- fflush(stdout); + exit(!received); + } + +-void catcher(void) ++static void catcher(void) + { +- struct timeval tv; ++ struct timeval tv, tv_s, tv_o; + + gettimeofday(&tv, NULL); + + if (start.tv_sec==0) + start = tv; + +- if (count-- == 0 || (timeout && MS_TDIFF(tv,start) > timeout*1000 + 500)) ++ timersub(&tv, &start, &tv_s); ++ tv_o.tv_sec = timeout; ++ tv_o.tv_usec = 500 * 1000; ++ ++ if (count-- == 0 || (timeout && timercmp(&tv_s, &tv_o, >))) + finish(); + +- if (last.tv_sec==0 || MS_TDIFF(tv,last) > 500) { +- send_pack(s, src, dst, &me, &he); ++ timersub(&tv, &last, &tv_s); ++ tv_o.tv_sec = 0; ++ ++ if (last.tv_sec==0 || timercmp(&tv_s, &tv_o, >)) { ++ send_pack(s, src, dst, ++ (struct sockaddr_ll *)&me, (struct sockaddr_ll *)&he); + if (count == 0 && unsolicited) + finish(); + } + alarm(1); + } + +-void print_hex(unsigned char *p, int len) ++static void print_hex(unsigned char *p, int len) + { + int i; + for (i=0; iar_pln != 4) + return 0; +- if (ah->ar_hln != me.sll_halen) ++ if (ah->ar_hln != ((struct sockaddr_ll *)&me)->sll_halen) + return 0; + if (len < sizeof(*ah) + 2*(4 + ah->ar_hln)) + return 0; +@@ -242,7 +435,7 @@ int recv_pack(unsigned char *buf, int len, struct sockaddr_ll *FROM) + return 0; + if (src.s_addr != dst_ip.s_addr) + return 0; +- if (memcmp(p+ah->ar_hln+4, &me.sll_addr, ah->ar_hln)) ++ if (memcmp(p+ah->ar_hln+4, ((struct sockaddr_ll *)&me)->sll_addr, ah->ar_hln)) + return 0; + } else { + /* DAD packet was: +@@ -260,7 +453,7 @@ int recv_pack(unsigned char *buf, int len, struct sockaddr_ll *FROM) + */ + if (src_ip.s_addr != dst.s_addr) + return 0; +- if (memcmp(p, &me.sll_addr, me.sll_halen) == 0) ++ if (memcmp(p, ((struct sockaddr_ll *)&me)->sll_addr, ((struct sockaddr_ll *)&me)->sll_halen) == 0) + return 0; + if (src.s_addr && src.s_addr != dst_ip.s_addr) + return 0; +@@ -276,7 +469,7 @@ int recv_pack(unsigned char *buf, int len, struct sockaddr_ll *FROM) + printf("for %s ", inet_ntoa(dst_ip)); + s_printed = 1; + } +- if (memcmp(p+ah->ar_hln+4, me.sll_addr, ah->ar_hln)) { ++ if (memcmp(p+ah->ar_hln+4, ((struct sockaddr_ll *)&me)->sll_addr, ah->ar_hln)) { + if (!s_printed) + printf("for "); + printf("["); +@@ -299,16 +492,78 @@ int recv_pack(unsigned char *buf, int len, struct sockaddr_ll *FROM) + brd_recv++; + if (ah->ar_op == htons(ARPOP_REQUEST)) + req_recv++; +- if (quit_on_reply) ++ if (quit_on_reply || (count == 0 && received == sent)) + finish(); + if(!broadcast_only) { +- memcpy(he.sll_addr, p, me.sll_halen); ++ memcpy(((struct sockaddr_ll *)&he)->sll_addr, p, ((struct sockaddr_ll *)&me)->sll_halen); + unicasting=1; + } + return 1; + } + +-#include ++#ifdef USE_SYSFS ++union sysfs_devattr_value { ++ unsigned long ulong; ++ void *ptr; ++}; ++ ++enum { ++ SYSFS_DEVATTR_IFINDEX, ++ SYSFS_DEVATTR_FLAGS, ++ SYSFS_DEVATTR_ADDR_LEN, ++#if 0 ++ SYSFS_DEVATTR_TYPE, ++ SYSFS_DEVATTR_ADDRESS, ++#endif ++ SYSFS_DEVATTR_BROADCAST, ++ SYSFS_DEVATTR_NUM ++}; ++ ++struct sysfs_devattr_values ++{ ++ char *ifname; ++ union sysfs_devattr_value value[SYSFS_DEVATTR_NUM]; ++}; ++ ++static int sysfs_devattr_ulong_dec(char *ptr, struct sysfs_devattr_values *v, unsigned idx); ++static int sysfs_devattr_ulong_hex(char *ptr, struct sysfs_devattr_values *v, unsigned idx); ++static int sysfs_devattr_macaddr(char *ptr, struct sysfs_devattr_values *v, unsigned idx); ++ ++struct sysfs_devattrs { ++ const char *name; ++ int (*handler)(char *ptr, struct sysfs_devattr_values *v, unsigned int idx); ++ int free; ++} sysfs_devattrs[SYSFS_DEVATTR_NUM] = { ++ [SYSFS_DEVATTR_IFINDEX] = { ++ .name = "ifindex", ++ .handler = sysfs_devattr_ulong_dec, ++ }, ++ [SYSFS_DEVATTR_ADDR_LEN] = { ++ .name = "addr_len", ++ .handler = sysfs_devattr_ulong_dec, ++ }, ++ [SYSFS_DEVATTR_FLAGS] = { ++ .name = "flags", ++ .handler = sysfs_devattr_ulong_hex, ++ }, ++#if 0 ++ [SYSFS_DEVATTR_TYPE] = { ++ .name = "type", ++ .handler = sysfs_devattr_ulong_dec, ++ }, ++ [SYSFS_DEVATTR_ADDRESS] = { ++ .name = "address", ++ .handler = sysfs_devattr_macaddr, ++ .free = 1, ++ }, ++#endif ++ [SYSFS_DEVATTR_BROADCAST] = { ++ .name = "broadcast", ++ .handler = sysfs_devattr_macaddr, ++ .free = 1, ++ }, ++}; ++#endif + + static void byebye(int nsig) + { +@@ -317,26 +572,477 @@ static void byebye(int nsig) + exit(nsig); + } + ++/* ++ * find_device() ++ * ++ * This function checks 1) if the device (if given) is okay for ARP, ++ * or 2) find fist appropriate device on the system. ++ * ++ * Return value: ++ * >0 : Succeeded, and appropriate device not found. ++ * device.ifindex remains 0. ++ * 0 : Succeeded, and approptiate device found. ++ * device.ifindex is set. ++ * <0 : Failed. Support not found, or other ++ * : system error. Try other method. ++ * ++ * If an appropriate device found, it is recorded inside the ++ * "device" variable for later reference. ++ * ++ * We have several implementations for this. ++ * by_ifaddrs(): requires getifaddr() in glibc, and rtnetlink in ++ * kernel. default and recommended for recent systems. ++ * by_sysfs(): requires libsysfs , and sysfs in kernel. ++ * by_ioctl(): unable to list devices without ipv4 address; this ++ * means, you need to supply the device name for ++ * DAD purpose. ++ */ ++/* Common check for ifa->ifa_flags */ ++static int check_ifflags(unsigned int ifflags, int fatal) ++{ ++ if (!(ifflags & IFF_UP)) { ++ if (fatal) { ++ if (!quiet) ++ printf("Interface \"%s\" is down\n", device.name); ++ exit(2); ++ } ++ return -1; ++ } ++ if (ifflags & (IFF_NOARP | IFF_LOOPBACK)) { ++ if (fatal) { ++ if (!quiet) ++ printf("Interface \"%s\" is not ARPable\n", device.name); ++ exit(dad ? 0 : 2); ++ } ++ return -1; ++ } ++ return 0; ++} ++ ++static int find_device_by_ifaddrs(void) ++{ ++#ifndef WITHOUT_IFADDRS ++ int rc; ++ struct ifaddrs *ifa0, *ifa; ++ int count = 0; ++ ++ rc = getifaddrs(&ifa0); ++ if (rc) { ++ perror("getifaddrs"); ++ return -1; ++ } ++ ++ for (ifa = ifa0; ifa; ifa = ifa->ifa_next) { ++ if (!ifa->ifa_addr) ++ continue; ++ if (ifa->ifa_addr->sa_family != AF_PACKET) ++ continue; ++ if (device.name && ifa->ifa_name && strcmp(ifa->ifa_name, device.name)) ++ continue; ++ ++ if (check_ifflags(ifa->ifa_flags, device.name != NULL) < 0) ++ continue; ++ ++ if (!((struct sockaddr_ll *)ifa->ifa_addr)->sll_halen) ++ continue; ++ if (!ifa->ifa_broadaddr) ++ continue; ++ ++ device.ifa = ifa; ++ ++ if (count++) ++ break; ++ } ++ ++ if (count == 1 && device.ifa) { ++ device.ifindex = if_nametoindex(device.ifa->ifa_name); ++ if (!device.ifindex) { ++ perror("arping: if_nametoindex"); ++ freeifaddrs(ifa0); ++ return -1; ++ } ++ device.name = device.ifa->ifa_name; ++ return 0; ++ } ++ return 1; ++#else ++ return -1; ++#endif ++} ++ ++#ifdef USE_SYSFS ++static void sysfs_devattr_values_init(struct sysfs_devattr_values *v, int do_free) ++{ ++ int i; ++ if (do_free) { ++ free(v->ifname); ++ for (i = 0; i < SYSFS_DEVATTR_NUM; i++) { ++ if (sysfs_devattrs[i].free) ++ free(v->value[i].ptr); ++ } ++ } ++ memset(v, 0, sizeof(*v)); ++} ++ ++static int sysfs_devattr_ulong(char *ptr, struct sysfs_devattr_values *v, unsigned int idx, ++ unsigned int base) ++{ ++ unsigned long *p; ++ char *ep; ++ ++ if (!ptr || !v) ++ return -1; ++ ++ p = &v->value[idx].ulong; ++ errno = 0; ++ *p = strtoul(ptr, &ep, base); ++ if ((*ptr && isspace(*ptr & 0xff)) || errno || (*ep != '\0' && *ep != '\n')) ++ goto out; ++ ++ return 0; ++out: ++ return -1; ++} ++ ++static int sysfs_devattr_ulong_dec(char *ptr, struct sysfs_devattr_values *v, unsigned int idx) ++{ ++ int rc = sysfs_devattr_ulong(ptr, v, idx, 10); ++ return rc; ++} ++ ++static int sysfs_devattr_ulong_hex(char *ptr, struct sysfs_devattr_values *v, unsigned int idx) ++{ ++ int rc = sysfs_devattr_ulong(ptr, v, idx, 16); ++ return rc; ++} ++ ++static int sysfs_devattr_macaddr(char *ptr, struct sysfs_devattr_values *v, unsigned int idx) ++{ ++ unsigned char *m; ++ int i; ++ unsigned int addrlen; ++ ++ if (!ptr || !v) ++ return -1; ++ ++ addrlen = v->value[SYSFS_DEVATTR_ADDR_LEN].ulong; ++ m = malloc(addrlen); ++ ++ for (i = 0; i < addrlen; i++) { ++ if (i && *(ptr + i * 3 - 1) != ':') ++ goto out; ++ if (sscanf(ptr + i * 3, "%02hhx", &m[i]) != 1) ++ goto out; ++ } ++ ++ v->value[idx].ptr = m; ++ return 0; ++out: ++ free(m); ++ return -1; ++} ++#endif ++ ++static int find_device_by_sysfs(void) ++{ ++ int rc = -1; ++#ifdef USE_SYSFS ++ struct sysfs_class *cls_net; ++ struct dlist *dev_list; ++ struct sysfs_class_device *dev; ++ struct sysfs_attribute *dev_attr; ++ struct sysfs_devattr_values sysfs_devattr_values; ++ int count = 0; ++ ++ if (!device.sysfs) { ++ device.sysfs = malloc(sizeof(*device.sysfs)); ++ sysfs_devattr_values_init(device.sysfs, 0); ++ } ++ ++ cls_net = sysfs_open_class("net"); ++ if (!cls_net) { ++ perror("sysfs_open_class"); ++ return -1; ++ } ++ ++ dev_list = sysfs_get_class_devices(cls_net); ++ if (!dev_list) { ++ perror("sysfs_get_class_devices"); ++ goto out; ++ } ++ ++ sysfs_devattr_values_init(&sysfs_devattr_values, 0); ++ ++ dlist_for_each_data(dev_list, dev, struct sysfs_class_device) { ++ int i; ++ int rc = -1; ++ ++ if (device.name && strcmp(dev->name, device.name)) ++ goto do_next; ++ ++ sysfs_devattr_values_init(&sysfs_devattr_values, 1); ++ ++ for (i = 0; i < SYSFS_DEVATTR_NUM; i++) { ++ ++ dev_attr = sysfs_get_classdev_attr(dev, sysfs_devattrs[i].name); ++ if (!dev_attr) { ++ perror("sysfs_get_classdev_attr"); ++ rc = -1; ++ break; ++ } ++ if (sysfs_read_attribute(dev_attr)) { ++ perror("sysfs_read_attribute"); ++ rc = -1; ++ break; ++ } ++ rc = sysfs_devattrs[i].handler(dev_attr->value, &sysfs_devattr_values, i); ++ ++ if (rc < 0) ++ break; ++ } ++ ++ if (rc < 0) ++ goto do_next; ++ ++ if (check_ifflags(sysfs_devattr_values.value[SYSFS_DEVATTR_FLAGS].ulong, ++ device.name != NULL) < 0) ++ goto do_next; ++ ++ if (!sysfs_devattr_values.value[SYSFS_DEVATTR_ADDR_LEN].ulong) ++ goto do_next; ++ ++ if (device.sysfs->value[SYSFS_DEVATTR_IFINDEX].ulong) { ++ if (device.sysfs->value[SYSFS_DEVATTR_FLAGS].ulong & IFF_RUNNING) ++ goto do_next; ++ } ++ ++ sysfs_devattr_values.ifname = strdup(dev->name); ++ if (!sysfs_devattr_values.ifname) { ++ perror("malloc"); ++ goto out; ++ } ++ ++ sysfs_devattr_values_init(device.sysfs, 1); ++ memcpy(device.sysfs, &sysfs_devattr_values, sizeof(*device.sysfs)); ++ sysfs_devattr_values_init(&sysfs_devattr_values, 0); ++ ++ if (count++) ++ break; ++ ++ continue; ++do_next: ++ sysfs_devattr_values_init(&sysfs_devattr_values, 1); ++ } ++ ++ if (count == 1) { ++ device.ifindex = device.sysfs->value[SYSFS_DEVATTR_IFINDEX].ulong; ++ device.name = device.sysfs->ifname; ++ } ++ rc = !device.ifindex; ++out: ++ sysfs_close_class(cls_net); ++#endif ++ return rc; ++} ++ ++static int check_device_by_ioctl(int s, struct ifreq *ifr) ++{ ++ if (ioctl(s, SIOCGIFFLAGS, ifr) < 0) { ++ perror("ioctl(SIOCGIFINDEX"); ++ return -1; ++ } ++ ++ if (check_ifflags(ifr->ifr_flags, device.name != NULL) < 0) ++ return 1; ++ ++ if (ioctl(s, SIOCGIFINDEX, ifr) < 0) { ++ perror("ioctl(SIOCGIFINDEX"); ++ return -1; ++ } ++ ++ return 0; ++} ++ ++static int find_device_by_ioctl(void) ++{ ++ int s; ++ struct ifreq *ifr0, *ifr, *ifr_end; ++ size_t ifrsize = sizeof(*ifr); ++ struct ifconf ifc; ++ static struct ifreq ifrbuf; ++ int count = 0; ++ ++ s = socket(AF_INET, SOCK_DGRAM, 0); ++ if (s < 0) { ++ perror("socket"); ++ return -1; ++ } ++ ++ memset(&ifrbuf, 0, sizeof(ifrbuf)); ++ ++ if (device.name) { ++ strncpy(ifrbuf.ifr_name, device.name, sizeof(ifrbuf.ifr_name) - 1); ++ if (check_device_by_ioctl(s, &ifrbuf)) ++ goto out; ++ count++; ++ } else { ++ do { ++ int rc; ++ ifr0 = malloc(ifrsize); ++ if (!ifr0) { ++ perror("malloc"); ++ goto out; ++ } ++ ++ ifc.ifc_buf = (char *)ifr0; ++ ifc.ifc_len = ifrsize; ++ ++ rc = ioctl(s, SIOCGIFCONF, &ifc); ++ if (rc < 0) { ++ perror("ioctl(SIOCFIFCONF"); ++ goto out; ++ } ++ ++ if (ifc.ifc_len + sizeof(*ifr0) + sizeof(struct sockaddr_storage) - sizeof(struct sockaddr) <= ifrsize) ++ break; ++ ifrsize *= 2; ++ free(ifr0); ++ ifr0 = NULL; ++ } while(ifrsize < INT_MAX / 2); ++ ++ if (!ifr0) { ++ fprintf(stderr, "arping: too many interfaces!?\n"); ++ goto out; ++ } ++ ++ ifr_end = (struct ifreq *)(((char *)ifr0) + ifc.ifc_len - sizeof(*ifr0)); ++ for (ifr = ifr0; ifr <= ifr_end; ifr++) { ++ if (check_device_by_ioctl(s, &ifrbuf)) ++ continue; ++ memcpy(&ifrbuf.ifr_name, ifr->ifr_name, sizeof(ifrbuf.ifr_name)); ++ if (count++) ++ break; ++ } ++ } ++ ++ close(s); ++ ++ if (count == 1) { ++ device.ifindex = ifrbuf.ifr_ifindex; ++ device.name = ifrbuf.ifr_name; ++ } ++ return !device.ifindex; ++out: ++ close(s); ++ return -1; ++} ++ ++static int find_device(void) ++{ ++ int rc; ++ rc = find_device_by_ifaddrs(); ++ if (rc >= 0) ++ goto out; ++ rc = find_device_by_sysfs(); ++ if (rc >= 0) ++ goto out; ++ rc = find_device_by_ioctl(); ++out: ++ return rc; ++} ++ ++/* ++ * set_device_broadcast() ++ * ++ * This fills the device "broadcast address" ++ * based on information found by find_device() funcion. ++ */ ++static int set_device_broadcast_ifaddrs_one(struct device *device, unsigned char *ba, size_t balen, int fatal) ++{ ++#ifndef WITHOUT_IFADDRS ++ struct ifaddrs *ifa; ++ struct sockaddr_ll *sll; ++ ++ if (!device) ++ return -1; ++ ++ ifa = device->ifa; ++ if (!ifa) ++ return -1; ++ ++ sll = (struct sockaddr_ll *)ifa->ifa_broadaddr; ++ ++ if (sll->sll_halen != balen) { ++ if (fatal) { ++ if (!quiet) ++ printf("Address length does not match...\n"); ++ exit(2); ++ } ++ return -1; ++ } ++ memcpy(ba, sll->sll_addr, sll->sll_halen); ++ return 0; ++#else ++ return -1; ++#endif ++} ++static int set_device_broadcast_sysfs(struct device *device, unsigned char *ba, size_t balen) ++{ ++#ifdef USE_SYSFS ++ struct sysfs_devattr_values *v; ++ if (!device) ++ return -1; ++ v = device->sysfs; ++ if (!v) ++ return -1; ++ if (v->value[SYSFS_DEVATTR_ADDR_LEN].ulong != balen) ++ return -1; ++ memcpy(ba, v->value[SYSFS_DEVATTR_BROADCAST].ptr, balen); ++ return 0; ++#else ++ return -1; ++#endif ++} ++ ++static int set_device_broadcast_fallback(struct device *device, unsigned char *ba, size_t balen) ++{ ++ if (!quiet) ++ fprintf(stderr, "WARNING: using default broadcast address.\n"); ++ memset(ba, -1, balen); ++ return 0; ++} ++ ++static void set_device_broadcast(struct device *dev, unsigned char *ba, size_t balen) ++{ ++ if (!set_device_broadcast_ifaddrs_one(dev, ba, balen, 0)) ++ return; ++ if (!set_device_broadcast_sysfs(dev, ba, balen)) ++ return; ++ set_device_broadcast_fallback(dev, ba, balen); ++} ++ + int + main(int argc, char **argv) + { + int socket_errno; + int ch; +- uid_t uid = getuid(); + int hb_mode = 0; + + signal(SIGTERM, byebye); + signal(SIGPIPE, byebye); +- +- device = strdup("eth0"); +- ++ ++ limit_capabilities(); ++ ++#ifdef USE_IDN ++ setlocale(LC_ALL, ""); ++#endif ++ ++ enable_capability_raw(); ++ + s = socket(PF_PACKET, SOCK_DGRAM, 0); + socket_errno = errno; + +- if (setuid(uid)) { +- perror("arping: setuid"); +- exit(-1); +- } ++ disable_capability_raw(); + + while ((ch = getopt(argc, argv, "h?bfDUAqc:w:s:I:Vr:i:p:")) != EOF) { + switch(ch) { +@@ -367,7 +1073,7 @@ main(int argc, char **argv) + timeout = atoi(optarg); + break; + case 'I': +- device = optarg; ++ device.name = optarg; + break; + case 'f': + quit_on_reply=1; +@@ -376,7 +1082,7 @@ main(int argc, char **argv) + source = optarg; + break; + case 'V': +- printf("send_arp utility\n"); ++ printf("send_arp utility, based on arping from iputils-%s\n", SNAPSHOT); + exit(0); + case 'p': + case 'i': +@@ -405,7 +1111,7 @@ main(int argc, char **argv) + */ + + unsolicited = 1; +- device = argv[optind]; ++ device.name = argv[optind]; + target = argv[optind+1]; + + } else { +@@ -417,10 +1123,8 @@ main(int argc, char **argv) + target = *argv; + } + +- if (device == NULL) { +- fprintf(stderr, "arping: device (option -I) is required\n"); +- usage(); +- } ++ if (device.name && !*device.name) ++ device.name = NULL; + + if (s < 0) { + errno = socket_errno; +@@ -428,39 +1132,42 @@ main(int argc, char **argv) + exit(2); + } + +- if (1) { +- struct ifreq ifr; +- memset(&ifr, 0, sizeof(ifr)); +- strncpy(ifr.ifr_name, device, IFNAMSIZ-1); +- if (ioctl(s, SIOCGIFINDEX, &ifr) < 0) { +- fprintf(stderr, "arping: unknown iface %s\n", device); +- exit(2); +- } +- ifindex = ifr.ifr_ifindex; ++ if (find_device() < 0) ++ exit(2); + +- if (ioctl(s, SIOCGIFFLAGS, (char*)&ifr)) { +- perror("ioctl(SIOCGIFFLAGS)"); ++ if (!device.ifindex) { ++ if (device.name) { ++ fprintf(stderr, "arping: Device %s not available.\n", device.name); + exit(2); + } +- if (!(ifr.ifr_flags&IFF_UP)) { +- if (!quiet) +- printf("Interface \"%s\" is down\n", device); +- exit(2); +- } +- if (ifr.ifr_flags&(IFF_NOARP|IFF_LOOPBACK)) { +- if (!quiet) +- printf("Interface \"%s\" is not ARPable\n", device); +- exit(dad?0:2); +- } ++ fprintf(stderr, "arping: device (option -I) is required.\n"); ++ usage(); + } + + if (inet_aton(target, &dst) != 1) { + struct hostent *hp; +- hp = gethostbyname2(target, AF_INET); ++ char *idn = target; ++#ifdef USE_IDN ++ int rc; ++ ++ rc = idna_to_ascii_lz(target, &idn, 0); ++ ++ if (rc != IDNA_SUCCESS) { ++ fprintf(stderr, "arping: IDN encoding failed: %s\n", idna_strerror(rc)); ++ exit(2); ++ } ++#endif ++ ++ hp = gethostbyname2(idn, AF_INET); + if (!hp) { + fprintf(stderr, "arping: unknown host %s\n", target); + exit(2); + } ++ ++#ifdef USE_IDN ++ free(idn); ++#endif ++ + memcpy(&dst, hp->h_addr, 4); + } + +@@ -480,9 +1187,13 @@ main(int argc, char **argv) + perror("socket"); + exit(2); + } +- if (device) { +- if (setsockopt(probe_fd, SOL_SOCKET, SO_BINDTODEVICE, device, strlen(device)+1) == -1) ++ if (device.name) { ++ enable_capability_raw(); ++ ++ if (setsockopt(probe_fd, SOL_SOCKET, SO_BINDTODEVICE, device.name, strlen(device.name)+1) == -1) + perror("WARNING: interface is ignored"); ++ ++ disable_capability_raw(); + } + memset(&saddr, 0, sizeof(saddr)); + saddr.sin_family = AF_INET; +@@ -514,9 +1225,9 @@ main(int argc, char **argv) + close(probe_fd); + }; + +- me.sll_family = AF_PACKET; +- me.sll_ifindex = ifindex; +- me.sll_protocol = htons(ETH_P_ARP); ++ ((struct sockaddr_ll *)&me)->sll_family = AF_PACKET; ++ ((struct sockaddr_ll *)&me)->sll_ifindex = device.ifindex; ++ ((struct sockaddr_ll *)&me)->sll_protocol = htons(ETH_P_ARP); + if (bind(s, (struct sockaddr*)&me, sizeof(me)) == -1) { + perror("bind"); + exit(2); +@@ -529,18 +1240,20 @@ main(int argc, char **argv) + exit(2); + } + } +- if (me.sll_halen == 0) { ++ if (((struct sockaddr_ll *)&me)->sll_halen == 0) { + if (!quiet) +- printf("Interface \"%s\" is not ARPable (no ll address)\n", device); ++ printf("Interface \"%s\" is not ARPable (no ll address)\n", device.name); + exit(dad?0:2); + } + + he = me; +- memset(he.sll_addr, -1, he.sll_halen); ++ ++ set_device_broadcast(&device, ((struct sockaddr_ll *)&he)->sll_addr, ++ ((struct sockaddr_ll *)&he)->sll_halen); + + if (!quiet) { + printf("ARPING %s ", inet_ntoa(dst)); +- printf("from %s %s\n", inet_ntoa(src), device ? : ""); ++ printf("from %s %s\n", inet_ntoa(src), device.name ? : ""); + } + + if (!src.s_addr && !dad) { +@@ -548,6 +1261,8 @@ main(int argc, char **argv) + exit(2); + } + ++ drop_capabilities(); ++ + set_signal(SIGINT, finish); + set_signal(SIGALRM, catcher); + +@@ -556,7 +1271,7 @@ main(int argc, char **argv) + while(1) { + sigset_t sset, osset; + unsigned char packet[4096]; +- struct sockaddr_ll from; ++ struct sockaddr_storage from; + socklen_t alen = sizeof(from); + int cc; + +@@ -565,11 +1280,12 @@ main(int argc, char **argv) + perror("arping: recvfrom"); + continue; + } ++ + sigemptyset(&sset); + sigaddset(&sset, SIGALRM); + sigaddset(&sset, SIGINT); + sigprocmask(SIG_BLOCK, &sset, &osset); +- recv_pack(packet, cc, &from); ++ recv_pack(packet, cc, (struct sockaddr_ll *)&from); + sigprocmask(SIG_SETMASK, &osset, NULL); + } + } diff --git a/SOURCES/bz1251484-redis-client-passwd-support.patch b/SOURCES/bz1251484-redis-client-passwd-support.patch new file mode 100644 index 00000000..f4506838 --- /dev/null +++ b/SOURCES/bz1251484-redis-client-passwd-support.patch @@ -0,0 +1,33 @@ +commit fe53056f225fadae184a0ab79f1f96430854812f +Author: David Vossel +Date: Thu Aug 13 14:11:30 2015 -0400 + + High: redis: use required client pass word when set + +diff --git a/heartbeat/redis b/heartbeat/redis +index e1d0795..65abb2a 100755 +--- a/heartbeat/redis ++++ b/heartbeat/redis +@@ -218,7 +218,11 @@ function set_score() + + function redis_client() { + ocf_log debug "redis_client: '$REDIS_CLIENT' -s '$REDIS_SOCKET' $@" +- "$REDIS_CLIENT" -s "$REDIS_SOCKET" "$@" | sed 's/\r//' ++ if [ -n "$clientpasswd" ]; then ++ "$REDIS_CLIENT" -s "$REDIS_SOCKET" -a "$clientpasswd" "$@" | sed 's/\r//' ++ else ++ "$REDIS_CLIENT" -s "$REDIS_SOCKET" "$@" | sed 's/\r//' ++ fi + } + + function simple_status() { +@@ -487,6 +491,9 @@ function validate() { + } + + NODENAME=$(ocf_local_nodename) ++if [ -f "$REDIS_CONFIG" ]; then ++ clientpasswd="$(cat $REDIS_CONFIG | sed -n -e 's/^\s*requirepass\s*\(.*\)\s*$/\1/p' | tail -n 1)" ++fi + + ocf_log debug "action=${1:-$__OCF_ACTION} notify_type=${OCF_RESKEY_CRM_meta_notify_type} notify_operation=${OCF_RESKEY_CRM_meta_notify_operation} master_host=${OCF_RESKEY_CRM_meta_notify_master_uname} slave_host=${OCF_RESKEY_CRM_meta_notify_slave_uname} promote_host=${OCF_RESKEY_CRM_meta_notify_promote_uname} demote_host=${OCF_RESKEY_CRM_meta_notify_demote_uname}; params: bin=${OCF_RESKEY_bin} client_bin=${OCF_RESKEY_client_bin} config=${OCF_RESKEY_config} user=${OCF_RESKEY_user} rundir=${OCF_RESKEY_rundir} port=${OCF_RESKEY_port}" + diff --git a/SOURCES/bz1260713-1-sapdatabase-process-count-suser.patch b/SOURCES/bz1260713-1-sapdatabase-process-count-suser.patch new file mode 100644 index 00000000..3a24e9dd --- /dev/null +++ b/SOURCES/bz1260713-1-sapdatabase-process-count-suser.patch @@ -0,0 +1,135 @@ +From fe55f9b909d81a0093dbfb1f00083706cf5d2cf1 Mon Sep 17 00:00:00 2001 +From: Alexander Krauth +Date: Fri, 19 Feb 2016 18:00:58 +0100 +Subject: [PATCH] High: SAPDatabase: Add support for Oracle 12c + +To work with Oracle 12c the agent needs an option +to pass the new Database Username to the resource. + +Example configuration: + +primitive oracle-database SAPDatabase \ + params \ + SID=HAO \ + DBTYPE=ORA \ + DBOUSER=oracle \ + STRICT_MONITORING=1 \ + op monitor interval=120 timeout=60 +--- + heartbeat/SAPDatabase | 12 +++++++++++- + heartbeat/sapdb.sh | 35 ++++++++++++++++++++++++++--------- + 2 files changed, 37 insertions(+), 10 deletions(-) + +diff --git a/heartbeat/SAPDatabase b/heartbeat/SAPDatabase +index de7959f..641bd40 100755 +--- a/heartbeat/SAPDatabase ++++ b/heartbeat/SAPDatabase +@@ -18,6 +18,7 @@ + # OCF_RESKEY_DIR_EXECUTABLE (optional, well known directories will be searched by default) + # OCF_RESKEY_DBTYPE (mandatory, one of the following values: ORA,ADA,DB6,SYB,HDB) + # OCF_RESKEY_DBINSTANCE (optional, Database instance name, if not equal to SID) ++# OCF_RESKEY_DBOSUSER (optional, the Linux user that owns the database processes on operating system level) + # OCF_RESKEY_STRICT_MONITORING (optional, activate application level monitoring - with Oracle a failover will occur in case of an archiver stuck) + # OCF_RESKEY_AUTOMATIC_RECOVER (optional, automatic startup recovery, default is false) + # OCF_RESKEY_MONITOR_SERVICES (optional, default is to monitor all database services) +@@ -69,7 +70,7 @@ meta_data() { + + + +-2.06 ++2.14 + + Manages a SAP database instance as an HA resource. + +@@ -115,6 +116,11 @@ Usually you can leave this empty. Then the default: /usr/sap/hostctrl/exe is use + Database instance name, if not equal to SID + + ++ ++ The parameter can be set, if the database processes on operating system level are not executed with the default user of the used database type. Defaults: ADA=taken from /etc/opt/sdb, DB6=db2SID, ORA=oraSID and oracle, SYB=sybSID, HDB=SIDadm ++ the Linux user that owns the database processes on operating system level ++ ++ + + Deprecated - do not use anymore. This parameter will be deleted in one of the next releases. + deprecated - do not use anymore +@@ -305,6 +311,10 @@ DBTYPE=`echo "$OCF_RESKEY_DBTYPE" | tr '[:lower:]' '[:upper:]'` + if saphostctrl_installed; then + . ${OCF_FUNCTIONS_DIR}/sapdb.sh + else ++ if [ -n "${OCF_RESKEY_DBOSUSER}" ]; then ++ ocf_exit_reason "Usage of parameter OCF_RESKEY_DBOSUSER is not possible without having SAP Host-Agent installed" ++ exit $OCF_ERR_ARGS ++ fi + . ${OCF_FUNCTIONS_DIR}/sapdb-nosha.sh + fi + sapdatabase_init +diff --git a/heartbeat/sapdb.sh b/heartbeat/sapdb.sh +index 7edb4b8..33d2033 100755 +--- a/heartbeat/sapdb.sh ++++ b/heartbeat/sapdb.sh +@@ -210,7 +210,11 @@ sapdatabase_monitor() { + then + DBINST="-dbinstance $OCF_RESKEY_DBINSTANCE " + fi +- output=`$SAPHOSTCTRL -function GetDatabaseStatus -dbname $SID -dbtype $DBTYPE $DBINST` ++ if [ -n "$OCF_RESKEY_DBOSUSER" ] ++ then ++ DBOSUSER="-dbuser $OCF_RESKEY_DBOSUSER " ++ fi ++ output=`$SAPHOSTCTRL -function GetDatabaseStatus -dbname $SID -dbtype $DBTYPE $DBINST $DBOSUSER` + + # we have to parse the output, because the returncode doesn't tell anything about the instance status + for SERVICE in `echo "$output" | grep -i 'Component[ ]*Name *[:=] [A-Za-z][A-Za-z0-9_]* (' | sed 's/^.*Component[ ]*Name *[:=] *\([A-Za-z][A-Za-z0-9_]*\).*$/\1/i'` +@@ -255,30 +259,43 @@ sapdatabase_monitor() { + # sapdatabase_status: Are there any database processes on this host ? + # + sapdatabase_status() { ++ sid=`echo $SID | tr '[:upper:]' '[:lower:]'` ++ ++ SUSER=${OCF_RESKEY_DBOSUSER:-""} ++ + case $DBTYPE in + ADA) SEARCH="$SID/db/pgm/kernel" +- SUSER=`grep "^SdbOwner" /etc/opt/sdb | awk -F'=' '{print $2}'` ++ [ -z "$SUSER" ] && SUSER=`grep "^SdbOwner" /etc/opt/sdb | awk -F'=' '{print $2}'` + SNUM=2 + ;; +- ORA) SEARCH="ora_[a-z][a-z][a-z][a-z]_" +- SUSER="ora`echo $SID | tr '[:upper:]' '[:lower:]'`" +- SNUM=4 ++ ORA) DBINST=${OCF_RESKEY_DBINSTANCE} ++ DBINST=${OCF_RESKEY_DBINSTANCE:-${SID}} ++ SEARCH="ora_[a-z][a-z][a-z][a-z]_$DBINST" ++ ++ if [ -z "$SUSER" ]; then ++ id "oracle" > /dev/null 2> /dev/null && SUSER="oracle" ++ id "ora${sid}" > /dev/null 2> /dev/null && SUSER="${SUSER:+${SUSER},}ora${sid}" ++ fi ++ ++ SNUM=4 + ;; + DB6) SEARCH="db2[a-z][a-z][a-z]" +- SUSER="db2`echo $SID | tr '[:upper:]' '[:lower:]'`" ++ [ -z "$SUSER" ] && SUSER="db2${sid}" + SNUM=2 + ;; + SYB) SEARCH="dataserver" +- SUSER="syb`echo $SID | tr '[:upper:]' '[:lower:]'`" ++ [ -z "$SUSER" ] && SUSER="syb${sid}" + SNUM=1 + ;; + HDB) SEARCH="hdb[a-z]*server" +- SUSER="`echo $SID | tr '[:upper:]' '[:lower:]'`adm" ++ [ -z "$SUSER" ] && SUSER="${sid}adm" + SNUM=1 + ;; + esac + +- cnt=`ps -u $SUSER -o args 2> /dev/null | grep -c $SEARCH` ++ [ -z "$SUSER" ] && return $OCF_ERR_INSTALLED ++ ++ cnt=`ps -u $SUSER -o args 2> /dev/null | grep -v grep | grep -c $SEARCH` + [ $cnt -ge $SNUM ] && return $OCF_SUCCESS + return $OCF_NOT_RUNNING + } diff --git a/SOURCES/bz1260713-2-sapdatabase-process-count-suser.patch b/SOURCES/bz1260713-2-sapdatabase-process-count-suser.patch new file mode 100644 index 00000000..c349f0d8 --- /dev/null +++ b/SOURCES/bz1260713-2-sapdatabase-process-count-suser.patch @@ -0,0 +1,24 @@ +From af5863ecd255d2d514113d39bbf03ab95b5ccca2 Mon Sep 17 00:00:00 2001 +From: =?UTF-8?q?Kristoffer=20Gr=C3=B6nlund?= +Date: Mon, 16 Nov 2015 17:14:43 +0100 +Subject: [PATCH] SAPDatabase: Add Oracle 12 to list of supported databases + (bsc#953991) + +This agent has been tested to work with Oracle database version 12. +--- + heartbeat/SAPDatabase | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/heartbeat/SAPDatabase b/heartbeat/SAPDatabase +index 3b77206..de7959f 100755 +--- a/heartbeat/SAPDatabase ++++ b/heartbeat/SAPDatabase +@@ -78,7 +78,7 @@ Resource script for SAP databases. It manages a SAP database of any type as an H + The purpose of the resource agent is to start, stop and monitor the database instance of a SAP system. Together with the RDBMS system it will also control the related network service for the database. Like the Oracle Listener and the xserver of MaxDB. + The resource agent expects a standard SAP installation of the database and therefore needs less parameters to configure. + The resource agent supports the following databases: +-- Oracle 10.2 and 11.2 ++- Oracle 10.2, 11.2 and 12 + - DB/2 UDB for Windows and Unix 9.x + - SAP-DB / MaxDB 7.x + - Sybase ASE 15.7 diff --git a/SOURCES/bz1263348-mysql-tmpfile-leak.patch b/SOURCES/bz1263348-mysql-tmpfile-leak.patch new file mode 100644 index 00000000..11175357 --- /dev/null +++ b/SOURCES/bz1263348-mysql-tmpfile-leak.patch @@ -0,0 +1,11 @@ +diff -uNr a/heartbeat/mysql b/heartbeat/mysql +--- a/heartbeat/mysql 2016-02-29 10:54:21.896786740 +0100 ++++ b/heartbeat/mysql 2016-02-29 10:59:13.377446910 +0100 +@@ -344,6 +344,7 @@ + + get_slave_info + rc=$? ++ rm -f $tmpfile + + if [ $rc -eq 0 ]; then + # show slave status is not empty diff --git a/SOURCES/bz1265527-sap_redhat_cluster_connector-hostnames-with-dash.patch b/SOURCES/bz1265527-sap_redhat_cluster_connector-hostnames-with-dash.patch new file mode 100644 index 00000000..33ac96c8 --- /dev/null +++ b/SOURCES/bz1265527-sap_redhat_cluster_connector-hostnames-with-dash.patch @@ -0,0 +1,37 @@ +diff -uNr a/sap_redhat_cluster_connector-6353d27/sap_redhat_cluster_connector b/sap_redhat_cluster_connector-6353d27/sap_redhat_cluster_connector +--- a/sap_redhat_cluster_connector-6353d27/sap_redhat_cluster_connector 2013-07-18 21:17:48.000000000 +0200 ++++ b/sap_redhat_cluster_connector-6353d27/sap_redhat_cluster_connector 2016-02-29 11:04:48.714352114 +0100 +@@ -251,13 +251,13 @@ + open CRMOUT, "$cmd_cibadmin --local -Q --xpath '//primitive[\@type=\"$sra\"]' --node-path 2>/dev/null |" || die "could not open cibadmin output"; + while () { + my $line = $_; +- if ($line =~ /primitive..id='([a-zA-Z0-9_]+)'/) { ++ if ($line =~ /primitive..id='([a-zA-Z0-9_-]+)'/) { + ($fname) = ($1); + } else { + next; + } + +- if ( $line =~ /[group|master|clone]..id='([a-zA-Z0-9_]+)'/) { ++ if ( $line =~ /[group|master|clone]..id='([a-zA-Z0-9_-]+)'/) { + ($fgname) = ($1); + } + +@@ -265,7 +265,7 @@ + open RESOURCE1_OUT, "$cmd_cibadmin -Q --xpath \"//primitive[\@id='$fname']//nvpair[\@name='$sparam']\" 2>/dev/null |" || die "could not open cibadmin output"; + while () { + my $result = $_; +- if ($result =~ /value="([a-zA-Z0-9_]+)"/) { ++ if ($result =~ /value="([a-zA-Z0-9_-]+)"/) { + my $finstance=$1; + if ( $1 =~ /^${sid}_[a-zA-Z0-9]+${ino}_[a-zA-Z0-9_-]+$/ ) { + $foundRes=1; +@@ -279,7 +279,7 @@ + open RESOURCE2_OUT, "$cmd_cibadmin -Q --xpath \"//primitive[\@id='$fname']//nvpair[\@name='$sparam2']\" 2>/dev/null |" || die "could not open cibadmin output"; + while () { + my $result = $_; +- if ($result =~ /value="([a-zA-Z0-9_]+)"/) { ++ if ($result =~ /value="([a-zA-Z0-9_-]+)"/) { + my $finstance=$1; + if ( $1 =~ /^${sid}_[a-zA-Z0-9]+${ino}_[a-zA-Z0-9_-]+$/ ) { + $foundRes=1; diff --git a/SOURCES/bz1276699-ipaddr2-use-ipv6-dad-for-collision-detection.patch b/SOURCES/bz1276699-ipaddr2-use-ipv6-dad-for-collision-detection.patch new file mode 100644 index 00000000..57748bfe --- /dev/null +++ b/SOURCES/bz1276699-ipaddr2-use-ipv6-dad-for-collision-detection.patch @@ -0,0 +1,60 @@ +diff -uNr a/heartbeat/IPaddr2 b/heartbeat/IPaddr2 +--- a/heartbeat/IPaddr2 2016-02-29 10:54:21.909786575 +0100 ++++ b/heartbeat/IPaddr2 2016-02-29 14:38:48.502852067 +0100 +@@ -673,19 +673,35 @@ + # + run_send_ua() { + local i +- # Wait until the allocated IPv6 address gets ready by checking +- # "tentative" flag is disappeared, otherwise send_ua can not +- # send the unsolicited advertisement requests. +- for i in 1 2 3 4 5; do +- $IP2UTIL -o -f $FAMILY addr show dev $NIC \ +- | grep -q -e "$OCF_RESKEY_ip/$NETMASK .* tentative" +- [ $? -ne 0 ] && break +- if [ $i -eq 5 ]; then +- ocf_log warn "$OCF_RESKEY_ip still has 'tentative' status. (ignored)" ++ ++ # Duplicate Address Detection [DAD] ++ # Kernel will flag the IP as 'tentative' until it ensured that ++ # there is no duplicates. ++ # If there is, it will flag it as 'dadfailed' ++ for i in $(seq 1 10); do ++ ipstatus=$($IP2UTIL -o -f $FAMILY addr show dev $NIC to $OCF_RESKEY_ip/$NETMASK) ++ case "$ipstatus" in ++ *dadfailed*) ++ ocf_log err "IPv6 address collision $OCF_RESKEY_ip [DAD]" ++ $IP2UTIL -f $FAMILY addr del dev $NIC $OCF_RESKEY_ip/$NETMASK ++ if [ $? -ne 0 ]; then ++ ocf_log err "Could not delete IPv6 address" ++ fi ++ return $OCF_ERR_GENERIC ++ ;; ++ *tentative*) ++ if [ $i -eq 10 ]; then ++ ofc_log warn "IPv6 address : DAD is still in tentative" ++ fi ++ ;; ++ *) + break +- fi ++ ;; ++ esac + sleep 1 + done ++ # Now the address should be usable ++ + ARGS="-i $OCF_RESKEY_arp_interval -c $OCF_RESKEY_arp_count $OCF_RESKEY_ip $NETMASK $NIC" + ocf_log info "$SENDUA $ARGS" + $SENDUA $ARGS || ocf_log err "Could not send ICMPv6 Unsolicited Neighbor Advertisements." +@@ -838,6 +854,10 @@ + else + if [ -x $SENDUA ]; then + run_send_ua ++ if [ $? -ne 0 ]; then ++ ocf_exit_reason "run_send_ua failed." ++ exit $OCF_ERR_GENERIC ++ fi + fi + fi + ;; diff --git a/SOURCES/bz1282723-novacompute-novaevacuate-fix-evacute-typo.patch b/SOURCES/bz1282723-novacompute-novaevacuate-fix-evacute-typo.patch new file mode 100644 index 00000000..9178089b --- /dev/null +++ b/SOURCES/bz1282723-novacompute-novaevacuate-fix-evacute-typo.patch @@ -0,0 +1,728 @@ +diff -uNr a/doc/man/Makefile.am b/doc/man/Makefile.am +--- a/doc/man/Makefile.am 2016-02-02 14:49:34.546698286 +0100 ++++ b/doc/man/Makefile.am 2016-02-02 14:50:29.893979453 +0100 +@@ -73,7 +73,7 @@ + ocf_heartbeat_MailTo.7 \ + ocf_heartbeat_ManageRAID.7 \ + ocf_heartbeat_ManageVE.7 \ +- ocf_heartbeat_NovaCompute.7 \ ++ ocf_heartbeat_nova-compute-wait.7 \ + ocf_heartbeat_NovaEvacuate.7 \ + ocf_heartbeat_Pure-FTPd.7 \ + ocf_heartbeat_Raid1.7 \ +diff -uNr a/heartbeat/Makefile.am b/heartbeat/Makefile.am +--- a/heartbeat/Makefile.am 2016-02-02 14:49:34.546698286 +0100 ++++ b/heartbeat/Makefile.am 2016-02-02 14:50:29.894979440 +0100 +@@ -52,7 +52,7 @@ + IPv6addr_LDADD = -lplumb $(LIBNETLIBS) + send_ua_LDADD = $(LIBNETLIBS) + +-osp_SCRIPTS = NovaCompute \ ++osp_SCRIPTS = nova-compute-wait \ + NovaEvacuate + + ocf_SCRIPTS = ClusterMon \ +diff -uNr a/heartbeat/NovaCompute b/heartbeat/NovaCompute +--- a/heartbeat/NovaCompute 2016-02-02 14:49:34.541698351 +0100 ++++ b/heartbeat/NovaCompute 1970-01-01 01:00:00.000000000 +0100 +@@ -1,366 +0,0 @@ +-#!/bin/sh +-# +-# +-# NovaCompute agent manages compute daemons. +-# +-# Copyright (c) 2015 +-# +-# This program is free software; you can redistribute it and/or modify +-# it under the terms of version 2 of the GNU General Public License as +-# published by the Free Software Foundation. +-# +-# This program is distributed in the hope that it would be useful, but +-# WITHOUT ANY WARRANTY; without even the implied warranty of +-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +-# +-# Further, this software is distributed without any warranty that it is +-# free of the rightful claim of any third person regarding infringement +-# or the like. Any license provided herein, whether implied or +-# otherwise, applies only to this software file. Patent licenses, if +-# any, provided herein do not apply to combinations of this program with +-# other software, or any other product whatsoever. +-# +-# You should have received a copy of the GNU General Public License +-# along with this program; if not, write the Free Software Foundation, +-# Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. +-# +- +-####################################################################### +-# Initialization: +- +-### +-: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat} +-. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs +-### +- +-: ${__OCF_ACTION=$1} +- +-####################################################################### +- +-meta_data() { +- cat < +- +- +-1.0 +- +- +-OpenStack Nova Compute Server. +- +-OpenStack Nova Compute Server +- +- +- +- +- +-Authorization URL for connecting to keystone in admin context +- +-Authorization URL +- +- +- +- +- +-Username for connecting to keystone in admin context +- +-Username +- +- +- +- +-Password for connecting to keystone in admin context +- +-Password +- +- +- +- +- +-Tenant name for connecting to keystone in admin context. +-Note that with Keystone V3 tenant names are only unique within a domain. +- +-Tenant name +- +- +- +- +- +-DNS domain in which hosts live, useful when the cluster uses short names and nova uses FQDN +- +-DNS domain +- +- +- +- +- +-Nova API location (internal, public or admin URL) +- +-Nova API location (internal, public or admin URL) +- +- +- +- +- +-Disable shared storage recovery for instances. Use at your own risk! +- +-Disable shared storage recovery for instances +- +- +- +- +- +-How long to wait for nova to finish evacuating instances elsewhere +-before starting nova-compute. Only used when the agent detects +-evacuations might be in progress. +- +-You may need to increase the start timeout when increasing this value. +- +-Delay to allow evacuations time to complete +- +- +- +- +- +- +- +- +- +- +- +- +- +-END +-} +- +-####################################################################### +- +-# don't exit on TERM, to test that lrmd makes sure that we do exit +-trap sigterm_handler TERM +-sigterm_handler() { +- ocf_log info "They use TERM to bring us down. No such luck." +- return +-} +- +-nova_usage() { +- cat </dev/null) +- if [ $? = 1 ]; then +- if [ "x${OCF_RESKEY_domain}" != x ]; then +- NOVA_HOST=$(uname -n | awk -F. '{print $1}') +- else +- NOVA_HOST=$(uname -n) +- fi +- fi +- +- # We only need to check a configured value, calculated ones are fine +- openstack-config --get /etc/nova/nova.conf DEFAULT host 2>/dev/null +- if [ $? = 0 ]; then +- if [ "x${OCF_RESKEY_domain}" != x ]; then +- short_host=$(uname -n | awk -F. '{print $1}') +- if [ "x$NOVA_HOST" != "x${short_host}" ]; then +- ocf_exit_reason "Invalid Nova host name, must be ${short_host} in order for instance recovery to function" +- rc=$OCF_ERR_CONFIGURED +- fi +- +- elif [ "x$NOVA_HOST" != "x$(uname -n)" ]; then +- ocf_exit_reason "Invalid Nova host name, must be $(uname -n) in order for instance recovery to function" +- rc=$OCF_ERR_CONFIGURED +- fi +- fi +- +- if [ $rc != $OCF_SUCCESS ]; then +- exit $rc +- fi +- return $rc +-} +- +-: ${OCF_RESKEY_evacuation_delay=120} +-case $__OCF_ACTION in +-meta-data) meta_data +- exit $OCF_SUCCESS +- ;; +-usage|help) nova_usage +- exit $OCF_SUCCESS +- ;; +-esac +- +-case $__OCF_ACTION in +-start) nova_validate; nova_start;; +-stop) nova_stop;; +-monitor) nova_validate; nova_monitor;; +-notify) nova_notify;; +-validate-all) exit $OCF_SUCCESS;; +-*) nova_usage +- exit $OCF_ERR_UNIMPLEMENTED +- ;; +-esac +-rc=$? +-ocf_log debug "${OCF_RESOURCE_INSTANCE} $__OCF_ACTION : $rc" +-exit $rc +diff -uNr a/heartbeat/nova-compute-wait b/heartbeat/nova-compute-wait +--- a/heartbeat/nova-compute-wait 1970-01-01 01:00:00.000000000 +0100 ++++ b/heartbeat/nova-compute-wait 2016-02-02 14:50:29.894979440 +0100 +@@ -0,0 +1,304 @@ ++#!/bin/sh ++# ++# ++# nova-compute-wait agent manages compute daemons. ++# ++# Copyright (c) 2015 ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of version 2 of the GNU General Public License as ++# published by the Free Software Foundation. ++# ++# This program is distributed in the hope that it would be useful, but ++# WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++# ++# Further, this software is distributed without any warranty that it is ++# free of the rightful claim of any third person regarding infringement ++# or the like. Any license provided herein, whether implied or ++# otherwise, applies only to this software file. Patent licenses, if ++# any, provided herein do not apply to combinations of this program with ++# other software, or any other product whatsoever. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write the Free Software Foundation, ++# Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. ++# ++ ++####################################################################### ++# Initialization: ++ ++### ++: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat} ++. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs ++### ++ ++: ${__OCF_ACTION=$1} ++ ++####################################################################### ++ ++meta_data() { ++ cat < ++ ++ ++1.0 ++ ++ ++OpenStack Nova Compute Server. ++ ++OpenStack Nova Compute Server ++ ++ ++ ++ ++ ++Authorization URL for connecting to keystone in admin context ++ ++Authorization URL ++ ++ ++ ++ ++ ++Username for connecting to keystone in admin context ++ ++Username ++ ++ ++ ++ ++Password for connecting to keystone in admin context ++ ++Password ++ ++ ++ ++ ++ ++Tenant name for connecting to keystone in admin context. ++Note that with Keystone V3 tenant names are only unique within a domain. ++ ++Tenant name ++ ++ ++ ++ ++ ++DNS domain in which hosts live, useful when the cluster uses short names and nova uses FQDN ++ ++DNS domain ++ ++ ++ ++ ++ ++Nova API location (internal, public or admin URL) ++ ++Nova API location (internal, public or admin URL) ++ ++ ++ ++ ++ ++Disable shared storage recovery for instances. Use at your own risk! ++ ++Disable shared storage recovery for instances ++ ++ ++ ++ ++ ++How long to wait for nova to finish evacuating instances elsewhere ++before starting nova-compute. Only used when the agent detects ++evacuations might be in progress. ++ ++You may need to increase the start timeout when increasing this value. ++ ++Delay to allow evacuations time to complete ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++END ++} ++ ++####################################################################### ++ ++# don't exit on TERM, to test that lrmd makes sure that we do exit ++trap sigterm_handler TERM ++sigterm_handler() { ++ ocf_log info "They use TERM to bring us down. No such luck." ++ return ++} ++ ++nova_usage() { ++ cat </dev/null) ++ if [ $? = 1 ]; then ++ if [ "x${OCF_RESKEY_domain}" != x ]; then ++ NOVA_HOST=$(uname -n | awk -F. '{print $1}') ++ else ++ NOVA_HOST=$(uname -n) ++ fi ++ fi ++ ++ # We only need to check a configured value, calculated ones are fine ++ openstack-config --get /etc/nova/nova.conf DEFAULT host 2>/dev/null ++ if [ $? = 0 ]; then ++ if [ "x${OCF_RESKEY_domain}" != x ]; then ++ short_host=$(uname -n | awk -F. '{print $1}') ++ if [ "x$NOVA_HOST" != "x${short_host}" ]; then ++ ocf_exit_reason "Invalid Nova host name, must be ${short_host} in order for instance recovery to function" ++ rc=$OCF_ERR_CONFIGURED ++ fi ++ ++ elif [ "x$NOVA_HOST" != "x$(uname -n)" ]; then ++ ocf_exit_reason "Invalid Nova host name, must be $(uname -n) in order for instance recovery to function" ++ rc=$OCF_ERR_CONFIGURED ++ fi ++ fi ++ ++ if [ $rc != $OCF_SUCCESS ]; then ++ exit $rc ++ fi ++ return $rc ++} ++ ++: ${OCF_RESKEY_evacuation_delay=120} ++case $__OCF_ACTION in ++meta-data) meta_data ++ exit $OCF_SUCCESS ++ ;; ++usage|help) nova_usage ++ exit $OCF_SUCCESS ++ ;; ++esac ++ ++case $__OCF_ACTION in ++start) nova_validate; nova_start;; ++stop) nova_stop;; ++monitor) nova_validate; nova_monitor;; ++notify) nova_notify;; ++validate-all) exit $OCF_SUCCESS;; ++*) nova_usage ++ exit $OCF_ERR_UNIMPLEMENTED ++ ;; ++esac ++rc=$? ++ocf_log debug "${OCF_RESOURCE_INSTANCE} $__OCF_ACTION : $rc" ++exit $rc +diff -uNr a/heartbeat/NovaEvacuate b/heartbeat/NovaEvacuate +--- a/heartbeat/NovaEvacuate 2016-02-02 14:49:34.541698351 +0100 ++++ b/heartbeat/NovaEvacuate 2016-02-02 14:50:22.768072003 +0100 +@@ -141,7 +141,7 @@ + } + + update_evacuation() { +- attrd_updater -p -n evacute -Q -N ${1} -v ${2} ++ attrd_updater -p -n evacuate -Q -N ${1} -v ${2} + arc=$? + if [ ${arc} != 0 ]; then + ocf_log warn "Can not set evacuation state of ${1} to ${2}: ${arc}" +@@ -219,7 +219,12 @@ + return $OCF_NOT_RUNNING + fi + +- handle_evacuations $(attrd_updater -n evacute -A | tr '="' ' ' | awk '{print $4" "$6}') ++ handle_evacuations $( ++ attrd_updater -n evacuate -A | ++ sed 's/ value=""/ value="no"/' | ++ tr '="' ' ' | ++ awk '{print $4" "$6}' ++ ) + return $OCF_SUCCESS + } + diff --git a/SOURCES/bz1284526-galera-crash-recovery.patch b/SOURCES/bz1284526-galera-crash-recovery.patch new file mode 100644 index 00000000..3e51ad0d --- /dev/null +++ b/SOURCES/bz1284526-galera-crash-recovery.patch @@ -0,0 +1,131 @@ +From d9833b68498e306d181be11adf9eee14b646a899 Mon Sep 17 00:00:00 2001 +From: Damien Ciabrini +Date: Tue, 2 Feb 2016 14:34:36 +0100 +Subject: [PATCH] galera: force crash recovery if needed during last commit + detection + +--- + heartbeat/galera | 90 +++++++++++++++++++++++++++++++++++++------------------- + 1 file changed, 60 insertions(+), 30 deletions(-) + +diff --git a/heartbeat/galera b/heartbeat/galera +index 7be2b00..ca94c21 100755 +--- a/heartbeat/galera ++++ b/heartbeat/galera +@@ -525,6 +525,58 @@ detect_first_master() + set_bootstrap_node $best_node + } + ++detect_last_commit() ++{ ++ local last_commit ++ local recover_args="--defaults-file=$OCF_RESKEY_config \ ++ --pid-file=$OCF_RESKEY_pid \ ++ --socket=$OCF_RESKEY_socket \ ++ --datadir=$OCF_RESKEY_datadir \ ++ --user=$OCF_RESKEY_user" ++ local recovered_position_regex='s/.*WSREP\:\s*[R|r]ecovered\s*position.*\:\(.*\)\s*$/\1/p' ++ ++ ocf_log info "attempting to detect last commit version by reading ${OCF_RESKEY_datadir}/grastate.dat" ++ last_commit="$(cat ${OCF_RESKEY_datadir}/grastate.dat | sed -n 's/^seqno.\s*\(.*\)\s*$/\1/p')" ++ if [ -z "$last_commit" ] || [ "$last_commit" = "-1" ]; then ++ local tmp=$(mktemp) ++ local tmperr=$(mktemp) ++ ++ ocf_log info "now attempting to detect last commit version using 'mysqld_safe --wsrep-recover'" ++ ++ ${OCF_RESKEY_binary} $recover_args --wsrep-recover > $tmp 2> $tmperr ++ ++ last_commit="$(cat $tmp | sed -n $recovered_position_regex)" ++ if [ -z "$last_commit" ]; then ++ # Galera uses InnoDB's 2pc transactions internally. If ++ # server was stopped in the middle of a replication, the ++ # recovery may find a "prepared" XA transaction in the ++ # redo log, and mysql won't recover automatically ++ ++ cat $tmperr | grep -q -E '\[ERROR\]\s+Found\s+[0-9]+\s+prepared\s+transactions!' 2>/dev/null ++ if [ $? -eq 0 ]; then ++ # we can only rollback the transaction, but that's OK ++ # since the DB will get resynchronized anyway ++ ocf_log warn "local node <${NODENAME}> was not shutdown properly. Rollback stuck transaction with --tc-heuristic-recover" ++ ${OCF_RESKEY_binary} $recover_args --wsrep-recover \ ++ --tc-heuristic-recover=rollback > $tmp 2>/dev/null ++ ++ last_commit="$(cat $tmp | sed -n $recovered_position_regex)" ++ fi ++ fi ++ rm -f $tmp $tmperr ++ fi ++ ++ if [ ! -z "$last_commit" ]; then ++ ocf_log info "Last commit version found: $last_commit" ++ set_last_commit $last_commit ++ return $OCF_SUCCESS ++ else ++ ocf_exit_reason "Unable to detect last known write sequence number" ++ clear_last_commit ++ return $OCF_ERR_GENERIC ++ fi ++} ++ + # For galera, promote is really start + galera_promote() + { +@@ -569,13 +620,15 @@ galera_demote() + clear_bootstrap_node + clear_last_commit + +- # record last commit by "starting" galera. start is just detection of the last sequence number +- galera_start ++ # record last commit for next promotion ++ detect_last_commit ++ rc=$? ++ return $rc + } + + galera_start() + { +- local last_commit ++ local rc + + echo $OCF_RESKEY_wsrep_cluster_address | grep -q $NODENAME + if [ $? -ne 0 ]; then +@@ -591,34 +644,11 @@ galera_start() + + mysql_common_prepare_dirs + +- ocf_log info "attempting to detect last commit version by reading ${OCF_RESKEY_datadir}/grastate.dat" +- last_commit="$(cat ${OCF_RESKEY_datadir}/grastate.dat | sed -n 's/^seqno.\s*\(.*\)\s*$/\1/p')" +- if [ -z "$last_commit" ] || [ "$last_commit" = "-1" ]; then +- ocf_log info "now attempting to detect last commit version using 'mysqld_safe --wsrep-recover'" +- local tmp=$(mktemp) +- ${OCF_RESKEY_binary} --defaults-file=$OCF_RESKEY_config \ +- --pid-file=$OCF_RESKEY_pid \ +- --socket=$OCF_RESKEY_socket \ +- --datadir=$OCF_RESKEY_datadir \ +- --user=$OCF_RESKEY_user \ +- --wsrep-recover > $tmp 2>&1 +- +- last_commit="$(cat $tmp | sed -n 's/.*WSREP\:\s*[R|r]ecovered\s*position.*\:\(.*\)\s*$/\1/p')" +- rm -f $tmp +- +- if [ "$last_commit" = "-1" ]; then +- last_commit="0" +- fi +- fi +- +- if [ -z "$last_commit" ]; then +- ocf_exit_reason "Unable to detect last known write sequence number" +- clear_last_commit +- return $OCF_ERR_GENERIC ++ detect_last_commit ++ rc=$? ++ if [ $rc -ne $OCF_SUCCESS ]; then ++ return $rc + fi +- ocf_log info "Last commit version found: $last_commit" +- +- set_last_commit $last_commit + + master_exists + if [ $? -eq 0 ]; then diff --git a/SOURCES/bz1284526-galera-heuristic-recovered.patch b/SOURCES/bz1284526-galera-heuristic-recovered.patch new file mode 100644 index 00000000..589fc110 --- /dev/null +++ b/SOURCES/bz1284526-galera-heuristic-recovered.patch @@ -0,0 +1,89 @@ +From 4d98bbcdadda60166faf7ccc512b9095b439e2bd Mon Sep 17 00:00:00 2001 +From: Damien Ciabrini +Date: Tue, 2 Feb 2016 16:29:10 +0100 +Subject: [PATCH] galera: prevent recovered nodes from bootstrapping cluster + when possible + +--- + heartbeat/README.galera | 19 ++++++++++++++++++- + heartbeat/galera | 41 +++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 59 insertions(+), 1 deletion(-) + +diff --git a/heartbeat/galera b/heartbeat/galera +index ca94c21..84c92fd 100755 +--- a/heartbeat/galera ++++ b/heartbeat/galera +@@ -276,6 +276,22 @@ is_bootstrap() + + } + ++set_heuristic_recovered() ++{ ++ ${HA_SBIN_DIR}/crm_attribute -N $NODENAME -l reboot --name "${INSTANCE_ATTR_NAME}-heuristic-recovered" -v "true" ++} ++ ++clear_heuristic_recovered() ++{ ++ ${HA_SBIN_DIR}/crm_attribute -N $NODENAME -l reboot --name "${INSTANCE_ATTR_NAME}-heuristic-recovered" -D ++} ++ ++is_heuristic_recovered() ++{ ++ local node=$1 ++ ${HA_SBIN_DIR}/crm_attribute -N $node -l reboot --name "${INSTANCE_ATTR_NAME}-heuristic-recovered" -Q 2>/dev/null ++} ++ + clear_last_commit() + { + ${HA_SBIN_DIR}/crm_attribute -N $NODENAME -l reboot --name "${INSTANCE_ATTR_NAME}-last-committed" -D +@@ -398,8 +414,19 @@ detect_first_master() + local best_node="$NODENAME" + local last_commit=0 + local missing_nodes=0 ++ local nodes="" ++ local nodes_recovered="" + ++ # avoid selecting a recovered node as bootstrap if possible + for node in $(echo "$OCF_RESKEY_wsrep_cluster_address" | sed 's/gcomm:\/\///g' | tr -d ' ' | tr -s ',' ' '); do ++ if is_heuristic_recovered $node; then ++ nodes_recovered="$nodes_recovered $node" ++ else ++ nodes="$nodes $node" ++ fi ++ done ++ ++ for node in $nodes_recovered $nodes; do + last_commit=$(get_last_commit $node) + + if [ -z "$last_commit" ]; then +@@ -466,6 +493,12 @@ detect_last_commit() + --tc-heuristic-recover=rollback > $tmp 2>/dev/null + + last_commit="$(cat $tmp | sed -n $recovered_position_regex)" ++ if [ ! -z "$last_commit" ]; then ++ ocf_log warn "State recovered. force SST at next restart for full resynchronization" ++ rm -f ${OCF_RESKEY_datadir}/grastate.dat ++ # try not to use this node if bootstrap is needed ++ set_heuristic_recovered ++ fi + fi + fi + rm -f $tmp $tmperr +@@ -549,11 +582,17 @@ galera_promote() + if ocf_is_true $bootstrap; then + promote_everyone + clear_bootstrap_node ++ # clear attribute heuristic-recovered. if last shutdown was ++ # not clean, we cannot be extra-cautious by requesting a SST ++ # since this is the bootstrap node ++ clear_heuristic_recovered + ocf_log info "Bootstrap complete, promoting the rest of the galera instances." + else + # if this is not the bootstrap node, make sure this instance + # syncs with the rest of the cluster before promotion returns. + wait_for_sync ++ # sync is done, clear info about last recovery ++ clear_heuristic_recovered + fi + + ocf_log info "Galera started" diff --git a/SOURCES/bz1284526-galera-no-grastate.patch b/SOURCES/bz1284526-galera-no-grastate.patch new file mode 100644 index 00000000..8f2ca233 --- /dev/null +++ b/SOURCES/bz1284526-galera-no-grastate.patch @@ -0,0 +1,113 @@ +From 422ef6a2018ebf9d6765e1f2965778f42c6a9d9c Mon Sep 17 00:00:00 2001 +From: Damien Ciabrini +Date: Tue, 15 Mar 2016 18:45:13 +0100 +Subject: [PATCH] galera: don't bootstrap from a node with no grastate.dat when + possible + +--- + heartbeat/README.galera | 9 ++++----- + heartbeat/galera | 36 ++++++++++++++++++++++-------------- + 2 files changed, 26 insertions(+), 19 deletions(-) + +diff --git a/heartbeat/galera b/heartbeat/galera +index 72add3c..e4495be 100755 +--- a/heartbeat/galera ++++ b/heartbeat/galera +@@ -276,20 +276,20 @@ is_bootstrap() + + } + +-set_heuristic_recovered() ++set_no_grastate() + { +- ${HA_SBIN_DIR}/crm_attribute -N $NODENAME -l reboot --name "${INSTANCE_ATTR_NAME}-heuristic-recovered" -v "true" ++ ${HA_SBIN_DIR}/crm_attribute -N $NODENAME -l reboot --name "${INSTANCE_ATTR_NAME}-no-grastate" -v "true" + } + +-clear_heuristic_recovered() ++clear_no_grastate() + { +- ${HA_SBIN_DIR}/crm_attribute -N $NODENAME -l reboot --name "${INSTANCE_ATTR_NAME}-heuristic-recovered" -D ++ ${HA_SBIN_DIR}/crm_attribute -N $NODENAME -l reboot --name "${INSTANCE_ATTR_NAME}-no-grastate" -D + } + +-is_heuristic_recovered() ++is_no_grastate() + { + local node=$1 +- ${HA_SBIN_DIR}/crm_attribute -N $node -l reboot --name "${INSTANCE_ATTR_NAME}-heuristic-recovered" -Q 2>/dev/null ++ ${HA_SBIN_DIR}/crm_attribute -N $node -l reboot --name "${INSTANCE_ATTR_NAME}-no-grastate" -Q 2>/dev/null + } + + clear_last_commit() +@@ -419,7 +419,7 @@ detect_first_master() + + # avoid selecting a recovered node as bootstrap if possible + for node in $(echo "$OCF_RESKEY_wsrep_cluster_address" | sed 's/gcomm:\/\///g' | tr -d ' ' | tr -s ',' ' '); do +- if is_heuristic_recovered $node; then ++ if is_no_grastate $node; then + nodes_recovered="$nodes_recovered $node" + else + nodes="$nodes $node" +@@ -473,6 +473,12 @@ detect_last_commit() + local tmp=$(mktemp) + local tmperr=$(mktemp) + ++ # if we pass here because grastate.dat doesn't exist, ++ # try not to bootstrap from this node if possible ++ if [ ! -f ${OCF_RESKEY_datadir}/grastate.dat ]; then ++ set_no_grastate ++ fi ++ + ocf_log info "now attempting to detect last commit version using 'mysqld_safe --wsrep-recover'" + + ${OCF_RESKEY_binary} $recover_args --wsrep-recover > $tmp 2> $tmperr +@@ -496,8 +502,8 @@ detect_last_commit() + if [ ! -z "$last_commit" ]; then + ocf_log warn "State recovered. force SST at next restart for full resynchronization" + rm -f ${OCF_RESKEY_datadir}/grastate.dat +- # try not to use this node if bootstrap is needed +- set_heuristic_recovered ++ # try not to bootstrap from this node if possible ++ set_no_grastate + fi + fi + fi +@@ -582,17 +588,17 @@ galera_promote() + if ocf_is_true $bootstrap; then + promote_everyone + clear_bootstrap_node +- # clear attribute heuristic-recovered. if last shutdown was ++ # clear attribute no-grastate. if last shutdown was + # not clean, we cannot be extra-cautious by requesting a SST + # since this is the bootstrap node +- clear_heuristic_recovered ++ clear_no_grastate + ocf_log info "Bootstrap complete, promoting the rest of the galera instances." + else + # if this is not the bootstrap node, make sure this instance + # syncs with the rest of the cluster before promotion returns. + wait_for_sync +- # sync is done, clear info about last recovery +- clear_heuristic_recovered ++ # sync is done, clear info about last startup ++ clear_no_grastate + fi + + ocf_log info "Galera started" +@@ -611,6 +617,7 @@ galera_demote() + # if this node was previously a bootstrap node, that is no longer the case. + clear_bootstrap_node + clear_last_commit ++ clear_no_grastate + + # record last commit for next promotion + detect_last_commit +@@ -722,6 +729,7 @@ galera_stop() + clear_last_commit + clear_master_score + clear_bootstrap_node ++ clear_no_grastate + return $rc + } + diff --git a/SOURCES/bz1287303-novaevacuate-invoke-off-action.patch b/SOURCES/bz1287303-novaevacuate-invoke-off-action.patch new file mode 100644 index 00000000..99699bcf --- /dev/null +++ b/SOURCES/bz1287303-novaevacuate-invoke-off-action.patch @@ -0,0 +1,31 @@ +From 5e9310bbbcd5086ea9a3edf85d523c4c2a57f1c3 Mon Sep 17 00:00:00 2001 +From: Andrew Beekhof +Date: Tue, 8 Dec 2015 13:54:12 +1100 +Subject: [PATCH] NovaEvacuate should invoke fence_compute with action 'off' + +Conceptually we are resurrecting in one direction only (off) and not +bringing it back to the current host afterwards (on) + +Also it will overwrite the attrd variable too soon. + +Change-Id: I9694945ca7eedae4f5cb6758fe1e8ce7f72ae808 +--- + ocf/NovaEvacuate | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/heartbeat/NovaEvacuate b/heartbeat/NovaEvacuate +index a17a159..0e22d7e 100644 +--- a/heartbeat/NovaEvacuate ++++ b/heartbeat/NovaEvacuate +@@ -198,7 +198,7 @@ handle_evacuations() { + return $OCF_SUCCESS + fi + +- fence_compute ${fence_options} -o reboot -n $node ++ fence_compute ${fence_options} -o off -n $node + rc=$? + + if [ $rc = 0 ]; then +-- +1.9.1 + diff --git a/SOURCES/bz1287314-novaevacuate-simplify-nova-check.patch b/SOURCES/bz1287314-novaevacuate-simplify-nova-check.patch new file mode 100644 index 00000000..24adb9cd --- /dev/null +++ b/SOURCES/bz1287314-novaevacuate-simplify-nova-check.patch @@ -0,0 +1,23 @@ +diff -uNr a/heartbeat/NovaEvacuate b/heartbeat/NovaEvacuate +--- a/heartbeat/NovaEvacuate 2016-02-29 10:54:21.933786269 +0100 ++++ b/heartbeat/NovaEvacuate 2016-02-29 13:29:27.000139496 +0100 +@@ -177,17 +177,10 @@ + esac + + if [ $need_evacuate = 1 ]; then +- found=0 + ocf_log notice "Initiating evacuation of $node" + +- for known in $(fence_compute ${fence_options} -o list | tr -d ','); do +- if [ ${known} = ${node} ]; then +- found=1 +- break +- fi +- done +- +- if [ $found = 0 ]; then ++ fence_compute ${fence_options} -o status -n ${node} ++ if [ $? != 0 ]; then + ocf_log info "Nova does not know about ${node}" + # Dont mark as no because perhaps nova is unavailable right now + continue diff --git a/SOURCES/bz1289107-saphana-mcos-support.patch b/SOURCES/bz1289107-saphana-mcos-support.patch new file mode 100644 index 00000000..1532f945 --- /dev/null +++ b/SOURCES/bz1289107-saphana-mcos-support.patch @@ -0,0 +1,1778 @@ +diff -uNr a/heartbeat/SAPHana b/heartbeat/SAPHana +--- a/heartbeat/SAPHana 2016-04-26 12:01:55.620889964 +0200 ++++ b/heartbeat/SAPHana 2016-04-26 12:03:17.240897137 +0200 +@@ -2,9 +2,9 @@ + # + # SAPHana + # +-# Description: Manages two single SAP HANA Instance in System Replication ++# Description: Manages two single SAP HANA Instance in System Replication + # Planned: do also manage scale-up scenarios +-# currently the SAPHana is dependent of the analysis of ++# currently the SAPHana is dependent of the analysis of + # SAPHanaTopology + # For supported scenarios please read the README file provided + # in the same software package (rpm) +@@ -16,16 +16,17 @@ + # Support: linux@sap.com + # License: GNU General Public License (GPL) + # Copyright: (c) 2013,2014 SUSE Linux Products GmbH ++# Copyright: (c) 2015 SUSE Linux GmbH + # +-# An example usage: ++# An example usage: + # See usage() function below for more details... + # + # OCF instance parameters: +-# OCF_RESKEY_SID +-# OCF_RESKEY_InstanceNumber +-# OCF_RESKEY_DIR_EXECUTABLE (optional, well known directories will be searched by default) +-# OCF_RESKEY_DIR_PROFILE (optional, well known directories will be searched by default) +-# OCF_RESKEY_INSTANCE_PROFILE (optional, well known directories will be searched by default) ++# OCF_RESKEY_SID ++# OCF_RESKEY_InstanceNumber ++# OCF_RESKEY_DIR_EXECUTABLE (optional, well known directories will be searched by default) ++# OCF_RESKEY_DIR_PROFILE (optional, well known directories will be searched by default) ++# OCF_RESKEY_INSTANCE_PROFILE (optional, well known directories will be searched by default) + # OCF_RESKEY_PREFER_SITE_TAKEOVER (optional, default is no) + # OCF_RESKEY_DUPLICATE_PRIMARY_TIMEOUT (optional, time difference needed between two last-primary-tiemstampe (lpt)) + # OCF_RESKEY_SAPHanaFilter (optional, should only be set if been told by support or for debugging purposes) +@@ -71,7 +72,7 @@ + info ) + case "$shf" in + all) skip=0 +- ;; ++ ;; + none ) + skip=1 + ;; +@@ -80,13 +81,13 @@ + mtype=${mtype#fh} + echo "$shf"| grep -iq ${mtype}; search=$? + if [ $search -eq 0 ]; then +- skip=0 ++ skip=0 + else + skip=1 + fi + ;; + esac +- ;; ++ ;; + esac + if [ $skip -eq 0 ]; then + ocf_log "$level" "$message" +@@ -103,8 +104,8 @@ + local rc=0 + methods=$(saphana_methods) + methods=$(echo $methods | tr ' ' '|') +- cat <<-! +- usage: $0 ($methods) ++ cat <<-EOF ++ usage: $0 ($methods) + + $0 manages a SAP HANA Instance as an HA resource. + +@@ -118,8 +119,17 @@ + The 'validate-all' operation reports whether the parameters are valid + The 'methods' operation reports on the methods $0 supports + +- ! +- return $rc ++EOF ++ return $rc ++} ++ ++function backup_global_and_nameserver() { ++ super_ocf_log info "FLOW $FUNCNAME ($*)" ++ local rc=0 ++ cp /hana/shared/LNX/global/hdb/custom/config/global.ini /hana/shared/LNX/global/hdb/custom/config/global.ini.$(date +"%s") ++ cp /hana/shared/LNX/global/hdb/custom/config/nameserver.ini /hana/shared/LNX/global/hdb/custom/config/nameserver.ini.$(date +"%s") ++ super_ocf_log info "FLOW $FUNCNAME rc=$rc" ++ return $rc + } + + # +@@ -130,11 +140,12 @@ + function saphana_meta_data() { + super_ocf_log info "FLOW $FUNCNAME ($*)" + local rc=0 +- cat < + + +-0.149.7 ++0.151.1 + + Manages two SAP HANA instances in system replication (SR). + +@@ -157,7 +168,7 @@ + 2. landscapeHostConfiguration + The interface is used to monitor a HANA system. The python script is named landscapeHostConfiguration.py. + landscapeHostConfiguration.py has some detailed output about HANA system status +- and node roles. For our monitor the overall status is relevant. This overall ++ and node roles. For our monitor the overall status is relevant. This overall + status is reported by the returncode of the script: + 0: Internal Fatal, 1: ERROR, 2: WARNING, 3: INFO, 4: OK + The SAPHana resource agent will interpret returncodes 0 as FATAL, 1 as not-running or ERROR and and returncodes 2+3+4 as RUNNING. +@@ -168,14 +179,14 @@ + system replication takeover (sr_takeover) or to register a former primary to a newer one (sr_register). + + 4. hdbsql / systemReplicationStatus +- Interface is SQL query into HANA (system replication table). The hdbsql query will be replaced by a python script ++ Interface is SQL query into HANA (system replication table). The hdbsql query will be replaced by a python script + "systemReplicationStatus.py" in SAP HANA SPS8 or 9. + As long as we need to use hdbsql you need to setup secure store users for linux user root to be able to + access the SAP HANA database. You need to configure a secure store user key "SAPHANA${SID}SR" which can connect the SAP +- HANA database: ++ HANA database: + + 5. saphostctrl +- The interface saphostctrl uses the function ListInstances to figure out the virtual host name of the ++ The interface saphostctrl uses the function ListInstances to figure out the virtual host name of the + SAP HANA instance. This is the hostname used during the HANA installation. + + +@@ -207,7 +218,7 @@ + + + Time difference needed between to primary time stamps, if a dual-primary situation occurs +- Time difference needed between to primary time stamps, ++ Time difference needed between to primary time stamps, + if a dual-primary situation occurs. If the time difference is + less than the time gap, then the cluster hold one or both instances in a "WAITING" status. This is to give an admin + a chance to react on a failover. A failed former primary will be registered after the time difference is passed. After +@@ -231,12 +242,8 @@ + + + +- Define SAPHana resource agent messages to be printed +- Define SAPHana resource agent messages to be printed. +- This parameter should only be set if requested by support. The default is sufficient for normal operation. +- Values: ra-act-lpa-dec-flow +- You could specify any combination of the above values like "ra-act-flow" +- ++ OUTDATED PARAMETER ++ OUTDATED PARAMETER + + + +@@ -271,7 +278,7 @@ + for m in start stop status monitor promote demote notify validate-all methods meta-data usage; do + echo "$m" + done +- return $rc ++ return $rc + } + + # +@@ -298,7 +305,7 @@ + local remoteNode="" + local rc=1 + for cl in ${otherNodes[@]}; do +- vHost=$(get_hana_attribute $cl ${ATTR_NAME_HANA_VHOST[@]}) ++ vHost=$(get_hana_attribute $cl ${ATTR_NAME_HANA_VHOST[@]} "$cl") + if [ "$vHost" = "$remoteHost" ]; then # we found the correct node + remoteNode=$cl + rc=0 +@@ -347,9 +354,10 @@ + } + + # +-# function: get_hana_attribute ++# function: get_hana_attribute + # params: NODE ATTR [STORE] + # globals: - ++# output: attribute value + # + function get_hana_attribute() + { +@@ -358,14 +366,20 @@ + local attr_node=$1 + local attr_name=$2 + local attr_store=${3:-reboot} # DONE: PRIO5 get this (optional) from parameter +- local attr_default=${5:-} ++ local attr_default=${4:-} ++ local dstr + local attr_val="" +- attr_val=$(crm_attribute -N ${attr_node} -G -n "$attr_name" -l $attr_store -q -d "$attr_default"); rc=$? +- if [ $debug_attributes -eq 1 ]; then +- dstr=$(date) +- echo "$dstr: SAPHana: crm_attribute -N ${attr_node} -G -n \"$attr_name\" -l $attr_store -q --> $attr_val" >> /var/log/fhATTRIBUTE +- fi +- echo "$attr_val" ++ dstr=$(date) ++ case "$attr_store" in ++ reboot | forever ) ++ echo "$dstr: SAPHana: crm_attribute -N ${attr_node} -G -n \"$attr_name\" -l $attr_store -q" >> /var/log/fhATTRIBUTE ++ crm_attribute -N ${attr_node} -G -n "$attr_name" -l $attr_store -q -d "$attr_default" 2>>/var/log/fhATTRIBUTE; rc=$? ++ ;; ++ props ) ++ echo "$dstr: SAPHana: crm_attribute -G -n \"$attr_name\" -t crm_config -q" >> /var/log/fhATTRIBUTE ++ crm_attribute -G -n "$attr_name" -t crm_config -q -d "$attr_default" 2>>/var/log/fhATTRIBUTE; rc=$? ++ ;; ++ esac + super_ocf_log info "FLOW $FUNCNAME rc=$rc" + return $rc + } +@@ -388,11 +402,17 @@ + attr_old=$(get_hana_attribute $attr_node $attr_name $attr_store $attr_default); get_rc=$? + if [ "$attr_old" != "$attr_value" ]; then + super_ocf_log debug "DBG: SET attribute $attr_name for node ${attr_node} to ${attr_value} former ($attr_old) get_rc=$get_rc " +- crm_attribute -N $attr_node -v $attr_value -n "$attr_name" -l $attr_store; rc=$? +- if [ $debug_attributes -eq 1 ]; then +- dstr=$(date) +- echo "$dstr: SAPHana: crm_attribute -N $attr_node -v $attr_value -n \"$attr_name\" -l $attr_store" >> /var/log/fhATTRIBUTE +- fi ++ dstr=$(date) ++ case "$attr_store" in ++ reboot | forever ) ++ echo "$dstr: SAPHana: crm_attribute -N $attr_node -v $attr_value -n \"$attr_name\" -l $attr_store" >> /var/log/fhATTRIBUTE ++ crm_attribute -N $attr_node -v $attr_value -n "$attr_name" -l $attr_store 2>>/var/log/fhATTRIBUTE; rc=$? ++ ;; ++ props ) ++ echo "$dstr: SAPHana: crm_attribute -v $attr_value -n \"$attr_name\" -t crm_config -s SAPHanaSR" >> /var/log/fhATTRIBUTE ++ crm_attribute -v $attr_value -n "$attr_name" -t crm_config -s SAPHanaSR 2>>/var/log/fhATTRIBUTE; rc=$? ++ ;; ++ esac + else + super_ocf_log debug "DBG: LET attribute $attr_name for node ${attr_node} still be ${attr_value}" + rc=0 +@@ -408,7 +428,8 @@ + # + function assert() { + super_ocf_log info "FLOW $FUNCNAME ($*)" +- local err_msg=$1 local default_rc=$OCF_NOT_RUNNING ++ local err_msg=$1 ++ local default_rc=$OCF_NOT_RUNNING + # DONE: Check, if we need to destinguish between probe and others + if ocf_is_probe; then + default_exit=$OCF_NOT_RUNNING +@@ -435,7 +456,7 @@ + local score=0 + if [ -n "$1" ]; then + score=$1 +- fi ++ fi + # DONE: PRIO2: Only adjust master if value is really different (try to check that) + oldscore=$(${HA_SBIN_DIR}/crm_master -G -q -l reboot) + if [ "$oldscore" != "$score" ]; then +@@ -452,7 +473,7 @@ + # + # function: scoring_crm_master - score instance due to role ans sync match (table SCORING_TABLE_PREFERRED_SITE_TAKEOVER) + # params: NODE_ROLES NODE_SYNC_STATUS +-# globals: SCORING_TABLE_PREFERRED_SITE_TAKEOVER[@], ++# globals: SCORING_TABLE_PREFERRED_SITE_TAKEOVER[@], + # + scoring_crm_master() + { +@@ -467,7 +488,7 @@ + if grep "$rolePatt" <<< "$roles"; then + if grep "$syncPatt" <<< "$sync"; then + skip=1 +- myScore=$score ++ myScore=$score + fi + fi + fi +@@ -496,7 +517,7 @@ + # function: saphana_init - initialize variables for the resource agent + # params: InstanceName + # globals: OCF_*(r), SID(w), sid(rw), sidadm(w), InstanceName(w), InstanceNr(w), SAPVIRHOST(w), PreferSiteTakeover(w), +-# globals: sr_name(w), remoteHost(w), otherNodes(w) ++# globals: sr_name(w), remoteHost(w), otherNodes(w), rem_SR_name(w) + # globals: ATTR_NAME_HANA_SYNC_STATUS(w), ATTR_NAME_HANA_CLONE_STATE(w) + # globals: DIR_EXECUTABLE(w), SAPSTARTSRV(w), SAPCONTROL(w), DIR_PROFILE(w), SAPSTARTPROFILE(w), LD_LIBRARY_PATH(w), PATH(w) + # globals: LPA_DIRECTORY(w), SIDInstanceName(w), remoteNode(w), hdbSrQueryTimeout(w) +@@ -506,6 +527,8 @@ + super_ocf_log info "FLOW $FUNCNAME ($*)" + local rc=$OCF_SUCCESS + local vName ++ local clN ++ # local site + # two parameter models (for transition only) + # OLD: InstanceName + # NEW: SID InstanceNumber +@@ -528,11 +551,10 @@ + # + # if saphostctrl does not know the answer, try to fallback to attribute provided by SAPHanaTopology + # +- vName=$(get_hana_attribute ${NODENAME} ${ATTR_NAME_HANA_VHOST[@]}); ++ vName=$(get_hana_attribute ${NODENAME} ${ATTR_NAME_HANA_VHOST[@]} "$NODENAME"); + fi + SAPVIRHOST=${vName} + PreferSiteTakeover="$OCF_RESKEY_PREFER_SITE_TAKEOVER" +- SAPHanaFilter="${OCF_RESKEY_SAPHanaFilter:-ra-act-dec-lpa}" + AUTOMATED_REGISTER="${OCF_RESKEY_AUTOMATED_REGISTER:-false}" + LPA_DIRECTORY=/var/lib/SAPHanaRA + LPA_ATTR=("lpa_${sid}_lpt" "forever") +@@ -591,6 +613,8 @@ + *openais* ) otherNodes=($(crm_node -l | awk '$3 == "member" { if ($2 != me) { print $2 }}' me=${NODENAME}));; + *cman* ) otherNodes=($(crm_node -l | awk '{for (i=1; i<=NF; i++) { if ($i != me) { print $i }}}' me=${NODENAME}));; + esac ++ # ++ # + + remoteHost=$(get_hana_attribute ${NODENAME} ${ATTR_NAME_HANA_REMOTEHOST[@]}); + if [ -z "$remoteHost" ]; then +@@ -611,9 +635,13 @@ + # ATTR_NAME_HANA_SITE + sr_name=$(get_hana_attribute ${NODENAME} ${ATTR_NAME_HANA_SITE[@]}); + sr_mode=$(get_hana_attribute "${NODENAME}" ${ATTR_NAME_HANA_SRMODE[@]}) ++ + if [ -z "$sr_mode" ]; then + sr_mode="sync" + fi ++ if [ -n "$remoteNode" ]; then ++ rem_SR_name=$(get_hana_attribute ${remoteNode} ${ATTR_NAME_HANA_SITE[@]}); ++ fi + super_ocf_log debug "DBG: sr_name=$sr_name, remoteHost=$remoteHost, remoteNode=$remoteNode, sr_mode=$sr_mode" + # optional OCF parameters, we try to guess which directories are correct + if [ -z "$OCF_RESKEY_DIR_EXECUTABLE" ] +@@ -706,7 +734,7 @@ + then + runninginst=$(echo "$output" | grep '^0 : ' | cut -d' ' -f3) + if [ "$runninginst" != "$InstanceName" ] +- then ++ then + super_ocf_log warn "ACT: sapstartsrv is running for instance $runninginst, that service will be killed" + restart=1 + else +@@ -784,38 +812,113 @@ + node_full_status=$(su - ${sidadm} -c "hdbnsutil -sr_state" 2>/dev/null ) + node_status=$(echo "$node_full_status" | awk '$1=="mode:" {print $2}') + super_ocf_log debug "DBG: check_for_primary: node_status=$node_status" ++ # TODO: PRIO2: Maybe we need to use a fallback interface when hdbnsitil does not answer properly -> lookup in config files? ++ # This might also solve some problems when we could not figure-out the ilocal or remote site name + for i in 1 2 3 4 5 6 7 8 9; do + case "$node_status" in +- primary ) +- super_ocf_log info "FLOW $FUNCNAME rc=HANA_STATE_PRIMARY" +- return $HANA_STATE_PRIMARY;; ++ primary ) ++ super_ocf_log info "FLOW: $FUNCNAME rc=HANA_STATE_PRIMARY" ++ return $HANA_STATE_PRIMARY;; + syncmem | sync | async ) +- super_ocf_log info "FLOW $FUNCNAME rc=HANA_STATE_SECONDARY" +- return $HANA_STATE_SECONDARY;; +- none ) # have seen that mode on second side BEFEORE we registered it as replica +- super_ocf_log info "FLOW $FUNCNAME rc=HANA_STATE_STANDALONE" +- return $HANA_STATE_STANDALONE;; ++ super_ocf_log info "FLOW: $FUNCNAME rc=HANA_STATE_SECONDARY" ++ return $HANA_STATE_SECONDARY;; ++ none ) # have seen that mode on second side BEFEORE we registered it as replica ++ super_ocf_log info "FLOW: $FUNCNAME rc=HANA_STATE_STANDALONE" ++ return $HANA_STATE_STANDALONE;; + * ) +- super_ocf_log err "ACT: check_for_primary: we didn't expect node_status to be: <$node_status>" +- dump=$( echo $node_status | hexdump -C ); +- super_ocf_log err "ACT: check_for_primary: we didn't expect node_status to be: DUMP <$dump>" +- node_full_status=$(su - ${sidadm} -c "hdbnsutil -sr_state" 2>/dev/null ) +- node_status=$(echo "$node_full_status" | awk '$1=="mode:" {print $2}') +- super_ocf_log debug "DEC: check_for_primary: loop=$i: node_status=$node_status" +- # TODO: PRIO1: Maybe we need to keep the old value for P/S/N, if hdbnsutil just crashes ++ super_ocf_log err "ACT: check_for_primary: we didn't expect node_status to be: <$node_status>" ++ dump=$( echo $node_status | hexdump -C ); ++ super_ocf_log err "ACT: check_for_primary: we didn't expect node_status to be: DUMP <$dump>" ++ node_full_status=$(su - ${sidadm} -c "hdbnsutil -sr_state" 2>/dev/null ) ++ node_status=$(echo "$node_full_status" | awk '$1=="mode:" {print $2}') ++ super_ocf_log debug "DEC: check_for_primary: loop=$i: node_status=$node_status" ++ # TODO: PRIO1: Maybe we need to keep the old value for P/S/N, if hdbnsutil just crashes + esac; + done + super_ocf_log info "FLOW $FUNCNAME rc=$rc" + return $rc + } + ++# function: analyze_hana_sync_statusSRS ++# params: - ++# globals: DIR_EXECUTABLE(r), FULL_SR_STATUS(w), remoteNode ++# ++# systemReplicationStatus.py return-codes: ++# NoHSR = 10 ++# Error = 11 ++# Unkown = 12 ++# Initializing = 13 ++# Syncing = 14 ++# Active = 15 ++function analyze_hana_sync_statusSRS() ++{ ++ super_ocf_log info "FLOW $FUNCNAME ($*)" ++ local rc=-1 srRc=0 all_nodes_other_side="" n="" siteParam="" ++ if [ -n "$rem_SR_name" ]; then ++ siteParam="--site=$rem_SR_name" ++ fi ++ FULL_SR_STATUS=$(su - $sidadm -c "python $DIR_EXECUTABLE/python_support/systemReplicationStatus.py $siteParam" 2>/dev/null); srRc=$? ++ super_ocf_log info "DEC $FUNCNAME systemReplicationStatus.py (to site '$rem_SR_name')-> $srRc" ++ super_ocf_log info "FLOW $FUNCNAME systemReplicationStatus.py (to site '$rem_SR_name')-> $srRc" ++ # ++ # TODO: PRIO2: Here we might also need to filter additional sites (if multi tier should be supported) ++ # And is the check for return code capable for chains? ++ # ++ if [ $srRc -eq 15 ]; then ++ # Fix for a HANA BUG, where a non-working SR resulted in RC 15: ++ if grep -q "ACTIVE" <<< "$FULL_SR_STATUS"; then ++ super_ocf_log info "FLOW $FUNCNAME SOK" ++ set_hana_attribute "$remoteNode" "SOK" ${ATTR_NAME_HANA_SYNC_STATUS[@]} ++ super_ocf_log info "ACT site=$sr_name, seting SOK for secondary (1)" ++ lpa_set_lpt 30 "$remoteNode" ++ rc=0; ++ else ++ # ok we should be careful and set secondary to SFAIL ++ super_ocf_log info "FLOW $FUNCNAME SFAIL" ++ set_hana_attribute "$remoteNode" "SFAIL" ${ATTR_NAME_HANA_SYNC_STATUS[@]} ++ super_ocf_log info "ACT site=$sr_name, seting SFAIL for secondary (6) - srRc=$srRc lss=$lss No ACTIVES found in cmd output" ++ # TODO: PRIO1 - P004: need to check LSS again to avoid dying primary to block (SFAIL) secondary ++ lpa_set_lpt 10 "$remoteNode" ++ fi ++ elif [ $srRc -le 11 ]; then # 11 and 10 ++ # if systemReplicationStatus is ERROR and landscapeHostConfiguration is down than do NOT set SFAIL ++ get_hana_landscape_status; lss=$? ++ if [ $lss -lt 2 ]; then ++ # keep everithing like it was ++ rc=2 ++ else ++ # ok we should be careful and set secondary to SFAIL ++ super_ocf_log info "FLOW $FUNCNAME SFAIL" ++ set_hana_attribute "$remoteNode" "SFAIL" ${ATTR_NAME_HANA_SYNC_STATUS[@]} ++ super_ocf_log info "ACT site=$sr_name, seting SFAIL for secondary (5) - srRc=$srRc lss=$lss" ++ # TODO: PRIO1 - P004: need to check LSS again to avoid dying primary to block (SFAIL) secondary ++ lpa_set_lpt 10 "$remoteNode" ++ rc=1 ++ fi ++ else ++ super_ocf_log info "FLOW $FUNCNAME SFAIL" ++ set_hana_attribute "$remoteNode" "SFAIL" ${ATTR_NAME_HANA_SYNC_STATUS[@]} ++ super_ocf_log info "ACT site=$sr_name, seting SFAIL for secondary (2) - srRc=$srRc" ++ # TODO: PRIO1 - P004: need to check LSS again to avoid dying primary to block (SFAIL) secondary ++ lpa_set_lpt 10 "$remoteNode" ++ rc=1; ++ fi ++ super_ocf_log info "FLOW $FUNCNAME PRIM+LPA" ++ super_ocf_log info "DBG PRIM" ++ super_ocf_log info "FLOW $FUNCNAME rc=$rc" ++ return $rc ++} ++ + # +-# function: analyze_hana_sync_status - query and check hana system replication status ++#### ++#### OLD HDBSQL STUFF FOR SPS6,7,8 AND SCALE-UP ONLY ++#### ++# function: analyze_hana_sync_statusSQL - query and check hana system replication status + # params: - + # globals: DIR_EXECUTABLE(r), remoteHost(r) + # get the HANA sync status +-# +-function analyze_hana_sync_status() ++# ++function analyze_hana_sync_statusSQL() + { + super_ocf_log info "FLOW $FUNCNAME ($*)" + local -a clusterNodes=() +@@ -863,35 +966,9 @@ + # TODO PRIO1: REMOVE remoteNode dependency - set SFAIL + set_hana_attribute "$remoteNode" "SFAIL" ${ATTR_NAME_HANA_SYNC_STATUS[@]} + fi +- # first get a list of all secondary hosts, than a list of all secondary hosts, if the is ANY failure at this site +- # TODO: PRIO9: for first we assume there is only ONE secondary site (like ROT) +- # TODO: PRIO3: should we loop over all cluster nodes fetching their roles-attribute? To minimize sql-queries? +- # +- all_secondary_hosts=$(timeout $hdbSrQueryTimeout hdbsql -a -x -U $secUser $query_secondaries ); sqlrc=$? +- all_secondary_hosts=$(echo $all_secondary_hosts | dequote); +- if [ "$sqlrc" -eq 0 ]; then +- all_broken_secondary_hosts=$(timeout $hdbSrQueryTimeout hdbsql -a -x -U $secUser $query_failed_secondaries); sqlrc=$? +- all_broken_secondary_hosts=$(echo $all_broken_secondary_hosts | dequote); +- if [ "$sqlrc" -eq 0 ]; then +- if [ -n "$all_broken_secondary_hosts" ]; then +- # +- # we have a broken secondary site - set all hosts to "SFAIL" +- # +- # Note: since HANA hostname can be different from nodename we need to check all vhost attributes +- for n in $all_broken_secondary_hosts; do +- for cl in ${otherNodes[@]}; do +- vHost=$(get_hana_attribute $cl ${ATTR_NAME_HANA_VHOST[@]}) +- if [ "$vHost" = "$n" ]; then # we found the correct node +- set_hana_attribute $cl "SFAIL" ${ATTR_NAME_HANA_SYNC_STATUS[@]} +- fi +- done +- done +- fi +- fi +- fi + else + case "$sqlrc" in +- 19 ) ++ 19 ) + # return codes 19: license error -> set SFAIL! + # DONE: PRIO1: We should NOT set SFAIL, if HDB is exactly broken now + # When HDB breaks during monitor this could prevent a prositive remote failover +@@ -901,7 +978,7 @@ + done + ;; + esac +- fi ++ fi + return $rc + } + +@@ -932,10 +1009,18 @@ + local remoteInstance=""; + remoteInstance=$InstanceNr + if ocf_is_true ${AUTOMATED_REGISTER}; then ++ # ++ # ++ # ++ # ++ # + super_ocf_log info "ACT: REGISTER: hdbnsutil -sr_register --remoteHost=$remoteHost --remoteInstance=$remoteInstance --mode=$sr_mode --name=$sr_name" ++ # ++ # + su - $sidadm -c "hdbnsutil -sr_register --remoteHost=$remoteHost --remoteInstance=$remoteInstance --mode=$sr_mode --name=$sr_name"; rc=$? ++ # backup_global_and_nameserver + else +- super_ocf_log info "ACT: IGNORE REGISTER because AUTOMATED_REGISTER is set to FALSE" ++ super_ocf_log info "ACT: SAPHANA DROP REGISTER because AUTOMATED_REGISTER is set to FALSE" + rc=1 + fi + super_ocf_log info "FLOW $FUNCNAME rc=$rc" +@@ -945,7 +1030,7 @@ + # + # function: saphana_status - pure status check + # params: - +-# globals: SIDInstanceName, OCF_*, ++# globals: SIDInstanceName, OCF_*, + function saphana_status() { + local binDeam="hdb.sap${SIDInstanceName}" rc=0 + binDeam=${binDeam:0:15} # Process name is limited to the first 15 characters +@@ -956,13 +1041,13 @@ + # + # function: saphana_start - start a hana instance + # params: - +-# globals: OCF_*, SAPCONTROL, InstanceNr, SID, InstanceName, ++# globals: OCF_*, SAPCONTROL, InstanceNr, SID, InstanceName, + # + function saphana_start() { + super_ocf_log info "FLOW $FUNCNAME ($*)" + local rc=$OCF_NOT_RUNNING + local output="" +- local loopcount=0 ++ local loopcount=0 + check_sapstartsrv + rc=$? + # +@@ -1000,11 +1085,11 @@ + # saphana_stop: Stop the SAP instance + # + function saphana_stop() { +- super_ocf_log info "FLOW $FUNCNAME ($*)" +- local output="" +- local rc=0 +- check_sapstartsrv; rc=$? +- if [ $rc -eq $OCF_SUCCESS ]; then ++ super_ocf_log info "FLOW $FUNCNAME ($*)" ++ local output="" ++ local rc=0 ++ check_sapstartsrv; rc=$? ++ if [ $rc -eq $OCF_SUCCESS ]; then + output=$($SAPCONTROL -nr $InstanceNr -function Stop) + rc=$? + super_ocf_log info "ACT: Stopping SAP Instance $SID-$InstanceName: $output" +@@ -1032,7 +1117,7 @@ + # function: saphana_validate - validation of (some) variables/parameters + # params: - + # globals: OCF_*(r), SID(r), InstanceName(r), InstanceNr(r), SAPVIRHOST(r) +-# saphana_validate: Check the symantic of the input parameters ++# saphana_validate: Check the symantic of the input parameters + # + function saphana_validate() { + super_ocf_log info "FLOW $FUNCNAME ($*)" +@@ -1060,12 +1145,12 @@ + # + # function: saphana_start_primary - handle startup of PRIMARY in M/S + # params: +-# globals: OCF_*(r), NODENAME, ATTR_NAME_*, HANA_STATE_*, ++# globals: OCF_*(r), NODENAME, ATTR_NAME_*, HANA_STATE_*, + # + function saphana_start_primary() + { + super_ocf_log info "FLOW $FUNCNAME ($*)" +- local primary_status sync_attr score_master rc=$OCF_NOT_RUNNING ++ local primary_status sync_attr score_master rc=$OCF_NOT_RUNNING + local lss sqlrc; + local rc=0 + local lpa_dec=4 +@@ -1074,7 +1159,7 @@ + # we will be a master (PRIMARY) so checking, if the is an OTHER master + # + super_ocf_log debug "DBG: saphana_primary - check_for_primary reports HANA_STATE_PRIMARY" +- # ++ # + lpa_init_lpt $HANA_STATE_PRIMARY + lpa_check_lpt_status; lpa_dec=$? + get_hana_landscape_status; lss=$? +@@ -1139,7 +1224,7 @@ + 1 ) # landcape says we are down, lets start and adjust scores and return code + super_ocf_log info "LPA: landcape: DOWN, LPA: start ==> start instance" + saphana_start +- rc=$? ++ rc=$? + LPTloc=$(date '+%s') + lpa_set_lpt $LPTloc + ;; +@@ -1152,7 +1237,7 @@ + # DONE: PRIO3: check if this reaction is correct - tell cluster about failed start + super_ocf_log info "LPA: landcape: UP, LPA: register ==> take down" + set_crm_master -inf +- rc=$OCF_NOT_RUNNING ++ rc=$OCF_NOT_RUNNING + ;; + 1 ) # lets try to register + # DONE: PRIO2: Like Action in start_secondary +@@ -1160,7 +1245,7 @@ + super_ocf_log info "DEC: AN OTHER HANA IS AVAILABLE ==> LETS REGISTER" + set_crm_master 0 + if wait_for_primary_master 1; then +- register_hana_secondary ++ register_hana_secondary + check_for_primary; primary_status=$? + if [ $primary_status -eq $HANA_STATE_SECONDARY ]; then + super_ocf_log info "ACT: Register successful" +@@ -1169,11 +1254,11 @@ + set_crm_master 0 + saphana_start_secondary + rc=$? +- lpa_set_lpt 30 ++ lpa_set_lpt 10 + else + super_ocf_log err "ACT: Register failed" + rc=$OCF_NOT_RUNNING +- fi ++ fi + else + # lets check next monitor, if we can register + rc=$OCF_SUCCESS +@@ -1185,6 +1270,9 @@ + case "$lss" in + 2 | 3 | 4 ) # as we ARE up we just keep it up + # TODO: PRIO3: I now change from "just keep it up to take that down" ++# TODO: PRIO1 differ lpt_advice!! ++# 2 => DOWN ++# 3 => KEEP + # TODO: PRIO3: OCF_SUCCESS, OCF_NOT_RUNNING or OCF_ERR_xxxx ? + set_crm_master -9000 + #scoring_crm_master "$my_role" "$my_sync" +@@ -1193,7 +1281,7 @@ + 1 ) # we are down, so we should wait --> followup in next monitor + super_ocf_log info "LPA: landcape: DOWN, LPA: wait ==> keep waiting" + # TODO: PRIO3: Check, if WAITING is correct here +- set_hana_attribute ${NODENAME} "WAITING" ${ATTR_NAME_HANA_CLONE_STATE[@]} ++ set_hana_attribute ${NODENAME} "WAITING4LPA" ${ATTR_NAME_HANA_CLONE_STATE[@]} + set_crm_master -9000 + rc=$OCF_SUCCESS + ;; +@@ -1202,7 +1290,7 @@ + fail ) # process a lpa FAIL + super_ocf_log info "LPA: LPA reports FAIL" + set_crm_master -inf +- rc=$OCF_NOT_RUNNING ++ rc=$OCF_NOT_RUNNING + ;; + esac + super_ocf_log info "FLOW $FUNCNAME rc=$rc" +@@ -1278,12 +1366,12 @@ + # + # function: saphana_start_secondary - handle startup of PRIMARY in M/S + # params: +-# globals: OCF_*(r), NODENAME, ATTR_NAME_*, ++# globals: OCF_*(r), NODENAME, ATTR_NAME_*, + # + function saphana_start_secondary() + { + super_ocf_log info "FLOW $FUNCNAME ($*)" +- local primary_status sync_attr score_master rc=$OCF_NOT_RUNNING ++ local primary_status sync_attr score_master rc=$OCF_NOT_RUNNING + local sqlrc; + set_crm_master 0 + # +@@ -1291,9 +1379,9 @@ + # + lpa_push_lpt 10 + lpa_set_lpt 10 +- # ++ # + ####### LPA - end +- # ++ # + # + # we would be slave (secondary) + # we first need to check, if there are Master Nodes, because the Scecondary only starts +@@ -1311,16 +1399,16 @@ + # It seams the stating secondary could not start because of stopping primary + # so this is a WAITING situation + super_ocf_log info "ACT: PRIMARY seams to be down now ==> WAITING" +- set_hana_attribute ${NODENAME} "WAITING" ${ATTR_NAME_HANA_CLONE_STATE[@]} ++ set_hana_attribute ${NODENAME} "WAITING4PRIM" ${ATTR_NAME_HANA_CLONE_STATE[@]} + set_crm_master -INFINITY + rc=$OCF_SUCCESS + fi + else +- lpa_set_lpt 30 ++ lpa_set_lpt 10 + fi + else + super_ocf_log info "ACT: wait_for_primary_master ==> WAITING" +- set_hana_attribute ${NODENAME} "WAITING" ${ATTR_NAME_HANA_CLONE_STATE[@]} ++ set_hana_attribute ${NODENAME} "WAITING4PRIM" ${ATTR_NAME_HANA_CLONE_STATE[@]} + set_crm_master -INFINITY + rc=$OCF_SUCCESS + fi +@@ -1329,11 +1417,71 @@ + } + + # ++# function: saphana_check_local_instance ++# params: ++# output: ++# rc: rc=0 (UP) rc=1 (DOWN) ++# globals: ++# ++function saphana_check_local_instance() ++{ ++ local rc=1 ++ local count=0 ++ local SERVNO ++ local output ++ local MONITOR_SERVICES="hdbnameserver|hdbdaemon" # TODO: PRIO1: exact list of Services ++ super_ocf_log info "FLOW $FUNCNAME ($*)" ++ check_sapstartsrv ++ rc=$? ++ if [ $rc -eq $OCF_SUCCESS ] ++ then ++ output=$($SAPCONTROL -nr $InstanceNr -function GetProcessList -format script) ++ # we have to parse the output, because the returncode doesn't tell anything about the instance status ++ for SERVNO in `echo "$output" | grep '^[0-9] ' | cut -d' ' -f1 | sort -u` ++ do ++ local COLOR=`echo "$output" | grep "^$SERVNO dispstatus: " | cut -d' ' -f3` ++ local SERVICE=`echo "$output" | grep "^$SERVNO name: " | cut -d' ' -f3` ++ local STATE=0 ++ local SEARCH ++ ++ case $COLOR in ++ GREEN|YELLOW) STATE=$OCF_SUCCESS;; ++ *) STATE=$OCF_NOT_RUNNING;; ++ esac ++ ++ SEARCH=`echo "$MONITOR_SERVICES" | sed 's/\+/\\\+/g' | sed 's/\./\\\./g'` ++ if [ `echo "$SERVICE" | egrep -c "$SEARCH"` -eq 1 ] ++ then ++ if [ $STATE -eq $OCF_NOT_RUNNING ] ++ then ++ [ "$MONLOG" != "NOLOG" ] && ocf_log err "SAP instance service $SERVICE is not running with status $COLOR !" ++ rc=$STATE ++ fi ++ count=1 ++ fi ++ done ++ ++ if [ $count -eq 0 -a $rc -eq $OCF_SUCCESS ] ++ then ++ if ocf_is_probe ++ then ++ rc=1 ++ else ++ [ "$MONLOG" != "NOLOG" ] && ocf_log err "The SAP instance does not run any services which this RA could monitor!" ++ rc=1 ++ fi ++ fi ++ fi ++ super_ocf_log info "FLOW $FUNCNAME rc=$rc" ++ return $rc ++} ++ ++# + # function: lpa_get_lpt - get lpt from cluster + # params: NODE + # output: LPT + # rc: rc=0: OK, rc=1: InternalERROR, rc=2: ERROR +-# globals: LPA_ATTR_*, ++# globals: LPA_ATTR_*, + # + function lpa_get_lpt() { + super_ocf_log info "FLOW $FUNCNAME ($*)" +@@ -1348,7 +1496,7 @@ + rc=2 + fi + super_ocf_log info "FLOW $FUNCNAME rc=$rc" +- return $rc ++ return $rc + } + + # +@@ -1372,7 +1520,7 @@ + rc=0 + fi + super_ocf_log info "FLOW $FUNCNAME rc=$rc" +- return $rc ++ return $rc + } + + # +@@ -1398,7 +1546,7 @@ + rc=2 + fi + super_ocf_log info "FLOW $FUNCNAME rc=$rc" +- return $rc ++ return $rc + } + + # +@@ -1422,15 +1570,15 @@ + rc=2 + else + rc=0 +- fi ++ fi + super_ocf_log info "FLOW $FUNCNAME rc=$rc" +- return $rc ++ return $rc + } + + # + # function: lpa_init_lpt - initialize local lpt, if needed + # params: HANA_STATE +-# globals: HANA_STATE_*(r), LPA_DIRECTORY(r), sid(r), NODENAME(r), ++# globals: HANA_STATE_*(r), LPA_DIRECTORY(r), sid(r), NODENAME(r), + # lpa_init_lpt + # + # Returncodes: +@@ -1439,7 +1587,7 @@ + # Initializing (if NO local LPT-file): + # SECONDARY sets to 0 + # PRIMARY sets to 1 +-# ++# + function lpa_init_lpt() { + super_ocf_log info "FLOW $FUNCNAME ($*)" + local rc=1 +@@ -1458,11 +1606,11 @@ + LPTloc=10 + lpa_push_lpt "10"; rc=$? + else +- rc=2 ++ rc=2 + fi + lpa_set_lpt $LPTloc + super_ocf_log info "FLOW $FUNCNAME rc=$rc" +- return $rc ++ return $rc + } + + # +@@ -1472,6 +1620,10 @@ + # lpa_check_lpt_status + # + # Returncodes: ++# 0: start ++# 1: register than start ++# 2: wait4gab ++# 3: wait4other + # + # Initializing (if NO local LPT-file): + # SECONDARY sets to 10 +@@ -1480,20 +1632,20 @@ + # LPRlocal OR LPTremore ARE real lpt (>1000) + # THEN: + # Bigger LPR wins, if delta-gab is OK +-# LPTlocal >> LPTremore ===> rc=0 (start) ++# LPTlocal >> LPTremore ===> rc=0 (start) + # LPTRemote >> LPTlocal ===> rc=1 (register) +-# Stalemate in all other cases ==> STALEMATE-HANDLING ===> rc=2 (wait) ++# Stalemate in all other cases ==> STALEMATE-HANDLING ===> rc=2 (wait4gab) + # LPRlocal AND LPTremore ARE NOT real lpt (<=1000) + # THEN: + # Bigger LPT wins +-# LPTlocal > LPTremore ===> rc=0 (start) ++# LPTlocal > LPTremore ===> rc=0 (start) + # LPTRemote > LPTlocal ===> rc=1 (register) +-# Stalemate in all other cases ==> STALEMATE-HANDLING ===> rc=2 (wait) ++# Stalemate in all other cases ==> STALEMATE-HANDLING ===> rc=2 (wait4gab) + # LPTRemote is not initialized or node not kown in cluster (crm_mon -l) (0) + # TODO: PRIO1: Need to introduce a return-code 3 for remote sides lpa not ready + # THEN: + # WAIT ==> like STALEMATE-HANDLING ===> rc=2 (wait) +-# ++# + function lpa_check_lpt_status() { + super_ocf_log info "FLOW $FUNCNAME ($*)" + local rc=0 +@@ -1501,6 +1653,8 @@ + local LPTrem=-1 + local LPTMark=1000 + local delta=0 ++ local remSn_name="" ++ local remHost="" + # + # First GET LPT from ATTR-FILE-DEFAULT + # +@@ -1550,7 +1704,20 @@ + fi + fi + super_ocf_log info "FLOW $FUNCNAME rc=$rc" +- return $rc ++ return $rc ++} ++ ++# function: is_the_master_nameserver ++# params: - ++# rc: 0: yes, local node is THE master nameserver ++# 1: else ++# globals: ++function is_the_master_nameserver() ++{ ++ super_ocf_log info "FLOW $FUNCNAME ($*)" ++ local rc=0 ++ super_ocf_log info "FLOW $FUNCNAME rc=$rc" ++ return $rc + } + + # +@@ -1574,11 +1741,12 @@ + check_for_primary; primary_status=$? + if [ $primary_status -eq $HANA_STATE_PRIMARY ]; then + saphana_start_primary; rc=$? +- else ++ else ++ lpa_set_lpt 10 + saphana_start_secondary; rc=$? +- lpa_set_lpt 30 +- fi ++ fi + fi ++ super_ocf_log info "FLOW $FUNCNAME rc=$rc" + return $rc + } + +@@ -1596,7 +1764,7 @@ + check_for_primary; primary_status=$? + if [ $primary_status -eq $HANA_STATE_SECONDARY ]; then + lpa_set_lpt 10 +- fi ++ fi + saphana_stop; rc=$? + return $rc + } +@@ -1637,7 +1805,7 @@ + DEMOTED ) + promoted=0; + ;; +- WAITING ) ++ WAITING* ) + # DONE: lpa_check_lpt_status to come out of here :) + # DONE: PRIO2: CHECK IF THE FIX FOR COMING OUT OF WAITING IS CORRECT + get_hana_landscape_status; lss=$? +@@ -1648,7 +1816,8 @@ + lpa_set_lpt $LPTloc + fi + lpa_check_lpt_status; lparc=$? +- if [ $lparc -ne 2 ]; then ++ # TODO: PRIO1: Need to differ lpa_check_lpt_status return codes ++ if [ $lparc -lt 2 ]; then + # lpa - no need to wait any longer - lets try a new start + saphana_start_clone + rc=$? +@@ -1663,7 +1832,7 @@ + super_ocf_log info "LPA: Dual primary detected and AUTOMATED_REGISTER='false' ==> WAITING" + fi + return $OCF_SUCCESS +- fi ++ fi + promoted=0; + ;; + UNDEFINED ) +@@ -1682,13 +1851,13 @@ + get_hana_landscape_status; lss=$? + super_ocf_log debug "DBG: saphana_monitor_clone: get_hana_landscape_status=$lss" + case "$lss" in +- 0 ) # FATAL or ERROR ++ 0 ) # FATAL or ERROR + rc=$OCF_ERR_GENERIC + ;; +- 1 ) # DOWN or ERROR ++ 1 ) # DOWN or ERROR + # DONE: PRIO2: Maybe we need to differ between 0 and 1. While 0 is a fatal sap error, 1 is down/error + if ocf_is_probe; then +- # ++ # + # leave master score untouched, only set return code + # + rc=$OCF_NOT_RUNNING +@@ -1699,7 +1868,7 @@ + # For Migration it would be good to decrease master score + # For Reload locally we should NOT adjust the master score + # ===> Should we rely on the migration threshold? +- # set_crm_master ++ # set_crm_master + if ocf_is_true "${PreferSiteTakeover}" ; then + # + # DONE: PRIO1: first check, if remote site is already (and still) in sync +@@ -1708,7 +1877,7 @@ + # TODO PRIO1: REMOVE remoteNode dependency - get_sync_status + remoteSync=$(get_hana_attribute $remoteNode ${ATTR_NAME_HANA_SYNC_STATUS[@]}) + case "$remoteSync" in +- SOK ) ++ SOK | PRIM ) + super_ocf_log info "DEC: PreferSiteTakeover selected so decrease promotion score here (and reset lpa)" + set_crm_master 5 + if check_for_primary_master; then +@@ -1718,11 +1887,11 @@ + SFAIL ) + super_ocf_log info "DEC: PreferSiteTakeover selected BUT remoteHost is not in sync (SFAIL) ==> local restart preferred" + ;; +- * ) ++ * ) + super_ocf_log info "DEC: PreferSiteTakeover selected BUT remoteHost is not in sync ($remoteSync) ==> local restart preferred" + ;; +- esac +- else ++ esac ++ else + # TODO: PRIO5: SCALE-OUT ONLY? Implement for local restart + # It maybe that for the local restart we only need to decrease the secondaries promotion score + #super_ocf_log info "DEC: PreferSiteTakeover selected so decrease promotion score here" +@@ -1765,8 +1934,12 @@ + case "$my_role" in + [12]:P:*:master:* ) # primary is down or may not anser hdbsql query so drop analyze_hana_sync_status + ;; +- [34]:P:*:master:* ) # primary is up and should now be able to anser hdbsql query +- analyze_hana_sync_status ++ [34]:P:*:*:* ) # primary is up and should now be able to anser hdbsql query ++ if [ -f $DIR_EXECUTABLE/python_support/systemReplicationStatus.py ]; then ++ analyze_hana_sync_statusSRS ++ else ++ analyze_hana_sync_statusSQL ++ fi + ;; + esac + rem_role=$(get_hana_attribute ${remoteNode} ${ATTR_NAME_HANA_ROLES[@]}) +@@ -1776,9 +1949,9 @@ + [234]:P:* ) # dual primary, but other instance marked as PROMOTED by the cluster + lpa_check_lpt_status; again_lpa_rc=$? + if [ $again_lpa_rc -eq 2 ]; then +- super_ocf_log info "DEC: Dual primary detected, other instance is PROMOTED and lpa stalemate ==> local restart" +- lpa_set_lpt 10 +- lpa_push_lpt 10 ++ super_ocf_log info "DEC: Dual primary detected, other instance is PROMOTED and lpa stalemate ==> local restart" ++ lpa_set_lpt 10 ++ lpa_push_lpt 10 + rc=$OCF_NOT_RUNNING + fi + ;; +@@ -1812,13 +1985,13 @@ + function saphana_monitor_secondary() + { + super_ocf_log info "FLOW $FUNCNAME ($*)" +- local rc=$OCF_ERR_GENERIC +- local promoted=0 ++ local rc=$OCF_ERR_GENERIC ++ local promoted=0 + local init_attribute=0 + local lss + # + # OK, we are running as HANA SECONDARY +- # ++ # + if ! lpa_get_lpt ${NODENAME}; then + lpa_set_lpt 10 + lpa_push_lpt 10 +@@ -1863,7 +2036,7 @@ + super_ocf_log debug "DBG: saphana_monitor_clone: HANA_STATE_SECONDARY" + # + # old method was: saphana_monitor - new method is get_hana_landscape_status +- get_hana_landscape_status; lss=$? ++ get_hana_landscape_status; lss=$? + super_ocf_log debug "DBG: saphana_monitor_clone: get_hana_landscape_status=$lss" + case "$lss" in + 0 ) # FATAL +@@ -1919,11 +2092,11 @@ + # a) returning 7 here and force cluster a restart of the slave + # b) starting the instance here inside the monitor -> may result in longer runtime, timeouts + # +- # first check with the status function (OS tools) if there could be something like a SAP instance running +- # as we do not know here, if we are in master or slave state we do not want to start our monitoring +- # agents (sapstartsrv) on the wrong host +- local rc=$OCF_ERR_GENERIC +- local promoted=0 ++ # first check with the status function (OS tools) if there could be something like a SAP instance running ++ # as we do not know here, if we are in master or slave state we do not want to start our monitoring ++ # agents (sapstartsrv) on the wrong host ++ local rc=$OCF_ERR_GENERIC ++ local promoted=0 + local init_attribute=0 + local lpaRc=0 + local mRc=0 +@@ -1973,7 +2146,7 @@ + # function: saphana_promote_clone - promote a hana clone + # params: - + # globals: OCF_*(r), NODENAME(r), HANA_STATE_*, SID(r), InstanceName(r), +-# saphana_promote_clone: ++# saphana_promote_clone: + # In a Master/Slave configuration get Master being the primary OR by running hana takeover + # + function saphana_promote_clone() { +@@ -2017,7 +2190,7 @@ + rc=$OCF_SUCCESS; + else + rc=$OCF_FAILED_MASTER +- fi ++ fi + ;; + * ) + super_ocf_log err "ACT: HANA SYNC STATUS IS NOT 'SOK' SO THIS HANA SITE COULD NOT BE PROMOTED" +@@ -2039,10 +2212,10 @@ + # + # function: saphana_demote_clone - demote a hana clone instance + # params: - +-# globals: OCF_*(r), NODENAME(r), ++# globals: OCF_*(r), NODENAME(r), + # saphana_demote_clone +-# the HANA System Replication (SR) runs in a Master/Slave +-# While we could not change a HANA instance to be really demoted, we only mark the status for ++# the HANA System Replication (SR) runs in a Master/Slave ++# While we could not change a HANA instance to be really demoted, we only mark the status for + # correct monitor return codes + # + function saphana_demote_clone() { +@@ -2056,9 +2229,9 @@ + } + + # +-# function: main - main function to operate ++# function: main - main function to operate + # params: ACTION +-# globals: OCF_*(r), SID(w), sidadm(w), InstanceName(w), SAPVIRHOST(w), DIR_EXECUTABLE(w), ++# globals: OCF_*(r), SID(w), sidadm(w), InstanceName(w), SAPVIRHOST(w), DIR_EXECUTABLE(w), + # globals: SAPSTARTSRV(w), SAPCONTROL(w), DIR_PROFILE(w), SAPSTARTPROFILE(w), ACTION(w), CLACT(w), ra_rc(rw), $0(r), %ENV(r) + # + +@@ -2073,7 +2246,7 @@ + SAPCONTROL="" + DIR_PROFILE="" + SAPSTARTPROFILE="" +-SAPHanaFilter="${OCF_RESKEY_SAPHanaFilter:-ra-act-dec-lpa}" ++SAPHanaFilter="ra-act-dec-lpa" + + NODENAME=$(crm_node -n) + +@@ -2100,7 +2273,7 @@ + exit $OCF_SUCCESS;; + *);; + esac +-saphana_init ++saphana_init + + if ! ocf_is_root + then +@@ -2141,7 +2314,7 @@ + saphana_$ACTION$CLACT + ra_rc=$? + ;; +- validate-all) ++ validate-all) + saphana_validate + ra_rc=$? + ;; +@@ -2149,12 +2322,13 @@ + lpa_check_lpt_status + ra_rc=$? + ;; +- *) # seams to be a unknown request +- saphana_methods ++ *) # seams to be a unknown request ++ saphana_methods + ra_rc=$OCF_ERR_UNIMPLEMENTED + ;; + esac + timeE=$(date '+%s') + (( timeR = timeE - timeB )) ++#super_ocf_log info "RA ==== SAPHanaFilter=$SAPHanaFilter" + super_ocf_log info "RA ==== end action $ACTION$CLACT with rc=${ra_rc} ($THE_VERSION) (${timeR}s)====" + exit ${ra_rc} +diff -uNr a/heartbeat/SAPHanaTopology b/heartbeat/SAPHanaTopology +--- a/heartbeat/SAPHanaTopology 2016-04-26 12:01:55.620889964 +0200 ++++ b/heartbeat/SAPHanaTopology 2016-04-26 12:03:18.033887556 +0200 +@@ -16,7 +16,7 @@ + # Copyright: (c) 2014 SUSE Linux Products GmbH + # (c) 2015 SUSE Linux GmbH + # +-# An example usage: ++# An example usage: + # See usage() function below for more details... + # + # OCF instance parameters: +@@ -41,7 +41,6 @@ + HANA_STATE_DEFECT=3 + + debug_attributes=0 +- + SH=/bin/sh + + # +@@ -57,7 +56,7 @@ + local shf="${SAPHanaFilter:-all}" + #ocf_log "info" "super_ocf_log: f:$shf l:$level m:$message" + # message levels: (dbg)|info|warn|err|error +- # ++ # + # message types: (ACT|RA|FLOW|DBG|LPA|DEC + case "$level" in + dbg | debug | warn | err | error ) skip=0 +@@ -65,7 +64,7 @@ + info ) + case "$shf" in + all) skip=0 +- ;; ++ ;; + none ) + skip=1 + ;; +@@ -74,13 +73,13 @@ + mtype=${mtype#fh} + echo "$shf"| grep -iq ${mtype}; search=$? + if [ $search -eq 0 ]; then +- skip=0 ++ skip=0 + else + skip=1 + fi + ;; + esac +- ;; ++ ;; + esac + if [ $skip -eq 0 ]; then + ocf_log "$level" "$message" +@@ -126,15 +125,15 @@ + + + +- 0.149.6 ++ 0.151.1 + Analyzes SAP HANA System Replication Topology. + This RA analyzes the SAP HANA topology and "sends" all findings via the node status attributes to + all nodes in the cluster. These attributes are taken by the SAPHana RA to control the SAP Hana Databases. + In addition it starts and monitors the local saphostagent. + +-1. Interface to monitor a HANA system: landscapeHostConfiguration.py ++1. Interface to monitor a HANA system: landscapeHostConfiguration.py + landscapeHostConfiguration.py has some detailed output about HANA system status +-and node roles. For our monitor the overall status is relevant. This overall ++and node roles. For our monitor the overall status is relevant. This overall + status is reported by the returncode of the script: + 0: Internal Fatal + 1: ERROR +@@ -150,7 +149,7 @@ + system replication takeover (sr_takeover) or to register a former primary to a newer one (sr_register). + + 3. saphostctrl +- The interface saphostctrl uses the function ListInstances to figure out the virtual host name of the ++ The interface saphostctrl uses the function ListInstances to figure out the virtual host name of the + SAP HANA instance. This is the hostname used during the HANA installation. + + +@@ -172,13 +171,8 @@ + + + +- Define type of SAPHanaTopology RA messages to be printed +- Define type of SAPHanaTopology RA messages to be printed. +-Define SAPHana resource agent messages to be printed. +- This parameter should only be set if requested by support. The default is sufficient for normal operation. +- Values: ra-act-lpa-dec-flow +- You could specify any combination of the above values like "ra-act-flow" +- ++ OUTDATED ++ OUTDATED + + + +@@ -197,7 +191,7 @@ + } + + # +-# function: get_hana_attribute ++# function: get_hana_attribute + # params: NODE ATTR [STORE] + # globals: - + # +@@ -208,16 +202,19 @@ + local attr_node=$1 + local attr_name=$2 + local attr_store=${3:-reboot} # DONE: PRIO5 get this (optional) from parameter +- local attr_val="" +- attr_val=$(crm_attribute -N ${attr_node} -G -n "$attr_name" -l $attr_store -q); rc=$? +- if [ $debug_attributes -eq 1 ]; then +- dstr=$(date) +- echo "$dstr: SAPHanaTopology: crm_attribute -N ${attr_node} -G -n \"$attr_name\" -l $attr_store -q --> $attr_val" >> /var/log/fhATTRIBUTE +- fi +- echo "$attr_val" +- if [ $rc -ne 0 ]; then +- super_ocf_log debug "DBG: ATTRIBUTE-FAILURE: crm_attribute -N $attr_node -G -n "$attr_name" -l $attr_store -q" +- fi ++ local attr_default=${4:-} ++ local dstr ++ dstr=$(date) ++ case "$attr_store" in ++ reboot | forever ) ++ echo "$dstr: SAPHanaTopology: crm_attribute -N ${attr_node} -G -n \"$attr_name\" -l $attr_store -q" >> /var/log/fhATTRIBUTE ++ crm_attribute -N ${attr_node} -G -n "$attr_name" -l $attr_store -q -d "$attr_default" 2>>/var/log/fhATTRIBUTE; rc=$? ++ ;; ++ props ) ++ echo "$dstr: SAPHanaTopology: crm_attribute -G -n \"$attr_name\" -t crm_config -q" >> /var/log/fhATTRIBUTE ++ crm_attribute -G -n "$attr_name" -t crm_config -q -d "$attr_default" 2>>/var/log/fhATTRIBUTE; rc=$? ++ ;; ++ esac + super_ocf_log info "FLOW $FUNCNAME rc=$rc" + return $rc + } +@@ -234,19 +231,24 @@ + local attr_value=$2 + local attr_name=$3 + local attr_store=${4:-reboot} # DONE: PRIO5 get this (optional) from parameter ++ local attr_default=${5:-} + local rc=1 +- local attr_old +- attr_old=$(get_hana_attribute $attr_node $attr_name $attr_store); get_rc=$? ++ local attr_old="" ++ local dstr ++ dstr=$(date) ++ attr_old=$(get_hana_attribute $attr_node $attr_name $attr_store $attr_default); get_rc=$? + if [ "$attr_old" != "$attr_value" ]; then + super_ocf_log debug "DBG: SET attribute $attr_name for node ${attr_node} to ${attr_value} former ($attr_old) get_rc=$get_rc " +- if [ $debug_attributes -eq 1 ]; then +- dstr=$(date) +- echo "$dstr: SAPHanaTopology: crm_attribute -N $attr_node -v $attr_value -n \"$attr_name\" -l $attr_store" >> /var/log/fhATTRIBUTE +- fi +- crm_attribute -N $attr_node -v "$attr_value" -n "$attr_name" -l $attr_store; rc=$? +- if [ $rc -ne 0 ]; then +- super_ocf_log debug "DBG: ATTRIBUTE-FAILURE: crm_attribute -N $attr_node -v $attr_value -n "$attr_name" -l $attr_store" +- fi ++ case "$attr_store" in ++ reboot | forever ) ++ echo "$dstr: SAPHanaTopology: crm_attribute -N $attr_node -v $attr_value -n \"$attr_name\" -l $attr_store" >> /var/log/fhATTRIBUTE ++ crm_attribute -N $attr_node -v $attr_value -n "$attr_name" -l $attr_store 2>>/var/log/fhATTRIBUTE; rc=$? ++ ;; ++ props ) ++ echo "$dstr: SAPHanaTopology: crm_attribute -v $attr_value -n \"$attr_name\" -t crm_config -s SAPHanaSR" >> /var/log/fhATTRIBUTE ++ crm_attribute -v $attr_value -n "$attr_name" -t crm_config -s SAPHanaSR 2>>/var/log/fhATTRIBUTE; rc=$? ++ ;; ++ esac + else + super_ocf_log debug "DBG: LET attribute $attr_name for node ${attr_node} still be ${attr_value}" + rc=0 +@@ -299,7 +301,7 @@ + # + # yes it is a clone config - check, if its configured well + # +- if [ "$OCF_RESKEY_CRM_meta_clone_node_max" -ne 1 ] ; then ++ if [ "$OCF_RESKEY_CRM_meta_clone_node_max" -ne 1 ] ; then + super_ocf_log err "ACT: Clone options misconfigured. (expect: clone_node_max=1)" + exit $OCF_ERR_CONFIGURED + fi +@@ -314,8 +316,8 @@ + # + # function: sht_init - initialize variables for the resource agent + # params: - +-# globals: OCF_*(r), SID(w), sid(rw), sidadm(w), InstanceName(w), InstanceNr(w), +-# globals: meta_notify_master_uname(w), HANA_SR_TOLOPOGY(w), sr_name(w), remoteHost(w) ++# globals: OCF_*(r), SID(w), sid(rw), sidadm(w), InstanceName(w), InstanceNr(w), ++# globals: meta_notify_master_uname(w), HANA_SR_TOLOPOGY(w), sr_name(w), remoteHost(w) + # globals: ATTR_NAME_HANA_SYNC_STATUS(w), ATTR_NAME_HANA_PRIMARY_AT(w), ATTR_NAME_HANA_CLONE_STATE(w) + # globals: DIR_EXECUTABLE(w), SAPSTARTSRV(w), SAPCONTROL(w), DIR_PROFILE(w), SAPSTARTPROFILE(w), LD_LIBRARY_PATH(w), PATH(w), nodelist(w) + # sht_init : Define global variables with default values, if optional parameters are not set +@@ -327,6 +329,8 @@ + local myInstanceName="" + local rc=$OCF_SUCCESS + local hdbANSWER="" ++ local siteID ++ local siteNAME + HOSTEXECNAME=saphostexec + USRSAP=/usr/sap + SAPSERVICE_PATH=${USRSAP}/sapservices +@@ -340,10 +344,9 @@ + super_ocf_log debug "DBG2: Used new method to get SID ($SID) and InstanceNr ($InstanceNr)" + sid=$(echo "$SID" | tr [:upper:] [:lower:]) + sidadm="${sid}adm" +- SAPHanaFilter="${OCF_RESKEY_SAPHanaFilter:-ra-act-dec-lpa}" + ocf_env=$(env | grep 'OCF_RESKEY_CRM') + super_ocf_log debug "DBG3: OCF: $ocf_env" +- ATTR_NAME_HANA_SYNC_STATUS=("hana_${sid}_sync_state" "reboot") # SOK, SFAIL, UNKNOWN? ++ ATTR_NAME_HANA_SYNC_STATUS=("hana_${sid}_sync_state" "reboot") # SOK, SFAIL, UNKNOWN? + ATTR_NAME_HANA_PRIMARY_AT=("hana_${sid}_primary_at" "reboot") # Not really used + ATTR_NAME_HANA_CLONE_STATE=("hana_${sid}_clone_state" "reboot") # UKNOWN?, DEMOTED, PROMOTED + ATTR_NAME_HANA_REMOTEHOST=("hana_${sid}_remoteHost" "forever") +@@ -352,8 +355,14 @@ + ATTR_NAME_HANA_SRMODE=("hana_${sid}_srmode" "forever") + ATTR_NAME_HANA_VHOST=("hana_${sid}_vhost" "forever") + ATTR_NAME_HANA_STATUS=("hana_${sid}_status" "reboot") +- ++ # ++ # new "central" attributes ++ # ++ ATTR_NAME_HANA_FILTER=("hana_${sid}_glob_filter" "props" "ra-act-dec-lpa") + # optional OCF parameters, we try to guess which directories are correct ++ ++ SAPHanaFilter=$(get_hana_attribute "X" ${ATTR_NAME_HANA_FILTER[@]}) ++ + if [ -z "$OCF_RESKEY_DIR_EXECUTABLE" ] + then + DIR_EXECUTABLE="/usr/sap/$SID/$InstanceName/exe" +@@ -387,19 +396,32 @@ + # we need: mode=primary|sync|syncmem|...; site name=; mapping/=/ (multiple lines) + case $(crm_attribute --type crm_config --name cluster-infrastructure -q) in + *corosync* ) nodelist=$(crm_node -l | awk '{ print $2 }');; +- *openais* ) nodelist=$(crm_node -l | awk '/member/ {print $2}');; +- *cman* ) nodelist=$(crm_node -l);; ++ *openais* ) nodelist=$(crm_node -l | awk '/member/ {print $2}');; ++ *cman* ) nodelist=$(crm_node -l);; + esac + #### SAP-CALL +- hdbANSWER=$(su - ${sidadm} -c "hdbnsutil -sr_state --sapcontrol=1" 2>/dev/null) +- super_ocf_log debug "DBG2: hdbANSWER=\$\(su - ${sidadm} -c \"hdbnsutil -sr_state --sapcontrol=1\"\)" +- site=$(echo "$hdbANSWER" | awk -F= '/site name/ {print $2}') ++ # hdbnsutil was a bit unstable in some tests so we recall the tool, if it fails to report the srmode ++ for i in 1 2 3 4 5 6 7 8 9; do ++ hdbANSWER=$(su - ${sidadm} -c "hdbnsutil -sr_state --sapcontrol=1" 2>/dev/null) ++ super_ocf_log debug "DBG2: hdbANSWER=\$\(su - ${sidadm} -c \"hdbnsutil -sr_state --sapcontrol=1\"\)" ++ srmode=$(echo "$hdbANSWER" | awk -F= '/mode/ {print $2}') ++ case "$srmode" in ++ primary | syncmem | sync | async | none ) ++ # we can leave the loop as we already got a result ++ break ++ ;; ++ * ) ++ # lets pause a bit to give hdbnsutil a chance to answer next time ++ sleep 2 ++ ;; ++ esac ++ done ++ # TODO PRIO3: Implement a file lookup, if we did not get a result ++ siteID=$(echo "$hdbANSWER" | awk -F= '/site id/ {print $2}') ++ siteNAME=$(echo "$hdbANSWER" | awk -F= '/site name/ {print $2}') ++ site=$siteNAME + srmode=$(echo "$hdbANSWER" | awk -F= '/mode/ {print $2}') +- if [ $debug_attributes -eq 1 ]; then +- dstr=$(date) +- echo "$dstr: SAPHanaTopology: srmode=$srmode" >> /var/log/fhATTRIBUTE +- fi +- MAPPING=$(echo "$hdbANSWER" | awk -F[=/] '$1 == "mapping" && $3 != site { print $4 }' site=$site) ++ MAPPING=$(echo "$hdbANSWER" | awk -F[=/] '$1 ~ "mapping" && $3 !~ site { print $4 }' site=$site) + super_ocf_log debug "DBG: site=$site, mode=$srmode, MAPPING=$MAPPING" + # + # filter all non-cluster mappings +@@ -413,12 +435,12 @@ + echo $hanaVHost; + fi; + done; +- done ) ++ done ) + super_ocf_log info "DEC: site=$site, mode=$srmode, MAPPING=$MAPPING, hanaRemoteHost=$hanaRemoteHost" + super_ocf_log debug "DBG: site=$site, mode=$srmode, MAPPING=$MAPPING, hanaRemoteHost=$hanaRemoteHost" + super_ocf_log info "FLOW $FUNCNAME rc=$OCF_SUCCESS" + return $OCF_SUCCESS +-} ++} + + # + # function: check_for_primary - check if local SAP HANA is configured as primary +@@ -428,32 +450,30 @@ + function check_for_primary() { + super_ocf_log info "FLOW $FUNCNAME ($*)" + local rc=0 +- # DONE: Change stderr location!! +- #sidadm=lnxadm +- #node_status=$(check_for_primary_single) +- node_status=$srmode +- super_ocf_log debug "DBG2: check_for_primary: node_status=$node_status" +- super_ocf_log debug "DBG: check_for_primary: node_status=$node_status" +- for i in 1 2 3 4 5 6 7 8 9; do +- case "$node_status" in +- primary ) ++ node_status=$srmode ++ super_ocf_log debug "DBG2: check_for_primary: node_status=$node_status" ++ super_ocf_log debug "DBG: check_for_primary: node_status=$node_status" ++ for i in 1 2 3 4 5 6 7 8 9; do ++ case "$node_status" in ++ primary ) + super_ocf_log info "FLOW $FUNCNAME rc=HANA_STATE_PRIMARY" + return $HANA_STATE_PRIMARY;; + syncmem | sync | async ) + super_ocf_log info "FLOW $FUNCNAME rc=HANA_STATE_SECONDARY" + return $HANA_STATE_SECONDARY;; +- none ) # have seen that mode on second side BEFEORE we registered it as replica ++ none ) # have seen that mode on second side BEFEORE we registered it as replica + super_ocf_log info "FLOW $FUNCNAME rc=HANA_STATE_STANDALONE" + return $HANA_STATE_STANDALONE;; + * ) +- super_ocf_log err "ACT: check_for_primary: we didn't expect node_status to be: <$node_status>" +- dump=$( echo $node_status | hexdump -C ); +- super_ocf_log err "ACT: check_for_primary: we didn't expect node_status to be: DUMP <$dump>" +- #### SAP-CALL +- node_full_status=$(su - ${sidadm} -c "hdbnsutil -sr_state" 2>/dev/null ) +- node_status=$(echo "$node_full_status" | awk '$1=="mode:" {print $2}') +- super_ocf_log info "DEC: check_for_primary: loop=$i: node_status=$node_status" +- # TODO: PRIO1: Maybe we need to keep the old value for P/S/N, if hdbnsutil just crashes ++ # TODO: PRIO1: Should we set SFAIL? ++ # TODO: PRIO2: Maybe we need to keep the old value for P/S/N, if hdbnsutil just crashes ++ dump=$( echo $node_status | hexdump -C ); ++ super_ocf_log err "ACT: check_for_primary: we didn't expect node_status to be: DUMP: <$dump>" ++ #### SAP-CALL ++ node_full_status=$(su - ${sidadm} -c "hdbnsutil -sr_state" 2>/dev/null ) ++ node_status=$(echo "$node_full_status" | awk '$1=="mode:" {print $2}') ++ super_ocf_log info "DEC: check_for_primary: loop=$i: node_status=$node_status" ++ # TODO: PRIO1: Maybe we need to keep the old value for P/S/N, if hdbnsutil just crashes + esac; + done + super_ocf_log info "FLOW $FUNCNAME rc=HANA_STATE_DEFECT" +@@ -464,7 +484,7 @@ + # + # function: start_saphostagent + # params: - +-# globals: ++# globals: HOSTEXEC_PATH(r), HOSTEXEC_PROFILE_PATH(r) + # + function start_saphostagent() + { +@@ -478,7 +498,7 @@ + # + # function: stop_saphostagent + # params: - +-# globals: ++# globals: HOSTEXEC_PATH(r) + # + function stop_saphostagent() + { +@@ -496,6 +516,8 @@ + function check_saphostagent() + { + local rc=1 ++ # TODO: PRIO3: should the path been removed like "saphostexec" instead of "/usr/sap/hostctrl/exe/saphostexec" ++ # or should we use ${HOSTEXEC_PATH} instead? + pgrep -f /usr/sap/hostctrl/exe/saphostexec; rc=$? + return $rc + } +@@ -509,15 +531,16 @@ + # sht_start : Start the SAP HANA instance + # + function sht_start() { +- + super_ocf_log info "FLOW $FUNCNAME ($*)" + + local rc=$OCF_NOT_RUNNING + local output="" +- local loopcount=0 ++ local loopcount=0 + +- mkdir -p /var/lib/SAPHana +- touch /var/lib/SAPHana/SAPTopologyON ++ # TODO: PRIO3: move the string "$HA_RSCTMP/SAPHana/SAPTopologyON" to a variable ++ # TODO: PRIO3: move the file to the clusters tmp directory? ++ mkdir -p $HA_RSCTMP/SAPHana ++ touch $HA_RSCTMP/SAPHana/SAPTopologyON + if ! check_saphostagent; then + start_saphostagent + fi +@@ -532,16 +555,16 @@ + # function: sht_stop - stop a hana instance + # params: - + # globals: OCF_*(r), SAPCONTROL(r), SID(r), InstanceName(r) +-# sht_stop: Stop the SAP instance ++# sht_stop: Stop the SAP HANA Topology Resource + # + function sht_stop() { + super_ocf_log info "FLOW $FUNCNAME ($*)" + local output="" + local rc=0 + +- rm /var/lib/SAPHana/SAPTopologyON ++ rm $HA_RSCTMP/SAPHana/SAPTopologyON + rc=$OCF_SUCCESS +- ++ + super_ocf_log info "FLOW $FUNCNAME rc=$rc" + return $rc + } +@@ -557,13 +580,13 @@ + super_ocf_log info "FLOW $FUNCNAME ($*)" + local rc=0 + +- if [ -f /var/lib/SAPHana/SAPTopologyON ]; then ++ if [ -f $HA_RSCTMP/SAPHana/SAPTopologyON ]; then + rc=$OCF_SUCCESS + else + rc=$OCF_NOT_RUNNING + fi + +- super_ocf_log info "FLOW $FUNCNAME rc=$rc" ++ super_ocf_log info "FLOW $FUNCNAME rc=$rc" + return $rc + } + +@@ -575,37 +598,37 @@ + # sht_status: Lightweight check of SAP instance only with OS tools + # + function sht_status() { +- super_ocf_log info "FLOW $FUNCNAME ($*)" +- local rc=0 ++ super_ocf_log info "FLOW $FUNCNAME ($*)" ++ local rc=0 + +- sht_monitor; rc=$? +- return $rc ++ sht_monitor; rc=$? ++ return $rc + } + + + # + # function: sht_validate - validation of (some) variables/parameters + # params: - +-# globals: OCF_*(r), SID(r), InstanceName(r), InstanceNr(r), +-# sht_validate: Check the symantic of the input parameters ++# globals: OCF_*(r), SID(r), InstanceName(r), InstanceNr(r), ++# sht_validate: Check the symantic of the input parameters + # + function sht_validate() { +- super_ocf_log info "FLOW $FUNCNAME ($*)" +- local rc=$OCF_SUCCESS +- if [ $(echo "$SID" | grep -c '^[A-Z][A-Z0-9][A-Z0-9]$') -ne 1 ] +- then +- super_ocf_log err "ACT: Parsing instance profile name: '$SID' is not a valid SID!" +- rc=$OCF_ERR_ARGS +- fi ++ super_ocf_log info "FLOW $FUNCNAME ($*)" ++ local rc=$OCF_SUCCESS ++ if [ $(echo "$SID" | grep -c '^[A-Z][A-Z0-9][A-Z0-9]$') -ne 1 ] ++ then ++ super_ocf_log err "ACT: Parsing instance profile name: '$SID' is not a valid SID!" ++ rc=$OCF_ERR_ARGS ++ fi + +- if [ $(echo "$InstanceNr" | grep -c '^[0-9][0-9]$') -ne 1 ] +- then +- super_ocf_log err "ACT: Parsing instance profile name: '$InstanceNr' is not a valid instance number!" +- rc=$OCF_ERR_ARGS +- fi ++ if [ $(echo "$InstanceNr" | grep -c '^[0-9][0-9]$') -ne 1 ] ++ then ++ super_ocf_log err "ACT: Parsing instance profile name: '$InstanceNr' is not a valid instance number!" ++ rc=$OCF_ERR_ARGS ++ fi + +- super_ocf_log info "FLOW $FUNCNAME rc=$rc" +- return $rc ++ super_ocf_log info "FLOW $FUNCNAME rc=$rc" ++ return $rc + } + + # +@@ -661,15 +684,15 @@ + + if ocf_is_probe; then + super_ocf_log debug "DBG2: PROBE ONLY" ++ sht_monitor; rc=$? + else + super_ocf_log debug "DBG2: REGULAR MONITOR" + if ! check_saphostagent; then + start_saphostagent + fi +- fi + # + # First check, if we are PRIMARY or SECONDARY +- # ++ # + super_ocf_log debug "DBG2: HANA SID $SID" + super_ocf_log debug "DBG2: HANA InstanceName $InstanceName" + super_ocf_log debug "DBG2: HANA InstanceNr $InstanceNr" +@@ -721,8 +744,8 @@ + set_hana_attribute ${NODENAME} "$site" ${ATTR_NAME_HANA_SITE[@]} + fi + case "$hanaPrim" in +- P ) ;; +- S ) # only secondary may propargate its sync status ++ P ) ;; ++ S ) # only secondary may propargate its sync status + case $(crm_attribute --type crm_config --name cluster-infrastructure -q) in + *corosync* ) nodelist=$(crm_node -l | awk '{ print $2 }');; + *openais* ) nodelist=$(crm_node -l | awk '/member/ {print $2}');; +@@ -732,8 +755,10 @@ + for n in ${nodelist}; do + set_hana_attribute ${n} "$srmode" ${ATTR_NAME_HANA_SRMODE[@]} + done +- ;; ++ ;; + esac ++ # ++ fi # end ocf_is_NOT_probe + super_ocf_log info "FLOW $FUNCNAME rc=$rc" + return $rc + } +@@ -752,7 +777,7 @@ + } + + # +-# function: main - main function to operate ++# function: main - main function to operate + # params: ACTION + # globals: OCF_*(r), SID(w), sidadm(w), InstanceName(w), DIR_EXECUTABLE(w), ACTION(w), CLACT(w), ra_rc(rw), $0(r), %ENV(r) + # +@@ -763,7 +788,7 @@ + InstanceName="" + InstanceNr="" + DIR_EXECUTABLE="" +-SAPHanaFilter="${OCF_RESKEY_SAPHanaFilter:-ra-act-dec-lpa}" ++SAPHanaFilter="ra-act-dec-lpa" + NODENAME=$(crm_node -n) + + if [ $# -ne 1 ] +@@ -785,11 +810,11 @@ + exit $OCF_SUCCESS;; + notify) sht_notify + exit $OCF_SUCCESS;; +- admin-setup) admin-setup +- exit $OCF_SUCCESS;; ++ admin-setup) admin-setup ++ exit $OCF_SUCCESS;; + *);; + esac +-sht_init ++sht_init + + if ! ocf_is_root + then +@@ -810,7 +835,6 @@ + exit $OCF_ERR_ARGS + fi + +- + if is_clone + then + CLACT=_clone +@@ -830,12 +854,12 @@ + sht_$ACTION$CLACT + ra_rc=$? + ;; +- validate-all) ++ validate-all) + sht_validate + ra_rc=$? + ;; +- *) # seams to be a unknown request +- sht_methods ++ *) # seams to be a unknown request ++ sht_methods + ra_rc=$OCF_ERR_UNIMPLEMENTED + ;; + esac diff --git a/SOURCES/bz1296406-virtualdomain-migration_speed-migration_downtime.patch b/SOURCES/bz1296406-virtualdomain-migration_speed-migration_downtime.patch new file mode 100644 index 00000000..fdbde386 --- /dev/null +++ b/SOURCES/bz1296406-virtualdomain-migration_speed-migration_downtime.patch @@ -0,0 +1,101 @@ +diff -uNr a/heartbeat/VirtualDomain b/heartbeat/VirtualDomain +--- a/heartbeat/VirtualDomain 2016-03-04 14:41:22.001333979 +0100 ++++ b/heartbeat/VirtualDomain 2016-03-04 14:42:34.516395470 +0100 +@@ -17,12 +17,16 @@ + . ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs + + # Defaults ++OCF_RESKEY_migration_downtime_default=0 ++OCF_RESKEY_migration_speed_default=0 + OCF_RESKEY_force_stop_default=0 + OCF_RESKEY_autoset_utilization_cpu_default="true" + OCF_RESKEY_autoset_utilization_hv_memory_default="true" + OCF_RESKEY_migrateport_default=$(( 49152 + $(ocf_maybe_random) % 64 )) + OCF_RESKEY_CRM_meta_timeout_default=90000 + ++: ${OCF_RESKEY_migration_downtime=${OCF_RESKEY_migration_downtime_default}} ++: ${OCF_RESKEY_migration_speed=${OCF_RESKEY_migration_speed_default}} + : ${OCF_RESKEY_force_stop=${OCF_RESKEY_force_stop_default}} + : ${OCF_RESKEY_autoset_utilization_cpu=${OCF_RESKEY_autoset_utilization_cpu_default}} + : ${OCF_RESKEY_autoset_utilization_hv_memory=${OCF_RESKEY_autoset_utilization_hv_memory_default}} +@@ -96,6 +100,22 @@ + + + ++ ++ ++Define max downtime during live migration in milliseconds ++ ++Live migration downtime ++ ++ ++ ++ ++ ++Define live migration speed per resource in MiB/s ++ ++Live migration speed ++ ++ ++ + + + Use a dedicated migration network. The migration URI is composed by +@@ -562,6 +582,7 @@ + local transport_suffix + local migrateuri + local migrate_opts ++ local migrate_pid + + target_node="$OCF_RESKEY_CRM_meta_migrate_target" + +@@ -586,9 +607,28 @@ + # Scared of that sed expression? So am I. :-) + remoteuri=$(echo ${OCF_RESKEY_hypervisor} | sed -e "s,\(.*\)://[^/:]*\(:\?[0-9]*\)/\(.*\),\1${transport_suffix}://${target_node}\2/\3,") + ++ # Live migration speed limit ++ if [ ${OCF_RESKEY_migration_speed} -ne 0 ]; then ++ ocf_log info "$DOMAIN_NAME: Setting live migration speed limit for $DOMAIN_NAME (using: virsh ${VIRSH_OPTIONS} migrate-setspeed $DOMAIN_NAME ${OCF_RESKEY_migration_speed})." ++ virsh ${VIRSH_OPTIONS} migrate-setspeed $DOMAIN_NAME ${OCF_RESKEY_migration_speed} ++ fi ++ + # OK, we know where to connect to. Now do the actual migration. +- ocf_log info "$DOMAIN_NAME: Starting live migration to ${target_node} (using virsh ${VIRSH_OPTIONS} migrate --live $migrate_opts $DOMAIN_NAME $remoteuri $migrateuri)." +- virsh ${VIRSH_OPTIONS} migrate --live $migrate_opts $DOMAIN_NAME $remoteuri $migrateuri ++ ocf_log info "$DOMAIN_NAME: Starting live migration to ${target_node} (using: virsh ${VIRSH_OPTIONS} migrate --live $migrate_opts $DOMAIN_NAME $remoteuri $migrateuri)." ++ virsh ${VIRSH_OPTIONS} migrate --live $migrate_opts $DOMAIN_NAME $remoteuri $migrateuri & ++ ++ migrate_pid=${!} ++ ++ # Live migration downtime interval ++ # Note: You can set downtime only while live migration is in progress ++ if [ ${OCF_RESKEY_migration_downtime} -ne 0 ]; then ++ sleep 2 ++ ocf_log info "$DOMAIN_NAME: Setting live migration downtime for $DOMAIN_NAME (using: virsh ${VIRSH_OPTIONS} migrate-setmaxdowntime $DOMAIN_NAME ${OCF_RESKEY_migration_downtime})." ++ virsh ${VIRSH_OPTIONS} migrate-setmaxdowntime $DOMAIN_NAME ${OCF_RESKEY_migration_downtime} ++ fi ++ ++ wait ${migrate_pid} ++ + rc=$? + if [ $rc -ne 0 ]; then + ocf_exit_reason "$DOMAIN_NAME: live migration to ${target_node} failed: $rc" +@@ -671,6 +711,18 @@ + return $OCF_ERR_INSTALLED + fi + fi ++ ++ # Check if migration_speed is a decimal value ++ if ! ocf_is_decimal ${OCF_RESKEY_migration_speed}; then ++ ocf_exit_reason "migration_speed has to be a decimal value" ++ return $OCF_ERR_CONFIGURED ++ fi ++ ++ # Check if migration_downtime is a decimal value ++ if ! ocf_is_decimal ${OCF_RESKEY_migration_downtime}; then ++ ocf_exit_reason "migration_downtime has to be a decimal value" ++ return $OCF_ERR_CONFIGURED ++ fi + } + + if [ $# -ne 1 ]; then diff --git a/SOURCES/bz1299404-galera-custom-host-port.patch b/SOURCES/bz1299404-galera-custom-host-port.patch new file mode 100644 index 00000000..fc3b9011 --- /dev/null +++ b/SOURCES/bz1299404-galera-custom-host-port.patch @@ -0,0 +1,33 @@ +From cbccff5ed9b1fc5641063f05ad531f897d366fa4 Mon Sep 17 00:00:00 2001 +From: Mike Bayer +Date: Tue, 15 Sep 2015 14:54:05 -0400 +Subject: [PATCH] galera: add support for MYSQL_HOST and MYSQL_PORT from + clustercheck + +--- + heartbeat/galera | 12 ++++++++++++ + 1 file changed, 12 insertions(+) + +diff --git a/heartbeat/galera b/heartbeat/galera +index 920507b..1a1a4ce 100755 +--- a/heartbeat/galera ++++ b/heartbeat/galera +@@ -704,6 +704,18 @@ if [ -n "${OCF_RESKEY_check_passwd}" ]; then + MYSQL_OPTIONS_CHECK="$MYSQL_OPTIONS_CHECK --password=${OCF_RESKEY_check_passwd}" + fi + ++# This value is automatically sourced from /etc/sysconfig/checkcluster if available ++if [ -n "${MYSQL_HOST}" ]; then ++ MYSQL_OPTIONS_CHECK="$MYSQL_OPTIONS_CHECK -h ${MYSQL_HOST}" ++fi ++ ++# This value is automatically sourced from /etc/sysconfig/checkcluster if available ++if [ -n "${MYSQL_PORT}" ]; then ++ MYSQL_OPTIONS_CHECK="$MYSQL_OPTIONS_CHECK -P ${MYSQL_PORT}" ++fi ++ ++ ++ + # What kind of method was invoked? + case "$1" in + start) galera_start;; diff --git a/SOURCES/bz1301189-virtualdomain-fix-locale.patch b/SOURCES/bz1301189-virtualdomain-fix-locale.patch new file mode 100644 index 00000000..904cc078 --- /dev/null +++ b/SOURCES/bz1301189-virtualdomain-fix-locale.patch @@ -0,0 +1,35 @@ +diff -uNr a/heartbeat/VirtualDomain b/heartbeat/VirtualDomain +--- a/heartbeat/VirtualDomain 2016-01-25 12:05:30.437008638 +0100 ++++ b/heartbeat/VirtualDomain 2016-01-25 12:25:06.850256377 +0100 +@@ -282,12 +282,13 @@ + status="no state" + while [ "$status" = "no state" ]; do + try=$(($try + 1 )) +- status=$(virsh $VIRSH_OPTIONS domstate $DOMAIN_NAME 2>&1 | tr 'A-Z' 'a-z') ++ status=$(LANG=C virsh $VIRSH_OPTIONS domstate $DOMAIN_NAME 2>&1 | tr 'A-Z' 'a-z') + case "$status" in +- *"error:"*"domain not found"*|"shut off") ++ *"error:"*"domain not found"|*"error:"*"failed to get domain"*|"shut off") + # shut off: domain is defined, but not started, will not happen if + # domain is created but not defined +- # Domain not found: domain is not defined and thus not started ++ # "Domain not found" or "failed to get domain": domain is not defined ++ # and thus not started + ocf_log debug "Virtual domain $DOMAIN_NAME is not running: $(echo $status | sed s/error://g)" + rc=$OCF_NOT_RUNNING + ;; +@@ -415,11 +416,12 @@ + local status=0 + + ocf_log info "Issuing forced shutdown (destroy) request for domain ${DOMAIN_NAME}." +- out=$(virsh $VIRSH_OPTIONS destroy ${DOMAIN_NAME} 2>&1|tr 'A-Z' 'a-z') ++ out=$(LANG=C virsh $VIRSH_OPTIONS destroy ${DOMAIN_NAME} 2>&1|tr 'A-Z' 'a-z') + ex=$? + echo >&2 "$out" + case $ex$out in +- *"error:"*"domain is not running"*|*"error:"*"domain not found"*) ++ *"error:"*"domain is not running"*|*"error:"*"domain not found"*|\ ++ *"error:"*"failed to get domain"*) + : ;; # unexpected path to the intended outcome, all is well + [!0]*) + ocf_exit_reason "forced stop failed" diff --git a/SOURCES/bz1303037-1-portblock.patch b/SOURCES/bz1303037-1-portblock.patch new file mode 100644 index 00000000..9ed8cd11 --- /dev/null +++ b/SOURCES/bz1303037-1-portblock.patch @@ -0,0 +1,207 @@ +diff -uNr a/heartbeat/portblock b/heartbeat/portblock +--- a/heartbeat/portblock 2013-06-18 15:22:27.000000000 +0200 ++++ b/heartbeat/portblock 2016-02-29 13:51:22.205860012 +0100 +@@ -24,8 +24,10 @@ + + # Defaults + OCF_RESKEY_ip_default="0.0.0.0/0" ++OCF_RESKEY_reset_local_on_unblock_stop_default="false" + + : ${OCF_RESKEY_ip=${OCF_RESKEY_ip_default}} ++: ${OCF_RESKEY_reset_local_on_unblock_stop=${OCF_RESKEY_reset_local_on_unblock_stop_default}} + ####################################################################### + CMD=`basename $0` + TICKLETCP=$HA_BIN/tickle_tcp +@@ -37,16 +39,22 @@ + + $CMD is used to temporarily block ports using iptables. + +- It can be used to turn off a port before bringing ++ It can be used to blackhole a port before bringing + up an IP address, and enable it after a service is started. +- To do that for samba, the following resource line can be used: ++ To do that for samba, the following can be used: + +- $CMD::tcp::137,138::block \\ +- 10.10.10.20 \\ +- nmbd smbd \\ +- $CMD::tcp::137,138::unblock ++ crm configure < + portno +- ++ + + + +@@ -149,6 +160,26 @@ + + + ++ ++ ++(try to) reset server TCP sessions when unblock stops ++ ++If for some reason the long lived server side TCP sessions won't be cleaned up ++by a reconfiguration/flush/stop of whatever services this portblock protects, ++they would linger in the connection table, even after the IP is gone ++and services have been switched over to an other node. ++ ++An example would be the default NFS kernel server. ++ ++These "known" connections may seriously confuse and delay a later switchback. ++ ++Enabling this option will cause this agent to try to get rid of these connections ++by injecting a temporary iptables rule to TCP-reset outgoing packets from the ++blocked ports, and additionally tickle them locally, ++just before it starts to DROP incoming packets on "unblock stop". ++ ++ ++ + + + The IP address used to be blocked/unblocked. +@@ -233,12 +264,34 @@ + fi + } + +-run_tickle_tcp() ++tickle_remote() + { + [ -z "$OCF_RESKEY_tickle_dir" ] && return + echo 1 > /proc/sys/net/ipv4/tcp_tw_recycle + f=$OCF_RESKEY_tickle_dir/$OCF_RESKEY_ip +- [ -f $f ] && cat $f | $TICKLETCP -n 3 ++ [ -r $f ] || return ++ $TICKLETCP -n 3 < $f ++} ++ ++tickle_local() ++{ ++ [ -z "$OCF_RESKEY_tickle_dir" ] && return ++ f=$OCF_RESKEY_tickle_dir/$OCF_RESKEY_ip ++ [ -r $f ] || return ++ # swap "local" and "remote" address, ++ # so we tickle ourselves. ++ # We set up a REJECT with tcp-reset before we do so, so we get rid of ++ # the no longer wanted potentially long lived "ESTABLISHED" connection ++ # entries on the IP we are going to delet in a sec. These would get in ++ # the way if we switch-over and then switch-back in quick succession. ++ local i ++ awk '{ print $2, $1; }' $f | $TICKLETCP ++ netstat -tn | grep -Fw $OCF_RESKEY_ip || return ++ for i in 0.1 0.5 1 2 4 ; do ++ sleep $i ++ awk '{ print $2, $1; }' $f | $TICKLETCP ++ netstat -tn | grep -Fw $OCF_RESKEY_ip || break ++ done + } + + SayActive() +@@ -304,15 +357,30 @@ + #IptablesBLOCK {udp|tcp} portno,portno ip + IptablesBLOCK() + { ++ local rc=0 ++ local try_reset=false ++ if [ "$1/$4/$__OCF_ACTION" = tcp/unblock/stop ] && ++ ocf_is_true $reset_local_on_unblock_stop ++ then ++ try_reset=true ++ fi + if + chain_isactive "$1" "$2" "$3" + then + : OK -- chain already active + else ++ if $try_reset ; then ++ $IPTABLES -I OUTPUT -p "$1" -s "$3" -m multiport --sports "$2" -j REJECT --reject-with tcp-reset ++ tickle_local ++ fi + $IPTABLES -I INPUT -p "$1" -d "$3" -m multiport --dports "$2" -j DROP ++ rc=$? ++ if $try_reset ; then ++ $IPTABLES -D OUTPUT -p "$1" -s "$3" -m multiport --sports "$2" -j REJECT --reject-with tcp-reset ++ fi + fi + +- return $? ++ return $rc + } + + #IptablesUNBLOCK {udp|tcp} portno,portno ip +@@ -338,7 +406,7 @@ + unblock) + IptablesUNBLOCK "$@" + rc=$? +- run_tickle_tcp ++ tickle_remote + #ignore run_tickle_tcp exit code! + return $rc + ;; +@@ -411,6 +479,17 @@ + exit $OCF_ERR_CONFIGURED + ;; + esac ++ ++ if ocf_is_true $reset_local_on_unblock_stop; then ++ if [ $action != unblock ] ; then ++ ocf_log err "reset_local_on_unblock_stop is only relevant with action=unblock" ++ exit $OCF_ERR_CONFIGURED ++ fi ++ if [ -z $OCF_RESKEY_tickle_dir ] ; then ++ ocf_log warn "reset_local_on_unblock_stop works best with tickle_dir enabled as well" ++ fi ++ fi ++ + return $OCF_SUCCESS + } + +@@ -451,6 +530,7 @@ + portno=$OCF_RESKEY_portno + action=$OCF_RESKEY_action + ip=$OCF_RESKEY_ip ++reset_local_on_unblock_stop=$OCF_RESKEY_reset_local_on_unblock_stop + + case $1 in + start) diff --git a/SOURCES/bz1303037-2-portblock.patch b/SOURCES/bz1303037-2-portblock.patch new file mode 100644 index 00000000..96d71cdf --- /dev/null +++ b/SOURCES/bz1303037-2-portblock.patch @@ -0,0 +1,31 @@ +From 8ac05986ac7ef354456253edbd22cbb4a2d96e90 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Fri, 16 Sep 2016 10:19:38 +0200 +Subject: [PATCH] portblock: create tickle_dir if it doesnt exist + +--- + heartbeat/portblock | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/heartbeat/portblock b/heartbeat/portblock +index c480954..c97488b 100755 +--- a/heartbeat/portblock ++++ b/heartbeat/portblock +@@ -466,8 +466,7 @@ IptablesValidateAll() + exit $OCF_ERR_CONFIGURED + fi + if [ ! -d "$OCF_RESKEY_tickle_dir" ]; then +- ocf_log err "The tickle dir doesn't exist!" +- exit $OCF_ERR_INSTALLED ++ mkdir -p $OCF_RESKEY_tickle_dir + fi + fi + +@@ -534,6 +533,7 @@ reset_local_on_unblock_stop=$OCF_RESKEY_reset_local_on_unblock_stop + + case $1 in + start) ++ IptablesValidateAll + IptablesStart $protocol $portno $ip $action + ;; + diff --git a/SOURCES/bz1303803-Backup-and-restore-rabbitmq-users-during-resource-re.patch b/SOURCES/bz1303803-Backup-and-restore-rabbitmq-users-during-resource-re.patch new file mode 100644 index 00000000..222a840d --- /dev/null +++ b/SOURCES/bz1303803-Backup-and-restore-rabbitmq-users-during-resource-re.patch @@ -0,0 +1,45 @@ +From: Peter Lemenkov +Date: Mon, 29 Feb 2016 12:46:50 +0100 +Subject: [PATCH] Backup and restore rabbitmq users during resource restart + +Signed-off-by: Peter Lemenkov + +diff --git a/heartbeat/rabbitmq-cluster b/heartbeat/rabbitmq-cluster +index cc45f09..4545495 100755 +--- a/heartbeat/rabbitmq-cluster ++++ b/heartbeat/rabbitmq-cluster +@@ -289,7 +289,19 @@ rmq_start() { + rmq_stop + rmq_wipe_data + rmq_join_existing "$join_list" +- if [ $? -ne 0 ]; then ++ rc=$? ++ ++ # Restore users (if any) ++ BaseDataDir=`dirname $RMQ_DATA_DIR` ++ if [ -f $BaseDataDir/users.erl ] ; then ++ rabbitmqctl eval " ++ {ok, [Users]} = file:consult(\"$BaseDataDir/users.erl\"), ++ lists:foreach(fun(X) -> mnesia:dirty_write(rabbit_user, X) end, Users). ++ " ++ rm -f $BaseDataDir/users.erl ++ fi ++ ++ if [ $rc -ne 0 ]; then + ocf_log info "node failed to join even after reseting local data. Check SELINUX policy" + return $OCF_ERR_GENERIC + fi +@@ -299,6 +311,13 @@ rmq_start() { + } + + rmq_stop() { ++ # Backup users ++ BaseDataDir=`dirname $RMQ_DATA_DIR` ++ rabbitmqctl eval " ++ Users = mnesia:dirty_select(rabbit_user, [{ {internal_user, '\\\$1', '_', '_'}, [{'/=', '\\\$1', <<\"guest\">>}], ['\\\$_'] } ]), ++ file:write_file(\"$BaseDataDir/users.erl\", io_lib:fwrite(\"~p.~n\", [Users])). ++ " ++ + rmq_monitor + if [ $? -eq $OCF_NOT_RUNNING ]; then + return $OCF_SUCCESS diff --git a/SOURCES/bz1305549-nova-compute-wait-nova-compute-unfence.patch b/SOURCES/bz1305549-nova-compute-wait-nova-compute-unfence.patch new file mode 100644 index 00000000..0901754c --- /dev/null +++ b/SOURCES/bz1305549-nova-compute-wait-nova-compute-unfence.patch @@ -0,0 +1,259 @@ +diff -uNr a/heartbeat/nova-compute-wait b/heartbeat/nova-compute-wait +--- a/heartbeat/nova-compute-wait 2017-02-02 11:23:38.263510362 +0100 ++++ b/heartbeat/nova-compute-wait 2017-02-02 11:28:27.181650906 +0100 +@@ -1,30 +1,15 @@ + #!/bin/sh ++# Copyright 2015 Red Hat, Inc. + # ++# Description: Manages compute daemons + # +-# nova-compute-wait agent manages compute daemons. ++# Authors: Andrew Beekhof + # +-# Copyright (c) 2015 +-# +-# This program is free software; you can redistribute it and/or modify +-# it under the terms of version 2 of the GNU General Public License as +-# published by the Free Software Foundation. +-# +-# This program is distributed in the hope that it would be useful, but +-# WITHOUT ANY WARRANTY; without even the implied warranty of +-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +-# +-# Further, this software is distributed without any warranty that it is +-# free of the rightful claim of any third person regarding infringement +-# or the like. Any license provided herein, whether implied or +-# otherwise, applies only to this software file. Patent licenses, if +-# any, provided herein do not apply to combinations of this program with +-# other software, or any other product whatsoever. +-# +-# You should have received a copy of the GNU General Public License +-# along with this program; if not, write the Free Software Foundation, +-# Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. ++# Support: openstack@lists.openstack.org ++# License: Apache Software License (ASL) 2.0 + # + ++ + ####################################################################### + # Initialization: + +@@ -137,6 +122,8 @@ + } + + nova_start() { ++ build_unfence_overlay ++ + state=$(attrd_updater -p -n evacuate -N ${NOVA_HOST} | sed -e 's/.*value=//' | tr -d '"' ) + if [ "x$state" = x ]; then + : never been fenced +@@ -147,8 +134,8 @@ + sleep ${OCF_RESKEY_evacuation_delay} + + else +- ocf_log info "Waiting for pending evacuations from ${NOVA_HOST}" + while [ "x$state" != "xno" ]; do ++ ocf_log info "Waiting for pending evacuations from ${NOVA_HOST}" + state=$(attrd_updater -p -n evacuate -N ${NOVA_HOST} | sed -e 's/.*value=//' | tr -d '"' ) + sleep 5 + done +@@ -156,14 +143,22 @@ + ocf_log info "Pausing to give evacuations from ${NOVA_HOST} time to complete" + sleep ${OCF_RESKEY_evacuation_delay} + fi ++ ++ touch "$statefile" ++ + return $OCF_SUCCESS + } + + nova_stop() { ++ rm -f "$statefile" + return $OCF_SUCCESS + } + + nova_monitor() { ++ if [ ! -f "$statefile" ]; then ++ return $OCF_NOT_RUNNING ++ fi ++ + return $OCF_SUCCESS + } + +@@ -171,17 +166,113 @@ + return $OCF_SUCCESS + } + ++build_unfence_overlay() { ++ fence_options="" ++ ++ if [ -z "${OCF_RESKEY_auth_url}" ]; then ++ candidates=$(/usr/sbin/stonith_admin -l ${NOVA_HOST}) ++ for candidate in ${candidates}; do ++ pcs stonith show $d | grep -q fence_compute ++ if [ $? = 0 ]; then ++ ocf_log info "Unfencing nova based on: $candidate" ++ fence_auth=$(pcs stonith show $candidate | grep Attributes: | sed -e s/Attributes:// -e s/-/_/g -e 's/[^ ]\+=/OCF_RESKEY_\0/g' -e s/passwd/password/g) ++ eval "export $fence_auth" ++ break ++ fi ++ done ++ fi ++ ++ # Copied from NovaEvacuate ++ if [ -z "${OCF_RESKEY_auth_url}" ]; then ++ ocf_exit_reason "auth_url not configured" ++ exit $OCF_ERR_CONFIGURED ++ fi ++ ++ fence_options="${fence_options} -k ${OCF_RESKEY_auth_url}" ++ ++ if [ -z "${OCF_RESKEY_username}" ]; then ++ ocf_exit_reason "username not configured" ++ exit $OCF_ERR_CONFIGURED ++ fi ++ ++ fence_options="${fence_options} -l ${OCF_RESKEY_username}" ++ ++ if [ -z "${OCF_RESKEY_password}" ]; then ++ ocf_exit_reason "password not configured" ++ exit $OCF_ERR_CONFIGURED ++ fi ++ ++ fence_options="${fence_options} -p ${OCF_RESKEY_password}" ++ ++ if [ -z "${OCF_RESKEY_tenant_name}" ]; then ++ ocf_exit_reason "tenant_name not configured" ++ exit $OCF_ERR_CONFIGURED ++ fi ++ ++ fence_options="${fence_options} -t ${OCF_RESKEY_tenant_name}" ++ ++ if [ -n "${OCF_RESKEY_domain}" ]; then ++ fence_options="${fence_options} -d ${OCF_RESKEY_domain}" ++ fi ++ ++ if [ -n "${OCF_RESKEY_region_name}" ]; then ++ fence_options="${fence_options} \ ++ --region-name ${OCF_RESKEY_region_name}" ++ fi ++ ++ if [ -n "${OCF_RESKEY_insecure}" ]; then ++ if ocf_is_true "${OCF_RESKEY_insecure}"; then ++ fence_options="${fence_options} --insecure" ++ fi ++ fi ++ ++ if [ -n "${OCF_RESKEY_no_shared_storage}" ]; then ++ if ocf_is_true "${OCF_RESKEY_no_shared_storage}"; then ++ fence_options="${fence_options} --no-shared-storage" ++ fi ++ fi ++ ++ if [ -n "${OCF_RESKEY_endpoint_type}" ]; then ++ case ${OCF_RESKEY_endpoint_type} in ++ adminURL|publicURL|internalURL) ++ ;; ++ *) ++ ocf_exit_reason "endpoint_type ${OCF_RESKEY_endpoint_type}" \ ++ "not valid. Use adminURL or publicURL or internalURL" ++ exit $OCF_ERR_CONFIGURED ++ ;; ++ esac ++ fence_options="${fence_options} -e ${OCF_RESKEY_endpoint_type}" ++ fi ++ ++ mkdir -p /run/systemd/system/openstack-nova-compute.service.d ++ cat</run/systemd/system/openstack-nova-compute.service.d/unfence-20.conf ++[Service] ++ExecStartPost=/sbin/fence_compute ${fence_options} -o on -n ${NOVA_HOST} ++EOF ++} ++ + nova_validate() { + rc=$OCF_SUCCESS + + check_binary crudini + check_binary nova-compute ++ check_binary fence_compute + + if [ ! -f /etc/nova/nova.conf ]; then + ocf_exit_reason "/etc/nova/nova.conf not found" + exit $OCF_ERR_CONFIGURED + fi + ++ # Is the state directory writable? ++ state_dir=$(dirname $statefile) ++ touch "$state_dir/$$" ++ if [ $? != 0 ]; then ++ ocf_exit_reason "Invalid state directory: $state_dir" ++ return $OCF_ERR_ARGS ++ fi ++ rm -f "$state_dir/$$" ++ + NOVA_HOST=$(crudini --get /etc/nova/nova.conf DEFAULT host 2>/dev/null) + if [ $? = 1 ]; then + short_host=$(uname -n | awk -F. '{print $1}') +@@ -198,6 +289,8 @@ + return $rc + } + ++statefile="${HA_RSCTMP}/${OCF_RESOURCE_INSTANCE}.active" ++ + : ${OCF_RESKEY_evacuation_delay=120} + case $__OCF_ACTION in + meta-data) meta_data +@@ -221,3 +314,4 @@ + rc=$? + ocf_log debug "${OCF_RESOURCE_INSTANCE} $__OCF_ACTION : $rc" + exit $rc ++ +diff -uNr a/heartbeat/NovaEvacuate b/heartbeat/NovaEvacuate +--- a/heartbeat/NovaEvacuate 2017-02-02 11:23:38.253510461 +0100 ++++ b/heartbeat/NovaEvacuate 2017-02-02 11:28:49.262432371 +0100 +@@ -1,30 +1,16 @@ + #!/bin/sh + # ++# Copyright 2015 Red Hat, Inc. + # +-# NovaCompute agent manages compute daemons. ++# Description: Manages evacuation of nodes running nova-compute + # +-# Copyright (c) 2015 ++# Authors: Andrew Beekhof + # +-# This program is free software; you can redistribute it and/or modify +-# it under the terms of version 2 of the GNU General Public License as +-# published by the Free Software Foundation. +-# +-# This program is distributed in the hope that it would be useful, but +-# WITHOUT ANY WARRANTY; without even the implied warranty of +-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. +-# +-# Further, this software is distributed without any warranty that it is +-# free of the rightful claim of any third person regarding infringement +-# or the like. Any license provided herein, whether implied or +-# otherwise, applies only to this software file. Patent licenses, if +-# any, provided herein do not apply to combinations of this program with +-# other software, or any other product whatsoever. +-# +-# You should have received a copy of the GNU General Public License +-# along with this program; if not, write the Free Software Foundation, +-# Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. ++# Support: openstack@lists.openstack.org ++# License: Apache Software License (ASL) 2.0 + # + ++ + ####################################################################### + # Initialization: + +@@ -180,7 +166,7 @@ + ocf_log notice "Initiating evacuation of $node" + + fence_compute ${fence_options} -o status -n ${node} +- if [ $? != 0 ]; then ++ if [ $? = 1 ]; then + ocf_log info "Nova does not know about ${node}" + # Dont mark as no because perhaps nova is unavailable right now + continue diff --git a/SOURCES/bz1305549-redis-notify-clients-of-master-being-demoted.patch b/SOURCES/bz1305549-redis-notify-clients-of-master-being-demoted.patch new file mode 100644 index 00000000..f7ba67af --- /dev/null +++ b/SOURCES/bz1305549-redis-notify-clients-of-master-being-demoted.patch @@ -0,0 +1,42 @@ +From f1c2249ef5e8524ddb986f0df879d5f18e935da3 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Fri, 20 Jan 2017 09:17:15 +0100 +Subject: [PATCH] redis: use "CLIENT KILL type normal" to notify clients of + master being demoted + +--- + heartbeat/redis | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/heartbeat/redis b/heartbeat/redis +index 1ea0025..d08e57a 100755 +--- a/heartbeat/redis ++++ b/heartbeat/redis +@@ -436,6 +436,11 @@ function demote() { + local master_host + local master_port + ++ # client kill is only supported in Redis 2.8.12 or greater ++ version=$(redis_client -v | awk '{print $NF}') ++ ocf_version_cmp "$version" "2.8.11" ++ client_kill=$? ++ + CHECK_SLAVE_STATE=1 + monitor + status=$? +@@ -478,9 +483,15 @@ function demote() { + while true; do + # Wait infinite if replication is syncing + # Then start/demote operation timeout determines timeout ++ if [ "$client_kill" -eq 2 ]; then ++ redis_client CLIENT PAUSE 2000 ++ fi + monitor + status=$? + if (( status == OCF_SUCCESS )); then ++ if [ "$client_kill" -eq 2 ]; then ++ redis_client CLIENT KILL type normal ++ fi + return $OCF_SUCCESS + fi + diff --git a/SOURCES/bz1307160-virtualdomain-fix-unnecessary-error-when-probing-nonexistent-domain.patch b/SOURCES/bz1307160-virtualdomain-fix-unnecessary-error-when-probing-nonexistent-domain.patch new file mode 100644 index 00000000..406be02e --- /dev/null +++ b/SOURCES/bz1307160-virtualdomain-fix-unnecessary-error-when-probing-nonexistent-domain.patch @@ -0,0 +1,20 @@ +diff -uNr a/heartbeat/VirtualDomain b/heartbeat/VirtualDomain +--- a/heartbeat/VirtualDomain 2016-04-26 12:22:22.345053246 +0200 ++++ b/heartbeat/VirtualDomain 2016-04-26 12:24:27.479535075 +0200 +@@ -263,8 +263,6 @@ + + if [ -n "$emulator" ]; then + basename $emulator +- else +- ocf_log error "Unable to determine emulator for $DOMAIN_NAME" + fi + } + +@@ -301,6 +299,7 @@ + ;; + # This can be expanded to check for additional emulators + *) ++ ocf_log error "Unable to determine emulator for $DOMAIN_NAME" + ;; + esac + diff --git a/SOURCES/bz1316130-systemd-drop-in-clvmd-LVM.patch b/SOURCES/bz1316130-systemd-drop-in-clvmd-LVM.patch new file mode 100644 index 00000000..153de9c3 --- /dev/null +++ b/SOURCES/bz1316130-systemd-drop-in-clvmd-LVM.patch @@ -0,0 +1,136 @@ +diff -uNr a/configure.ac b/configure.ac +--- a/configure.ac 2017-05-03 10:00:54.396040173 +0200 ++++ b/configure.ac 2017-05-03 10:07:28.969236697 +0200 +@@ -65,6 +65,21 @@ + AM_CONDITIONAL(OCFT_FEDORA_CASES, test "x$OCFT_TEST_CASES" = "xfedora" ) + AM_CONDITIONAL(OCFT_DEFAULT_CASES, test "x$OCFT_TEST_CASES" = "xdefault" ) + ++AC_ARG_WITH([systemdsystemunitdir], ++ [AS_HELP_STRING([--with-systemdsystemunitdir=DIR], [Directory for systemd service files])],, ++ [with_systemdsystemunitdir=auto]) ++AS_IF([test "x$with_systemdsystemunitdir" = "xyes" -o "x$with_systemdsystemunitdir" = "xauto"], [ ++ def_systemdsystemunitdir=$($PKGCONFIG --variable=systemdsystemunitdir systemd) ++ ++ AS_IF([test "x$def_systemdsystemunitdir" = "x"], ++ [AS_IF([test "x$with_systemdsystemunitdir" = "xyes"], ++ [AC_MSG_ERROR([systemd support requested but pkg-config unable to query systemd package])]) ++ with_systemdsystemunitdir=no], ++ [with_systemdsystemunitdir="$def_systemdsystemunitdir"])]) ++AS_IF([test "x$with_systemdsystemunitdir" != "xno"], ++ [AC_SUBST([systemdsystemunitdir], [$with_systemdsystemunitdir])]) ++AM_CONDITIONAL([HAVE_SYSTEMD], [test "x$with_systemdsystemunitdir" != "xno"]) ++ + dnl + dnl AM_INIT_AUTOMAKE([1.11.1 foreign dist-bzip2 dist-xz]) + dnl +@@ -857,6 +872,7 @@ + heartbeat/ocf-directories \ + heartbeat/ocf-shellfuncs \ + heartbeat/shellfuncs \ ++systemd/Makefile \ + tools/Makefile \ + tools/ocf-tester \ + tools/ocft/Makefile \ +diff -uNr a/heartbeat/clvm b/heartbeat/clvm +--- a/heartbeat/clvm 2017-05-03 10:00:54.560038569 +0200 ++++ b/heartbeat/clvm 2017-05-03 10:01:13.309855171 +0200 +@@ -353,6 +353,18 @@ + return $? + fi + ++ # systemd drop-in to stop process before storage services during ++ # shutdown/reboot ++ if ps -p 1 | grep -q systemd ; then ++ systemdrundir="/run/systemd/system/resource-agents-deps.target.d" ++ mkdir "$systemdrundir" ++ cat > "$systemdrundir/99-clvmd.conf" < "$systemdrundir/99-LVM.conf" < +Date: Fri, 18 Mar 2016 11:10:17 +0100 +Subject: [PATCH] oracle: "shutdown immediate;" is needed after cleanup to be + able to recover from the ORA-01081 error + +--- + heartbeat/oracle | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/heartbeat/oracle b/heartbeat/oracle +index 951221c..5a8aca8 100755 +--- a/heartbeat/oracle ++++ b/heartbeat/oracle +@@ -611,6 +611,7 @@ oracle_start() { + if echo "$output" | grep ORA-01081 >/dev/null 2>&1; then + ocf_log info "ORA-01081 error found, trying to cleanup oracle (dbstart_mount output: $output)" + ora_cleanup ++ output=`dbasql dbstop_immediate` + output=`dbasql dbstart_mount` + fi + fi diff --git a/SOURCES/bz1320783-nova-compute-wait-fix-invalid-hostname-issue.patch b/SOURCES/bz1320783-nova-compute-wait-fix-invalid-hostname-issue.patch new file mode 100644 index 00000000..4f9e7cb0 --- /dev/null +++ b/SOURCES/bz1320783-nova-compute-wait-fix-invalid-hostname-issue.patch @@ -0,0 +1,169 @@ +diff -uNr a/heartbeat/nova-compute-wait b/heartbeat/nova-compute-wait +--- a/heartbeat/nova-compute-wait 2016-05-13 11:50:54.434532591 +0200 ++++ b/heartbeat/nova-compute-wait 2016-05-13 12:04:41.997856291 +0200 +@@ -52,34 +52,25 @@ + + + +- +-Authorization URL for connecting to keystone in admin context +- +-Authorization URL ++Deprecated - do not use anymore. ++Deprecated - do not use anymore + + + + +- +-Username for connecting to keystone in admin context +- +-Username ++Deprecated - do not use anymore. ++Deprecated - do not use anymore + + + +- +-Password for connecting to keystone in admin context +- +-Password ++Deprecated - do not use anymore. ++Deprecated - do not use anymore + + + + +- +-Tenant name for connecting to keystone in admin context. +-Note that with Keystone V3 tenant names are only unique within a domain. +- +-Tenant name ++Deprecated - do not use anymore. ++Deprecated - do not use anymore + + + +@@ -92,18 +83,14 @@ + + + +- +-Nova API location (internal, public or admin URL) +- +-Nova API location (internal, public or admin URL) ++Deprecated - do not use anymore. ++Deprecated - do not use anymore + + + + +- +-Disable shared storage recovery for instances. Use at your own risk! +- +-Disable shared storage recovery for instances ++Deprecated - do not use anymore. ++Deprecated - do not use anymore + + + +@@ -186,9 +173,8 @@ + + nova_validate() { + rc=$OCF_SUCCESS +- fence_options="" + +- check_binary openstack-config ++ check_binary crudini + check_binary nova-compute + + if [ ! -f /etc/nova/nova.conf ]; then +@@ -196,81 +182,14 @@ + exit $OCF_ERR_CONFIGURED + fi + +- if [ -z "${OCF_RESKEY_auth_url}" ]; then +- ocf_exit_reason "auth_url not configured" +- exit $OCF_ERR_CONFIGURED +- fi +- +- fence_options="${fence_options} -k ${OCF_RESKEY_auth_url}" +- +- if [ -z "${OCF_RESKEY_username}" ]; then +- ocf_exit_reason "username not configured" +- exit $OCF_ERR_CONFIGURED +- fi +- +- fence_options="${fence_options} -l ${OCF_RESKEY_username}" +- +- if [ -z "${OCF_RESKEY_password}" ]; then +- ocf_exit_reason "password not configured" +- exit $OCF_ERR_CONFIGURED +- fi +- +- fence_options="${fence_options} -p ${OCF_RESKEY_password}" +- +- if [ -z "${OCF_RESKEY_tenant_name}" ]; then +- ocf_exit_reason "tenant_name not configured" +- exit $OCF_ERR_CONFIGURED +- fi +- +- fence_options="${fence_options} -t ${OCF_RESKEY_tenant_name}" +- +- if [ -n "${OCF_RESKEY_domain}" ]; then +- fence_options="${fence_options} -d ${OCF_RESKEY_domain}" +- fi +- +- if [ -n "${OCF_RESKEY_no_shared_storage}" ]; then +- if ocf_is_true "${OCF_RESKEY_no_shared_storage}"; then +- fence_options="${fence_options} --no-shared-storage" +- fi +- fi +- +- if [ -n "${OCF_RESKEY_endpoint_type}" ]; then +- case ${OCF_RESKEY_endpoint_type} in +- adminURL|publicURL|internalURL) ;; +- *) +- ocf_exit_reason "endpoint_type ${OCF_RESKEY_endpoint_type} not valid. Use adminURL or publicURL or internalURL" +- exit $OCF_ERR_CONFIGURED +- ;; +- esac +- fence_options="${fence_options} -e ${OCF_RESKEY_endpoint_type}" +- fi +- +- # we take a chance here and hope that host is either not configured +- # or configured in nova.conf +- +- NOVA_HOST=$(openstack-config --get /etc/nova/nova.conf DEFAULT host 2>/dev/null) ++ NOVA_HOST=$(crudini --get /etc/nova/nova.conf DEFAULT host 2>/dev/null) + if [ $? = 1 ]; then +- if [ "x${OCF_RESKEY_domain}" != x ]; then +- NOVA_HOST=$(uname -n | awk -F. '{print $1}') +- else +- NOVA_HOST=$(uname -n) +- fi +- fi +- +- # We only need to check a configured value, calculated ones are fine +- openstack-config --get /etc/nova/nova.conf DEFAULT host 2>/dev/null +- if [ $? = 0 ]; then +- if [ "x${OCF_RESKEY_domain}" != x ]; then +- short_host=$(uname -n | awk -F. '{print $1}') +- if [ "x$NOVA_HOST" != "x${short_host}" ]; then +- ocf_exit_reason "Invalid Nova host name, must be ${short_host} in order for instance recovery to function" +- rc=$OCF_ERR_CONFIGURED +- fi +- +- elif [ "x$NOVA_HOST" != "x$(uname -n)" ]; then +- ocf_exit_reason "Invalid Nova host name, must be $(uname -n) in order for instance recovery to function" +- rc=$OCF_ERR_CONFIGURED +- fi ++ short_host=$(uname -n | awk -F. '{print $1}') ++ if [ "x${OCF_RESKEY_domain}" != x ]; then ++ NOVA_HOST=${short_host}.${OCF_RESKEY_domain} ++ else ++ NOVA_HOST=$(uname -n) ++ fi + fi + + if [ $rc != $OCF_SUCCESS ]; then diff --git a/SOURCES/bz1325453-nfsserver-var-lib-nfs-fix.patch b/SOURCES/bz1325453-nfsserver-var-lib-nfs-fix.patch new file mode 100644 index 00000000..7b96ee80 --- /dev/null +++ b/SOURCES/bz1325453-nfsserver-var-lib-nfs-fix.patch @@ -0,0 +1,29 @@ +diff -uNr a/heartbeat/nfsserver b/heartbeat/nfsserver +--- a/heartbeat/nfsserver 2016-04-11 10:28:05.988977035 +0200 ++++ b/heartbeat/nfsserver 2016-04-11 16:31:50.150445968 +0200 +@@ -332,7 +332,11 @@ + + case $EXEC_MODE in + 1) ${OCF_RESKEY_nfs_init_script} $cmd;; +- 2) systemctl $cmd ${svc}.service ;; ++ 2) if ! echo $svc | grep -q "\."; then ++ svc="${svc}.service" ++ fi ++ systemctl $cmd $svc ++ ;; + esac + } + +@@ -587,6 +591,12 @@ + ocf_log debug "$fp is already bound to /var/lib/nfs" + return 0 + fi ++ ++ if nfs_exec status var-lib-nfs-rpc_pipefs.mount; then ++ ocf_log debug "/var/lib/nfs/rpc_pipefs already mounted. Unmounting in preparation to bind mount nfs dir" ++ nfs_exec stop var-lib-nfs-rpc_pipefs.mount ++ fi ++ + mount --bind $fp /var/lib/nfs + [ $SELINUX_ENABLED -eq 0 ] && restorecon /var/lib/nfs + } diff --git a/SOURCES/bz1328018-garbd-Introduces-garbd-resource-agent.patch b/SOURCES/bz1328018-garbd-Introduces-garbd-resource-agent.patch new file mode 100644 index 00000000..af182864 --- /dev/null +++ b/SOURCES/bz1328018-garbd-Introduces-garbd-resource-agent.patch @@ -0,0 +1,474 @@ +From beb8dd713fa3a15ca01738de33f2031d1e5925d9 Mon Sep 17 00:00:00 2001 +From: Damien Ciabrini +Date: Wed, 1 Jun 2016 17:14:04 +0200 +Subject: [PATCH 1/2] garbd: Introduces garbd resource-agent + +--- + heartbeat/garbd | 417 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 417 insertions(+) + create mode 100755 heartbeat/garbd + +diff --git a/heartbeat/garbd b/heartbeat/garbd +new file mode 100755 +index 0000000..950df76 +--- /dev/null ++++ b/heartbeat/garbd +@@ -0,0 +1,417 @@ ++#!/bin/sh ++# ++# Copyright (c) 2015 Damien Ciabrini ++# All Rights Reserved. ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of version 2 of the GNU General Public License as ++# published by the Free Software Foundation. ++# ++# This program is distributed in the hope that it would be useful, but ++# WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++# ++# Further, this software is distributed without any warranty that it is ++# free of the rightful claim of any third person regarding infringement ++# or the like. Any license provided herein, whether implied or ++# otherwise, applies only to this software file. Patent licenses, if ++# any, provided herein do not apply to combinations of this program with ++# other software, or any other product whatsoever. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write the Free Software Foundation, ++# Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. ++# ++ ++## ++# README. ++# ++# Resource agent for garbd, the Galera arbitrator ++# ++# You can use this agent if you run an even number of galera nodes, ++# and you want an additional node to avoid split-brain situations. ++# ++# garbd requires that a Galera cluster is running, so make sure to ++# add a proper ordering constraint to the cluster, e.g.: ++# ++# pcs constraint order galera-master then garbd ++# ++# If you add garbd to the cluster while Galera is not running, you ++# might want to disable it before setting up ordering constraint, e.g.: ++# ++# pcs resource create garbd garbd \ ++# wsrep_cluster_address=gcomm://node1:4567,node2:4567 \ ++# meta target-role=stopped ++# ++# Use location constraints to avoid running galera and garbd on ++# the same node, e.g.: ++# ++# pcs constraint colocation add garbd with galera-master -INFINITY ++# pcs constraint location garbd prefers node3=INFINITY ++# ++## ++ ++####################################################################### ++# Initialization: ++ ++: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat} ++. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs ++ ++####################################################################### ++# Set default paramenter values ++ ++OCF_RESKEY_binary_default="/usr/sbin/garbd" ++OCF_RESKEY_log_default="/var/log/garbd.log" ++OCF_RESKEY_pid_default="/var/run/garbd.pid" ++OCF_RESKEY_user_default="mysql" ++if [ "X${HOSTOS}" = "XOpenBSD" ];then ++ OCF_RESKEY_group_default="_mysql" ++else ++ OCF_RESKEY_group_default="mysql" ++fi ++ ++: ${OCF_RESKEY_binary=${OCF_RESKEY_binary_default}} ++: ${OCF_RESKEY_log=${OCF_RESKEY_log_default}} ++: ${OCF_RESKEY_pid=${OCF_RESKEY_pid_default}} ++: ${OCF_RESKEY_user=${OCF_RESKEY_user_default}} ++: ${OCF_RESKEY_group=${OCF_RESKEY_group_default}} ++ ++usage() { ++ cat < ++ ++ ++1.0 ++ ++ ++Resource script for managing Galera arbitrator. ++ ++Manages a galera arbitrator instance ++ ++ ++ ++ ++Location of the Galera arbitrator binary ++ ++garbd server binary ++ ++ ++ ++ ++ ++User running the garbd process ++ ++garbd user ++ ++ ++ ++ ++ ++Group running garbd (for logfile permissions) ++ ++garbd group ++ ++ ++ ++ ++ ++The logfile to be used for garbd. ++ ++Galera arbitrator log file ++ ++ ++ ++ ++ ++The pidfile to be used for garbd. ++ ++Galera arbitrator pidfile ++ ++ ++ ++ ++ ++Additional parameters which are passed to garbd on startup. ++ ++Additional parameters to pass to garbd ++ ++ ++ ++ ++ ++The galera cluster address. This takes the form of: ++gcomm://node:port,node:port,node:port ++ ++Unlike Galera servers, port is mandatory for garbd. ++ ++Galera cluster address ++ ++ ++ ++ ++ ++The group name of the Galera cluster to connect to. ++ ++Galera cluster name ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++END ++} ++ ++ ++garbd_start() ++{ ++ local rc ++ local pid ++ local start_wait ++ local garbd_params ++ ++ garbd_status info ++ rc=$? ++ if [ $rc -eq $OCF_SUCCESS ]; then ++ ocf_exit_reason "garbd started outside of the cluster's control" ++ return $OCF_ERR_GENERIC; ++ fi ++ ++ touch $OCF_RESKEY_log ++ chown $OCF_RESKEY_user:$OCF_RESKEY_group $OCF_RESKEY_log ++ chmod 0640 $OCF_RESKEY_log ++ [ -x /sbin/restorecon ] && /sbin/restorecon $OCF_RESKEY_log ++ ++ garbd_params="--address=${OCF_RESKEY_wsrep_cluster_address} \ ++ --group ${OCF_RESKEY_wsrep_cluster_name} \ ++ --log ${OCF_RESKEY_log}" ++ ++ if [ ! -z "${OCF_RESKEY_options}" ]; then ++ garbd_params="${garbd_params} --options=${OCF_RESKEY_options}" ++ fi ++ ++ # garbd has no parameter to run as a specific user, ++ # so we need to start it by our own means ++ pid=$(su - -s /bin/sh $OCF_RESKEY_user -c "${OCF_RESKEY_binary} ${garbd_params} >/dev/null 2>&1 & echo \$!") ++ ++ # garbd doesn't create a pidfile either, so we create our own ++ echo $pid > $OCF_RESKEY_pid ++ if [ $? -ne 0 ]; then ++ ocf_exit_reason "Cannot create pidfile for garbd at $OCF_RESKEY_pid (rc=$?), please check your installation" ++ return $OCF_ERR_GENERIC ++ fi ++ ++ # Spin waiting for garbd to connect to the cluster. ++ # Let the CRM/LRM time us out if required. ++ start_wait=1 ++ while [ $start_wait -eq 1 ]; do ++ garbd_monitor info ++ rc=$? ++ if [ $rc -eq $OCF_NOT_RUNNING ]; then ++ ocf_exit_reason "garbd failed to start (pid=$pid), check logs in ${OCF_RESKEY_log}" ++ return $OCF_ERR_GENERIC ++ elif [ $rc -eq $OCF_SUCCESS ]; then ++ start_wait=0 ++ fi ++ sleep 2 ++ done ++ ++ ocf_log info "garbd connected to cluster \"${OCF_RESKEY_wsrep_cluster_name}\"" ++ return $OCF_SUCCESS ++} ++ ++garbd_status() ++{ ++ local loglevel=$1 ++ local rc ++ ocf_pidfile_status $OCF_RESKEY_pid ++ rc=$? ++ ++ if [ $rc -eq 0 ]; then ++ return $OCF_SUCCESS ++ elif [ $rc -eq 2 ]; then ++ return $OCF_NOT_RUNNING ++ else ++ # clean up if pidfile is stale ++ if [ $rc -eq 1 ]; then ++ ocf_log $loglevel "garbd not running: removing old PID file" ++ rm -f $OCF_RESKEY_pid ++ fi ++ return $OCF_ERR_GENERIC ++ fi ++} ++ ++garbd_monitor() ++{ ++ local rc ++ local pid ++ local loglevel=$1 ++ ++ # Set loglevel to info during probe ++ if ocf_is_probe; then ++ loglevel="info" ++ fi ++ ++ garbd_status $loglevel ++ rc=$? ++ ++ # probe just wants to know if garbd is running or not ++ if [ ocf_is_probe -a $rc -ne $OCF_SUCCESS ]; then ++ rc=$OCF_NOT_RUNNING ++ fi ++ ++ # Consider garbd is working if it's connected to at least ++ # one node in the galera cluster. ++ # Note: a Galera node in Non-Primary state will be ++ # stopped by the galera RA. So we can assume that ++ # garbd will always be connected to the right partition ++ if [ $rc -eq $OCF_SUCCESS ]; then ++ pid=`cat $OCF_RESKEY_pid 2> /dev/null ` ++ netstat -tnp 2>/dev/null | grep -s -q "ESTABLISHED.*${pid}/" ++ if [ $? -ne 0 ]; then ++ ocf_log $loglevel "garbd disconnected from cluster \"${OCF_RESKEY_wsrep_cluster_name}\"" ++ rc=$OCF_ERR_GENERIC ++ fi ++ fi ++ ++ return $rc ++} ++ ++garbd_stop() ++{ ++ local rc ++ local pid ++ ++ if [ ! -f $OCF_RESKEY_pid ]; then ++ ocf_log info "garbd is not running" ++ return $OCF_SUCCESS ++ fi ++ ++ pid=`cat $OCF_RESKEY_pid 2> /dev/null ` ++ ++ ocf_log info "stopping garbd" ++ ++ # make sure the process is stopped ++ ocf_stop_processes TERM 10 $pid ++ rc=$? ++ ++ if [ $rc -ne 0 ]; then ++ return $OCF_ERR_GENERIC ++ else ++ rm -f $OCF_RESKEY_pid ++ ocf_log info "garbd stopped" ++ return $OCF_SUCCESS ++ fi ++} ++ ++garbd_validate() ++{ ++ if ! have_binary "$OCF_RESKEY_binary"; then ++ ocf_exit_reason "Setup problem: couldn't find command: $OCF_RESKEY_binary" ++ return $OCF_ERR_INSTALLED; ++ fi ++ ++ if ! have_binary "netstat"; then ++ ocf_exit_reason "Setup problem: couldn't find command: netstat" ++ return $OCF_ERR_INSTALLED; ++ fi ++ ++ if [ -z "$OCF_RESKEY_wsrep_cluster_address" ]; then ++ ocf_exit_reason "garbd must be configured with a wsrep_cluster_address value." ++ return $OCF_ERR_CONFIGURED ++ fi ++ ++ # unlike galera RA, ports must be set in cluster address for garbd ++ # https://github.com/codership/galera/issues/98 ++ for node in $(echo "$OCF_RESKEY_wsrep_cluster_address" | sed 's/gcomm:\/\///g' | tr -d ' ' | tr -s ',' ' '); do ++ echo $node | grep -s -q ':[1-9][0-9]*$' ++ if [ $? -ne 0 ]; then ++ ocf_exit_reason "wsrep_cluster_address must specify ports (gcomm://node1:port,node2:port)." ++ return $OCF_ERR_CONFIGURED ++ fi ++ done ++ ++ # Ensure that the encryption method is set if garbd is configured ++ # to use SSL. ++ echo $OCF_RESKEY_options | grep -s -q -i -E '\bsocket.ssl_(key|cert)=' ++ if [ $? -eq 0 ]; then ++ echo $OCF_RESKEY_options | grep -s -q -i -E '\bsocket.ssl_cipher=' ++ if [ $? -ne 0 ]; then ++ ocf_exit_reason "option socket.ssl_cipher must be set if SSL is enabled." ++ return $OCF_ERR_CONFIGURED ++ fi ++ fi ++ ++ if [ -z "$OCF_RESKEY_wsrep_cluster_name" ]; then ++ ocf_exit_reason "garbd must be configured with a wsrep_cluster_name value." ++ return $OCF_ERR_CONFIGURED ++ fi ++ ++ if ! getent passwd $OCF_RESKEY_user >/dev/null 2>&1; then ++ ocf_exit_reason "User $OCF_RESKEY_user doesn't exist" ++ return $OCF_ERR_INSTALLED ++ fi ++ ++ if ! getent group $OCF_RESKEY_group >/dev/null 2>&1; then ++ ocf_exit_reason "Group $OCF_RESKEY_group doesn't exist" ++ return $OCF_ERR_INSTALLED ++ fi ++ ++ return $OCF_SUCCESS ++} ++ ++case "$1" in ++ meta-data) meta_data ++ exit $OCF_SUCCESS;; ++ usage|help) usage ++ exit $OCF_SUCCESS;; ++esac ++ ++garbd_validate ++rc=$? ++ ++# trap configuration errors early, but don't block stop in such cases ++LSB_STATUS_STOPPED=3 ++if [ $rc -ne 0 ]; then ++ case "$1" in ++ stop) exit $OCF_SUCCESS;; ++ status) exit $LSB_STATUS_STOPPED;; ++ *) exit $rc;; ++ esac ++fi ++ ++# What kind of method was invoked? ++case "$1" in ++ start) garbd_start;; ++ stop) garbd_stop;; ++ status) garbd_status err;; ++ monitor) garbd_monitor err;; ++ promote) garbd_promote;; ++ demote) garbd_demote;; ++ validate-all) exit $OCF_SUCCESS;; ++ ++ *) usage ++ exit $OCF_ERR_UNIMPLEMENTED;; ++esac +-- +2.5.5 + + +From f36298aa97fc4cbed3e2eff28d6821f4314becbe Mon Sep 17 00:00:00 2001 +From: Damien Ciabrini +Date: Fri, 3 Jun 2016 18:27:38 +0200 +Subject: [PATCH 2/2] garbd: fix install and man page + +--- + doc/man/Makefile.am | 1 + + heartbeat/Makefile.am | 1 + + 2 files changed, 2 insertions(+) + +diff --git a/doc/man/Makefile.am b/doc/man/Makefile.am +index 5e28895..25fb29b 100644 +--- a/doc/man/Makefile.am ++++ b/doc/man/Makefile.am +@@ -105,6 +105,7 @@ man_MANS = ocf_heartbeat_AoEtarget.7 \ + ocf_heartbeat_exportfs.7 \ + ocf_heartbeat_fio.7 \ + ocf_heartbeat_galera.7 \ ++ ocf_heartbeat_garbd.7 \ + ocf_heartbeat_iSCSILogicalUnit.7 \ + ocf_heartbeat_iSCSITarget.7 \ + ocf_heartbeat_iface-bridge.7 \ +diff --git a/heartbeat/Makefile.am b/heartbeat/Makefile.am +index b70c104..df0e3b8 100644 +--- a/heartbeat/Makefile.am ++++ b/heartbeat/Makefile.am +@@ -76,6 +76,7 @@ ocf_SCRIPTS = ClusterMon \ + Filesystem \ + fio \ + galera \ ++ garbd \ + ids \ + iscsi \ + ICP \ +-- +2.5.5 + diff --git a/SOURCES/bz1328386-1-oracle-monprofile-container-databases.patch b/SOURCES/bz1328386-1-oracle-monprofile-container-databases.patch new file mode 100644 index 00000000..975cce28 --- /dev/null +++ b/SOURCES/bz1328386-1-oracle-monprofile-container-databases.patch @@ -0,0 +1,24 @@ +From 8ec7eb9fa6ccc242555eea7e3f0ebd7537799943 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Tue, 19 Apr 2016 14:27:39 +0200 +Subject: [PATCH] oracle: inform user that monprofile must start with C## for + container databases + +--- + heartbeat/oracle | 3 +++ + 1 file changed, 3 insertions(+) + +diff --git a/heartbeat/oracle b/heartbeat/oracle +index 5a8aca8..d68fa6e 100755 +--- a/heartbeat/oracle ++++ b/heartbeat/oracle +@@ -402,6 +402,9 @@ check_mon_profile() { + output=`dbasql mk_mon_profile show_mon_profile` + if echo "$output" | grep -iw "^$MONPROFILE" >/dev/null; then + return 0 ++ elif echo "$output" | grep ORA-65140 >/dev/null 2>&1; then ++ ocf_exit_reason "monprofile must start with C## for container databases" ++ return $OCF_ERR_CONFIGURED + else + ocf_log err "could not create $MONPROFILE oracle profile" + ocf_log err "sqlplus output: $output" diff --git a/SOURCES/bz1328386-2-oracle-monprofile-container-databases.patch b/SOURCES/bz1328386-2-oracle-monprofile-container-databases.patch new file mode 100644 index 00000000..c0774d9b --- /dev/null +++ b/SOURCES/bz1328386-2-oracle-monprofile-container-databases.patch @@ -0,0 +1,49 @@ +From f84cdaa6ecf0febb6d33733bfdb30f3d41f615e1 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Mon, 29 Aug 2016 16:54:30 +0200 +Subject: [PATCH] oracle: fix issue with C## in monprofile + +--- + heartbeat/oracle | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/heartbeat/oracle b/heartbeat/oracle +index e8e6148..da322a7 100755 +--- a/heartbeat/oracle ++++ b/heartbeat/oracle +@@ -371,7 +371,7 @@ show_mon_profile() { + } + mk_mon_profile() { + cat< +Date: Mon, 29 Aug 2016 17:33:01 +0200 +Subject: [PATCH] oracle: add quotes for monuser and monpassword and inform + user to start monuser with C## if it's a container database + +--- + heartbeat/oracle | 17 ++++++++++------- + 1 file changed, 10 insertions(+), 7 deletions(-) + +diff --git a/heartbeat/oracle b/heartbeat/oracle +index da322a7..6fad5bc 100755 +--- a/heartbeat/oracle ++++ b/heartbeat/oracle +@@ -291,7 +291,7 @@ dbasql() { + runsql "connect / as sysdba" $* + } + monsql() { +- runsql "connect $MONUSR/\"$MONPWD\"" $* ++ runsql "connect \"$MONUSR\"/\"$MONPWD\"" $* + } + # use dbasql_one if the query should result in a single line output + # at times people stuff commands in oracle .profile +@@ -379,19 +379,19 @@ show_mon_user() { + } + mk_mon_user() { + cat</dev/null; then + return 0 ++ elif echo "$output" | grep ORA-65096 >/dev/null 2>&1; then ++ ocf_exit_reason "monuser must start with C## for container databases" ++ return $OCF_ERR_CONFIGURED + else + ocf_exit_reason "could not create $MONUSR oracle user" + ocf_log err "sqlplus output: $output" +@@ -757,7 +760,7 @@ MONUSR=${OCF_RESKEY_monuser:-$OCF_RESKEY_monuser_default} + MONPWD=${OCF_RESKEY_monpassword:-$OCF_RESKEY_monpassword_default} + MONPROFILE=${OCF_RESKEY_monprofile:-$OCF_RESKEY_monprofile_default} + +-MONUSR=$(echo $MONUSR | awk '{print toupper($0)}') ++MONUSR=$(echo "$MONUSR" | awk '{print toupper($0)}') + MONPROFILE=$(echo "$MONPROFILE" | awk '{print toupper($0)}') + OCF_REQUIRED_PARAMS="sid" + OCF_REQUIRED_BINARIES="sqlplus" diff --git a/SOURCES/bz1337109-tickle_tcp-fix.patch b/SOURCES/bz1337109-tickle_tcp-fix.patch new file mode 100644 index 00000000..fd2363e0 --- /dev/null +++ b/SOURCES/bz1337109-tickle_tcp-fix.patch @@ -0,0 +1,23 @@ +From 1e3c0b11d68b8713f20abe12d6997eb853def797 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Tue, 19 Apr 2016 10:15:50 +0200 +Subject: [PATCH] tickle_tcp: Fix "Failed to open raw socket (Invalid + argument)" issue + +--- + tools/tickle_tcp.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tools/tickle_tcp.c b/tools/tickle_tcp.c +index cf0bdcb..7c5a537 100644 +--- a/tools/tickle_tcp.c ++++ b/tools/tickle_tcp.c +@@ -245,7 +245,7 @@ int send_tickle_ack(const sock_addr *dst, + ip4pkt.tcp.window = htons(1234); + ip4pkt.tcp.check = tcp_checksum((uint16_t *)&ip4pkt.tcp, sizeof(ip4pkt.tcp), &ip4pkt.ip); + +- s = socket(AF_INET, SOCK_RAW, htons(IPPROTO_RAW)); ++ s = socket(AF_INET, SOCK_RAW, IPPROTO_RAW); + if (s == -1) { + fprintf(stderr, "Failed to open raw socket (%s)\n", strerror(errno)); + return -1; diff --git a/SOURCES/bz1337124-mysql-use-replication_port-parameter.patch b/SOURCES/bz1337124-mysql-use-replication_port-parameter.patch new file mode 100644 index 00000000..ef3aa56d --- /dev/null +++ b/SOURCES/bz1337124-mysql-use-replication_port-parameter.patch @@ -0,0 +1,55 @@ +From 98e235caa31c7cc73a834d8046e6f2ec2d04b832 Mon Sep 17 00:00:00 2001 +From: Marian Marinov +Date: Sun, 10 Apr 2016 22:44:16 +0300 +Subject: [PATCH] heartbeat/mysql: Handle non-standard mysql server port + +Signed-off-by: Marian Marinov +--- + heartbeat/mysql | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/heartbeat/mysql b/heartbeat/mysql +index e2d54dd..be914d3 100755 +--- a/heartbeat/mysql ++++ b/heartbeat/mysql +@@ -549,6 +549,7 @@ set_master() { + + ocf_run $MYSQL $MYSQL_OPTIONS_REPL \ + -e "CHANGE MASTER TO MASTER_HOST='$new_master', \ ++ MASTER_PORT=$OCF_RESKEY_replication_port, \ + MASTER_USER='$OCF_RESKEY_replication_user', \ + MASTER_PASSWORD='$OCF_RESKEY_replication_passwd' $master_params" + rm -f $tmpfile +-- +2.5.5 + +From e78f106cc5edabc50eb3622ce384ed2493250ec5 Mon Sep 17 00:00:00 2001 +From: Mathieu Peltier +Date: Thu, 6 Nov 2014 17:16:38 +0100 +Subject: [PATCH] Modified replication_user description: RELOAD privilege is + required for RESET SLAVE or RESET SLAVE ALL command. + +--- + heartbeat/mysql | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/heartbeat/mysql b/heartbeat/mysql +index d895369..df65502 100755 +--- a/heartbeat/mysql ++++ b/heartbeat/mysql +@@ -211,9 +211,9 @@ Additional parameters which are passed to the mysqld on startup. + MySQL replication user. This user is used for starting and stopping + MySQL replication, for setting and resetting the master host, and for + setting and unsetting read-only mode. Because of that, this user must +-have SUPER, REPLICATION SLAVE, REPLICATION CLIENT, and PROCESS +-privileges on all nodes within the cluster. Mandatory if you define +-a master-slave resource. ++have SUPER, REPLICATION SLAVE, REPLICATION CLIENT, PROCESS and RELOAD ++privileges on all nodes within the cluster. Mandatory if you define a ++master-slave resource. + + MySQL replication user + +-- +2.5.5 + diff --git a/SOURCES/bz1337615-nfsserver-rpcpipefs_dir.patch b/SOURCES/bz1337615-nfsserver-rpcpipefs_dir.patch new file mode 100644 index 00000000..45a802d2 --- /dev/null +++ b/SOURCES/bz1337615-nfsserver-rpcpipefs_dir.patch @@ -0,0 +1,60 @@ +diff -uNr a/heartbeat/nfsserver b/heartbeat/nfsserver +--- a/heartbeat/nfsserver 2016-07-21 12:38:01.298076314 +0200 ++++ b/heartbeat/nfsserver 2016-07-21 12:39:05.345432538 +0200 +@@ -245,14 +245,8 @@ + fp="$OCF_RESKEY_nfs_shared_infodir" + : ${OCF_RESKEY_nfs_notify_cmd="$DEFAULT_NOTIFY_CMD"} + : ${OCF_RESKEY_nfs_notify_foreground="$DEFAULT_NOTIFY_FOREGROUND"} +- +-if [ -z ${OCF_RESKEY_rpcpipefs_dir} ]; then +- rpcpipefs_make_dir=$fp/rpc_pipefs +- rpcpipefs_umount_dir=${DEFAULT_RPCPIPEFS_DIR} +-else +- rpcpipefs_make_dir=${OCF_RESKEY_rpcpipefs_dir} +- rpcpipefs_umount_dir=${OCF_RESKEY_rpcpipefs_dir} +-fi ++: ${OCF_RESKEY_rpcpipefs_dir="$DEFAULT_RPCPIPEFS_DIR"} ++OCF_RESKEY_rpcpipefs_dir=${OCF_RESKEY_rpcpipefs_dir%/} + + # Use statd folder if it exists + if [ -d "/var/lib/nfs/statd" ]; then +@@ -554,7 +548,7 @@ + fi + + [ -d "$fp" ] || mkdir -p $fp +- [ -d "$rpcpipefs_make_dir" ] || mkdir -p $rpcpipefs_make_dir ++ [ -d "$OCF_RESKEY_rpcpipefs_dir" ] || mkdir -p $OCF_RESKEY_rpcpipefs_dir + [ -d "$fp/v4recovery" ] || mkdir -p $fp/v4recovery + + [ -d "$fp/$STATD_DIR" ] || mkdir -p "$fp/$STATD_DIR" +@@ -603,9 +597,18 @@ + + unbind_tree () + { +- if `mount | grep -q " on $rpcpipefs_umount_dir"`; then +- umount -t rpc_pipefs $rpcpipefs_umount_dir +- fi ++ local i=1 ++ while `mount | grep -q " on $OCF_RESKEY_rpcpipefs_dir"` && [ "$i" -le 10 ]; do ++ ocf_log info "Stop: umount ($i/10 attempts)" ++ umount -t rpc_pipefs $OCF_RESKEY_rpcpipefs_dir ++ sleep 1 ++ i=$((i + 1)) ++ done ++ ++ case $EXEC_MODE in ++ [23]) nfs_exec stop var-lib-nfs-rpc_pipefs.mount;; ++ esac ++ + if is_bound /var/lib/nfs; then + umount /var/lib/nfs + fi +@@ -771,6 +774,8 @@ + prepare_directory + bind_tree + ++ mount -t rpc_pipefs sunrpc $OCF_RESKEY_rpcpipefs_dir ++ + # remove the sm-notify pid so sm-notify will be allowed to run again without requiring a reboot. + rm -f /var/run/sm-notify.pid + # diff --git a/SOURCES/bz1342376-2-rabbitmq-cluster-backup-and-restore-users-policies.patch b/SOURCES/bz1342376-2-rabbitmq-cluster-backup-and-restore-users-policies.patch new file mode 100644 index 00000000..153abc94 --- /dev/null +++ b/SOURCES/bz1342376-2-rabbitmq-cluster-backup-and-restore-users-policies.patch @@ -0,0 +1,29 @@ +From 57807fdcd3edf4428e193d43033a56cd9542b150 Mon Sep 17 00:00:00 2001 +From: Peter Lemenkov +Date: Tue, 30 May 2017 13:43:19 +0200 +Subject: [PATCH] [rabbitmq] Typo fix + +Unfortunately we introduced a regression with commit +1f57e26816d8148e0c77ff7573457b8d2599bf8b. This patch addresses it and +fixes #982. + +Thanks @seabres for the heads up. + +Signed-off-by: Peter Lemenkov +--- + heartbeat/rabbitmq-cluster | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/heartbeat/rabbitmq-cluster b/heartbeat/rabbitmq-cluster +index b5060b155..30f032066 100755 +--- a/heartbeat/rabbitmq-cluster ++++ b/heartbeat/rabbitmq-cluster +@@ -455,7 +455,7 @@ rmq_stop() { + {'EXIT', _} -> []; + Any -> Any + end, +- Result /= [] andalso file:write_file(Filename, io_lib:fwrite(\"~p.~n\", [RuntimeParams])) ++ Result /= [] andalso file:write_file(Filename, io_lib:fwrite(\"~p.~n\", [Result])) + end, + + %% Backup users diff --git a/SOURCES/bz1342376-3-rabbitmq-cluster-backup-and-restore-users-policies.patch b/SOURCES/bz1342376-3-rabbitmq-cluster-backup-and-restore-users-policies.patch new file mode 100644 index 00000000..13b1128c --- /dev/null +++ b/SOURCES/bz1342376-3-rabbitmq-cluster-backup-and-restore-users-policies.patch @@ -0,0 +1,24 @@ +From a045342ebe8523d1408afb87b062bb7d71927c46 Mon Sep 17 00:00:00 2001 +From: Dave Holland +Date: Thu, 8 Jun 2017 14:38:15 +0100 +Subject: [PATCH] rabbitmq-cluster: typo fix + +fix a small typo which causes errors in corosync.log e.g. +Jun 08 09:00:14 [6504] overcloud-controller-1.localdomain lrmd: notice: operation_finished: rabbitmq_start_0:7504:stderr [ Error: syntax error before: ')' ] +--- + heartbeat/rabbitmq-cluster | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/heartbeat/rabbitmq-cluster b/heartbeat/rabbitmq-cluster +index 30f032066..1e78d9eca 100755 +--- a/heartbeat/rabbitmq-cluster ++++ b/heartbeat/rabbitmq-cluster +@@ -398,7 +398,7 @@ rmq_start() { + case file:consult(Filename) of + {error, _} -> + ok; +- {ok, [Result]) -> ++ {ok, [Result]} -> + lists:foreach(fun(X) -> mnesia:dirty_write(Table, PostprocessFun(X)) end, Result), + file:delete(Filename) + end diff --git a/SOURCES/bz1342376-rabbitmq-cluster-backup-and-restore-users-policies.patch b/SOURCES/bz1342376-rabbitmq-cluster-backup-and-restore-users-policies.patch new file mode 100644 index 00000000..011e2e83 --- /dev/null +++ b/SOURCES/bz1342376-rabbitmq-cluster-backup-and-restore-users-policies.patch @@ -0,0 +1,167 @@ +From 1f57e26816d8148e0c77ff7573457b8d2599bf8b Mon Sep 17 00:00:00 2001 +From: Peter Lemenkov +Date: Wed, 5 Apr 2017 19:12:26 +0200 +Subject: [PATCH] Backup and restore policies + +- Backup and restore policies. +- Simplify code + +Signed-off-by: Peter Lemenkov +--- + heartbeat/rabbitmq-cluster | 123 ++++++++++++++++++++++++--------------------- + 1 file changed, 66 insertions(+), 57 deletions(-) + +diff --git a/heartbeat/rabbitmq-cluster b/heartbeat/rabbitmq-cluster +index 6a17590..b5060b1 100755 +--- a/heartbeat/rabbitmq-cluster ++++ b/heartbeat/rabbitmq-cluster +@@ -388,83 +388,92 @@ rmq_start() { + return $OCF_ERR_GENERIC + fi + +- # Restore users and users' permissions (if any) ++ # Restore users, user permissions, and policies (if any) + BaseDataDir=`dirname $RMQ_DATA_DIR` +- if [ -f $BaseDataDir/users.erl ] ; then +- rabbitmqctl eval " +- %% Run only if Mnesia is ready. +- lists:any(fun({mnesia,_,_}) -> true; ({_,_,_}) -> false end, application:which_applications()) andalso +- begin +- [WildPattern] = ets:select(mnesia_gvar, [ { {{rabbit_user, wild_pattern}, '\\\$1'}, [], ['\\\$1'] } ]), +- +- %% Read users first +- {ok, [Users]} = file:consult(\"$BaseDataDir/users.erl\"), +- +- Upgrade = fun +- ({internal_user, A, B, C}) -> {internal_user, A, B, C, rabbit_password_hashing_md5}; +- ({internal_user, A, B, C, D}) -> {internal_user, A, B, C, D} +- end, ++ rabbitmqctl eval " ++ %% Run only if Mnesia is ready. ++ lists:any(fun({mnesia,_,_}) -> true; ({_,_,_}) -> false end, application:which_applications()) andalso ++ begin ++ Restore = fun(Table, PostprocessFun, Filename) -> ++ case file:consult(Filename) of ++ {error, _} -> ++ ok; ++ {ok, [Result]) -> ++ lists:foreach(fun(X) -> mnesia:dirty_write(Table, PostprocessFun(X)) end, Result), ++ file:delete(Filename) ++ end ++ end, + +- Downgrade = fun +- ({internal_user, A, B, C}) -> {internal_user, A, B, C}; +- ({internal_user, A, B, C, rabbit_password_hashing_md5}) -> {internal_user, A, B, C}; +- %% Incompatible scheme, so we will loose user's password ('B' value) during conversion. +- %% Unfortunately, this case will require manual intervention - user have to run: +- %% rabbitmqctl change_password +- ({internal_user, A, B, C, _}) -> {internal_user, A, B, C} +- end, ++ %% Restore users + +- case WildPattern of +- %% Version < 3.6.0 +- {internal_user,'_','_','_'} -> +- lists:foreach(fun(X) -> mnesia:dirty_write(rabbit_user, Downgrade(X)) end, Users); +- %% Version >= 3.6.0 +- {internal_user,'_','_','_','_'} -> +- lists:foreach(fun(X) -> mnesia:dirty_write(rabbit_user, Upgrade(X)) end, Users) +- end, ++ Upgrade = fun ++ ({internal_user, A, B, C}) -> {internal_user, A, B, C, rabbit_password_hashing_md5}; ++ ({internal_user, A, B, C, D}) -> {internal_user, A, B, C, D} ++ end, + +- ok = file:delete(\"$BaseDataDir/users.erl\") +- end. +- " +- fi +- if [ -f $BaseDataDir/users_perms.erl ] ; then +- rabbitmqctl eval " +- %% Run only if Mnesia is ready. +- lists:any(fun({mnesia,_,_}) -> true; ({_,_,_}) -> false end, application:which_applications()) andalso +- begin +- {ok, [UsersPerms]} = file:consult(\"$BaseDataDir/users_perms.erl\"), +- lists:foreach(fun(X) -> mnesia:dirty_write(rabbit_user_permission, X) end, UsersPerms), +- +- ok = file:delete(\"$BaseDataDir/users_perms.erl\") +- end. +- " +- fi ++ Downgrade = fun ++ ({internal_user, A, B, C}) -> {internal_user, A, B, C}; ++ ({internal_user, A, B, C, rabbit_password_hashing_md5}) -> {internal_user, A, B, C}; ++ %% Incompatible scheme, so we will loose user's password ('B' value) during conversion. ++ %% Unfortunately, this case will require manual intervention - user have to run: ++ %% rabbitmqctl change_password ++ ({internal_user, A, B, C, _}) -> {internal_user, A, B, C} ++ end, ++ ++ %% Check db scheme first ++ [WildPattern] = ets:select(mnesia_gvar, [ { {{rabbit_user, wild_pattern}, '\\\$1'}, [], ['\\\$1'] } ]), ++ case WildPattern of ++ %% Version < 3.6.0 ++ {internal_user,'_','_','_'} -> ++ Restore(rabbit_user, Downgrade, \"$BaseDataDir/users.erl\"); ++ %% Version >= 3.6.0 ++ {internal_user,'_','_','_','_'} -> ++ Restore(rabbit_user, Upgrade, \"$BaseDataDir/users.erl\") ++ end, + ++ NoOp = fun(X) -> X end, ++ ++ %% Restore user permissions ++ Restore(rabbit_user_permission, NoOp, \"$BaseDataDir/users_perms.erl\"), ++ ++ %% Restore policies ++ Restore(rabbit_runtime_parameters, NoOp, \"$BaseDataDir/policies.erl\") ++ end. ++ " + return $OCF_SUCCESS + } + + rmq_stop() { +- # Backup users and users' permissions ++ # Backup users, user permissions, and policies + BaseDataDir=`dirname $RMQ_DATA_DIR` + rabbitmqctl eval " + %% Run only if Mnesia is still available. + lists:any(fun({mnesia,_,_}) -> true; ({_,_,_}) -> false end, application:which_applications()) andalso + begin +- [WildPattern] = ets:select(mnesia_gvar, [ { {{rabbit_user, wild_pattern}, '\\\$1'}, [], ['\\\$1'] } ]), ++ Backup = fun(Table, SelectPattern, Filter, Filename) -> ++ Result = case catch mnesia:dirty_select(Table, [{SelectPattern, [Filter], ['\\\$_']}]) of ++ {'EXIT', _} -> []; ++ Any -> Any ++ end, ++ Result /= [] andalso file:write_file(Filename, io_lib:fwrite(\"~p.~n\", [RuntimeParams])) ++ end, + +- Users = case WildPattern of ++ %% Backup users ++ %% Check db scheme first ++ [WildPattern] = ets:select(mnesia_gvar, [ { {{rabbit_user, wild_pattern}, '\\\$1'}, [], ['\\\$1'] } ]), ++ UsersSelectPattern = case WildPattern of + %% Version < 3.6.0 +- {internal_user,'_','_','_'} -> +- mnesia:dirty_select(rabbit_user, [{ {internal_user, '\\\$1', '_', '_'}, [{'/=', '\\\$1', <<\"guest\">>}], ['\\\$_'] } ]); ++ {internal_user,'_','_','_'} -> {internal_user, '\\\$1', '_', '_'}; + %% Version >= 3.6.0 +- {internal_user,'_','_','_','_'} -> +- mnesia:dirty_select(rabbit_user, [{ {internal_user, '\\\$1', '_', '_', '_'}, [{'/=', '\\\$1', <<\"guest\">>}], ['\\\$_'] } ]) ++ {internal_user,'_','_','_','_'} -> {internal_user, '\\\$1', '_', '_', '_'} + end, ++ Backup(rabbit_user, UsersSelectPattern, {'/=', '\\\$1', <<\"guest\">>}, \"$BaseDataDir/users.erl\"), + +- Users /= [] andalso file:write_file(\"$BaseDataDir/users.erl\", io_lib:fwrite(\"~p.~n\", [Users])), ++ %% Backup user permissions ++ Backup(rabbit_user_permission, {'\\\$1', {'\\\$2', '\\\$3','\\\$4'}, '\\\$5'}, {'/=', '\\\$3', <<\"guest\">>}, \"$BaseDataDir/users_perms.erl\"), + +- UsersPerms = mnesia:dirty_select(rabbit_user_permission, [{{'\\\$1', {'\\\$2', '\\\$3','\\\$4'}, '\\\$5'}, [{'/=', '\\\$3', <<\"guest\">>}], ['\\\$_']}]), +- UsersPerms /= [] andalso file:write_file(\"$BaseDataDir/users_perms.erl\", io_lib:fwrite(\"~p.~n\", [UsersPerms])) ++ %% Backup policies ++ Backup(rabbit_runtime_parameters, {runtime_parameters, {'_', '\\\$1', '_'}, '_'}, {'==', '\\\$1', <<\"policy\">>}, \"$BaseDataDir/policies.erl\") + end. + " + diff --git a/SOURCES/bz1342478-rabbitmq-cluster-return-code-69-not-running.patch b/SOURCES/bz1342478-rabbitmq-cluster-return-code-69-not-running.patch new file mode 100644 index 00000000..7fc59b16 --- /dev/null +++ b/SOURCES/bz1342478-rabbitmq-cluster-return-code-69-not-running.patch @@ -0,0 +1,73 @@ +diff -uNr a/heartbeat/rabbitmq-cluster b/heartbeat/rabbitmq-cluster +--- a/heartbeat/rabbitmq-cluster 2016-06-03 16:17:09.794967156 +0200 ++++ b/heartbeat/rabbitmq-cluster 2016-06-03 16:27:29.777803932 +0200 +@@ -167,8 +167,13 @@ + rmq_delete_nodename + return $OCF_NOT_RUNNING + ;; ++ 69) ++ ocf_log info "RabbitMQ server is not running" ++ rmq_delete_nodename ++ return $OCF_NOT_RUNNING ++ ;; + *) +- ocf_log err "Unexpected return code from '$RMQ_CTL cluster status' exit code: $rc" ++ ocf_log err "Unexpected return code from '$RMQ_CTL cluster_status' exit code: $rc" + rmq_delete_nodename + return $OCF_ERR_GENERIC + ;; +From 41657b4108211725878b6b46883ff6cc72e44fa9 Mon Sep 17 00:00:00 2001 +From: Peter Lemenkov +Date: Mon, 4 Jul 2016 17:09:16 +0200 +Subject: [PATCH] More RabbitMQ POSIX error codes + +We must add the following POSIX error codes in order to detect node +failure: + +* 68 - EX_NOHOST +* 69 - EX_UNAVAILABLE +* 70 - EX_SOFTWARE +* 75 - EX_TEMPFAIL +* 78 - EX_CONFIG + +The following commits introduced these return values: + +* rabbitmq/rabbitmq-server@7984540175d0b8852025165b6b6a0ac05d692c98 +* rabbitmq/rabbitmq-common@92ae50e5964d4f079c7b2abed1caaa8ab54a439b + +For the error codes meanings go to: + +* http://www.sbras.ru/cgi-bin/www/unix_help/unix-man?sysexits+3 +* http://linux.die.net/include/sysexits.h +* https://sourceware.org/git/?p=glibc.git;a=blob_plain;f=misc/sysexits.h;hb=HEAD + +Note that the following error valies do not mean that the node is +stopped and therefore doesn't covered by this commit: + +* 64 - EX_USAGE +* 65 - EX_DATAERR +* 67 - EX_NOUSER + +Signed-off-by: Peter Lemenkov +--- + heartbeat/rabbitmq-cluster | 7 +------ + 1 file changed, 1 insertion(+), 6 deletions(-) + +diff --git a/heartbeat/rabbitmq-cluster b/heartbeat/rabbitmq-cluster +index b9ae38e..651b837 100755 +--- a/heartbeat/rabbitmq-cluster ++++ b/heartbeat/rabbitmq-cluster +@@ -162,12 +162,7 @@ rmq_monitor() { + + return $OCF_SUCCESS + ;; +- 2) +- ocf_log info "RabbitMQ server is not running" +- rmq_delete_nodename +- return $OCF_NOT_RUNNING +- ;; +- 69) ++ 2|68|69|70|75|78) + ocf_log info "RabbitMQ server is not running" + rmq_delete_nodename + return $OCF_NOT_RUNNING diff --git a/SOURCES/bz1343905-1-rabbitmq-cluster-dump-restore-users-3.6.x.patch b/SOURCES/bz1343905-1-rabbitmq-cluster-dump-restore-users-3.6.x.patch new file mode 100644 index 00000000..47975b42 --- /dev/null +++ b/SOURCES/bz1343905-1-rabbitmq-cluster-dump-restore-users-3.6.x.patch @@ -0,0 +1,102 @@ +From f00a952bd5e133cad30689d9edcc98f5d33a71a9 Mon Sep 17 00:00:00 2001 +From: Peter Lemenkov +Date: Thu, 16 Jun 2016 16:44:48 +0200 +Subject: [PATCH] Enable dump/restore users from RabbitMQ ver. 3.6.x + +RabbitMQ changed internal_users scheme since ver. 3.6.0. See the +following links for further details: + +* rabbitmq/rabbitmq-server#270 +* rabbitmq/rabbitmq-server#310 +* rabbitmq/rabbitmq-common@9c86a7401cf464dc20527890192c5dc0fe43b6c8 +* rabbitmq/rabbitmq-server@93b5a3a8092f52063cbca3ab661c7c6bae43c512 + +CC @oalbrigt + +Signed-off-by: Peter Lemenkov +--- + heartbeat/rabbitmq-cluster | 64 ++++++++++++++++++++++++++++++++++++---------- + 1 file changed, 50 insertions(+), 14 deletions(-) + +diff --git a/heartbeat/rabbitmq-cluster b/heartbeat/rabbitmq-cluster +index 0724901..facca35 100755 +--- a/heartbeat/rabbitmq-cluster ++++ b/heartbeat/rabbitmq-cluster +@@ -342,14 +342,40 @@ rmq_start() { + rmq_join_existing "$join_list" + rc=$? + +- # Restore users (if any) +- BaseDataDir=`dirname $RMQ_DATA_DIR` +- if [ -f $BaseDataDir/users.erl ] ; then +- rabbitmqctl eval " +- {ok, [Users]} = file:consult(\"$BaseDataDir/users.erl\"), +- lists:foreach(fun(X) -> mnesia:dirty_write(rabbit_user, X) end, Users). +- " +- rm -f $BaseDataDir/users.erl ++ # Restore users (if any) ++ BaseDataDir=`dirname $RMQ_DATA_DIR` ++ if [ -f $BaseDataDir/users.erl ] ; then ++ rabbitmqctl eval " ++ ++ [WildPattern] = ets:select(mnesia_gvar, [ { {{rabbit_user, wild_pattern}, '\\\$1'}, [], ['\\\$1'] } ]), ++ ++ %% Read users first ++ {ok, [Users]} = file:consult(\"$BaseDataDir/users.erl\"), ++ ++ Upgrade = fun ++ ({internal_user, A, B, C}) -> {internal_user, A, B, C, rabbit_password_hashing_md5}; ++ ({internal_user, A, B, C, D}) -> {internal_user, A, B, C, D} ++ end, ++ ++ Downgrade = fun ++ ({internal_user, A, B, C}) -> {internal_user, A, B, C}; ++ ({internal_user, A, B, C, rabbit_password_hashing_md5}) -> {internal_user, A, B, C}; ++ %% Incompatible scheme, so we will loose user's password ('B' value) during conversion. ++ %% Unfortunately, this case will require manual intervention - user have to run: ++ %% rabbitmqctl change_password ++ ({internal_user, A, B, C, _}) -> {internal_user, A, B, C} ++ end, ++ ++ case WildPattern of ++ %% Version < 3.6.0 ++ {internal_user,'_','_','_'} -> ++ lists:foreach(fun(X) -> mnesia:dirty_write(rabbit_user, Downgrade(X)) end, Users); ++ %% Version >= 3.6.0 ++ {internal_user,'_','_','_','_'} -> ++ lists:foreach(fun(X) -> mnesia:dirty_write(rabbit_user, Upgrade(X)) end, Users) ++ end. ++ " ++ rm -f $BaseDataDir/users.erl + fi + + if [ $rc -ne 0 ]; then +@@ -362,12 +388,22 @@ rmq_start() { + } + + rmq_stop() { +- # Backup users +- BaseDataDir=`dirname $RMQ_DATA_DIR` +- rabbitmqctl eval " +- Users = mnesia:dirty_select(rabbit_user, [{ {internal_user, '\\\$1', '_', '_'}, [{'/=', '\\\$1', <<\"guest\">>}], ['\\\$_'] } ]), +- file:write_file(\"$BaseDataDir/users.erl\", io_lib:fwrite(\"~p.~n\", [Users])). +- " ++ # Backup users ++ BaseDataDir=`dirname $RMQ_DATA_DIR` ++ rabbitmqctl eval " ++ [WildPattern] = ets:select(mnesia_gvar, [ { {{rabbit_user, wild_pattern}, '\\\$1'}, [], ['\\\$1'] } ]), ++ ++ Users = case WildPattern of ++ %% Version < 3.6.0 ++ {internal_user,'_','_','_'} -> ++ mnesia:dirty_select(rabbit_user, [{ {internal_user, '\\\$1', '_', '_'}, [{'/=', '\\\$1', <<\"guest\">>}], ['\\\$_'] } ]); ++ %% Version >= 3.6.0 ++ {internal_user,'_','_','_','_'} -> ++ mnesia:dirty_select(rabbit_user, [{ {internal_user, '\\\$1', '_', '_', '_'}, [{'/=', '\\\$1', <<\"guest\">>}], ['\\\$_'] } ]) ++ end, ++ ++ file:write_file(\"$BaseDataDir/users.erl\", io_lib:fwrite(\"~p.~n\", [Users])). ++ " + + rmq_monitor + if [ $? -eq $OCF_NOT_RUNNING ]; then diff --git a/SOURCES/bz1343905-2-rabbitmq-cluster-dump-restore-users-3.6.x.patch b/SOURCES/bz1343905-2-rabbitmq-cluster-dump-restore-users-3.6.x.patch new file mode 100644 index 00000000..32a05c3b --- /dev/null +++ b/SOURCES/bz1343905-2-rabbitmq-cluster-dump-restore-users-3.6.x.patch @@ -0,0 +1,37 @@ +From 74b3cff4fce5483d126b16131db53f8bd5804c82 Mon Sep 17 00:00:00 2001 +From: Peter Lemenkov +Date: Tue, 21 Jun 2016 15:48:07 +0200 +Subject: [PATCH] Don't run scriptlets if Mnesia isn't available + +See this rhbz for further details and symptoms: + +https://bugzilla.redhat.com/1343905 + +Signed-off-by: Peter Lemenkov +--- + heartbeat/rabbitmq-cluster | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/heartbeat/rabbitmq-cluster b/heartbeat/rabbitmq-cluster +index facca35..18e3206 100755 +--- a/heartbeat/rabbitmq-cluster ++++ b/heartbeat/rabbitmq-cluster +@@ -346,6 +346,8 @@ rmq_start() { + BaseDataDir=`dirname $RMQ_DATA_DIR` + if [ -f $BaseDataDir/users.erl ] ; then + rabbitmqctl eval " ++ %% Run only if Mnesia is ready, otherwise exit. ++ lists:any(fun({mnesia,_,_}) -> true; ({_,_,_}) -> false end, application:which_applications()) orelse halt(), + + [WildPattern] = ets:select(mnesia_gvar, [ { {{rabbit_user, wild_pattern}, '\\\$1'}, [], ['\\\$1'] } ]), + +@@ -391,6 +393,9 @@ rmq_stop() { + # Backup users + BaseDataDir=`dirname $RMQ_DATA_DIR` + rabbitmqctl eval " ++ %% Run only if Mnesia is still available, otherwise exit. ++ lists:any(fun({mnesia,_,_}) -> true; ({_,_,_}) -> false end, application:which_applications()) orelse halt(), ++ + [WildPattern] = ets:select(mnesia_gvar, [ { {{rabbit_user, wild_pattern}, '\\\$1'}, [], ['\\\$1'] } ]), + + Users = case WildPattern of diff --git a/SOURCES/bz1343905-3-rabbitmq-cluster-dump-restore-users-3.6.x.patch b/SOURCES/bz1343905-3-rabbitmq-cluster-dump-restore-users-3.6.x.patch new file mode 100644 index 00000000..2d1abe85 --- /dev/null +++ b/SOURCES/bz1343905-3-rabbitmq-cluster-dump-restore-users-3.6.x.patch @@ -0,0 +1,53 @@ +From 279bae7ec9a571a4d52b0d876850e27772eb0933 Mon Sep 17 00:00:00 2001 +From: Jiri Stransky +Date: Thu, 23 Jun 2016 12:55:06 +0200 +Subject: [PATCH] RabbitMQ: Forget node before 2nd joining attempt + +If a first attempt at joining an existing cluster has failed and we +resort to wiping the local RabbitMQ data, make sure we also request the +local node to be forgotten from the existing cluster before we make the +join attempt, otherwise the node will be rejected. +--- + heartbeat/rabbitmq-cluster | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) + +diff --git a/heartbeat/rabbitmq-cluster b/heartbeat/rabbitmq-cluster +index 0724901..b9ae38e 100755 +--- a/heartbeat/rabbitmq-cluster ++++ b/heartbeat/rabbitmq-cluster +@@ -279,6 +279,22 @@ rmq_join_existing() + return $OCF_SUCCESS + } + ++rmq_forget_cluster_node_remotely() { ++ local running_cluster_nodes="$1" ++ local node_to_forget="$2" ++ ++ ocf_log info "Forgetting $node_to_forget via nodes [ $(echo $running_cluster_nodes | tr '\n' ' ') ]." ++ for running_cluster_node in $running_cluster_nodes; do ++ rabbitmqctl -n $running_cluster_node forget_cluster_node $node_to_forget ++ if [ $? = 0 ]; then ++ ocf_log info "Succeeded forgetting $node_to_forget via $running_cluster_node." ++ return ++ else ++ ocf_log err "Failed to forget node $node_to_forget via $running_cluster_node." ++ fi ++ done ++} ++ + rmq_notify() { + node_list="${OCF_RESKEY_CRM_meta_notify_stop_uname}" + mode="${OCF_RESKEY_CRM_meta_notify_type}-${OCF_RESKEY_CRM_meta_notify_operation}" +@@ -336,9 +352,12 @@ rmq_start() { + rmq_join_existing "$join_list" + if [ $? -ne 0 ]; then + ocf_log info "node failed to join, wiping data directory and trying again" ++ local local_rmq_node="$(${HA_SBIN_DIR}/crm_attribute -N $NODENAME -l forever --query --name $RMQ_CRM_ATTR_COOKIE_LAST_KNOWN -q)" ++ + # if the graceful join fails, use the hammer and reset all the data. + rmq_stop + rmq_wipe_data ++ rmq_forget_cluster_node_remotely "$join_list" "$local_rmq_node" + rmq_join_existing "$join_list" + rc=$? + diff --git a/SOURCES/bz1343905-rabbitmq-automatic-cluster-recovery.patch b/SOURCES/bz1343905-rabbitmq-automatic-cluster-recovery.patch new file mode 100644 index 00000000..d51cfe76 --- /dev/null +++ b/SOURCES/bz1343905-rabbitmq-automatic-cluster-recovery.patch @@ -0,0 +1,39 @@ +commit 1621dbb60454840d469f3a0e317a97d94510f7ab +Author: John Eckersberg +Date: Tue Jul 26 13:47:39 2016 -0400 + + rabbitmq: Allow automatic cluster recovery before forcing it + + When joining a node into an existing cluster, check to see if it is + already clustered before force removing it from the cluster and + re-adding. If the clustering is already functional there's no need to + force it again. + +diff --git a/heartbeat/rabbitmq-cluster b/heartbeat/rabbitmq-cluster +index 651b837..966dd64 100755 +--- a/heartbeat/rabbitmq-cluster ++++ b/heartbeat/rabbitmq-cluster +@@ -238,6 +238,11 @@ rmq_start_first() + return $rc + } + ++rmq_is_clustered() ++{ ++ $RMQ_CTL eval 'rabbit_mnesia:is_clustered().' | grep -q true ++} ++ + rmq_join_existing() + { + local join_list="$1" +@@ -249,6 +254,11 @@ rmq_join_existing() + return $OCF_ERR_GENERIC + fi + ++ if rmq_is_clustered; then ++ ocf_log info "Successfully re-joined existing rabbitmq cluster automatically" ++ return $OCF_SUCCESS ++ fi ++ + # unconditionally join the cluster + $RMQ_CTL stop_app > /dev/null 2>&1 + for node in $(echo "$join_list"); do diff --git a/SOURCES/bz1358895-oracle-fix-monprofile.patch b/SOURCES/bz1358895-oracle-fix-monprofile.patch new file mode 100644 index 00000000..1ef61d47 --- /dev/null +++ b/SOURCES/bz1358895-oracle-fix-monprofile.patch @@ -0,0 +1,22 @@ +From 5f1088e7e6b7d15e6615d57dcf77834df9ded690 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Fri, 22 Jul 2016 10:39:59 +0200 +Subject: [PATCH] oracle: fix MONPROFILE to use monprofile parameter when set + +--- + heartbeat/oracle | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/heartbeat/oracle b/heartbeat/oracle +index d68fa6e..e8e6148 100755 +--- a/heartbeat/oracle ++++ b/heartbeat/oracle +@@ -755,7 +755,7 @@ PROCS_CLEANUP_TIME="30" + + MONUSR=${OCF_RESKEY_monuser:-$OCF_RESKEY_monuser_default} + MONPWD=${OCF_RESKEY_monpassword:-$OCF_RESKEY_monpassword_default} +-MONPROFILE=${OCF_RESKEY_monprofile_default:-$OCF_RESKEY_monprofile_default} ++MONPROFILE=${OCF_RESKEY_monprofile:-$OCF_RESKEY_monprofile_default} + + MONUSR=$(echo $MONUSR | awk '{print toupper($0)}') + MONPROFILE=$(echo $MONPROFILE | awk '{print toupper($0)}') diff --git a/SOURCES/bz1359252-clvm-remove-reload-action.patch b/SOURCES/bz1359252-clvm-remove-reload-action.patch new file mode 100644 index 00000000..dc33e8df --- /dev/null +++ b/SOURCES/bz1359252-clvm-remove-reload-action.patch @@ -0,0 +1,21 @@ +From 0f7685998bb233716ef39d127de6a686e7fb003b Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Mon, 6 Mar 2017 16:42:10 +0100 +Subject: [PATCH] clvm: remove reload action from metadata + +--- + heartbeat/clvm | 1 - + 1 file changed, 1 deletion(-) + +diff --git a/heartbeat/clvm b/heartbeat/clvm +index a778333..8eae6c3 100755 +--- a/heartbeat/clvm ++++ b/heartbeat/clvm +@@ -78,7 +78,6 @@ is set to. + + + +- + + + diff --git a/SOURCES/bz1360768-galera-prevent-promote-after-demote.patch b/SOURCES/bz1360768-galera-prevent-promote-after-demote.patch new file mode 100644 index 00000000..8c2dc27a --- /dev/null +++ b/SOURCES/bz1360768-galera-prevent-promote-after-demote.patch @@ -0,0 +1,27 @@ +From d16f9dad57d9dae587b6a267fbd250c1ff3a2a20 Mon Sep 17 00:00:00 2001 +From: Damien Ciabrini +Date: Fri, 18 Nov 2016 09:43:29 +0100 +Subject: [PATCH] galera: prevent promote right after demote + +--- + heartbeat/galera | 7 +++++++ + 1 file changed, 7 insertions(+) + +diff --git a/heartbeat/galera b/heartbeat/galera +index 543200d..66d5ad8 100755 +--- a/heartbeat/galera ++++ b/heartbeat/galera +@@ -764,6 +764,13 @@ galera_demote() + clear_sync_needed + clear_no_grastate + ++ # Clear master score here rather than letting pacemaker do so once ++ # demote finishes. This way a promote cannot take place right ++ # after this demote even if pacemaker is requested to do so. It ++ # will first have to run a start/monitor op, to reprobe the state ++ # of the other galera nodes and act accordingly. ++ clear_master_score ++ + # record last commit for next promotion + detect_last_commit + rc=$? diff --git a/SOURCES/bz1364242-ethmonitor-add-intel-omnipath-support.patch b/SOURCES/bz1364242-ethmonitor-add-intel-omnipath-support.patch new file mode 100644 index 00000000..c7451ab5 --- /dev/null +++ b/SOURCES/bz1364242-ethmonitor-add-intel-omnipath-support.patch @@ -0,0 +1,71 @@ +From 5e8f593b58409c8c1c7793576a3980eb56e8c200 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Thu, 2 Nov 2017 14:01:05 +0100 +Subject: [PATCH 1/2] ethmonitor: add intel omnipath support + +--- + heartbeat/ethmonitor | 12 +++++++++--- + 1 file changed, 9 insertions(+), 3 deletions(-) + +diff --git a/heartbeat/ethmonitor b/heartbeat/ethmonitor +index 7f5579f94..952a9f91f 100755 +--- a/heartbeat/ethmonitor ++++ b/heartbeat/ethmonitor +@@ -219,7 +219,10 @@ infiniband_status() + device="${OCF_RESKEY_infiniband_device}:${OCF_RESKEY_infiniband_port}" + fi + +- ibstatus ${device} | grep -q ACTIVE ++ case "${OCF_RESKEY_infiniband_device}" in ++ *mlx*) ibstatus ${device} | grep -q ACTIVE ;; ++ *hfi*) opainfo | grep -q Active ;; ++ esac + } + + if_init() { +@@ -291,8 +294,11 @@ if_init() { + fi + + if [ -n "$OCF_RESKEY_infiniband_device" ]; then +- #ibstatus is required if an infiniband_device is provided +- check_binary ibstatus ++ #ibstatus or opainfo is required if an infiniband_device is provided ++ case "${OCF_RESKEY_infiniband_device}" in ++ *mlx*) check_binary ibstatus ;; ++ *hfi*) check_binary opainfo ;; ++ esac + fi + return $OCF_SUCCESS + } + +From 7e15a3ccfa0bd0e9dab92a6be21df968b073ec3d Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Tue, 7 Nov 2017 16:42:37 +0100 +Subject: [PATCH 2/2] ethmonitor: add /dev/ib* device to case-statement + +--- + heartbeat/ethmonitor | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/heartbeat/ethmonitor b/heartbeat/ethmonitor +index 952a9f91f..21bf12be7 100755 +--- a/heartbeat/ethmonitor ++++ b/heartbeat/ethmonitor +@@ -220,7 +220,7 @@ infiniband_status() + fi + + case "${OCF_RESKEY_infiniband_device}" in +- *mlx*) ibstatus ${device} | grep -q ACTIVE ;; ++ *ib*|*mlx*) ibstatus ${device} | grep -q ACTIVE ;; + *hfi*) opainfo | grep -q Active ;; + esac + } +@@ -296,7 +296,7 @@ if_init() { + if [ -n "$OCF_RESKEY_infiniband_device" ]; then + #ibstatus or opainfo is required if an infiniband_device is provided + case "${OCF_RESKEY_infiniband_device}" in +- *mlx*) check_binary ibstatus ;; ++ *ib*|*mlx*) check_binary ibstatus ;; + *hfi*) check_binary opainfo ;; + esac + fi diff --git a/SOURCES/bz1376588-iSCSITarget-properly-create-portals-for-lio-t.patch b/SOURCES/bz1376588-iSCSITarget-properly-create-portals-for-lio-t.patch new file mode 100644 index 00000000..c63115b9 --- /dev/null +++ b/SOURCES/bz1376588-iSCSITarget-properly-create-portals-for-lio-t.patch @@ -0,0 +1,38 @@ +From b10e2de76ccb143fdfd69988c8105ad4336d57d2 Mon Sep 17 00:00:00 2001 +From: Patrick Emer +Date: Sat, 27 Jun 2015 15:29:12 +0200 +Subject: [PATCH] iSCSITarget: properly create portals for lio-t implementation + +Even when defining the "portals" parameter, targetcli creates a +default portal at 0.0.0.0:3260 if the auto_add_default_portal option +is set to true (default), causing the resource to fail with +OCF_ERR_GENERIC. + +Suppress creation of the default portal by setting +auto_add_default_portal=false if the "portals" parameter is set, +and retain the original behavior if it is not. + +Fixes ClusterLabs/resource-agents#630. +--- + heartbeat/iSCSITarget | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/heartbeat/iSCSITarget b/heartbeat/iSCSITarget +index 72ec64a..401e98c 100755 +--- a/heartbeat/iSCSITarget ++++ b/heartbeat/iSCSITarget +@@ -326,10 +326,13 @@ iSCSITarget_start() { + # automatically creates the corresponding target if it + # doesn't already exist. + for portal in ${OCF_RESKEY_portals}; do +- ocf_run targetcli /iscsi create ${OCF_RESKEY_iqn} || exit $OCF_ERR_GENERIC + if [ $portal != ${OCF_RESKEY_portals_default} ] ; then ++ ocf_run targetcli /iscsi set global auto_add_default_portal=false || exit $OCF_ERR_GENERIC ++ ocf_run targetcli /iscsi create ${OCF_RESKEY_iqn} || exit $OCF_ERR_GENERIC + IFS=':' read -a sep_portal <<< "$portal" + ocf_run targetcli /iscsi/${OCF_RESKEY_iqn}/tpg1/portals create "${sep_portal[0]}" "${sep_portal[1]}" || exit $OCF_ERR_GENERIC ++ else ++ ocf_run targetcli /iscsi create ${OCF_RESKEY_iqn} || exit $OCF_ERR_GENERIC + fi + done + # in lio, we can set target parameters by manipulating diff --git a/SOURCES/bz1380405-send_arp-usage.patch b/SOURCES/bz1380405-send_arp-usage.patch new file mode 100644 index 00000000..b1acda36 --- /dev/null +++ b/SOURCES/bz1380405-send_arp-usage.patch @@ -0,0 +1,252 @@ +From 922ef94eefd55ca25df7ce7c98ac7c87134aa982 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Tue, 4 Apr 2017 12:12:35 +0200 +Subject: [PATCH] send_arp: update usage info + +--- + heartbeat/IPaddr2 | 2 +- + heartbeat/SendArp | 2 +- + tools/send_arp.libnet.c | 70 ++++++++++++++++--------------------------------- + tools/send_arp.linux.c | 60 ++++++++++++++++-------------------------- + 4 files changed, 48 insertions(+), 86 deletions(-) + +diff --git a/heartbeat/IPaddr2 b/heartbeat/IPaddr2 +index 27b7208..d07c622 100755 +--- a/heartbeat/IPaddr2 ++++ b/heartbeat/IPaddr2 +@@ -708,7 +708,7 @@ run_send_arp() { + LOGLEVEL=info + fi + if [ $ARP_COUNT -ne 0 ] ; then +- ARGS="-i $OCF_RESKEY_arp_interval -r $ARP_COUNT -p $SENDARPPIDFILE $NIC $OCF_RESKEY_ip $MY_MAC not_used not_used" ++ ARGS="-i $OCF_RESKEY_arp_interval -c $ARP_COUNT -p $SENDARPPIDFILE -I $NIC -m $MY_MAC $OCF_RESKEY_ip" + ocf_log $LOGLEVEL "$SENDARP $ARGS" + if ocf_is_true $OCF_RESKEY_arp_bg; then + ($SENDARP $ARGS || ocf_log err "Could not send gratuitous arps")& >&2 +diff --git a/heartbeat/SendArp b/heartbeat/SendArp +index dbcc7dc..033865f 100755 +--- a/heartbeat/SendArp ++++ b/heartbeat/SendArp +@@ -156,7 +156,7 @@ sendarp_start() { + fi + + +- ARGS="-i $ARP_INTERVAL_MS -r $ARP_REPEAT -p $SENDARPPIDFILE $INTERFACE $BASEIP auto $BASEIP $ARP_NETMASK" ++ ARGS="-i $ARP_INTERVAL_MS -c $ARP_REPEAT -p $SENDARPPIDFILE -I $INTERFACE -m auto $BASEIP" + ocf_log debug "$SENDARP $ARGS" + + rc=$OCF_SUCCESS +diff --git a/tools/send_arp.libnet.c b/tools/send_arp.libnet.c +index 12fe7f1..bd96a49 100644 +--- a/tools/send_arp.libnet.c ++++ b/tools/send_arp.libnet.c +@@ -62,35 +62,14 @@ + #define PIDFILE_BASE PIDDIR "/send_arp-" + + static char print_usage[]={ +-"send_arp: sends out custom ARP packet.\n" +-" usage: send_arp [-i repeatinterval-ms] [-r repeatcount] [-p pidfile] \\\n" +-" device src_ip_addr src_hw_addr broadcast_ip_addr netmask\n" +-"\n" +-" where:\n" +-" repeatinterval-ms: timing, in milliseconds of sending arp packets\n" +-" For each ARP announcement requested, a pair of ARP packets is sent,\n" +-" an ARP request, and an ARP reply. This is becuse some systems\n" +-" ignore one or the other, and this combination gives the greatest\n" +-" chance of success.\n" +-"\n" +-" Each time an ARP is sent, if another ARP will be sent then\n" +-" the code sleeps for half of repeatinterval-ms.\n" +-"\n" +-" repeatcount: how many pairs of ARP packets to send.\n" +-" See above for why pairs are sent\n" +-"\n" +-" pidfile: pid file to use\n" +-"\n" +-" device: netowrk interace to use\n" +-"\n" +-" src_ip_addr: source ip address\n" +-"\n" +-" src_hw_addr: source hardware address.\n" +-" If \"auto\" then the address of device\n" +-"\n" +-" broadcast_ip_addr: ignored\n" +-"\n" +-" netmask: ignored\n" ++"Usage: send_arp [-i repeatinterval-ms] [-c count] [-p pidfile] [-I device] [-m mac] destination\n" ++" -i repeatinterval-ms : repeat interval in milliseconds (ignored in Linux version)\n" ++" -c count : how many packets to send\n" ++" -p pidfile : pid file (ignored in Linux version)\n" ++" -I device : which ethernet device to use\n" ++" -m mac : source MAC address (ignored in Linux version).\n" ++" If \"auto\" device address is used\n" ++" destination : ask for what ip address\n" + }; + + static const char * SENDARPNAME = "send_arp"; +@@ -158,41 +137,38 @@ main(int argc, char *argv[]) + cl_log_set_facility(LOG_USER); + cl_inherit_logging_environment(0); + +- while ((flag = getopt(argc, argv, "i:r:p:")) != EOF) { ++ while ((flag = getopt(argc, argv, "h?c:I:i:p:m:")) != EOF) { + switch(flag) { + + case 'i': msinterval= atol(optarg); + break; + +- case 'r': repeatcount= atoi(optarg); ++ case 'c': repeatcount= atoi(optarg); + break; + + case 'p': pidfilename= optarg; + break; + ++ case 'I': device= optarg; ++ break; ++ ++ case 'm': macaddr= optarg; ++ break; ++ ++ case 'h': ++ case '?': + default: fprintf(stderr, "%s\n\n", print_usage); + return 1; + break; + } + } +- if (argc-optind != 5) { +- fprintf(stderr, "%s\n\n", print_usage); +- return 1; +- } + +- /* +- * argv[optind+1] DEVICE dc0,eth0:0,hme0:0, +- * argv[optind+2] IP 192.168.195.186 +- * argv[optind+3] MAC ADDR 00a0cc34a878 +- * argv[optind+4] BROADCAST 192.168.195.186 +- * argv[optind+5] NETMASK ffffffffffff +- */ ++ argc -= optind; ++ argv += optind; ++ if (argc != 1) ++ usage(); + +- device = argv[optind]; +- ipaddr = argv[optind+1]; +- macaddr = argv[optind+2]; +- broadcast = argv[optind+3]; +- netmask = argv[optind+4]; ++ ipaddr = *argv; + + if (!pidfilename) { + if (snprintf(pidfilenamebuf, sizeof(pidfilenamebuf), "%s%s", +diff --git a/tools/send_arp.linux.c b/tools/send_arp.linux.c +index 477100a..348794c 100644 +--- a/tools/send_arp.linux.c ++++ b/tools/send_arp.linux.c +@@ -137,22 +137,25 @@ static socklen_t sll_len(size_t halen) + void usage(void) + { + fprintf(stderr, +- "Usage: arping [-fqbDUAV] [-c count] [-w timeout] [-I device] [-s source] destination\n" +- " -f : quit on first reply\n" +- " -q : be quiet\n" +- " -b : keep broadcasting, don't go unicast\n" +- " -D : duplicate address detection mode\n" +- " -U : Unsolicited ARP mode, update your neighbours\n" +- " -A : ARP answer mode, update your neighbours\n" +- " -V : print version and exit\n" ++ "Usage: send_arp [-fqbDUAV] [-c count] [-w timeout] [-I device] [-s source] destination\n" ++ " -f : quit on first reply (not available in libnet version)\n" ++ " -q : be quiet (not available in libnet version)\n" ++ " -b : keep broadcasting, don't go unicast (not available in libnet version)\n" ++ " -i : repeat interval in milliseconds (ignored)\n" ++ " -p : pid file (ignored)\n" ++ " -D : duplicate address detection mode (not available in libnet version)\n" ++ " -U : Unsolicited ARP mode, update your neighbours (not available in libnet version)\n" ++ " -A : ARP answer mode, update your neighbours (not available in libnet version)\n" ++ " -V : print version and exit (not available in libnet version)\n" + " -c count : how many packets to send\n" +- " -w timeout : how long to wait for a reply\n" ++ " -w timeout : how long to wait for a reply (not available in libnet version)\n" + " -I device : which ethernet device to use" + #ifdef DEFAULT_DEVICE_STR + " (" DEFAULT_DEVICE_STR ")" + #endif + "\n" +- " -s source : source ip address\n" ++ " -s source : source ip address (not available in libnet version)\n" ++ " -m mac : source MAC address (ignored).\n" + " destination : ask for what ip address\n" + ); + exit(2); +@@ -1044,7 +1047,7 @@ main(int argc, char **argv) + + disable_capability_raw(); + +- while ((ch = getopt(argc, argv, "h?bfDUAqc:w:s:I:Vr:i:p:")) != EOF) { ++ while ((ch = getopt(argc, argv, "h?bfDUAqc:w:s:I:Vi:m:p:")) != EOF) { + switch(ch) { + case 'b': + broadcast_only=1; +@@ -1063,9 +1066,6 @@ main(int argc, char **argv) + case 'q': + quiet++; + break; +- case 'r': /* send_arp.libnet compatibility option */ +- hb_mode = 1; +- /* fall-through */ + case 'c': + count = atoi(optarg); + break; +@@ -1086,9 +1086,10 @@ main(int argc, char **argv) + exit(0); + case 'p': + case 'i': +- hb_mode = 1; +- /* send_arp.libnet compatibility options, ignore */ +- break; ++ case 'm': ++ hb_mode = 1; ++ /* send_arp.libnet compatibility options, ignore */ ++ break; + case 'h': + case '?': + default: +@@ -1098,30 +1099,15 @@ main(int argc, char **argv) + + if(hb_mode) { + /* send_arp.libnet compatibility mode */ +- if (argc - optind != 5) { +- usage(); +- return 1; +- } +- /* +- * argv[optind+1] DEVICE dc0,eth0:0,hme0:0, +- * argv[optind+2] IP 192.168.195.186 +- * argv[optind+3] MAC ADDR 00a0cc34a878 +- * argv[optind+4] BROADCAST 192.168.195.186 +- * argv[optind+5] NETMASK ffffffffffff +- */ +- + unsolicited = 1; +- device.name = argv[optind]; +- target = argv[optind+1]; ++ } + +- } else { +- argc -= optind; +- argv += optind; +- if (argc != 1) ++ argc -= optind; ++ argv += optind; ++ if (argc != 1) + usage(); + +- target = *argv; +- } ++ target = *argv; + + if (device.name && !*device.name) + device.name = NULL; diff --git a/SOURCES/bz1384955-nfsserver-dont-stop-rpcbind.patch b/SOURCES/bz1384955-nfsserver-dont-stop-rpcbind.patch new file mode 100644 index 00000000..7d64cfbb --- /dev/null +++ b/SOURCES/bz1384955-nfsserver-dont-stop-rpcbind.patch @@ -0,0 +1,13 @@ +diff -uNr a/heartbeat/nfsserver b/heartbeat/nfsserver +--- a/heartbeat/nfsserver 2016-11-01 14:49:44.005585567 +0100 ++++ b/heartbeat/nfsserver 2016-11-01 14:50:17.280266118 +0100 +@@ -918,9 +918,6 @@ + + # systemd + if [ "$EXEC_MODE" -eq "2" ]; then +- nfs_exec stop rpcbind > /dev/null 2>&1 +- ocf_log info "Stop: rpcbind" +- + nfs_exec stop rpc-gssd > /dev/null 2>&1 + ocf_log info "Stop: rpc-gssd" + fi diff --git a/SOURCES/bz1387363-Filesystem-submount-check.patch b/SOURCES/bz1387363-Filesystem-submount-check.patch new file mode 100644 index 00000000..b7aef4bf --- /dev/null +++ b/SOURCES/bz1387363-Filesystem-submount-check.patch @@ -0,0 +1,16 @@ +diff -uNr a/heartbeat/Filesystem b/heartbeat/Filesystem +--- a/heartbeat/Filesystem 2016-12-20 14:16:29.439700386 +0100 ++++ b/heartbeat/Filesystem 2016-12-20 14:18:04.954623779 +0100 +@@ -538,6 +538,12 @@ + Filesystem_notify + fi + ++ # Check if there are any mounts mounted under the mountpoint ++ if list_mounts | grep -q -E " $MOUNTPOINT/\w+" >/dev/null 2>&1; then ++ ocf_log err "There is one or more mounts mounted under $MOUNTPOINT." ++ return $OCF_ERR_CONFIGURED ++ fi ++ + # See if the device is already mounted. + if Filesystem_status >/dev/null 2>&1 ; then + ocf_log info "Filesystem $MOUNTPOINT is already mounted." diff --git a/SOURCES/bz1387491-nfsserver-keep-options.patch b/SOURCES/bz1387491-nfsserver-keep-options.patch new file mode 100644 index 00000000..2889084c --- /dev/null +++ b/SOURCES/bz1387491-nfsserver-keep-options.patch @@ -0,0 +1,54 @@ +diff -uNr a/heartbeat/nfsserver b/heartbeat/nfsserver +--- a/heartbeat/nfsserver 2016-10-28 10:51:35.357385160 +0200 ++++ b/heartbeat/nfsserver 2016-10-28 13:22:16.844380108 +0200 +@@ -434,7 +434,12 @@ + # only write to the tmp /etc/sysconfig/nfs if sysconfig exists. + # otherwise this distro does not support setting these options. + if [ -d "/etc/sysconfig" ]; then +- echo "${key}=\"${value}\"" >> $file ++ # replace if the value exists, append otherwise ++ if grep "^\s*${key}=" $file ; then ++ sed -i "s/\s*${key}=.*$/${key}=\"${value}\"/" $file ++ else ++ echo "${key}=\"${value}\"" >> $file ++ fi + elif [ "$requires_sysconfig" = "true" ]; then + ocf_log warn "/etc/sysconfig/nfs not found, unable to set port and nfsd args." + fi +@@ -447,6 +452,11 @@ + local tmpconfig=$(mktemp ${HA_RSCTMP}/nfsserver-tmp-XXXXX) + local statd_args + ++ if [ -f "$NFS_SYSCONFIG" ]; then ++ ## Take the $NFS_SYSCONFIG file as our skeleton ++ cp $NFS_SYSCONFIG $tmpconfig ++ fi ++ + # nfsd args + set_arg "RPCNFSDARGS" "$OCF_RESKEY_nfsd_args" "$tmpconfig" "true" + +@@ -477,14 +487,20 @@ + + # override local nfs config. preserve previous local config though. + if [ -s $tmpconfig ]; then +- cat $NFS_SYSCONFIG | grep -e "$NFS_SYSCONFIG_AUTOGEN_TAG" ++ cat $NFS_SYSCONFIG | grep -q -e "$NFS_SYSCONFIG_AUTOGEN_TAG" > /dev/null 2>&1 + if [ $? -ne 0 ]; then + # backup local nfs config if it doesn't have our HA autogen tag in it. + mv -f $NFS_SYSCONFIG $NFS_SYSCONFIG_LOCAL_BACKUP + fi +- echo "# $NFS_SYSCONFIG_AUTOGEN_TAG" > $NFS_SYSCONFIG +- echo "# local config backup stored here, '$NFS_SYSCONFIG_LOCAL_BACKUP'" >> $NFS_SYSCONFIG +- cat $tmpconfig >> $NFS_SYSCONFIG ++ ++ cat $tmpconfig | grep -q -e "$NFS_SYSCONFIG_AUTOGEN_TAG" > /dev/null 2>&1 ++ if [ $? -ne 0 ]; then ++ echo "# $NFS_SYSCONFIG_AUTOGEN_TAG" > $NFS_SYSCONFIG ++ echo "# local config backup stored here, '$NFS_SYSCONFIG_LOCAL_BACKUP'" >> $NFS_SYSCONFIG ++ cat $tmpconfig >> $NFS_SYSCONFIG ++ else ++ cat $tmpconfig > $NFS_SYSCONFIG ++ fi + fi + rm -f $tmpconfig + } diff --git a/SOURCES/bz1388854-delay-change-startdelay.patch b/SOURCES/bz1388854-delay-change-startdelay.patch new file mode 100644 index 00000000..d9582a95 --- /dev/null +++ b/SOURCES/bz1388854-delay-change-startdelay.patch @@ -0,0 +1,41 @@ +From 9134a62cec26106a0540309f60db9a420e7488b6 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Wed, 19 Oct 2016 12:02:06 +0200 +Subject: [PATCH] Delay: set default startdelay lower than start timeout to + avoid it timing out before starting with default values + +--- + heartbeat/Delay | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/heartbeat/Delay b/heartbeat/Delay +index 9cfa939..f9d303b 100755 +--- a/heartbeat/Delay ++++ b/heartbeat/Delay +@@ -14,7 +14,7 @@ + # OCF_RESKEY_mondelay + # + # +-# OCF_RESKEY_startdelay defaults to 30 (seconds) ++# OCF_RESKEY_startdelay defaults to 20 (seconds) + # OCF_RESKEY_stopdelay defaults to $OCF_RESKEY_startdelay + # OCF_RESKEY_mondelay defaults to $OCF_RESKEY_startdelay + # +@@ -55,7 +55,7 @@ This script is a test resource for introducing delay. + How long in seconds to delay on start operation. + + Start delay +- ++ + + + +@@ -195,7 +195,7 @@ if [ $# -ne 1 ]; then + exit $OCF_ERR_ARGS + fi + +-: ${OCF_RESKEY_startdelay=30} ++: ${OCF_RESKEY_startdelay=20} + : ${OCF_RESKEY_stopdelay=$OCF_RESKEY_startdelay} + : ${OCF_RESKEY_mondelay=$OCF_RESKEY_startdelay} + diff --git a/SOURCES/bz1389300-iSCSILogicalUnit-IPv6-support.patch b/SOURCES/bz1389300-iSCSILogicalUnit-IPv6-support.patch new file mode 100644 index 00000000..0f371420 --- /dev/null +++ b/SOURCES/bz1389300-iSCSILogicalUnit-IPv6-support.patch @@ -0,0 +1,25 @@ +From b22e59bc72c93df40846b0a528f2839466e185de Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Thu, 23 Feb 2017 16:20:29 +0100 +Subject: [PATCH] iSCSILogicalUnit: lio-t IPv6-support + +--- + heartbeat/iSCSILogicalUnit | 5 +++++ + 1 file changed, 5 insertions(+) + +diff --git a/heartbeat/iSCSILogicalUnit b/heartbeat/iSCSILogicalUnit +index 0a07c5f..99e7686 100755 +--- a/heartbeat/iSCSILogicalUnit ++++ b/heartbeat/iSCSILogicalUnit +@@ -379,6 +379,11 @@ iSCSILogicalUnit_start() { + fi + ocf_run targetcli /iscsi/${OCF_RESKEY_target_iqn}/tpg1/luns create /backstores/block/${OCF_RESOURCE_INSTANCE} ${OCF_RESKEY_lun} || exit $OCF_ERR_GENERIC + ++ if $(ip a | grep -q inet6); then ++ ocf_run -q targetcli /iscsi/${OCF_RESKEY_target_iqn}/tpg1/portals delete 0.0.0.0 3260 ++ ocf_run -q targetcli /iscsi/${OCF_RESKEY_target_iqn}/tpg1/portals create ::0 ++ fi ++ + if [ -n "${OCF_RESKEY_allowed_initiators}" ]; then + for initiator in ${OCF_RESKEY_allowed_initiators}; do + ocf_run targetcli /iscsi/${OCF_RESKEY_target_iqn}/tpg1/acls create ${initiator} add_mapped_luns=False || exit $OCF_ERR_GENERIC diff --git a/SOURCES/bz1390974-redis-fix-selinux-permissions.patch b/SOURCES/bz1390974-redis-fix-selinux-permissions.patch new file mode 100644 index 00000000..b6c7a983 --- /dev/null +++ b/SOURCES/bz1390974-redis-fix-selinux-permissions.patch @@ -0,0 +1,29 @@ +From 70b13e3c27944292cfe658284878de5cb3a4918c Mon Sep 17 00:00:00 2001 +From: Gabriele Cerami +Date: Wed, 2 Nov 2016 00:44:37 +0100 +Subject: [PATCH] Redis: restore rundir security context + +When selinux rules packages are installed, rundir does not yet exist, +and security context for it cannot be applied. Calling restorecon after +dir creation ensures that the proper context is applied to the rundir. +If the context is not applied, selinux denies write permission, the unix +socket cannot be created, and redis does not start +--- + heartbeat/redis | 4 ++++ + 1 file changed, 4 insertions(+) + +diff --git a/heartbeat/redis b/heartbeat/redis +index f85b2f7..1fe8906 100755 +--- a/heartbeat/redis ++++ b/heartbeat/redis +@@ -324,6 +324,10 @@ function start() { + + [[ ! -d "$REDIS_RUNDIR" ]] && mkdir -p "$REDIS_RUNDIR" + chown -R "$REDIS_USER" "$REDIS_RUNDIR" ++ if have_binary "restorecon"; then ++ restorecon -Rv "$REDIS_RUNDIR" ++ fi ++ + + # check for 0 byte database dump file. This is an unrecoverable start + # condition that we can avoid by deleting the 0 byte database file. diff --git a/SOURCES/bz1391470-galera-last-commit-fix-for-mariadb-10.1.18.patch b/SOURCES/bz1391470-galera-last-commit-fix-for-mariadb-10.1.18.patch new file mode 100644 index 00000000..1afe40d0 --- /dev/null +++ b/SOURCES/bz1391470-galera-last-commit-fix-for-mariadb-10.1.18.patch @@ -0,0 +1,83 @@ +From 4e62e214f560c68f037d7a4730076ddc6ee72301 Mon Sep 17 00:00:00 2001 +From: Damien Ciabrini +Date: Thu, 17 Nov 2016 22:19:56 +0100 +Subject: [PATCH] galera: make last commit parsing compatible with mariadb + 10.1.18+ + +--- + heartbeat/galera | 39 +++++++++++++++++++++------------------ + 1 file changed, 21 insertions(+), 18 deletions(-) + +diff --git a/heartbeat/galera b/heartbeat/galera +index 543200d..44c52a5 100755 +--- a/heartbeat/galera ++++ b/heartbeat/galera +@@ -662,13 +662,13 @@ detect_last_commit() + --socket=$OCF_RESKEY_socket \ + --datadir=$OCF_RESKEY_datadir \ + --user=$OCF_RESKEY_user" ++ local recovery_file_regex='s/.*WSREP\:.*position\s*recovery.*--log_error='\''\([^'\'']*\)'\''.*/\1/p' + local recovered_position_regex='s/.*WSREP\:\s*[R|r]ecovered\s*position.*\:\(.*\)\s*$/\1/p' + + ocf_log info "attempting to detect last commit version by reading ${OCF_RESKEY_datadir}/grastate.dat" + last_commit="$(cat ${OCF_RESKEY_datadir}/grastate.dat | sed -n 's/^seqno.\s*\(.*\)\s*$/\1/p')" + if [ -z "$last_commit" ] || [ "$last_commit" = "-1" ]; then + local tmp=$(mktemp) +- local tmperr=$(mktemp) + + # if we pass here because grastate.dat doesn't exist, + # try not to bootstrap from this node if possible +@@ -678,33 +678,36 @@ detect_last_commit() + + ocf_log info "now attempting to detect last commit version using 'mysqld_safe --wsrep-recover'" + +- ${OCF_RESKEY_binary} $recover_args --wsrep-recover > $tmp 2> $tmperr ++ ${OCF_RESKEY_binary} $recover_args --wsrep-recover --log-error=$tmp 2>/dev/null + +- last_commit="$(cat $tmp | sed -n $recovered_position_regex)" ++ last_commit="$(cat $tmp | sed -n $recovered_position_regex | tail -1)" + if [ -z "$last_commit" ]; then + # Galera uses InnoDB's 2pc transactions internally. If + # server was stopped in the middle of a replication, the + # recovery may find a "prepared" XA transaction in the + # redo log, and mysql won't recover automatically + +- cat $tmperr | grep -q -E '\[ERROR\]\s+Found\s+[0-9]+\s+prepared\s+transactions!' 2>/dev/null +- if [ $? -eq 0 ]; then +- # we can only rollback the transaction, but that's OK +- # since the DB will get resynchronized anyway +- ocf_log warn "local node <${NODENAME}> was not shutdown properly. Rollback stuck transaction with --tc-heuristic-recover" +- ${OCF_RESKEY_binary} $recover_args --wsrep-recover \ +- --tc-heuristic-recover=rollback > $tmp 2>/dev/null +- +- last_commit="$(cat $tmp | sed -n $recovered_position_regex)" +- if [ ! -z "$last_commit" ]; then +- ocf_log warn "State recovered. force SST at next restart for full resynchronization" +- rm -f ${OCF_RESKEY_datadir}/grastate.dat +- # try not to bootstrap from this node if possible +- set_no_grastate ++ local recovery_file="$(cat $tmp | sed -n $recovery_file_regex)" ++ if [ -e $recovery_file ]; then ++ cat $recovery_file | grep -q -E '\[ERROR\]\s+Found\s+[0-9]+\s+prepared\s+transactions!' 2>/dev/null ++ if [ $? -eq 0 ]; then ++ # we can only rollback the transaction, but that's OK ++ # since the DB will get resynchronized anyway ++ ocf_log warn "local node <${NODENAME}> was not shutdown properly. Rollback stuck transaction with --tc-heuristic-recover" ++ ${OCF_RESKEY_binary} $recover_args --wsrep-recover \ ++ --tc-heuristic-recover=rollback --log-error=$tmp 2>/dev/null ++ ++ last_commit="$(cat $tmp | sed -n $recovered_position_regex | tail -1)" ++ if [ ! -z "$last_commit" ]; then ++ ocf_log warn "State recovered. force SST at next restart for full resynchronization" ++ rm -f ${OCF_RESKEY_datadir}/grastate.dat ++ # try not to bootstrap from this node if possible ++ set_no_grastate ++ fi + fi + fi + fi +- rm -f $tmp $tmperr ++ rm -f $tmp + fi + + if [ ! -z "$last_commit" ]; then diff --git a/SOURCES/bz1391580-portblock-return-success-on-stop-with-invalid-ip.patch b/SOURCES/bz1391580-portblock-return-success-on-stop-with-invalid-ip.patch new file mode 100644 index 00000000..c1035372 --- /dev/null +++ b/SOURCES/bz1391580-portblock-return-success-on-stop-with-invalid-ip.patch @@ -0,0 +1,22 @@ +From 501316b1c6c072c8750c8bd951594a4e1ef408f4 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Fri, 25 Nov 2016 12:13:17 +0100 +Subject: [PATCH] IPaddr2: return success on stop with invalid IP + +--- + heartbeat/IPaddr2 | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/heartbeat/IPaddr2 b/heartbeat/IPaddr2 +index b224ca5..aea7a19 100755 +--- a/heartbeat/IPaddr2 ++++ b/heartbeat/IPaddr2 +@@ -351,7 +351,7 @@ ip_init() { + exit $OCF_ERR_INSTALLED + fi + +- if [ X"$OCF_RESKEY_ip" = "X" ]; then ++ if [ X"$OCF_RESKEY_ip" = "X" ] && [ "$__OCF_ACTION" != "stop" ]; then + ocf_exit_reason "IP address (the ip parameter) is mandatory" + exit $OCF_ERR_CONFIGURED + fi diff --git a/SOURCES/bz1392432-LVM-partial_activation-fix.patch b/SOURCES/bz1392432-LVM-partial_activation-fix.patch new file mode 100644 index 00000000..147f185e --- /dev/null +++ b/SOURCES/bz1392432-LVM-partial_activation-fix.patch @@ -0,0 +1,33 @@ +From 42d298191993fd8d851a881a067e09aca2d4a079 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Fri, 27 Jan 2017 10:25:18 +0100 +Subject: [PATCH] LVM: fix partial activation + +--- + heartbeat/LVM | 6 ++++-- + 1 file changed, 4 insertions(+), 2 deletions(-) + +diff --git a/heartbeat/LVM b/heartbeat/LVM +index 79c2791..90a900b 100755 +--- a/heartbeat/LVM ++++ b/heartbeat/LVM +@@ -548,7 +548,8 @@ LVM_validate_all() { + # "unknown device" then another node may have marked a device missing + # where we have access to all of them and can start without issue. + if vgs -o pv_attr --noheadings $OCF_RESKEY_volgrpname 2>/dev/null | grep 'm' > /dev/null 2>&1; then +- if vgs -o pv_name --noheadings $OCF_RESKEY_volgrpname 2>/dev/null | grep 'unknown device' > /dev/null 2>&1; then ++ case $(vgs -o attr --noheadings $OCF_RESKEY_volgrpname | tr -d ' ') in ++ ???p??*) + if ! ocf_is_true "$OCF_RESKEY_partial_activation" ; then + # We are missing devices and cannot activate partially + ocf_exit_reason "Volume group [$VOLUME] has devices missing. Consider partial_activation=true to attempt to activate partially" +@@ -558,7 +559,8 @@ LVM_validate_all() { + # Assume that caused the vgck failure and carry on + ocf_log warn "Volume group inconsistency detected with missing device(s) and partial_activation enabled. Proceeding with requested action." + fi +- fi ++ ;; ++ esac + # else the vg is partial but all devices are accounted for, so another + # node must have marked the device missing. Proceed. + else diff --git a/SOURCES/bz1393189-1-IPaddr2-detect-duplicate-IP.patch b/SOURCES/bz1393189-1-IPaddr2-detect-duplicate-IP.patch new file mode 100644 index 00000000..30b717dc --- /dev/null +++ b/SOURCES/bz1393189-1-IPaddr2-detect-duplicate-IP.patch @@ -0,0 +1,76 @@ +From 24edeaaacf0648b3df0032ef5d1deb3a9e11b388 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Wed, 11 Jan 2017 14:11:21 +0100 +Subject: [PATCH] IPaddr2 detect duplicate IP + +--- + heartbeat/IPaddr2 | 28 ++++++++++++++++++++++++---- + 1 file changed, 24 insertions(+), 4 deletions(-) + +diff --git a/heartbeat/IPaddr2 b/heartbeat/IPaddr2 +index b416e31..2d5e1ea 100755 +--- a/heartbeat/IPaddr2 ++++ b/heartbeat/IPaddr2 +@@ -79,6 +79,7 @@ OCF_RESKEY_arp_count_default=5 + OCF_RESKEY_arp_count_refresh_default=0 + OCF_RESKEY_arp_bg_default=true + OCF_RESKEY_arp_mac_default="ffffffffffff" ++OCF_RESKEY_run_arping_default=false + + : ${OCF_RESKEY_lvs_support=${OCF_RESKEY_lvs_support_default}} + : ${OCF_RESKEY_lvs_ipv6_addrlabel=${OCF_RESKEY_lvs_ipv6_addrlabel_default}} +@@ -90,6 +91,7 @@ OCF_RESKEY_arp_mac_default="ffffffffffff" + : ${OCF_RESKEY_arp_count_refresh=${OCF_RESKEY_arp_count_refresh_default}} + : ${OCF_RESKEY_arp_bg=${OCF_RESKEY_arp_bg_default}} + : ${OCF_RESKEY_arp_mac=${OCF_RESKEY_arp_mac_default}} ++: ${OCF_RESKEY_run_arping=${OCF_RESKEY_run_arping_default}} + ####################################################################### + + SENDARP=$HA_BIN/send_arp +@@ -340,6 +342,14 @@ IP address goes away. + + + ++ ++ ++Whether or not to run arping for IPv4 collision detection check. ++ ++Run arping for IPv4 collision detection check ++ ++ ++ + + + +@@ -556,6 +566,15 @@ add_interface () { + iface="$4" + label="$5" + ++ if [ "$FAMILY" = "inet" ] && ocf_is_true $OCF_RESKEY_run_arping && ++ check_binary arping; then ++ arping -q -c 2 -w 3 -D -I $iface $ipaddr ++ if [ $? = 1 ]; then ++ ocf_log err "IPv4 address collision $ipaddr [DAD]" ++ return $OCF_ERR_CONFIGURED ++ fi ++ fi ++ + if [ "$FAMILY" = "inet6" ] && ocf_is_true $OCF_RESKEY_lvs_ipv6_addrlabel ;then + add_ipv6_addrlabel $ipaddr + fi +@@ -877,10 +896,11 @@ ip_start() { + fi + + add_interface $OCF_RESKEY_ip $NETMASK ${BRDCAST:-none} $NIC $IFLABEL +- +- if [ $? -ne 0 ]; then +- ocf_exit_reason "$CMD failed." +- exit $OCF_ERR_GENERIC ++ rc=$? ++ ++ if [ $rc -ne $OCF_SUCCESS ]; then ++ ocf_exit_reason "Failed to add $OCF_RESKEY_ip" ++ exit $rc + fi + fi + diff --git a/SOURCES/bz1393189-2-IPaddr2-detect-duplicate-IP.patch b/SOURCES/bz1393189-2-IPaddr2-detect-duplicate-IP.patch new file mode 100644 index 00000000..f3acf297 --- /dev/null +++ b/SOURCES/bz1393189-2-IPaddr2-detect-duplicate-IP.patch @@ -0,0 +1,54 @@ +From 303a738d177a60d001209c6d334ef44f05e1b93b Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Tue, 28 Mar 2017 14:15:49 +0200 +Subject: [PATCH] IPaddr2: fix gratuitious ARP checks + +--- + heartbeat/IPaddr2 | 24 ++++++++++++++++-------- + 1 file changed, 16 insertions(+), 8 deletions(-) + +diff --git a/heartbeat/IPaddr2 b/heartbeat/IPaddr2 +index 27b7208..aea2aa2 100755 +--- a/heartbeat/IPaddr2 ++++ b/heartbeat/IPaddr2 +@@ -710,10 +710,14 @@ run_send_arp() { + if [ $ARP_COUNT -ne 0 ] ; then + ARGS="-i $OCF_RESKEY_arp_interval -r $ARP_COUNT -p $SENDARPPIDFILE $NIC $OCF_RESKEY_ip $MY_MAC not_used not_used" + ocf_log $LOGLEVEL "$SENDARP $ARGS" +- if ocf_is_true $OCF_RESKEY_arp_bg; then +- ($SENDARP $ARGS || ocf_log err "Could not send gratuitous arps")& >&2 +- else +- $SENDARP $ARGS || ocf_log err "Could not send gratuitous arps" ++ output=$($SENDARP $ARGS 2>&1) ++ rc=$? ++ if [ $rc -ne $OCF_SUCCESS ]; then ++ if ! ocf_is_true $OCF_RESKEY_arp_bg; then ++ ocf_log err "send_arp output: $output" ++ fi ++ ocf_exit_reason "Could not send gratuitous arps" ++ exit $OCF_ERR_GENERIC + fi + fi + } +@@ -771,10 +775,14 @@ run_send_ib_arp() { + if [ $ARP_COUNT -ne 0 ] ; then + ARGS="-q -c $ARP_COUNT -U -I $NIC $OCF_RESKEY_ip" + ocf_log $LOGLEVEL "ipoibarping $ARGS" +- if ocf_is_true $OCF_RESKEY_arp_bg; then +- (ipoibarping $ARGS || ocf_log err "Could not send gratuitous arps")& >&2 +- else +- ipoibarping $ARGS || ocf_log err "Could not send gratuitous arps" ++ output=$(ipoibarping $ARGS 2>&1) ++ rc=$? ++ if [ $rc -ne $OCF_SUCCESS ]; then ++ if ! ocf_is_true $OCF_RESKEY_arp_bg; then ++ ocf_log err "ipoibarping output: $output" ++ fi ++ ocf_exit_reason "Could not send gratuitous arps" ++ exit $OCF_ERR_GENERIC + fi + fi + } +-- +2.9.3 + diff --git a/SOURCES/bz1395142-1-update-saphana-saphanatopology.patch b/SOURCES/bz1395142-1-update-saphana-saphanatopology.patch new file mode 100644 index 00000000..5cd8ffa0 --- /dev/null +++ b/SOURCES/bz1395142-1-update-saphana-saphanatopology.patch @@ -0,0 +1,1990 @@ +diff -uNr a/heartbeat/SAPHana b/heartbeat/SAPHana +--- a/heartbeat/SAPHana 2016-10-14 10:09:56.479051279 +0200 ++++ b/heartbeat/SAPHana 2016-10-14 10:29:23.990066292 +0200 +@@ -2,8 +2,8 @@ + # + # SAPHana + # +-# Description: Manages two single SAP HANA Instance in System Replication +-# Planned: do also manage scale-up scenarios ++# Description: Manages two SAP HANA Databases in System Replication ++# Planned: do also manage scale-out scenarios + # currently the SAPHana is dependent of the analysis of + # SAPHanaTopology + # For supported scenarios please read the README file provided +@@ -16,7 +16,7 @@ + # Support: linux@sap.com + # License: GNU General Public License (GPL) + # Copyright: (c) 2013,2014 SUSE Linux Products GmbH +-# Copyright: (c) 2015 SUSE Linux GmbH ++# (c) 2015-2016 SUSE Linux GmbH + # + # An example usage: + # See usage() function below for more details... +@@ -29,12 +29,13 @@ + # OCF_RESKEY_INSTANCE_PROFILE (optional, well known directories will be searched by default) + # OCF_RESKEY_PREFER_SITE_TAKEOVER (optional, default is no) + # OCF_RESKEY_DUPLICATE_PRIMARY_TIMEOUT (optional, time difference needed between two last-primary-tiemstampe (lpt)) +-# OCF_RESKEY_SAPHanaFilter (optional, should only be set if been told by support or for debugging purposes) ++# OCF_RESKEY_SAPHanaFilter (outdated, replaced by cluster property hana_${sid}_glob_filter) + # + # + ####################################################################### + # + # Initialization: ++SAPHanaVersion="0.152.17" + timeB=$(date '+%s') + + : ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat} +@@ -43,6 +44,12 @@ + # + ####################################################################### + # ++log_attributes=false ++if ocf_is_true "$log_attributes"; then ++ log_attr_file="/var/log/fhATTRIBUTES" ++else ++ log_attr_file="/dev/null" ++fi + + HANA_STATE_PRIMARY=0 + HANA_STATE_SECONDARY=1 +@@ -107,7 +114,7 @@ + cat <<-EOF + usage: $0 ($methods) + +- $0 manages a SAP HANA Instance as an HA resource. ++ $0 manages two SAP HANA databases (scale-up) in system replication. + + The 'start' operation starts the HANA instance or bring the "clone instance" to a WAITING status + The 'stop' operation stops the HANA instance +@@ -145,15 +152,14 @@ + + + +-0.151.1 ++$SAPHanaVersion + +-Manages two SAP HANA instances in system replication (SR). ++Manages two SAP HANA database systems in system replication (SR). + +-The SAPHanaSR resource agent manages two SAP Hana instances (databases) which are configured +-in system replication. This first version is limited to the scale-up scenario. Scale-Out is +-not supported in this version. ++The SAPHanaSR resource agent manages two SAP HANA database systems which are configured ++in system replication. SAPHana supports Scale-Up scenarios. + +-Managing the two SAP HANA instances means that the resource agent controls the start/stop of the ++Managing the two SAP HANA database systems means that the resource agent controls the start/stop of the + instances. In addition the resource agent is able to monitor the SAP HANA databases to check their + availability on landscape host configuration level. For this monitoring the resource agent relies on interfaces + provided by SAP. A third task of the resource agent is to also check the synchronisation status +@@ -205,9 +211,10 @@ + Should cluster/RA prefer to switchover to slave instance instead of restarting master locally? Default="yes" + no: Do prefer restart locally + yes: Do prefer takever to remote site ++ never: Do never run a sr_takeover (promote) at the secondary side. THIS VALUE IS CURRENTLY NOT SUPPORTED. + + Local or site recover preferred? +- ++ + + + Define, if a former primary should automatically be registered. +@@ -220,7 +227,7 @@ + Time difference needed between to primary time stamps, if a dual-primary situation occurs + Time difference needed between to primary time stamps, + if a dual-primary situation occurs. If the time difference is +- less than the time gap, then the cluster hold one or both instances in a "WAITING" status. This is to give an admin ++ less than the time gap, then the cluster holds one or both instances in a "WAITING" status. This is to give an admin + a chance to react on a failover. A failed former primary will be registered after the time difference is passed. After + this registration to the new primary all data will be overwritten by the system replication. + +@@ -290,6 +297,45 @@ + local rc=0; tr -d '"'; return $rc + } + ++# function: version: cpmpare two HANA version strings ++function ver_lt() { ++ ocf_version_cmp $1 $2 ++ test $? -eq 0 && return 0 || return 1 ++} ++ ++function ver_le() { ++ ocf_version_cmp $1 $2 ++ test $? -eq 0 -o $? -eq 1 && return 0 || return 1 ++} ++ ++function ver_gt() { ++ ocf_version_cmp $1 $2 ++ test $? -eq 2 && return 0 || return 1 ++} ++ ++function ver_ge() { ++ ocf_version_cmp $1 $2 ++ test $? -eq 2 -o $? -eq 1 && return 0 || return 1 ++} ++# ++# function: version: cpmpare two HANA version strings ++# ++function version() { ++ if [ $# -eq 3 ]; then ++ case "$2" in ++ LE | le | "<=" ) ver_le $1 $3;; ++ LT | lt | "<" ) ver_lt $1 $3;; ++ GE | ge | ">=" ) ver_ge $1 $3;; ++ GT | gt | ">" ) ver_gt $1 $3;; ++ * ) return 1; ++ esac ++ elif [ $# -ge 5 ]; then ++ version $1 $2 $3 && shift 2 && version $* ++ else ++ return 1; ++ fi ++} ++ + # + # function: remoteHost2remoteNode - convert a SAP remoteHost to the cluster node name + # params: remoteHost +@@ -372,12 +418,16 @@ + dstr=$(date) + case "$attr_store" in + reboot | forever ) +- echo "$dstr: SAPHana: crm_attribute -N ${attr_node} -G -n \"$attr_name\" -l $attr_store -q" >> /var/log/fhATTRIBUTE +- crm_attribute -N ${attr_node} -G -n "$attr_name" -l $attr_store -q -d "$attr_default" 2>>/var/log/fhATTRIBUTE; rc=$? ++ if ocf_is_true "$log_attributes"; then ++ echo "$dstr: SAPHana: crm_attribute -N ${attr_node} -G -n \"$attr_name\" -l $attr_store -q" >> $log_attr_file ++ fi ++ crm_attribute -N ${attr_node} -G -n "$attr_name" -l $attr_store -q -d "$attr_default" 2>>$log_attr_file; rc=$? + ;; + props ) +- echo "$dstr: SAPHana: crm_attribute -G -n \"$attr_name\" -t crm_config -q" >> /var/log/fhATTRIBUTE +- crm_attribute -G -n "$attr_name" -t crm_config -q -d "$attr_default" 2>>/var/log/fhATTRIBUTE; rc=$? ++ if ocf_is_true "$log_attributes"; then ++ echo "$dstr: SAPHana: crm_attribute -G -n \"$attr_name\" -t crm_config -q" >> $log_attr_file ++ fi ++ crm_attribute -G -n "$attr_name" -t crm_config -q -d "$attr_default" 2>>$log_attr_file; rc=$? + ;; + esac + super_ocf_log info "FLOW $FUNCNAME rc=$rc" +@@ -405,12 +455,16 @@ + dstr=$(date) + case "$attr_store" in + reboot | forever ) +- echo "$dstr: SAPHana: crm_attribute -N $attr_node -v $attr_value -n \"$attr_name\" -l $attr_store" >> /var/log/fhATTRIBUTE +- crm_attribute -N $attr_node -v $attr_value -n "$attr_name" -l $attr_store 2>>/var/log/fhATTRIBUTE; rc=$? ++ if ocf_is_true "$log_attributes"; then ++ echo "$dstr: SAPHana: crm_attribute -N $attr_node -v $attr_value -n \"$attr_name\" -l $attr_store" >> $log_attr_file ++ fi ++ crm_attribute -N $attr_node -v $attr_value -n "$attr_name" -l $attr_store 2>>$log_attr_file; rc=$? + ;; + props ) +- echo "$dstr: SAPHana: crm_attribute -v $attr_value -n \"$attr_name\" -t crm_config -s SAPHanaSR" >> /var/log/fhATTRIBUTE +- crm_attribute -v $attr_value -n "$attr_name" -t crm_config -s SAPHanaSR 2>>/var/log/fhATTRIBUTE; rc=$? ++ if ocf_is_true "$log_attributes"; then ++ echo "$dstr: SAPHana: crm_attribute -v $attr_value -n \"$attr_name\" -t crm_config -s SAPHanaSR" >> $log_attr_file ++ fi ++ crm_attribute -v $attr_value -n "$attr_name" -t crm_config -s SAPHanaSR 2>>$log_attr_file; rc=$? + ;; + esac + else +@@ -460,6 +514,10 @@ + # DONE: PRIO2: Only adjust master if value is really different (try to check that) + oldscore=$(${HA_SBIN_DIR}/crm_master -G -q -l reboot) + if [ "$oldscore" != "$score" ]; then ++ dstr=$(date) ++ if ocf_is_true "$log_attributes"; then ++ echo "$dstr: SAPHana: crm_master -v $score -l reboot " >> $log_attr_file ++ fi + super_ocf_log debug "DBG: SET crm master: $score (old: $oldscore)" + ${HA_SBIN_DIR}/crm_master -v $score -l reboot; rc=$? + else +@@ -471,9 +529,9 @@ + } + + # +-# function: scoring_crm_master - score instance due to role ans sync match (table SCORING_TABLE_PREFERRED_SITE_TAKEOVER) ++# function: scoring_crm_master - score instance due to role ans sync match (table SCORING_TABLE) + # params: NODE_ROLES NODE_SYNC_STATUS +-# globals: SCORING_TABLE_PREFERRED_SITE_TAKEOVER[@], ++# globals: SCORING_TABLE[@], + # + scoring_crm_master() + { +@@ -482,7 +540,7 @@ + local sync="$2" + local skip=0 + local myScore="" +- for scan in "${SCORING_TABLE_PREFERRED_SITE_TAKEOVER[@]}"; do ++ for scan in "${SCORING_TABLE[@]}"; do + if [ $skip -eq 0 ]; then + read rolePatt syncPatt score <<< $scan + if grep "$rolePatt" <<< "$roles"; then +@@ -494,7 +552,7 @@ + fi + done + super_ocf_log debug "DBG: scoring_crm_master adjust score $myScore" +- # TODO: PRIO1: DO Not Score, If we did not found our role/sync at this moment - bsc#919925 ++ # DONE: PRIO1: DO Not Score, If we did not found our role/sync at this moment - bsc#919925 + if [ -n "$myScore" ]; then + set_crm_master $myScore + fi +@@ -514,28 +572,91 @@ + } + + # ++# function: HANA_CALL ++# params: timeout-in-seconds cmd-line ++# globals: sid(r), SID(r), InstanceName(r) ++# ++function HANA_CALL() ++{ ++ # ++ # TODO: PRIO 5: remove 'su - ${sidadm} later, when SAP HANA resoled issue with ++ # root-user-called hdbnsutil -sr_state (which creates root-owned shared memory file in /var/lib/hdb/SID/shmgrp) ++ # TODO: PRIO 5: Maybe make "su" optional by a parameter ++ local timeOut=0 ++ local onTimeOut="" ++ local rc=0 ++ local use_su=1 # Default to be changed later (see TODO above) ++ local pre_cmd="" ++ local cmd="" ++ local pre_script="" ++ local output="" ++ while [ $# -gt 0 ]; do ++ case "$1" in ++ --timeout ) timeOut=$2; shift;; ++ --use-su ) use_su=1;; ++ --on-timeout ) onTimeOut="$2"; shift;; ++ --cmd ) shift; cmd="$*"; break;; ++ esac ++ shift ++ done ++ ++ if [ $use_su -eq 1 ]; then ++ pre_cmd="su - ${sid}adm -c" ++ pre_script="true" ++ else ++ # as root user we need the library path to the SAP kernel to be able to call sapcontrol ++ # check, if we already added DIR_EXECUTABLE at the beginning of LD_LIBRARY_PATH ++ if [ "${LD_LIBRARY_PATH%%*:}" != "$DIR_EXECUTABLE" ] ++ then ++ MY_LD_LIBRARY_PATH=$DIR_EXECUTABLE${LD_LIBRARY_PATH:+:}$LD_LIBRARY_PATH ++ fi ++ pre_cmd="bash -c" ++ pre_script="LD_LIBRARY_PATH=$MY_LD_LIBRARY_PATH; export LD_LIBRARY_PATH" ++ fi ++ case $timeOut in ++ 0 | inf ) ++ output=$($pre_cmd "$pre_script; /usr/sap/$SID/$InstanceName/HDBSettings.sh $cmd"); rc=$? ++ ;; ++ * ) ++ output=$(timeout $timeOut $pre_cmd "$pre_script; /usr/sap/$SID/$InstanceName/HDBSettings.sh $cmd"); rc=$? ++ # ++ # on timeout ... ++ # ++ if [ $rc -eq 124 -a -n "$onTimeOut" ]; then ++ local second_output="" ++ second_output=$($pre_cmd "$pre_script; /usr/sap/$SID/$InstanceName/HDBSettings.sh $onTimeOut"); ++ fi ++ ;; ++ esac ++ echo "$output" ++ return $rc; ++} ++ ++# + # function: saphana_init - initialize variables for the resource agent + # params: InstanceName +-# globals: OCF_*(r), SID(w), sid(rw), sidadm(w), InstanceName(w), InstanceNr(w), SAPVIRHOST(w), PreferSiteTakeover(w), +-# globals: sr_name(w), remoteHost(w), otherNodes(w), rem_SR_name(w) ++# globals: OCF_*(r), SID(w), sid(rw), sidadm(w), InstanceName(w), InstanceNr(w), SAPVIRHOST(w), PreferSiteTakeover(w), ++# globals: sr_name(w), remoteHost(w), otherNodes(w), remSR_name(w) + # globals: ATTR_NAME_HANA_SYNC_STATUS(w), ATTR_NAME_HANA_CLONE_STATE(w) + # globals: DIR_EXECUTABLE(w), SAPSTARTSRV(w), SAPCONTROL(w), DIR_PROFILE(w), SAPSTARTPROFILE(w), LD_LIBRARY_PATH(w), PATH(w) + # globals: LPA_DIRECTORY(w), SIDInstanceName(w), remoteNode(w), hdbSrQueryTimeout(w) ++# globals: NODENAME(w), vNAME(w), hdbver(w), + # saphana_init : Define global variables with default values, if optional parameters are not set + # + function saphana_init() { + super_ocf_log info "FLOW $FUNCNAME ($*)" + local rc=$OCF_SUCCESS +- local vName + local clN + # local site + # two parameter models (for transition only) + # OLD: InstanceName + # NEW: SID InstanceNumber ++ NODENAME=$(crm_node -n) + SID=$OCF_RESKEY_SID + InstanceNr=$OCF_RESKEY_InstanceNumber + SIDInstanceName="${SID}_HDB${InstanceNr}" + InstanceName="HDB${InstanceNr}" ++ export SAPSYSTEMNAME=$SID + super_ocf_log debug "DBG: Used new method to get SID ($SID) and InstanceNr ($InstanceNr)" + sid=$(echo "$SID" | tr [:upper:] [:lower:]) + sidadm="${sid}adm" +@@ -544,15 +665,23 @@ + # DONE: PRIO4: SAPVIRHOST might be different to NODENAME + # DONE: PRIO1: ASK: Is the output format of ListInstances fix? Could we take that as an API? Answer: Yes + # try to catch: Inst Info : LNX - 42 - lv9041 - 740, patch 36, changelist 1444691 +- # We rely on the following format: SID is word#4, NR is work#6, vHost is word#8 +- vName=$(/usr/sap/hostctrl/exe/saphostctrl -function ListInstances \ +- | awk '$4 == SID && $6=NR { print $8 }' SID=$SID NR=$InstanceNr) ++ # We rely on the following format: SID is word#4, SYSNR is work#6, vHost is word#8 ++ if [ -e /usr/sap/hostctrl/exe/saphostctrl ]; then ++ vName=$(/usr/sap/hostctrl/exe/saphostctrl -function ListInstances \ ++ | awk '$4 == SID && $6 == SYSNR { print $8 }' SID=$SID SYSNR=$InstanceNr 2>/dev/null ) ++ super_ocf_log debug "DBG: ListInstances: $(/usr/sap/hostctrl/exe/saphostctrl -function ListInstances)" ++ else ++ super_ocf_log error "ERR: SAPHOSTAGENT is not installed at /usr/sap/hostctrl/exe (saphostctrl missing)" ++ fi + if [ -z "$vName" ]; then + # + # if saphostctrl does not know the answer, try to fallback to attribute provided by SAPHanaTopology + # + vName=$(get_hana_attribute ${NODENAME} ${ATTR_NAME_HANA_VHOST[@]} "$NODENAME"); + fi ++ if [ -z "$vName" ]; then # last fallback if we are not able to figure out the virtual host name ++ vName="$NODENAME" ++ fi + SAPVIRHOST=${vName} + PreferSiteTakeover="$OCF_RESKEY_PREFER_SITE_TAKEOVER" + AUTOMATED_REGISTER="${OCF_RESKEY_AUTOMATED_REGISTER:-false}" +@@ -571,6 +700,12 @@ + ATTR_NAME_HANA_SRMODE=("hana_${sid}_srmode" "forever") + ATTR_NAME_HANA_VHOST=("hana_${sid}_vhost" "forever") + ATTR_NAME_HANA_STATUS=("hana_${sid}_status" "reboot") ++ ATTR_NAME_HANA_OPERATION_MODE=("hana_${sid}_op_mode" "forever") ++ # ++ # new "central" attributes ++ # ++ ATTR_NAME_HANA_FILTER=("hana_${sid}_glob_filter" "props" "ra-act-dec-lpa") ++ SAPHanaFilter=$(get_hana_attribute "X" ${ATTR_NAME_HANA_FILTER[@]}) + # + # TODO: PRIO4: Table for non-preferred-site-takeover + # +@@ -591,9 +726,7 @@ + ) + SCORING_TABLE_PREFERRED_LOCAL_RESTART=( + "[0-9]*:P:[^:]*:master .* 150" +- "[0-9]*:P:[^:]*:slave .* 140" +- "[0-9]*:P:[^:]*:\? .* 0" +- "[0-9]*:P:[^:]*:- .* 0" ++ "[0-9]*:P:[^:]*:.* .* 140" + "[0-9]*:S:[^:]*:master SOK 100" + "[0-9]*:S:[^:]*:master SFAIL -INFINITY" + "[0-9]*:S:[^:]*:slave SOK 10" +@@ -602,6 +735,25 @@ + "[0-9]*:S:[^:]*:- .* 0" + ".* .* -1" + ) ++ SCORING_TABLE_PREFERRED_NEVER=( ++ "[234]*:P:[^:]*:master .* 150" ++ "[015-9]*:P:[^:]*:master .* 90" ++ "[0-9]*:P:[^:]*:.* .* -INFINITY" ++ "[0-9]*:S:[^:]*:.* .* -INFINITY" ++ ".* .* -INFINITY" ++ ) ++ if ocf_is_true $PreferSiteTakeover; then ++ SCORING_TABLE=("${SCORING_TABLE_PREFERRED_SITE_TAKEOVER[@]}") ++ else ++ case "$PreferSiteTakeover" in ++ never|NEVER|Never ) ++ SCORING_TABLE=("${SCORING_TABLE_PREFERRED_NEVER[@]}") ++ ;; ++ * ) ++ SCORING_TABLE=("${SCORING_TABLE_PREFERRED_LOCAL_RESTART[@]}") ++ ;; ++ esac ++ fi + # + DUPLICATE_PRIMARY_TIMEOUT="${OCF_RESKEY_DUPLICATE_PRIMARY_TIMEOUT:-7200}" + super_ocf_log debug "DBG: DUPLICATE_PRIMARY_TIMEOUT=$DUPLICATE_PRIMARY_TIMEOUT" +@@ -615,7 +767,7 @@ + esac + # + # +- ++ # + remoteHost=$(get_hana_attribute ${NODENAME} ${ATTR_NAME_HANA_REMOTEHOST[@]}); + if [ -z "$remoteHost" ]; then + if [ ${#otherNodes[@]} -eq 1 ]; then # we are a 2 node cluster, lets assume the other is the remote-host +@@ -640,7 +792,7 @@ + sr_mode="sync" + fi + if [ -n "$remoteNode" ]; then +- rem_SR_name=$(get_hana_attribute ${remoteNode} ${ATTR_NAME_HANA_SITE[@]}); ++ remSR_name=$(get_hana_attribute ${remoteNode} ${ATTR_NAME_HANA_SITE[@]}); + fi + super_ocf_log debug "DBG: sr_name=$sr_name, remoteHost=$remoteHost, remoteNode=$remoteNode, sr_mode=$sr_mode" + # optional OCF parameters, we try to guess which directories are correct +@@ -671,26 +823,21 @@ + # + SAPSTARTPROFILE="$(ls -1 $DIR_PROFILE/${OCF_RESKEY_INSTANCE_PROFILE:-${SID}_${InstanceName}_*})" + fi +- # as root user we need the library path to the SAP kernel to be able to call sapcontrol +- # check, if we already added DIR_EXECUTABLE at the beginning of LD_LIBRARY_PATH +- if [ "${LD_LIBRARY_PATH%%*:}" != "$DIR_EXECUTABLE" ] +- then +- LD_LIBRARY_PATH=$DIR_EXECUTABLE${LD_LIBRARY_PATH:+:}$LD_LIBRARY_PATH +- export LD_LIBRARY_PATH +- fi + PATH=${PATH}:${DIR_EXECUTABLE}; export PATH ++ local ges_ver ++ ges_ver=$(HANA_CALL --timeout 10 --cmd "HDB version" | tr -d " " | awk -F: '$1 == "version" {print $2}') ++ hdbver=${ges_ver%.*.*} ++ # ++ # since rev 111.00 we should use a new hdbnsutil option to get the -sr_state ++ # since rev 112.03 the old option is changed and we should use -sr_stateConfiguration where ever possible ++ # ++ hdbState="hdbnsutil -sr_state" ++ hdbMap="hdbnsutil -sr_state" ++ if version "$hdbver" ">=" "1.00.111"; then ++ hdbState="hdbnsutil -sr_stateConfiguration" ++ hdbMap="hdbnsutil -sr_stateHostMapping" ++ fi + super_ocf_log info "FLOW $FUNCNAME rc=$OCF_SUCCESS" +- ############################# +- # TODO: PRIO9: To be able to call landscapeHostConfig.py without su (so as root) +- # TODO: PRIO9: Research for environment script .htacces or something like that +- #export SAPSYSTEMNAME=ZLF +- #export DIR_INSTANCE=/usr/sap/ZLF/HDB02 +- #export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$DIR_INSTANCE/exe:$DIR_INSTANCE/exe/Python/lib +- #export PYTHONPATH=$DIR_INSTANCE/$HOST:$DIR_INSTANCE/exe/python_support:$DIR_INSTANCE/exe +- #export PYTHONHOME=$DIR_INSTANCE/exe/Python +- #export SAP_RETRIEVAL_PATH=$DIR_INSTANCE/$HOST +- #export DIR_EXECUTABLE=$DIR_INSTANCE/exe +- ############################# + return $OCF_SUCCESS + } + +@@ -765,7 +912,11 @@ + # or ownership - they will be recreated by sapstartsrv during next start + rm -f /tmp/.sapstream5${InstanceNr}13 + rm -f /tmp/.sapstream5${InstanceNr}14 +- $SAPSTARTSRV pf=$SAPSTARTPROFILE -D -u $sidadm ++ ( ++ export PATH="$DIR_EXECUTABLE${PATH:+:}$PATH" ++ export LD_LIBRARY_PATH="$DIR_EXECUTABLE${LD_LIBRARY_PATH:+:}$LD_LIBRARY_PATH" ++ $SAPSTARTSRV pf=$SAPSTARTPROFILE -D -u $sidadm ++ ) + # now make sure the daemon has been started and is able to respond + local srvrc=1 + while [ $srvrc -eq 1 -a $(pgrep -f "sapstartsrv.*$runninginst" | wc -l) -gt 0 ] +@@ -809,31 +960,47 @@ + function check_for_primary() { + super_ocf_log info "FLOW $FUNCNAME ($*)" + local rc=$HANA_STATE_DEFECT +- node_full_status=$(su - ${sidadm} -c "hdbnsutil -sr_state" 2>/dev/null ) +- node_status=$(echo "$node_full_status" | awk '$1=="mode:" {print $2}') +- super_ocf_log debug "DBG: check_for_primary: node_status=$node_status" +- # TODO: PRIO2: Maybe we need to use a fallback interface when hdbnsitil does not answer properly -> lookup in config files? ++ # TODO: PRIO 3: Check beginning from which SPS does SAP support HDBSettings.sh? ++ # TODO: Limit the runtime of hdbnsutil and use getParameter.py as fallback ++ # TODO: PRIO2: Maybe we need to use a fallback interface when hdbnsutil does not answer properly -> lookup in config files? + # This might also solve some problems when we could not figure-out the ilocal or remote site name +- for i in 1 2 3 4 5 6 7 8 9; do ++ local chkMethod="" ++ for chkMethod in hU hU hU gP; do ++ case "$chkMethod" in ++ gP ) ++ local gpKeys="" ++ gpKeys=$(echo --key=global.ini/system_replication/{mode,site_name,site_id}) ++ node_full_status=$(HANA_CALL --timeout 60 --cmd "HDBSettings.sh getParameter.py $gpKeys --sapcontrol=1" 2>&1 | awk -F/ 'BEGIN {out=0} /^SAPCONTROL-OK: / { out=1 } /^SAPCONTROL-OK: / { out=0 } /=/ {if (out==1) {print $3} }') ++ node_status=$(echo "$node_full_status" | awk -F= '$1=="mode" {print $2}') ++ super_ocf_log info "ACT: Using getParameter.py as fallback - node_status=$node_status" ++ ;; ++ hU | * ) ++ # DONE: PRIO1: Begginning from SAP HANA rev 112.03 -sr_state is not longer supported ++ node_full_status=$(HANA_CALL --timeout 60 --cmd "$hdbState" 2>/dev/null ) ++ node_status=$(echo "$node_full_status" | awk '$1=="mode:" {print $2}') ++ super_ocf_log debug "DBG: check_for_primary: node_status=$node_status" ++ ;; ++ esac + case "$node_status" in + primary ) +- super_ocf_log info "FLOW: $FUNCNAME rc=HANA_STATE_PRIMARY" +- return $HANA_STATE_PRIMARY;; ++ rc=$HANA_STATE_PRIMARY ++ break;; + syncmem | sync | async ) +- super_ocf_log info "FLOW: $FUNCNAME rc=HANA_STATE_SECONDARY" +- return $HANA_STATE_SECONDARY;; ++ rc=$HANA_STATE_SECONDARY ++ break;; + none ) # have seen that mode on second side BEFEORE we registered it as replica +- super_ocf_log info "FLOW: $FUNCNAME rc=HANA_STATE_STANDALONE" +- return $HANA_STATE_STANDALONE;; ++ rc=$HANA_STATE_STANDALONE ++ break;; + * ) + super_ocf_log err "ACT: check_for_primary: we didn't expect node_status to be: <$node_status>" + dump=$( echo $node_status | hexdump -C ); + super_ocf_log err "ACT: check_for_primary: we didn't expect node_status to be: DUMP <$dump>" +- node_full_status=$(su - ${sidadm} -c "hdbnsutil -sr_state" 2>/dev/null ) +- node_status=$(echo "$node_full_status" | awk '$1=="mode:" {print $2}') ++ # TODO: Limit the runtime of hdbnsutil and use getParameter.py as fallback ++ # SAP_CALL + super_ocf_log debug "DEC: check_for_primary: loop=$i: node_status=$node_status" + # TODO: PRIO1: Maybe we need to keep the old value for P/S/N, if hdbnsutil just crashes + esac; ++ sleep 2 + done + super_ocf_log info "FLOW $FUNCNAME rc=$rc" + return $rc +@@ -854,12 +1021,18 @@ + { + super_ocf_log info "FLOW $FUNCNAME ($*)" + local rc=-1 srRc=0 all_nodes_other_side="" n="" siteParam="" +- if [ -n "$rem_SR_name" ]; then +- siteParam="--site=$rem_SR_name" ++ if [ -n "$remSR_name" ]; then ++ siteParam="--site=$remSR_name" + fi +- FULL_SR_STATUS=$(su - $sidadm -c "python $DIR_EXECUTABLE/python_support/systemReplicationStatus.py $siteParam" 2>/dev/null); srRc=$? +- super_ocf_log info "DEC $FUNCNAME systemReplicationStatus.py (to site '$rem_SR_name')-> $srRc" +- super_ocf_log info "FLOW $FUNCNAME systemReplicationStatus.py (to site '$rem_SR_name')-> $srRc" ++ # TODO: Get rid of the su by using a new interface: ++ # SAPSYSTEMNAME=SLE /usr/sap/SLE/HDB00/HDBSettings.sh systemReplicationStatus.py $siteParam ++ # TODO: Check beginning from which SPS does SAP support HDBSettings.sh? ++ # TODO: Limit the runtime of systemReplicationStatus.py ++ # SAP_CALL ++ # FULL_SR_STATUS=$(su - $sidadm -c "python $DIR_EXECUTABLE/python_support/systemReplicationStatus.py $siteParam" 2>/dev/null); srRc=$? ++ FULL_SR_STATUS=$(HANA_CALL --timeout 60 --cmd "systemReplicationStatus.py" 2>/dev/null); srRc=$? ++ super_ocf_log info "DEC $FUNCNAME systemReplicationStatus.py (to site '$remSR_name')-> $srRc" ++ super_ocf_log info "FLOW $FUNCNAME systemReplicationStatus.py (to site '$remSR_name')-> $srRc" + # + # TODO: PRIO2: Here we might also need to filter additional sites (if multi tier should be supported) + # And is the check for return code capable for chains? +@@ -890,7 +1063,7 @@ + # ok we should be careful and set secondary to SFAIL + super_ocf_log info "FLOW $FUNCNAME SFAIL" + set_hana_attribute "$remoteNode" "SFAIL" ${ATTR_NAME_HANA_SYNC_STATUS[@]} +- super_ocf_log info "ACT site=$sr_name, seting SFAIL for secondary (5) - srRc=$srRc lss=$lss" ++ super_ocf_log info "ACT site=$sr_name, setting SFAIL for secondary (5) - srRc=$srRc lss=$lss" + # TODO: PRIO1 - P004: need to check LSS again to avoid dying primary to block (SFAIL) secondary + lpa_set_lpt 10 "$remoteNode" + rc=1 +@@ -898,7 +1071,7 @@ + else + super_ocf_log info "FLOW $FUNCNAME SFAIL" + set_hana_attribute "$remoteNode" "SFAIL" ${ATTR_NAME_HANA_SYNC_STATUS[@]} +- super_ocf_log info "ACT site=$sr_name, seting SFAIL for secondary (2) - srRc=$srRc" ++ super_ocf_log info "ACT site=$sr_name, setting SFAIL for secondary (2) - srRc=$srRc" + # TODO: PRIO1 - P004: need to check LSS again to avoid dying primary to block (SFAIL) secondary + lpa_set_lpt 10 "$remoteNode" + rc=1; +@@ -992,14 +1165,28 @@ + super_ocf_log info "FLOW $FUNCNAME ($*)" + local rc=0 + # +- su - $sidadm -c "python $DIR_EXECUTABLE/python_support/landscapeHostConfiguration.py" 1>/dev/null 2>/dev/null; rc=$? ++ # TODO: Get rid of the su by using a new interface: ++ # SAPSYSTEMNAME=SLE /usr/sap/SLE/HDB00/HDBSettings.sh landscapeHostConfiguration.py ++ # TODO: Check beginning from which SPS does SAP support HDBSettings.sh? ++ # DONE: Limit the runtime of landscapeHostConfiguration.py ++ HANA_CALL --timeout 60 --cmd "landscapeHostConfiguration.py" 1>/dev/null 2>/dev/null; rc=$? ++ if [ $rc -eq 124 ]; then ++ # TODO: PRIO 1: Check, if we should loop here like 'for i in 1 2 3 ...' ? ++ # landscape timeout ++ sleep 20 ++ HANA_CALL --timeout 60 --cmd "landscapeHostConfiguration.py" 1>/dev/null 2>/dev/null; rc=$? ++ if [ $rc -eq 124 ]; then ++ # TODO PRIO2: How to handle still hanging lss - current solution is to say "FATAL" ++ rc=0 ++ fi ++ fi + return $rc; + } + + # + # function: register_hana_secondary - register local hana as secondary to the other site + # params: - +-# globals: sidadm(r), remoteHost(r), InstanceNr(r), sr_mode(r), sr_name(r) ++# globals: sidadm(r), remoteHost(r), InstanceNr(r), sr_mode(r), sr_name(r), hdbver(r) + # register_hana_secondary + # + function register_hana_secondary() +@@ -1007,17 +1194,31 @@ + super_ocf_log info "FLOW $FUNCNAME ($*)" + local rc=2; + local remoteInstance=""; ++ local newParameter=0 + remoteInstance=$InstanceNr ++ ++ ++ if version "$hdbver" ">=" "1.00.110"; then ++ newParameter=1 ++ fi ++ + if ocf_is_true ${AUTOMATED_REGISTER}; then +- # +- # +- # +- # +- # +- super_ocf_log info "ACT: REGISTER: hdbnsutil -sr_register --remoteHost=$remoteHost --remoteInstance=$remoteInstance --mode=$sr_mode --name=$sr_name" +- # +- # +- su - $sidadm -c "hdbnsutil -sr_register --remoteHost=$remoteHost --remoteInstance=$remoteInstance --mode=$sr_mode --name=$sr_name"; rc=$? ++ # TODO: Get rid of the su by using a new interface: ++ # SAPSYSTEMNAME=SLE /usr/sap/SLE/HDB00/HDBSettings.sh hdbnsutil -sr_register ... ++ # TODO: Check beginning from which SPS does SAP support HDBSettings.sh? ++ # TODO: Limit the runtime of hdbnsutil -sr_register ???? ++ if [ $newParameter -eq 1 ]; then ++ local hanaOM="" ++ hanaOM=$(get_hana_attribute ${NODENAME} ${ATTR_NAME_HANA_OPERATION_MODE[@]}) ++ if [ -n "$hanaOM" ]; then ++ hanaOM="--operationMode=$hanaOM" ++ fi ++ super_ocf_log info "ACT: REGISTER: hdbnsutil -sr_register --remoteHost=$remoteHost --remoteInstance=$remoteInstance --replicationMode=$sr_mode $hanaOM --name=$sr_name" ++ HANA_CALL --timeout inf --use-su --cmd "hdbnsutil -sr_register --remoteHost=$remoteHost --remoteInstance=$remoteInstance --replicationMode=$sr_mode $hanaOM --name=$sr_name"; rc=$? ++ else ++ super_ocf_log info "ACT: REGISTER: hdbnsutil -sr_register --remoteHost=$remoteHost --remoteInstance=$remoteInstance --mode=$sr_mode --name=$sr_name" ++ HANA_CALL --timeout inf --use-su --cmd "hdbnsutil -sr_register --remoteHost=$remoteHost --remoteInstance=$remoteInstance --mode=$sr_mode --name=$sr_name"; rc=$? ++ fi + # backup_global_and_nameserver + else + super_ocf_log info "ACT: SAPHANA DROP REGISTER because AUTOMATED_REGISTER is set to FALSE" +@@ -1051,7 +1252,7 @@ + check_sapstartsrv + rc=$? + # +- # TODO: ASK: PRIO5: For SCALE-OUT - do we need to use an other call like StartSystem? Or better to use the HDB command? ++ # DONE: ASK: PRIO5: For SCALE-OUT - do we need to use an other call like StartSystem? Or better to use the HDB command? + # + if [ $rc -eq $OCF_SUCCESS ]; then + output=$($SAPCONTROL -nr $InstanceNr -function Start) +@@ -1169,7 +1370,7 @@ + 0 ) # LPA says start-up + lpa_advice="start" + # TODO: PRIO1: We need to do a special handling for remote being a 234-Secondary in SR Status SOK +- # if ( remote_role like [234]:S ) && ( remote_sync_status is SOK|PRIM ) && ( PreferSiteTakeover ) ++ # if ( remote_role like [234]:S ) && ( remote_sync_status is SOK|PRIM ) && ( PreferSiteTakeover ) + # then lpa_advice="wait" + remoteRole=$(get_hana_attribute $remoteNode ${ATTR_NAME_HANA_ROLES[@]}) + remoteSync=$(get_hana_attribute $remoteNode ${ATTR_NAME_HANA_SYNC_STATUS[@]}) +@@ -1193,17 +1394,20 @@ + 1) # LPA says register! + lpa_advice="register" + ;; +- 2) # LPA says wait for second LPT ++ 2) # LPA says wait for older LPA to expire ++ lpa_advice="wait" ++ ;; ++ 3) # LPA says to wait for remote LPA to be reported/announced + lpa_advice="wait" + ;; +- 3 | 4 ) # LPA says something is completely wrong - FAIL resource # TODO: PRIO1: RC3 for waiting remote side to report lss ++ 4) # LPA says something is completely wrong - FAIL resource # TODO: PRIO1: RC3 for waiting remote side to report lss + lpa_advice="fail" + ;; +- * ) # LPA failed with an unkonown status - FAIL resource ++ *) # LPA failed with an unkonown status - FAIL resource + lpa_advice="fail" + ;; + esac +- ++ + # DONE: PRIO2: Do we need to differ 0 and 1 here? While 0 is a fatal SAP error, 1 for down/error + if [ $lss -eq 0 ]; then + super_ocf_log err "ACT: get_hana_landscape_status reports FATAL" +@@ -1218,7 +1422,7 @@ + 2 | 3 | 4 ) # as landcape says we are up - just set the scores and return code + super_ocf_log info "LPA: landcape: UP, LPA: start ==> keep running" + LPTloc=$(date '+%s') +- lpa_set_lpt $LPTloc ++ lpa_set_lpt $LPTloc $NODENAME + rc=$OCF_SUCCESS + ;; + 1 ) # landcape says we are down, lets start and adjust scores and return code +@@ -1226,7 +1430,7 @@ + saphana_start + rc=$? + LPTloc=$(date '+%s') +- lpa_set_lpt $LPTloc ++ lpa_set_lpt $LPTloc $NODENAME + ;; + esac + scoring_crm_master "$my_role" "$my_sync" +@@ -1250,11 +1454,11 @@ + if [ $primary_status -eq $HANA_STATE_SECONDARY ]; then + super_ocf_log info "ACT: Register successful" + lpa_push_lpt 10 +- lpa_set_lpt 10 ++ lpa_set_lpt 10 $NODENAME + set_crm_master 0 + saphana_start_secondary + rc=$? +- lpa_set_lpt 10 ++ lpa_set_lpt 10 $NODENAME + else + super_ocf_log err "ACT: Register failed" + rc=$OCF_NOT_RUNNING +@@ -1279,11 +1483,19 @@ + rc=$OCF_ERR_GENERIC + ;; + 1 ) # we are down, so we should wait --> followup in next monitor +- super_ocf_log info "LPA: landcape: DOWN, LPA: wait ==> keep waiting" +- # TODO: PRIO3: Check, if WAITING is correct here +- set_hana_attribute ${NODENAME} "WAITING4LPA" ${ATTR_NAME_HANA_CLONE_STATE[@]} +- set_crm_master -9000 +- rc=$OCF_SUCCESS ++ # DONE: PRIO3: Check, if WAITING is correct here ++ if ocf_is_true "$AUTOMATED_REGISTER" ; then ++ super_ocf_log info "LPA: landcape: DOWN, LPA: wait ==> keep waiting" ++ super_ocf_log info "RA: landcape: DOWN, LPA: wait ==> keep waiting" ++ set_hana_attribute ${NODENAME} "WAITING4LPA" ${ATTR_NAME_HANA_CLONE_STATE[@]} ++ set_crm_master -9000 ++ rc=$OCF_SUCCESS ++ else ++ super_ocf_log warning "LPA: OLD primary needs manual registration (AUTOMATED_REGISTER='false')" ++ set_hana_attribute ${NODENAME} "WAITING4REG" ${ATTR_NAME_HANA_CLONE_STATE[@]} ++ set_crm_master -9000 ++ rc=$OCF_NOT_RUNNING ++ fi + ;; + esac + ;; +@@ -1309,22 +1521,24 @@ + local ch ch_role + # + # get actual list of cluster members +- # ++ # + if [ -n "$otherNodes" ]; then + for ch in ${otherNodes[@]}; do + if [ $rc -eq 1 ]; then + ch_role=$(get_hana_attribute ${ch} ${ATTR_NAME_HANA_ROLES[@]}) +-# TODO: PRIO3: check if [0-9], [234] or [34] is correct +-# TODO: PRIO4: Do we need different checks like "any-primary-master" or "running-primary-master" ? +-# grep '[0-9]*:P:[^:]*:master:' <<< $ch_role && rc=0 +-# grep '[34]:P:[^:]*:master:' <<< $ch_role && rc=0 +-# Match "Running+Available Primary" Master -> Match field 1: 3/4, 2: P, 4: master +- awk -F: 'BEGIN { rc=1 } +- $1 ~ "[34]" && $2 ="P" && $4="master" { rc=0 } +- END { exit rc }' <<< $ch_role ; rc=$? ++ # TODO: PRIO3: check if [0-9], [234] or [34] is correct ++ # TODO: PRIO4: Do we need different checks like "any-primary-master" or "running-primary-master" ? ++ # grep '[0-9]*:P:[^:]*:master:' <<< $ch_role && rc=0 ++ # grep '[34]:P:[^:]*:master:' <<< $ch_role && rc=0 ++ # Match "Running+Available Primary" Master -> Match field 1: 3/4, 2: P, 4: master ++ super_ocf_log debug "DBG: check_for_primary_master (3) ch_role=$ch_role" ++ awk -F: 'BEGIN { rc=1 } ++ $1 ~ "[34]" && $2 == "P" && $4 == "master" { rc=0 } ++ END { exit rc }' <<< $ch_role ; rc=$? ++ super_ocf_log debug "DBG: check_for_primary_master (4) rc=$rc" + fi + done +- fi ++ fi + super_ocf_log info "FLOW $FUNCNAME rc=$rc" + return $rc + } +@@ -1378,7 +1592,7 @@ + ####### LPA - begin + # + lpa_push_lpt 10 +- lpa_set_lpt 10 ++ lpa_set_lpt 10 $NODENAME + # + ####### LPA - end + # +@@ -1404,7 +1618,7 @@ + rc=$OCF_SUCCESS + fi + else +- lpa_set_lpt 10 ++ lpa_set_lpt 10 $NODENAME + fi + else + super_ocf_log info "ACT: wait_for_primary_master ==> WAITING" +@@ -1454,7 +1668,7 @@ + then + if [ $STATE -eq $OCF_NOT_RUNNING ] + then +- [ "$MONLOG" != "NOLOG" ] && ocf_log err "SAP instance service $SERVICE is not running with status $COLOR !" ++ [ "$MONLOG" != "NOLOG" ] && ocf_log err "SAP instance service $SERVICE status color is $COLOR !" + rc=$STATE + fi + count=1 +@@ -1511,13 +1725,17 @@ + local crm_rc=1 + local lpt=$1 + local clpt=-1 +- local node=${2:-${NODENAME}} ++ local node=$2 + set_hana_attribute ${node} "$lpt" ${LPA_ATTR[@]}; crm_rc=$? +- clpt=$(lpa_get_lpt $NODENAME) +- if [ "$lpt" != "$clpt" ]; then +- rc=2 ++ if [ -n "$node" ]; then ++ clpt=$(lpa_get_lpt $NODENAME) ++ if [ "$lpt" != "$clpt" ]; then ++ rc=2 ++ else ++ rc=0 ++ fi + else +- rc=0 ++ super_ocf_log info "DEC: lpa_set_lpt ignore to change value for empty node name" + fi + super_ocf_log info "FLOW $FUNCNAME rc=$rc" + return $rc +@@ -1608,7 +1826,7 @@ + else + rc=2 + fi +- lpa_set_lpt $LPTloc ++ lpa_set_lpt $LPTloc $NODENAME + super_ocf_log info "FLOW $FUNCNAME rc=$rc" + return $rc + } +@@ -1621,9 +1839,10 @@ + # + # Returncodes: + # 0: start +-# 1: register than start +-# 2: wait4gab +-# 3: wait4other ++# 1: register (then start) ++# 2: wait4gab (WAIT4LPA - Older LPA needs to expire) ++# 3: wait4other (WAIT4LPA - Remote LPA needs to be announced) ++# 4: lpa internal error + # + # Initializing (if NO local LPT-file): + # SECONDARY sets to 10 +@@ -1648,7 +1867,7 @@ + # + function lpa_check_lpt_status() { + super_ocf_log info "FLOW $FUNCNAME ($*)" +- local rc=0 ++ local rc=4 + local LPTloc=-1 + local LPTrem=-1 + local LPTMark=1000 +@@ -1666,16 +1885,16 @@ + if [ -z "$LPTloc" -o "$LPTloc" -eq -1 -o "$lparc" -ne 0 ]; then + # last option - try to initialize as PRIMARY + lpa_push_lpt 20 +- lpa_set_lpt 20 ++ lpa_set_lpt 20 $NODENAME + LPTloc=20 # DEFAULT + fi + fi +- # TODO PRIO1: REMOVE remoteNode dependency - lpa_get_lpt ++ # TODO PRIO1: REMOVE remoteNode dependency - lpa_get_lpt + LPTrem=$(lpa_get_lpt $remoteNode); lparc=$? + if [ $lparc -ne 0 ]; then + # LPT of the other node could not be evaluated - LPA says WAIT + super_ocf_log debug "DBG: LPA: LPTloc=$LPTloc, LPTrem undefined ==> WAIT" +- rc=2 ++ rc=3 + else + super_ocf_log debug "DBG: LPA: LPTloc ($LPTloc) LPTrem ($LPTrem) delta ($delta)" + if [ $LPTloc -lt $LPTMark -a $LPTrem -lt $LPTMark ]; then +@@ -1683,11 +1902,11 @@ + else + delta=$DUPLICATE_PRIMARY_TIMEOUT # at least one of the lpts is a real timestamp so include delta-gap + fi +- if (( delta < LPTloc - LPTrem )); then ++ if (( delta < LPTloc - LPTrem )); then + # We are the winner - LPA says STARTUP + super_ocf_log debug "DBG: LPA: LPTloc wins $LPTloc > $LPTrem + $delta ==> START" + rc=0 +- elif (( delta < LPTrem - LPTloc )); then ++ elif (( delta < LPTrem - LPTloc )); then + if ocf_is_true "$AUTOMATED_REGISTER" ; then + # The other one has won - LPA says REGISTER + super_ocf_log debug "DBG: LPA: LPTrem wins $LPTrem > $LPTloc + $delta ==> REGISTER" +@@ -1697,12 +1916,12 @@ + rc=2 + fi + +- else ++ else + super_ocf_log debug "DBG: LPA: Difference between LPTloc and LPTrem is less than delta ($delta) ==> WAIT" + # TODO: PRIO3: ADD STALEMATE-HANDLING HERE; currently admin should set one of the lpa to 20 + rc=2 +- fi +- fi ++ fi ++ fi + super_ocf_log info "FLOW $FUNCNAME rc=$rc" + return $rc + } +@@ -1716,6 +1935,7 @@ + { + super_ocf_log info "FLOW $FUNCNAME ($*)" + local rc=0 ++ # always true for scale-up + super_ocf_log info "FLOW $FUNCNAME rc=$rc" + return $rc + } +@@ -1728,23 +1948,15 @@ + # + function saphana_start_clone() { + super_ocf_log info "FLOW $FUNCNAME ($*)" +- local primary_status sync_attr score_master rc=$OCF_NOT_RUNNING ++ local primary_status sync_attr score_master rc=$OCF_NOT_RUNNING + local sqlrc; +- local chkusr; +- # TODO: PRIO4: remove check_secstore_users later +- secUser=$(check_secstore_users SAPHANA${SID}SR SLEHALOC RHELHALOC) ; chkusr=$? +- if [ $chkusr -ne 0 ]; then +- super_ocf_log err "ACT: Secure store users are missing (see best practice manual how to setup the users)" +- rc=$OCF_ERR_CONFIGURED ++ set_hana_attribute ${NODENAME} "DEMOTED" ${ATTR_NAME_HANA_CLONE_STATE[@]} ++ check_for_primary; primary_status=$? ++ if [ $primary_status -eq $HANA_STATE_PRIMARY ]; then ++ saphana_start_primary; rc=$? + else +- set_hana_attribute ${NODENAME} "DEMOTED" ${ATTR_NAME_HANA_CLONE_STATE[@]} +- check_for_primary; primary_status=$? +- if [ $primary_status -eq $HANA_STATE_PRIMARY ]; then +- saphana_start_primary; rc=$? +- else +- lpa_set_lpt 10 +- saphana_start_secondary; rc=$? +- fi ++ lpa_set_lpt 10 $NODENAME ++ saphana_start_secondary; rc=$? + fi + super_ocf_log info "FLOW $FUNCNAME rc=$rc" + return $rc +@@ -1761,9 +1973,10 @@ + local rc=0 + local primary_status="x" + set_hana_attribute ${NODENAME} "UNDEFINED" ${ATTR_NAME_HANA_CLONE_STATE[@]} ++ super_ocf_log debug "DBG: SET UNDEFINED" + check_for_primary; primary_status=$? + if [ $primary_status -eq $HANA_STATE_SECONDARY ]; then +- lpa_set_lpt 10 ++ lpa_set_lpt 10 $NODENAME + fi + saphana_stop; rc=$? + return $rc +@@ -1813,26 +2026,42 @@ + # seems admin already decided that for us? -> we are running - set DEMOTED + promoted=0; + LPTloc=$(date '+%s') +- lpa_set_lpt $LPTloc ++ lpa_set_lpt $LPTloc $NODENAME + fi + lpa_check_lpt_status; lparc=$? +- # TODO: PRIO1: Need to differ lpa_check_lpt_status return codes +- if [ $lparc -lt 2 ]; then +- # lpa - no need to wait any longer - lets try a new start +- saphana_start_clone +- rc=$? +- super_ocf_log info "FLOW $FUNCNAME rc=$rc" +- return $rc +- else +- lpa_init_lpt $HANA_STATE_PRIMARY +- # still waiting for second site to report lpa-lpt +- if ocf_is_true "$AUTOMATED_REGISTER" ; then +- super_ocf_log info "LPA: Still waiting for remote site to report LPA status" +- else +- super_ocf_log info "LPA: Dual primary detected and AUTOMATED_REGISTER='false' ==> WAITING" +- fi +- return $OCF_SUCCESS +- fi ++ # DONE: PRIO1: Need to differ lpa_check_lpt_status return codes ++ case "$lparc" in ++ 0 | 1 ) ++ # lpa - no need to wait any longer - lets try a new start ++ saphana_start_clone ++ rc=$? ++ super_ocf_log info "FLOW $FUNCNAME rc=$rc" ++ return $rc ++ ;; ++ 2 ) ++ lpa_init_lpt $HANA_STATE_PRIMARY ++ # still waiting for second site to expire ++ if ocf_is_true "$AUTOMATED_REGISTER" ; then ++ super_ocf_log info "LPA: Still waiting for remote site to report LPA status" ++ else ++ super_ocf_log info "LPA: Dual primary detected and AUTOMATED_REGISTER='false' ==> WAITING" ++ super_ocf_log info "LPA: You need to manually sr_register the older primary" ++ fi ++ return $OCF_SUCCESS ++ ;; ++ 3 ) ++ lpa_init_lpt $HANA_STATE_PRIMARY ++ # still waiting for second site to report lpa-lpt ++ super_ocf_log info "LPA: Still waiting for remote site to report LPA status" ++ return $OCF_SUCCESS ++ ;; ++ 4 ) ++ # lpa internal error ++ # TODO PRIO3: Impplement special handling for this issue - should we fail the ressource? ++ super_ocf_log info "LPA: LPA reports an internal error" ++ return $OCF_SUCCESS ++ ;; ++ esac + promoted=0; + ;; + UNDEFINED ) +@@ -1848,7 +2077,7 @@ + ;; + esac + fi +- get_hana_landscape_status; lss=$? ++ get_hana_landscape_status; lss=$? + super_ocf_log debug "DBG: saphana_monitor_clone: get_hana_landscape_status=$lss" + case "$lss" in + 0 ) # FATAL or ERROR +@@ -1876,19 +2105,20 @@ + # + # TODO PRIO1: REMOVE remoteNode dependency - get_sync_status + remoteSync=$(get_hana_attribute $remoteNode ${ATTR_NAME_HANA_SYNC_STATUS[@]}) ++ # TODO HANDLING OF "NEVER" + case "$remoteSync" in + SOK | PRIM ) + super_ocf_log info "DEC: PreferSiteTakeover selected so decrease promotion score here (and reset lpa)" + set_crm_master 5 + if check_for_primary_master; then +- lpa_set_lpt 20 ++ lpa_set_lpt 20 $NODENAME + fi + ;; + SFAIL ) +- super_ocf_log info "DEC: PreferSiteTakeover selected BUT remoteHost is not in sync (SFAIL) ==> local restart preferred" ++ super_ocf_log info "DEC: PreferSiteTakeover selected BUT remoteHost is not in sync (SFAIL) ==> local restart preferred" + ;; + * ) +- super_ocf_log info "DEC: PreferSiteTakeover selected BUT remoteHost is not in sync ($remoteSync) ==> local restart preferred" ++ super_ocf_log info "DEC: PreferSiteTakeover selected BUT remoteHost is not in sync ($remoteSync) ==> local restart preferred" + ;; + esac + else +@@ -1916,7 +2146,7 @@ + rc=$OCF_SUCCESS + else + LPTloc=$(date '+%s') +- lpa_set_lpt $LPTloc ++ lpa_set_lpt $LPTloc $NODENAME + lpa_push_lpt $LPTloc + if [ "$promoted" -eq 1 ]; then + set_hana_attribute "$NODENAME" "PRIM" ${ATTR_NAME_HANA_SYNC_STATUS[@]} +@@ -1931,12 +2161,14 @@ + fi + my_sync=$(get_hana_attribute ${NODENAME} ${ATTR_NAME_HANA_SYNC_STATUS[@]}) + my_role=$(get_hana_attribute ${NODENAME} ${ATTR_NAME_HANA_ROLES[@]}) +- case "$my_role" in ++ case "$my_role" in + [12]:P:*:master:* ) # primary is down or may not anser hdbsql query so drop analyze_hana_sync_status + ;; + [34]:P:*:*:* ) # primary is up and should now be able to anser hdbsql query + if [ -f $DIR_EXECUTABLE/python_support/systemReplicationStatus.py ]; then +- analyze_hana_sync_statusSRS ++ if [ "$promote_attr" = "PROMOTED" ]; then ++ analyze_hana_sync_statusSRS ++ fi + else + analyze_hana_sync_statusSQL + fi +@@ -1949,8 +2181,8 @@ + [234]:P:* ) # dual primary, but other instance marked as PROMOTED by the cluster + lpa_check_lpt_status; again_lpa_rc=$? + if [ $again_lpa_rc -eq 2 ]; then +- super_ocf_log info "DEC: Dual primary detected, other instance is PROMOTED and lpa stalemate ==> local restart" +- lpa_set_lpt 10 ++ super_ocf_log info "DEC: Dual primary detected, other instance is PROMOTED and lpa stalemate ==> local restart" ++ lpa_set_lpt 10 $NODENAME + lpa_push_lpt 10 + rc=$OCF_NOT_RUNNING + fi +@@ -1993,7 +2225,7 @@ + # OK, we are running as HANA SECONDARY + # + if ! lpa_get_lpt ${NODENAME}; then +- lpa_set_lpt 10 ++ lpa_set_lpt 10 $NODENAME + lpa_push_lpt 10 + fi + promote_attr=$(get_hana_attribute ${NODENAME} ${ATTR_NAME_HANA_CLONE_STATE[@]}) +@@ -2042,17 +2274,25 @@ + 0 ) # FATAL + # DONE: PRIO1: Maybe we need to differ between 0 and 1. While 0 is a fatal sap error, 1 is down/error + # TODO: PRIO3: is OCF_ERR_GENERIC best option? +- lpa_set_lpt 10 ++ lpa_set_lpt 10 $NODENAME + rc=$OCF_ERR_GENERIC + ;; + 1 ) # ERROR +- lpa_set_lpt 10 ++ lpa_set_lpt 10 $NODENAME + rc=$OCF_NOT_RUNNING + ;; + 2 | 3 | 4 ) # WARN INFO OK + rc=$OCF_SUCCESS +- lpa_set_lpt 30 ++ lpa_set_lpt 30 $NODENAME + sync_attr=$(get_hana_attribute ${NODENAME} ${ATTR_NAME_HANA_SYNC_STATUS[@]}) ++ local hanaOM="" ++ local hanaOut1="" ++ # TODO: PRIO 3: check, if using getParameter.py is the best option to analyze the set operationMode ++ # DONE: PRIO 3: Should we default to logreplay for SAP HANA >= SPS11 ? ++ hanaOut1=$(HANA_CALL --timeout 10 --use-su --cmd "getParameter.py --key=global.ini/system_replication/operation_mode --sapcontrol=1") ++ hanaFilter1=$(echo "$hanaOut1" | awk -F/ 'BEGIN {out=0} /^SAPCONTROL-OK: / { out=1 } /^SAPCONTROL-OK: / { out=0 } /=/ {if (out==1) {print $3} }') ++ hanaOM=$(echo "$hanaFilter1" | awk -F= '$1=="operation_mode" {print $2}') ++ set_hana_attribute ${NODENAME} "$hanaOM" ${ATTR_NAME_HANA_OPERATION_MODE[@]} + super_ocf_log debug "DBG: sync_attr=$sync_attr" + case "$sync_attr" in + "SOK" ) # This is a possible node to promote, when primary is missing +@@ -2112,7 +2352,7 @@ + fi + # + # First check, if we are PRIMARY or SECONDARY +- # ++ # + check_for_primary; primary_status=$? + if [ $primary_status -eq $HANA_STATE_PRIMARY ]; then + # FIX: bsc#919925 Leaving Node Maintenance stops HANA Resource Agent +@@ -2145,7 +2385,7 @@ + # + # function: saphana_promote_clone - promote a hana clone + # params: - +-# globals: OCF_*(r), NODENAME(r), HANA_STATE_*, SID(r), InstanceName(r), ++# globals: OCF_*(r), NODENAME(r), HANA_STATE_*, SID(r), InstanceName(r), + # saphana_promote_clone: + # In a Master/Slave configuration get Master being the primary OR by running hana takeover + # +@@ -2169,7 +2409,7 @@ + else + if [ $primary_status -eq $HANA_STATE_SECONDARY ]; then + # +- # we are SECONDARY/SLAVE and need to takepover ... ++ # we are SECONDARY/SLAVE and need to takeover ... promote on the replica (secondary) side... + # promote on the replica side... + # + hana_sync=$(get_hana_attribute ${NODENAME} ${ATTR_NAME_HANA_SYNC_STATUS[@]}) +@@ -2178,9 +2418,14 @@ + super_ocf_log info "ACT: !!!!!!! Promote REPLICA $SID-$InstanceName to be primary. !!!!!!" + LPTloc=$(date '+%s') + # lpa_set_lpt 20 $remoteNode +- lpa_set_lpt $LPTloc ++ lpa_set_lpt $LPTloc $NODENAME + lpa_push_lpt $LPTloc +- su - $sidadm -c "hdbnsutil -sr_takeover" ++ # TODO: Get rid of the su by using a new interface: ++ # SAPSYSTEMNAME=SLE /usr/sap/SLE/HDB00/HDBSettings.sh hdbnsutil -sr_takeover ... ++ # TODO: Check beginning from which SPS does SAP support HDBSettings.sh? ++ # TODO: Limit the runtime of hdbnsutil -sr_takeover ???? ++ # SAP_CALL ++ HANA_CALL --timeout inf --use-su --cmd "hdbnsutil -sr_takeover" + # + # now gain check, if we are primary NOW + # +@@ -2248,7 +2493,6 @@ + SAPSTARTPROFILE="" + SAPHanaFilter="ra-act-dec-lpa" + +-NODENAME=$(crm_node -n) + + + if [ $# -ne 1 ] +@@ -2306,8 +2550,7 @@ + fi + + # What kind of method was invoked? +-THE_VERSION=$(saphana_meta_data | grep ' + + +- 0.151.1 ++ $SAPHanaVersion + Analyzes SAP HANA System Replication Topology. + This RA analyzes the SAP HANA topology and "sends" all findings via the node status attributes to + all nodes in the cluster. These attributes are taken by the SAPHana RA to control the SAP Hana Databases. +@@ -207,12 +215,12 @@ + dstr=$(date) + case "$attr_store" in + reboot | forever ) +- echo "$dstr: SAPHanaTopology: crm_attribute -N ${attr_node} -G -n \"$attr_name\" -l $attr_store -q" >> /var/log/fhATTRIBUTE +- crm_attribute -N ${attr_node} -G -n "$attr_name" -l $attr_store -q -d "$attr_default" 2>>/var/log/fhATTRIBUTE; rc=$? ++ echo "$dstr: SAPHanaTopology: crm_attribute -N ${attr_node} -G -n \"$attr_name\" -l $attr_store -q" >> $log_attr_file ++ crm_attribute -N ${attr_node} -G -n "$attr_name" -l $attr_store -q -d "$attr_default" 2>>$log_attr_file; rc=$? + ;; + props ) +- echo "$dstr: SAPHanaTopology: crm_attribute -G -n \"$attr_name\" -t crm_config -q" >> /var/log/fhATTRIBUTE +- crm_attribute -G -n "$attr_name" -t crm_config -q -d "$attr_default" 2>>/var/log/fhATTRIBUTE; rc=$? ++ echo "$dstr: SAPHanaTopology: crm_attribute -G -n \"$attr_name\" -t crm_config -q" >> $log_attr_file ++ crm_attribute -G -n "$attr_name" -t crm_config -q -d "$attr_default" 2>>$log_attr_file; rc=$? + ;; + esac + super_ocf_log info "FLOW $FUNCNAME rc=$rc" +@@ -282,6 +290,53 @@ + } + + # ++# function: dequote - filter: remove quotes (") from stdin ++# params: - ++# globals: - ++function dequote() ++{ ++ local rc=0; tr -d '"'; return $rc ++} ++ ++# function: version: cpmpare two HANA version strings ++function ver_lt() { ++ ocf_version_cmp $1 $2 ++ test $? -eq 0 && return 0 || return 1 ++} ++ ++function ver_le() { ++ ocf_version_cmp $1 $2 ++ test $? -eq 0 -o $? -eq 1 && return 0 || return 1 ++} ++ ++function ver_gt() { ++ ocf_version_cmp $1 $2 ++ test $? -eq 2 && return 0 || return 1 ++} ++ ++function ver_ge() { ++ ocf_version_cmp $1 $2 ++ test $? -eq 2 -o $? -eq 1 && return 0 || return 1 ++} ++# ++# function: version: cpmpare two HANA version strings ++# ++function version() { ++ if [ $# -eq 3 ]; then ++ case "$2" in ++ LE | le | "<=" ) ver_le $1 $3;; ++ LT | lt | "<" ) ver_lt $1 $3;; ++ GE | ge | ">=" ) ver_ge $1 $3;; ++ GT | gt | ">" ) ver_gt $1 $3;; ++ * ) return 1; ++ esac ++ elif [ $# -ge 5 ]; then ++ version $1 $2 $3 && shift 2 && version $* ++ else ++ return 1; ++ fi ++} ++# + # function: is_clone - report, if resource is configured as a clone (also master/slave) + # params: - + # globals: OCF_*(r) +@@ -314,12 +369,74 @@ + } + + # ++# function: HANA_CALL ++# params: timeout-in-seconds cmd-line ++# globals: sid(r), SID(r), InstanceName(r) ++# ++function HANA_CALL() ++{ ++ # ++ # TODO: PRIO 5: remove 'su - ${sidadm} later, when SAP HANA resoled issue with ++ # root-user-called hdbnsutil -sr_state (which creates root-owned shared memory file in /var/lib/hdb/SID/shmgrp) ++ # TODO: PRIO 5: Maybe make "su" optional by a parameter ++ local timeOut=0 ++ local onTimeOut="" ++ local rc=0 ++ local use_su=1 # Default to be changed later (see TODO above) ++ local pre_cmd="" ++ local cmd="" ++ local pre_script="" ++ local output="" ++ while [ $# -gt 0 ]; do ++ case "$1" in ++ --timeout ) timeOut=$2; shift;; ++ --use-su ) use_su=1;; ++ --on-timeout ) onTimeOut="$2"; shift;; ++ --cmd ) shift; cmd="$*"; break;; ++ esac ++ shift ++ done ++ ++ if [ $use_su -eq 1 ]; then ++ pre_cmd="su - ${sid}adm -c" ++ pre_script="true" ++ else ++ # as root user we need the library path to the SAP kernel to be able to call sapcontrol ++ # check, if we already added DIR_EXECUTABLE at the beginning of LD_LIBRARY_PATH ++ if [ "${LD_LIBRARY_PATH%%*:}" != "$DIR_EXECUTABLE" ] ++ then ++ MY_LD_LIBRARY_PATH=$DIR_EXECUTABLE${LD_LIBRARY_PATH:+:}$LD_LIBRARY_PATH ++ fi ++ pre_cmd="bash -c" ++ pre_script="LD_LIBRARY_PATH=$MY_LD_LIBRARY_PATH; export LD_LIBRARY_PATH" ++ fi ++ case $timeout in ++ 0 | inf ) ++ output=$($pre_cmd "$pre_script; /usr/sap/$SID/$InstanceName/HDBSettings.sh $cmd"); rc=$? ++ ;; ++ * ) ++ output=$(timeout $timeOut $pre_cmd "$pre_script; /usr/sap/$SID/$InstanceName/HDBSettings.sh $cmd"); rc=$? ++ # ++ # on timeout ... ++ # ++ if [ $rc -eq 124 -a -n "$onTimeOut" ]; then ++ local second_output="" ++ second_output=$($pre_cmd "$pre_script; /usr/sap/$SID/$InstanceName/HDBSettings.sh $onTimeOut"); ++ fi ++ ;; ++ esac ++ echo "$output" ++ return $rc; ++} ++ ++# + # function: sht_init - initialize variables for the resource agent + # params: - + # globals: OCF_*(r), SID(w), sid(rw), sidadm(w), InstanceName(w), InstanceNr(w), +-# globals: meta_notify_master_uname(w), HANA_SR_TOLOPOGY(w), sr_name(w), remoteHost(w) ++# globals: meta_notify_master_uname(w), HANA_SR_TOLOPOGY(w), sr_name(w) + # globals: ATTR_NAME_HANA_SYNC_STATUS(w), ATTR_NAME_HANA_PRIMARY_AT(w), ATTR_NAME_HANA_CLONE_STATE(w) + # globals: DIR_EXECUTABLE(w), SAPSTARTSRV(w), SAPCONTROL(w), DIR_PROFILE(w), SAPSTARTPROFILE(w), LD_LIBRARY_PATH(w), PATH(w), nodelist(w) ++# globals: NODENAME(w), hdbver(w) + # sht_init : Define global variables with default values, if optional parameters are not set + # + # +@@ -331,12 +448,14 @@ + local hdbANSWER="" + local siteID + local siteNAME ++ local chkMethod="" + HOSTEXECNAME=saphostexec + USRSAP=/usr/sap + SAPSERVICE_PATH=${USRSAP}/sapservices + SAPHOSTCTRL_PATH=${USRSAP}/hostctrl/exe + HOSTEXEC_PATH=${SAPHOSTCTRL_PATH}/${HOSTEXECNAME} + HOSTEXEC_PROFILE_PATH=${SAPHOSTCTRL_PATH}/host_profile ++ NODENAME=$(crm_node -n) + SID=$OCF_RESKEY_SID + InstanceNr=$OCF_RESKEY_InstanceNumber + myInstanceName="${SID}_HDB${InstanceNr}" +@@ -382,13 +501,6 @@ + DIR_PROFILE="$OCF_RESKEY_DIR_PROFILE" + fi + +- # as root user we need the library path to the SAP kernel to be able to call sapcontrol +- # check, if we already added DIR_EXECUTABLE at the beginning of LD_LIBRARY_PATH +- if [ "${LD_LIBRARY_PATH%%*:}" != "$DIR_EXECUTABLE" ] +- then +- LD_LIBRARY_PATH=$DIR_EXECUTABLE${LD_LIBRARY_PATH:+:}$LD_LIBRARY_PATH +- export LD_LIBRARY_PATH +- fi + + PATH=${PATH}:${DIR_EXECUTABLE} + # +@@ -399,12 +511,45 @@ + *openais* ) nodelist=$(crm_node -l | awk '/member/ {print $2}');; + *cman* ) nodelist=$(crm_node -l);; + esac ++ # ++ # get HANA version ++ # ++ local ges_ver ++ ges_ver=$(HANA_CALL --timeout 10 --cmd "HDB version" | tr -d " " | awk -F: '$1 == "version" {print $2}') ++ hdbver=${ges_ver%.*.*} ++ # ++ # since rev 111.00 we should use a new hdbnsutil option to get the -sr_state ++ # since rev 112.03 the old option is changed and we should use -sr_stateConfiguration where ever possible ++ # ++ hdbState="hdbnsutil -sr_state" ++ hdbMap="hdbnsutil -sr_state" ++ if version "$hdbver" ">=" "1.00.111"; then ++ hdbState="hdbnsutil -sr_stateConfiguration" ++ hdbMap="hdbnsutil -sr_stateHostMapping" ++ fi + #### SAP-CALL + # hdbnsutil was a bit unstable in some tests so we recall the tool, if it fails to report the srmode +- for i in 1 2 3 4 5 6 7 8 9; do +- hdbANSWER=$(su - ${sidadm} -c "hdbnsutil -sr_state --sapcontrol=1" 2>/dev/null) +- super_ocf_log debug "DBG2: hdbANSWER=\$\(su - ${sidadm} -c \"hdbnsutil -sr_state --sapcontrol=1\"\)" +- srmode=$(echo "$hdbANSWER" | awk -F= '/mode/ {print $2}') ++ for chkMethod in hU hU hU gP ; do ++ # DONE: Limit the runtime of hdbnsutil. ++ # TODO: Use getParameter.py if we get no answer ++ # SAP_CALL ++ #super_ocf_log debug "DBG2: hdbANSWER=$hdbANSWER" ++ #srmode=$(echo "$hdbANSWER" | awk -F= '/mode/ {print $2}') ++ case "$chkMethod" in ++ gP ) # call getParameter (gP) ++ local gpKeys="" ++ gpKeys=$(echo --key=global.ini/system_replication/{mode,site_name,site_id}) ++ hdbANSWER=$(HANA_CALL --timeout 60 --cmd "HDBSettings.sh getParameter.py $gpKeys --sapcontrol=1" 2>&1 | awk -F/ 'BEGIN {out=0} /^SAPCONTROL-OK: / { out=1 } /^SAPCONTROL-OK: / { out=0 } /=/ {if (out==1) {print $3} }') ++ srmode=$(echo "$hdbANSWER" | awk -F= '$1=="mode" {print $2}') ++ super_ocf_log info "ACT: hdbnsutil not answering - using global.ini as fallback - srmode=$srmode" ++ ;; ++ hU | * ) # call hdbnsUtil (hU) ( also for unknown chkMethod ) ++ # DONE: PRIO1: Begginning from SAP HANA rev 112.03 -sr_state is not longer supported ++ hdbANSWER=$(HANA_CALL --timeout 60 --cmd "$hdbState --sapcontrol=1" 2>/dev/null) ++ super_ocf_log debug "DBG2: hdbANSWER=$hdbANSWER" ++ srmode=$(echo "$hdbANSWER" | awk -F= '$1=="mode" {print $2}') ++ ;; ++ esac + case "$srmode" in + primary | syncmem | sync | async | none ) + # we can leave the loop as we already got a result +@@ -417,27 +562,51 @@ + esac + done + # TODO PRIO3: Implement a file lookup, if we did not get a result +- siteID=$(echo "$hdbANSWER" | awk -F= '/site id/ {print $2}') +- siteNAME=$(echo "$hdbANSWER" | awk -F= '/site name/ {print $2}') ++ siteID=$(echo "$hdbANSWER" | awk -F= '/site.id/ {print $2}') # allow 'site_id' AND 'site id' ++ siteNAME=$(echo "$hdbANSWER" | awk -F= '/site.name/ {print $2}') + site=$siteNAME + srmode=$(echo "$hdbANSWER" | awk -F= '/mode/ {print $2}') +- MAPPING=$(echo "$hdbANSWER" | awk -F[=/] '$1 ~ "mapping" && $3 !~ site { print $4 }' site=$site) +- super_ocf_log debug "DBG: site=$site, mode=$srmode, MAPPING=$MAPPING" + # +- # filter all non-cluster mappings ++ # for rev >= 111 we use the new mapping query + # +- # DONE: PRIO2: Need mapping between HANA HOSTS not cluster NODES +- local hanaVHost +- hanaRemoteHost=$(for n1 in $nodelist; do +- hanaVHost=$(get_hana_attribute ${n1} ${ATTR_NAME_HANA_VHOST[@]}) +- for n2 in $MAPPING; do +- if [ "$hanaVHost" == "$n2" ]; then +- echo $hanaVHost; +- fi; +- done; +- done ) +- super_ocf_log info "DEC: site=$site, mode=$srmode, MAPPING=$MAPPING, hanaRemoteHost=$hanaRemoteHost" +- super_ocf_log debug "DBG: site=$site, mode=$srmode, MAPPING=$MAPPING, hanaRemoteHost=$hanaRemoteHost" ++ if version "$hdbver" ">=" "1.00.111"; then ++ hdbANSWER=$(HANA_CALL --timeout 60 --cmd "$hdbMap --sapcontrol=1" 2>/dev/null) ++ fi ++ MAPPING=$(echo "$hdbANSWER" | awk -F[=/] '$1 == "mapping" && $3 != site { print $4 }' site=$site) ++ super_ocf_log debug "DBG: site=$site, mode=$srmode, MAPPING=$MAPPING" ++ if [ -n "$MAPPING" ]; then ++ # we have a mapping from HANA, lets use it ++ # ++ # filter all non-cluster mappings ++ # ++ local hanaVHost="" ++ local n1="" ++ hanaRemoteHost="" ++ for n1 in $nodelist; do ++ hanaVHost=$(get_hana_attribute ${n1} ${ATTR_NAME_HANA_VHOST[@]}) ++ for n2 in $MAPPING; do ++ if [ "$hanaVHost" == "$n2" ]; then ++ hanaRemoteHost="$hanaVHost" ++ fi; ++ done; ++ done ++ super_ocf_log info "DEC: site=$site, mode=$srmode, MAPPING=$MAPPING, hanaRemoteHost=$hanaRemoteHost" ++ super_ocf_log debug "DBG: site=$site, mode=$srmode, MAPPING=$MAPPING, hanaRemoteHost=$hanaRemoteHost" ++ else ++ # HANA DID NOT TOLD THE MAPPING, LETS TRY TO USE THE SITE ATTRIBUTES ++ local n1="" ++ local hanaSite="" ++ for n1 in $nodelist; do ++ # TODO: PRIO9 - For multi tier with more than 2 chain/star members IN the cluster we might need to be ++ # able to catch more than one remoteHost ++ # currently having more than 2 HANA in a chain/star members IN the cluster is not allowed, the third must be external ++ if [ "$NODENAME" != "$n1" ]; then ++ hanaSite=$(get_hana_attribute ${n1} ${ATTR_NAME_HANA_SITE[@]}) ++ hanaRemoteHost="$n1" ++ fi ++ done ++ super_ocf_log info "DEC: site=$site, mode=$srmode, hanaRemoteHost=$hanaRemoteHost - found by remote site ($hanaSite)" ++ fi + super_ocf_log info "FLOW $FUNCNAME rc=$OCF_SUCCESS" + return $OCF_SUCCESS + } +@@ -446,38 +615,29 @@ + # function: check_for_primary - check if local SAP HANA is configured as primary + # params: - + # globals: HANA_STATE_PRIMARY(r), HANA_STATE_SECONDARY(r), HANA_STATE_DEFECT(r), HANA_STATE_STANDALONE(r) ++# srmode(r) + # + function check_for_primary() { + super_ocf_log info "FLOW $FUNCNAME ($*)" + local rc=0 +- node_status=$srmode +- super_ocf_log debug "DBG2: check_for_primary: node_status=$node_status" +- super_ocf_log debug "DBG: check_for_primary: node_status=$node_status" +- for i in 1 2 3 4 5 6 7 8 9; do +- case "$node_status" in +- primary ) +- super_ocf_log info "FLOW $FUNCNAME rc=HANA_STATE_PRIMARY" +- return $HANA_STATE_PRIMARY;; +- syncmem | sync | async ) +- super_ocf_log info "FLOW $FUNCNAME rc=HANA_STATE_SECONDARY" +- return $HANA_STATE_SECONDARY;; +- none ) # have seen that mode on second side BEFEORE we registered it as replica +- super_ocf_log info "FLOW $FUNCNAME rc=HANA_STATE_STANDALONE" +- return $HANA_STATE_STANDALONE;; +- * ) +- # TODO: PRIO1: Should we set SFAIL? +- # TODO: PRIO2: Maybe we need to keep the old value for P/S/N, if hdbnsutil just crashes +- dump=$( echo $node_status | hexdump -C ); +- super_ocf_log err "ACT: check_for_primary: we didn't expect node_status to be: DUMP: <$dump>" +- #### SAP-CALL +- node_full_status=$(su - ${sidadm} -c "hdbnsutil -sr_state" 2>/dev/null ) +- node_status=$(echo "$node_full_status" | awk '$1=="mode:" {print $2}') +- super_ocf_log info "DEC: check_for_primary: loop=$i: node_status=$node_status" +- # TODO: PRIO1: Maybe we need to keep the old value for P/S/N, if hdbnsutil just crashes +- esac; +- done +- super_ocf_log info "FLOW $FUNCNAME rc=HANA_STATE_DEFECT" +- return $HANA_STATE_DEFECT ++ super_ocf_log debug "DBG: check_for_primary: srmode=$srmode" ++ case "$srmode" in ++ primary ) ++ super_ocf_log info "FLOW $FUNCNAME rc=HANA_STATE_PRIMARY" ++ rc=$HANA_STATE_PRIMARY;; ++ syncmem | sync | async ) ++ super_ocf_log info "FLOW $FUNCNAME rc=HANA_STATE_SECONDARY" ++ rc=$HANA_STATE_SECONDARY;; ++ none ) # have seen that mode on second side BEFEORE we registered it as replica ++ super_ocf_log info "FLOW $FUNCNAME rc=HANA_STATE_STANDALONE" ++ rc=$HANA_STATE_STANDALONE;; ++ * ) ++ dump=$( echo $srmode | hexdump -C ); ++ super_ocf_log err "ACT: check_for_primary: we didn't expect srmode to be: DUMP: <$dump>" ++ rc=$HANA_STATE_DEFECT ++ esac; ++ super_ocf_log info "FLOW $FUNCNAME rc=$rc" ++ return $rc + } + + +@@ -653,7 +813,7 @@ + function sht_stop_clone() { + super_ocf_log info "FLOW $FUNCNAME ($*)" + local rc=0 +- check_for_primary; primary_status=$? ++ check_for_primary; primary_status=$? + if [ $primary_status -eq $HANA_STATE_PRIMARY ]; then + hanaPrim="P" + elif [ $primary_status -eq $HANA_STATE_SECONDARY ]; then +@@ -663,7 +823,7 @@ + else + hanaPrim="-" + fi +- set_hana_attribute "${NODENAME}" "1:$hanaPrim:-:-:-:-" ${ATTR_NAME_HANA_ROLES[@]} ++ set_hana_attribute "${NODENAME}" "1:$hanaPrim:-:-:-:-" ${ATTR_NAME_HANA_ROLES[@]} + sht_stop; rc=$? + return $rc + } +@@ -718,28 +878,49 @@ + fi + # DONE: PRIO1: ASK: Is the output format of ListInstances fix? Could we take that as an API? + # try to catch: Inst Info : LNX - 42 - lv9041 - 740, patch 36, changelist 1444691 +- # We rely on the following format: SID is word#4, NR is work#6, vHost is word#8 ++ # We rely on the following format: SID is word#4, SYSNR is word#6, vHost is word#8 + #### SAP-CALL + vName=$(/usr/sap/hostctrl/exe/saphostctrl -function ListInstances \ +- | awk '$4 == SID && $6=NR { print $8 }' SID=$SID NR=$InstanceNr 2>/dev/null ) ++ | awk '$4 == SID && $6 == SYSNR { print $8 }' SID=$SID SYSNR=$InstanceNr 2>/dev/null ) + # super_ocf_log debug "DBG: ListInstances: $(/usr/sap/hostctrl/exe/saphostctrl -function ListInstances)" + if [ -n "$vName" ]; then +- set_hana_attribute ${NODENAME} "$vName" ${ATTR_NAME_HANA_VHOST[@]} ++ set_hana_attribute ${NODENAME} "$vName" ${ATTR_NAME_HANA_VHOST[@]} + else + vName=$(get_hana_attribute ${NODENAME} ${ATTR_NAME_HANA_VHOST[@]}) + fi + #site=$(get_site_name) + #### SAP-CALL +- hanaANSWER=$(su - $sidadm -c "python exe/python_support/landscapeHostConfiguration.py" 2>/dev/null); hanalrc="$?" +- hanarole=$(echo "$hanaANSWER" | tr -d ' ' | awk -F'|' '$2 == host { printf "%s:%s:%s:%s\n",$10,$11,$12,$13 } ' host=${vName}) ++ # SAP_CALL ++ #hanaANSWER=$(su - $sidadm -c "python exe/python_support/landscapeHostConfiguration.py" 2>/dev/null); hanalrc="$?" ++ # ++ # since rev 09x SAP has added the --sapcontrol option for the landscapeHostConfiguration interface ++ # we begin to use --sapcontrol with rev 100 ++ # since rev 120 we need to use the --sapcontrol, because SAP changed the tool output ++ # ++ if version "$hdbver" ">=" "1.00.100"; then ++ hanaANSWER=$(HANA_CALL --timeout 60 --cmd "landscapeHostConfiguration.py --sapcontrol=1" 2>/dev/null); hanalrc="$?" ++ # TODO: PRIO9: Do we need to check the lines: 'SAPCONTROL-OK: ' and 'SAPCONTROL-OK: '? ++ hanarole=$(echo "$hanaANSWER" | tr -d ' ' | \ ++ awk -F= '$1 == "nameServerConfigRole" {f1=$2} ++ $1 == "nameServerActualRole" {f2=$2} ++ $1 == "indexServerConfigRole" {f3=$2} ++ $1 == "indexServerActualRole" {f4=$2} ++ END { printf "%s:%s:%s:%s\n", f1, f2, f3,f4 }') ++ else ++ # ++ # old code for backward compatability ++ # ++ hanaANSWER=$(HANA_CALL --timeout 60 --cmd "landscapeHostConfiguration.py" 2>/dev/null); hanalrc="$?" ++ hanarole=$(echo "$hanaANSWER" | tr -d ' ' | awk -F'|' '$2 == host { printf "%s:%s:%s:%s\n",$10,$11,$12,$13 } ' host=${vName}) ++ fi + #if [ -z "$MAPPING" ]; then + # super_ocf_log info "ACT: Did not find remote Host at this moment" + #fi + # FH TODO PRIO3: TRY TO GET RID OF "ATTR_NAME_HANA_REMOTEHOST" + if [ -n "$hanaRemoteHost" ]; then +- set_hana_attribute ${NODENAME} "$hanaRemoteHost" ${ATTR_NAME_HANA_REMOTEHOST[@]} ++ set_hana_attribute ${NODENAME} "$hanaRemoteHost" ${ATTR_NAME_HANA_REMOTEHOST[@]} + fi +- set_hana_attribute ${NODENAME} "$hanalrc:$hanaPrim:$hanarole" ${ATTR_NAME_HANA_ROLES[@]} ++ set_hana_attribute ${NODENAME} "$hanalrc:$hanaPrim:$hanarole" ${ATTR_NAME_HANA_ROLES[@]} + if [ -n "$site" ]; then + set_hana_attribute ${NODENAME} "$site" ${ATTR_NAME_HANA_SITE[@]} + fi +@@ -748,8 +929,8 @@ + S ) # only secondary may propargate its sync status + case $(crm_attribute --type crm_config --name cluster-infrastructure -q) in + *corosync* ) nodelist=$(crm_node -l | awk '{ print $2 }');; +- *openais* ) nodelist=$(crm_node -l | awk '/member/ {print $2}');; +- *cman* ) nodelist=$(crm_node -l);; ++ *openais* ) nodelist=$(crm_node -l | awk '/member/ {print $2}');; ++ *cman* ) nodelist=$(crm_node -l);; + esac + + for n in ${nodelist}; do +@@ -789,7 +970,6 @@ + InstanceNr="" + DIR_EXECUTABLE="" + SAPHanaFilter="ra-act-dec-lpa" +-NODENAME=$(crm_node -n) + + if [ $# -ne 1 ] + then +@@ -846,8 +1026,7 @@ + fi + fi + +-THE_VERSION=$(sht_meta_data | grep ' ++# License: GPL v2+ ++my $Version="0.18.2016.02.16.1"; + # ++################################################################## + use POSIX; + use strict; ++use Sys::Syslog; ++use Sys::Hostname; ++use File::Path; ++use Getopt::Long; ++use lib '/usr/share/SAPHanaSR/tests'; ++use SAPHanaSRTools; ++ ++################################### ++## this part is not for scale out and currently NOT zero-config ++ ++my $ClusterNodes=2; ++my $ClusterPrimaries=1; ++my $ClusterSecondaries=1; ++my %Name; ++my %Host; ++my $host = hostname(); + ++my $varlib='/var/lib/SAPHanaTD'; ++my $testfile='SAPHanaTD.status'; ++my $testcount=0; ++my $first_test=1; + my $sid=""; +-my $table_title = "Host \\ Attr"; +-my %Name; ++my @sids; ++my $ino=""; ++my $sortBy=""; ++my $table_titleH = "Host"; ++#my %Name; + my %Host; ++my %Site; ++my %Global; ++my %HName; ++my %SName; ++my %GName; ++my $help; ++my $version; ++my $cibFile=""; ++ ++sub init() ++{ ++ my $result = GetOptions ("sid=s" => \@sids, ++ "sort=s" => \$sortBy, ++ "cib=s" => \$cibFile, ++ "version" => \$version, ++ "help" => \$help, ++ ); ++ return 0; ++} ++ ++init(); ++ ++if ( $help ) { ++ printf "SAPHanaSR-showAttr {[--sid=]} [--sort=] [--cib=]\n"; ++ printf ""; ++ exit 0; ++} ++if ( $version ) { ++ printf "%s\n", $Version; ++ exit 0; ++} ++ ++if ( $cibFile ne "" ) { ++ printf "Using cib file %s\n", $cibFile; ++} + + sub max { # thanks to http://www.perlunity.de/perl/forum/thread_018329.shtml + my $a = shift; +@@ -21,113 +80,75 @@ + return $a > $b ? $a : $b; + } + +-sub print_attr_host() +-{ +- my ($HKey, $AKey); +- printf "%-22s", "Attribute \\ Host"; +- foreach $HKey (sort keys %Host) { +- printf "%-16s ", $HKey; +- } +- printf "\n"; +- +- printf "%s\n", "-" x 120 ; +- +- foreach $AKey (sort keys %Name) { +- printf "%-22s", $AKey; +- foreach $HKey (sort keys %Host) { +- printf "%-16.16s ", $Host{$HKey} -> {$AKey}; +- } +- +- printf "\n"; +- } +- return 0; +-} +- +-sub print_host_attr() +-{ +- my ($AKey, $HKey, $len, $line_len, $hclen); +- $hclen=$Name{_hosts}->{_length}; +- $line_len=$hclen+1; +- printf "%-$hclen.${hclen}s ", "$table_title"; +- foreach $AKey (sort keys %Name) { +- if ($AKey ne "_hosts") { +- $len = $Name{$AKey}->{_length}; +- $line_len=$line_len+$len+1; +- printf "%-$len.${len}s ", $Name{$AKey}->{_title}; ++sub read_cib($) { ++ my $sid = shift(); ++ if ( $cibFile eq "" ) { ++ printf "Open live cib\n"; ++ open CIB, "cibadmin -Ql |" or die "CIB could not be read from cluster"; ++ } else { ++ open CIB, "<$cibFile" or die "CIB file $cibFile not found or not able to read it"; ++ } ++ while () { ++ chomp; ++ my ($host, $name, $site, $value); ++ if ( $_ =~ /cib-last-written="([^"]*)"/ ) { ++ printf "CIB-time: %s\n", $1; + } +- } +- printf "\n"; +- printf "%s\n", "-" x $line_len ; +- foreach $HKey (sort keys %Host) { +- printf "%-$hclen.${hclen}s ", $HKey; +- foreach $AKey (sort keys %Name) { +- if ($AKey ne "_hosts") { +- $len = $Name{$AKey}->{_length}; +- printf "%-$len.${len}s ", $Host{$HKey} -> {$AKey}; +- } +- } +- printf "\n"; +- } +- return 0; +-} +- +-open ListInstances, "/usr/sap/hostctrl/exe/saphostctrl -function ListInstances|"; +-while () { +- # try to catch: Inst Info : LNX - 42 - lv9041 - 740, patch 36, changelist 1444691 +- chomp; +- if ( $_ =~ /:\s+([A-Z][A-Z0-9][A-Z0-9])\s+-/ ) { +- $sid=tolower("$1"); +- } +-} +-close ListInstances; +- +- +-open CIB, "cibadmin -Ql |"; +-while () { +- chomp; +- my ($host, $name, $value); +- my $found=0; +- if ( $_ =~ /nvpair.*name="(\w+_${sid}_\w+)"/ ) { +- $name=$1; +- # find attribute in forever and reboot store :) +- if ( $_ =~ /id="(status|nodes)-([a-zA-Z0-9\_\-]+)-/ ) { +- $host=$2; +- } +- if ( $_ =~ /value="([^"]+)"/ ) { +- $value=$1; +- $found=1; +- } +- } +- if ( $found == 1 ) { +- # +- # handle the hosts name and table-title +- # +- $Host{$host}->{$name}=${value}; +- if ( defined ($Name{_hosts}->{_length})) { +- $Name{_hosts}->{_length} = max($Name{_hosts}->{_length}, length($host )); +- } else { +- $Name{_hosts}->{_length} = length($host ); ++ if ( $_ =~ /node_state id=".+" uname="([a-zA-Z0-9\-\_]+)" .*crmd="([a-zA-Z0-9\-\_]+)"/ ) { ++ insertAttribute($sid, \%Host, \%HName, $1, "node_status", $2); + } +- $Name{_hosts}->{_length} = max($Name{_hosts}->{_length}, length( $table_title)); +- # +- # now handle the attributes name and value +- # +- $Name{$name}->{$host}=${value}; +- if ( defined ($Name{$name}->{_length})) { +- $Name{$name}->{_length} = max($Name{$name}->{_length}, length($value )); +- } else { +- $Name{$name}->{_length} = length($value ); ++ if ( $_ =~ /nvpair.*name="([a-zA-Z0-9\_\-]+_${sid}_([a-zA-Z0-9\-\_]+))"/ ) { ++ $name=$1; ++ if ( $_ =~ /id=.(status|nodes)-([a-zA-Z0-9\_\-]+)-/ ) { ++ # found attribute in nodes forever and reboot store ++ $host=$2; ++ if ( $_ =~ /value="([^"]+)"/ ) { ++ $value=$1; ++ insertAttribute($sid, \%Host, \%HName, $host, $name, $value); ++ } ++ } elsif ( $_ =~ /id=.SAPHanaSR-[a-zA-Z0-9\_\-]+_site_[a-zA-Z0-9\-]+_([a-zA-Z0-9\_\-]+)/) { ++ # found a site attribute ++ $site=$1; ++ if ( $name =~ /[a-zA-Z0-9\_\-]+_site_([a-zA-Z0-9\-]+)/ ) { ++ $name = $1; ++ } ++ if ( $_ =~ /value="([^"]+)"/ ) { ++ $value=$1; ++ insertAttribute($sid, \%Site, \%SName, $site, $name, $value); ++ } ++ } elsif ( $_ =~ /id=.SAPHanaSR-[a-zA-Z0-9\_\-]+_glob_[a-zA-Z0-9\_\-]+/) { ++ # found a global attribute ++ $host="GLOBAL"; ++ if ( $name =~ /([a-zA-Z0-9\_\-]+)_glob_([a-zA-Z0-9\_\-]+)/ ) { ++ $name = $2; ++ } ++ if ( $_ =~ /value="([^"]+)"/ ) { ++ $value=$1; ++ insertAttribute($sid, \%Global, \%GName, "global", $name, $value); ++ } ++ } + } +- if ( $name =~ /hana_${sid}_(.*)/ ) { +- $Name{$name}->{_title} = $1; +- } else { +- $Name{$name}->{_title} = $name; +- } +- $Name{$name}->{_length} = max($Name{$name}->{_length}, length( $Name{$name}->{_title})); +- # printf "%-8s %-20s %-30s\n", $1, $2, $3; +- } ++ } ++ close CIB; + } +-close CIB; + +-#print_attr_host; +-print_host_attr; ++if ( 0 == @sids ) { ++ my $sid_ino_list; ++ ( $sid_ino_list ) = get_sid_and_InstNr(); ++ @sids = split(",", $sid_ino_list); ++ ++} ++ ++foreach $sid (@sids) { ++ ( $sid, $ino ) = split(":", $sid); ++ $sid=tolower("$sid"); ++ %Host=(); ++ %HName=(); ++ read_cib($sid); ++ get_hana_attributes($sid); ++ if ( keys(%Host) == 0 ) { ++ printf "No attributes found for SID=%s\n", $sid; ++ } else { ++ print_host_attr(\%Host, \%HName, "Hosts", $sortBy); ++ } ++} diff --git a/SOURCES/bz1395142-2-update-saphana-saphanatopology.patch b/SOURCES/bz1395142-2-update-saphana-saphanatopology.patch new file mode 100644 index 00000000..2b9637b6 --- /dev/null +++ b/SOURCES/bz1395142-2-update-saphana-saphanatopology.patch @@ -0,0 +1,14 @@ +diff -uNr a/heartbeat/SAPHana b/heartbeat/SAPHana +--- a/heartbeat/SAPHana 2016-11-17 09:35:47.460984046 +0100 ++++ b/heartbeat/SAPHana 2016-11-17 09:36:20.536591188 +0100 +@@ -133,8 +133,8 @@ + function backup_global_and_nameserver() { + super_ocf_log info "FLOW $FUNCNAME ($*)" + local rc=0 +- cp /hana/shared/LNX/global/hdb/custom/config/global.ini /hana/shared/LNX/global/hdb/custom/config/global.ini.$(date +"%s") +- cp /hana/shared/LNX/global/hdb/custom/config/nameserver.ini /hana/shared/LNX/global/hdb/custom/config/nameserver.ini.$(date +"%s") ++ cp /hana/shared/$SID/global/hdb/custom/config/global.ini /hana/shared/$SID/global/hdb/custom/config/global.ini.$(date +"%s") ++ cp /hana/shared/$SID/global/hdb/custom/config/nameserver.ini /hana/shared/$SID/global/hdb/custom/config/nameserver.ini.$(date +"%s") + super_ocf_log info "FLOW $FUNCNAME rc=$rc" + return $rc + } diff --git a/SOURCES/bz1397393-rabbitmq-cluster-reset-mnesia-before-join.patch b/SOURCES/bz1397393-rabbitmq-cluster-reset-mnesia-before-join.patch new file mode 100644 index 00000000..37726748 --- /dev/null +++ b/SOURCES/bz1397393-rabbitmq-cluster-reset-mnesia-before-join.patch @@ -0,0 +1,169 @@ +diff -uNr a/heartbeat/rabbitmq-cluster b/heartbeat/rabbitmq-cluster +--- a/heartbeat/rabbitmq-cluster 2017-01-20 15:37:43.698833068 +0100 ++++ b/heartbeat/rabbitmq-cluster 2017-01-20 16:28:56.170739557 +0100 +@@ -1,6 +1,6 @@ + #!/bin/sh + # +-# Copyright (c) 2014 David Vossel ++# Copyright (c) 2014 David Vossel + # All Rights Reserved. + # + # This program is free software; you can redistribute it and/or modify +@@ -52,7 +52,7 @@ + cat < + +- ++ + 1.0 + + +@@ -111,7 +111,7 @@ + + rmq_join_list() + { +- cibadmin -Q 2>/dev/null | grep "$RMQ_CRM_ATTR_COOKIE" | sed -n -e "s/^.*value=.\(.*\)\".*$/\1/p" ++ cibadmin -Q --xpath "//node_state[@crmd='online']//nvpair[@name='$RMQ_CRM_ATTR_COOKIE']" | grep "$RMQ_CRM_ATTR_COOKIE" | sed -n -e "s/^.*value=.\(.*\)\".*$/\1/p" + } + + rmq_write_nodename() +@@ -203,7 +203,7 @@ + + rmq_set_policy() + { +- $RMQ_CTL set_policy $@ > /dev/null 2>&1 ++ $RMQ_CTL set_policy "$@" > /dev/null 2>&1 + } + + rmq_start_first() +@@ -284,7 +284,6 @@ + return $OCF_SUCCESS + } + +- + rmq_forget_cluster_node_remotely() { + local running_cluster_nodes="$1" + local node_to_forget="$2" +@@ -354,26 +353,28 @@ + return $rc + fi + +- # first try to join without wiping mnesia data +- rmq_join_existing "$join_list" +- if [ $? -ne 0 ]; then +- ocf_log info "node failed to join, wiping data directory and trying again" +- local local_rmq_node="$(${HA_SBIN_DIR}/crm_attribute -N $NODENAME -l forever --query --name $RMQ_CRM_ATTR_COOKIE_LAST_KNOWN -q)" ++ # Try to join existing cluster ++ ocf_log info "wiping data directory before joining" ++ local local_rmq_node="$(${HA_SBIN_DIR}/crm_attribute -N $NODENAME -l forever --query --name $RMQ_CRM_ATTR_COOKIE_LAST_KNOWN -q)" + +- # if the graceful join fails, use the hammer and reset all the data. +- rmq_stop +- rmq_wipe_data +- rmq_forget_cluster_node_remotely "$join_list" "$local_rmq_node" +- rmq_join_existing "$join_list" +- rc=$? ++ rmq_stop ++ rmq_wipe_data ++ rmq_forget_cluster_node_remotely "$join_list" "$local_rmq_node" ++ rmq_join_existing "$join_list" ++ rc=$? + +- # Restore users (if any) +- BaseDataDir=`dirname $RMQ_DATA_DIR` +- if [ -f $BaseDataDir/users.erl ] ; then +- rabbitmqctl eval " +- %% Run only if Mnesia is ready, otherwise exit. +- lists:any(fun({mnesia,_,_}) -> true; ({_,_,_}) -> false end, application:which_applications()) orelse halt(), ++ if [ $rc -ne 0 ]; then ++ ocf_log info "node failed to join even after reseting local data. Check SELINUX policy" ++ return $OCF_ERR_GENERIC ++ fi + ++ # Restore users and users' permissions (if any) ++ BaseDataDir=`dirname $RMQ_DATA_DIR` ++ if [ -f $BaseDataDir/users.erl ] ; then ++ rabbitmqctl eval " ++ %% Run only if Mnesia is ready. ++ lists:any(fun({mnesia,_,_}) -> true; ({_,_,_}) -> false end, application:which_applications()) andalso ++ begin + [WildPattern] = ets:select(mnesia_gvar, [ { {{rabbit_user, wild_pattern}, '\\\$1'}, [], ['\\\$1'] } ]), + + %% Read users first +@@ -400,39 +401,51 @@ + %% Version >= 3.6.0 + {internal_user,'_','_','_','_'} -> + lists:foreach(fun(X) -> mnesia:dirty_write(rabbit_user, Upgrade(X)) end, Users) +- end. +- " +- rm -f $BaseDataDir/users.erl +- fi +- +- if [ $rc -ne 0 ]; then +- ocf_log info "node failed to join even after reseting local data. Check SELINUX policy" +- return $OCF_ERR_GENERIC +- fi ++ end, ++ ++ ok = file:delete(\"$BaseDataDir/users.erl\") ++ end. ++ " ++ fi ++ if [ -f $BaseDataDir/users_perms.erl ] ; then ++ rabbitmqctl eval " ++ %% Run only if Mnesia is ready. ++ lists:any(fun({mnesia,_,_}) -> true; ({_,_,_}) -> false end, application:which_applications()) andalso ++ begin ++ {ok, [UsersPerms]} = file:consult(\"$BaseDataDir/users_perms.erl\"), ++ lists:foreach(fun(X) -> mnesia:dirty_write(rabbit_user_permission, X) end, UsersPerms), ++ ++ ok = file:delete(\"$BaseDataDir/users_perms.erl\") ++ end. ++ " + fi + + return $OCF_SUCCESS + } + + rmq_stop() { +- # Backup users ++ # Backup users and users' permissions + BaseDataDir=`dirname $RMQ_DATA_DIR` + rabbitmqctl eval " +- %% Run only if Mnesia is still available, otherwise exit. +- lists:any(fun({mnesia,_,_}) -> true; ({_,_,_}) -> false end, application:which_applications()) orelse halt(), +- +- [WildPattern] = ets:select(mnesia_gvar, [ { {{rabbit_user, wild_pattern}, '\\\$1'}, [], ['\\\$1'] } ]), +- +- Users = case WildPattern of +- %% Version < 3.6.0 +- {internal_user,'_','_','_'} -> +- mnesia:dirty_select(rabbit_user, [{ {internal_user, '\\\$1', '_', '_'}, [{'/=', '\\\$1', <<\"guest\">>}], ['\\\$_'] } ]); +- %% Version >= 3.6.0 +- {internal_user,'_','_','_','_'} -> +- mnesia:dirty_select(rabbit_user, [{ {internal_user, '\\\$1', '_', '_', '_'}, [{'/=', '\\\$1', <<\"guest\">>}], ['\\\$_'] } ]) +- end, +- +- file:write_file(\"$BaseDataDir/users.erl\", io_lib:fwrite(\"~p.~n\", [Users])). ++ %% Run only if Mnesia is still available. ++ lists:any(fun({mnesia,_,_}) -> true; ({_,_,_}) -> false end, application:which_applications()) andalso ++ begin ++ [WildPattern] = ets:select(mnesia_gvar, [ { {{rabbit_user, wild_pattern}, '\\\$1'}, [], ['\\\$1'] } ]), ++ ++ Users = case WildPattern of ++ %% Version < 3.6.0 ++ {internal_user,'_','_','_'} -> ++ mnesia:dirty_select(rabbit_user, [{ {internal_user, '\\\$1', '_', '_'}, [{'/=', '\\\$1', <<\"guest\">>}], ['\\\$_'] } ]); ++ %% Version >= 3.6.0 ++ {internal_user,'_','_','_','_'} -> ++ mnesia:dirty_select(rabbit_user, [{ {internal_user, '\\\$1', '_', '_', '_'}, [{'/=', '\\\$1', <<\"guest\">>}], ['\\\$_'] } ]) ++ end, ++ ++ Users /= [] andalso file:write_file(\"$BaseDataDir/users.erl\", io_lib:fwrite(\"~p.~n\", [Users])), ++ ++ UsersPerms = mnesia:dirty_select(rabbit_user_permission, [{{'\\\$1', {'\\\$2', '\\\$3','\\\$4'}, '\\\$5'}, [{'/=', '\\\$3', <<\"guest\">>}], ['\\\$_']}]), ++ UsersPerms /= [] andalso file:write_file(\"$BaseDataDir/users_perms.erl\", io_lib:fwrite(\"~p.~n\", [UsersPerms])) ++ end. + " + + rmq_monitor diff --git a/SOURCES/bz1400172-IPsrcaddr-fix-duplicate-routes.patch b/SOURCES/bz1400172-IPsrcaddr-fix-duplicate-routes.patch new file mode 100644 index 00000000..02d74463 --- /dev/null +++ b/SOURCES/bz1400172-IPsrcaddr-fix-duplicate-routes.patch @@ -0,0 +1,22 @@ +From f35491fd18693d2816ad6f83c32e133b26193aa2 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Wed, 21 Dec 2016 15:34:50 +0100 +Subject: [PATCH] IPsrcaddr: match exact route to avoid failing + +--- + heartbeat/IPsrcaddr | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/heartbeat/IPsrcaddr b/heartbeat/IPsrcaddr +index 08fd8a6..0efe154 100755 +--- a/heartbeat/IPsrcaddr ++++ b/heartbeat/IPsrcaddr +@@ -469,7 +469,7 @@ rc=$? + } + + INTERFACE=`echo $findif_out | awk '{print $1}'` +-NETWORK=`ip route list dev $INTERFACE scope link match $ipaddress|grep -o '^[^ ]*'` ++NETWORK=`ip route list dev $INTERFACE scope link proto kernel match $ipaddress|grep -o '^[^ ]*'` + + case $1 in + start) srca_start $ipaddress diff --git a/SOURCES/bz1402370-portblock-wait.patch b/SOURCES/bz1402370-portblock-wait.patch new file mode 100644 index 00000000..b57e5cf7 --- /dev/null +++ b/SOURCES/bz1402370-portblock-wait.patch @@ -0,0 +1,114 @@ +From 14b45df580668220cf97744df93cb9ee5484a14e Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Thu, 8 Dec 2016 11:18:10 +0100 +Subject: [PATCH 1/2] portblock: Use -w (wait) to avoid "insufficient + privileges" error + +--- + heartbeat/portblock | 10 +++++----- + 1 file changed, 5 insertions(+), 5 deletions(-) + +diff --git a/heartbeat/portblock b/heartbeat/portblock +index c480954..e7de217 100755 +--- a/heartbeat/portblock ++++ b/heartbeat/portblock +@@ -242,7 +242,7 @@ active_grep_pat() + chain_isactive() + { + PAT=`active_grep_pat "$1" "$2" "$3"` +- $IPTABLES -n -L INPUT | grep "$PAT" >/dev/null ++ $IPTABLES -w -n -L INPUT | grep "$PAT" >/dev/null + } + + save_tcp_connections() +@@ -370,13 +370,13 @@ IptablesBLOCK() + : OK -- chain already active + else + if $try_reset ; then +- $IPTABLES -I OUTPUT -p "$1" -s "$3" -m multiport --sports "$2" -j REJECT --reject-with tcp-reset ++ $IPTABLES -w -I OUTPUT -p "$1" -s "$3" -m multiport --sports "$2" -j REJECT --reject-with tcp-reset + tickle_local + fi +- $IPTABLES -I INPUT -p "$1" -d "$3" -m multiport --dports "$2" -j DROP ++ $IPTABLES -w -I INPUT -p "$1" -d "$3" -m multiport --dports "$2" -j DROP + rc=$? + if $try_reset ; then +- $IPTABLES -D OUTPUT -p "$1" -s "$3" -m multiport --sports "$2" -j REJECT --reject-with tcp-reset ++ $IPTABLES -w -D OUTPUT -p "$1" -s "$3" -m multiport --sports "$2" -j REJECT --reject-with tcp-reset + fi + fi + +@@ -389,7 +389,7 @@ IptablesUNBLOCK() + if + chain_isactive "$1" "$2" "$3" + then +- $IPTABLES -D INPUT -p "$1" -d "$3" -m multiport --dports "$2" -j DROP ++ $IPTABLES -w -D INPUT -p "$1" -d "$3" -m multiport --dports "$2" -j DROP + else + : Chain Not active + fi + +From 57d31bc04a0421cf2746830d5e987e52f9f9acd3 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Fri, 9 Dec 2016 13:57:49 +0100 +Subject: [PATCH 2/2] portblock: version check for -w + +--- + heartbeat/portblock | 19 ++++++++++++++----- + 1 file changed, 14 insertions(+), 5 deletions(-) + +diff --git a/heartbeat/portblock b/heartbeat/portblock +index e7de217..92f7071 100755 +--- a/heartbeat/portblock ++++ b/heartbeat/portblock +@@ -242,7 +242,7 @@ active_grep_pat() + chain_isactive() + { + PAT=`active_grep_pat "$1" "$2" "$3"` +- $IPTABLES -w -n -L INPUT | grep "$PAT" >/dev/null ++ $IPTABLES $wait -n -L INPUT | grep "$PAT" >/dev/null + } + + save_tcp_connections() +@@ -370,13 +370,13 @@ IptablesBLOCK() + : OK -- chain already active + else + if $try_reset ; then +- $IPTABLES -w -I OUTPUT -p "$1" -s "$3" -m multiport --sports "$2" -j REJECT --reject-with tcp-reset ++ $IPTABLES $wait -I OUTPUT -p "$1" -s "$3" -m multiport --sports "$2" -j REJECT --reject-with tcp-reset + tickle_local + fi +- $IPTABLES -w -I INPUT -p "$1" -d "$3" -m multiport --dports "$2" -j DROP ++ $IPTABLES $wait -I INPUT -p "$1" -d "$3" -m multiport --dports "$2" -j DROP + rc=$? + if $try_reset ; then +- $IPTABLES -w -D OUTPUT -p "$1" -s "$3" -m multiport --sports "$2" -j REJECT --reject-with tcp-reset ++ $IPTABLES $wait -D OUTPUT -p "$1" -s "$3" -m multiport --sports "$2" -j REJECT --reject-with tcp-reset + fi + fi + +@@ -389,7 +389,7 @@ IptablesUNBLOCK() + if + chain_isactive "$1" "$2" "$3" + then +- $IPTABLES -w -D INPUT -p "$1" -d "$3" -m multiport --dports "$2" -j DROP ++ $IPTABLES $wait -D INPUT -p "$1" -d "$3" -m multiport --dports "$2" -j DROP + else + : Chain Not active + fi +@@ -526,6 +526,15 @@ if [ -z "$OCF_RESKEY_action" ]; then + exit $OCF_ERR_CONFIGURED + fi + ++# iptables v1.4.20+ is required to use -w (wait) ++version=$(iptables -V | awk -F ' v' '{print $NF}') ++ocf_version_cmp "$version" "1.4.19.1" ++if [ "$?" -eq "2" ]; then ++ wait="-w" ++else ++ wait="" ++fi ++ + protocol=$OCF_RESKEY_protocol + portno=$OCF_RESKEY_portno + action=$OCF_RESKEY_action diff --git a/SOURCES/bz1406152-exportfs-ipv6-fix.patch b/SOURCES/bz1406152-exportfs-ipv6-fix.patch new file mode 100644 index 00000000..ac5eb183 --- /dev/null +++ b/SOURCES/bz1406152-exportfs-ipv6-fix.patch @@ -0,0 +1,14 @@ +diff -uNr a/heartbeat/exportfs b/heartbeat/exportfs +--- a/heartbeat/exportfs 2016-12-22 14:29:11.347973419 +0100 ++++ b/heartbeat/exportfs 2016-12-22 14:30:10.273326342 +0100 +@@ -204,6 +204,10 @@ + is_exported() { + local dir=$1 + local spec=$2 ++ ++ # IPv6 addressed are encased in brackets that need to be removed ++ spec=$(echo $spec | sed 's/\[//;s/\]//') ++ + exportfs | + sed -e '$! N; s/\n[[:space:]]\+/ /; t; s/[[:space:]]\+\([^[:space:]]\+\)\(\n\|$\)/ \1\2/g; P;D;' | + grep -q -x -F "$dir $spec" diff --git a/SOURCES/bz1408656-ethmonitor-monitor-interface-without-ip.patch b/SOURCES/bz1408656-ethmonitor-monitor-interface-without-ip.patch new file mode 100644 index 00000000..d5ba5b8d --- /dev/null +++ b/SOURCES/bz1408656-ethmonitor-monitor-interface-without-ip.patch @@ -0,0 +1,25 @@ +From 8ec7bd4cfcbdbff10c1c5717eae91d8c41037cda Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Fri, 24 Mar 2017 12:56:23 +0100 +Subject: [PATCH] ethmonitor: fix to be able to monitor interface without IP + +--- + heartbeat/ethmonitor | 5 +++-- + 1 file changed, 3 insertions(+), 2 deletions(-) + +diff --git a/heartbeat/ethmonitor b/heartbeat/ethmonitor +index 7f5579f..81a7c0b 100755 +--- a/heartbeat/ethmonitor ++++ b/heartbeat/ethmonitor +@@ -206,8 +206,9 @@ is_interface() { + # + # List interfaces but exclude FreeS/WAN ipsecN virtual interfaces + # +- local iface=`$IP2UTIL -o -f inet addr show | grep " $1 " \ +- | cut -d ' ' -f2 | sort -u | grep -v '^ipsec[0-9][0-9]*$'` ++ local iface=`$IP2UTIL -o -f link addr show | grep " $1:" \ ++ | cut -d ' ' -f2 | sort -u | grep -v '^ipsec[0-9][0-9]*$' \ ++ | sed -e 's/:$//'` + [ "$iface" != "" ] + } + diff --git a/SOURCES/bz1411225-oraasm.patch b/SOURCES/bz1411225-oraasm.patch new file mode 100644 index 00000000..6e07cb9b --- /dev/null +++ b/SOURCES/bz1411225-oraasm.patch @@ -0,0 +1,221 @@ +From 70030ab28f81609292cfbb3c7b34f3f033b09c57 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Thu, 23 Mar 2017 10:50:45 +0100 +Subject: [PATCH] oraasm: new resource agent for Oracle ASM Disk Groups + +--- + doc/man/Makefile.am | 1 + + heartbeat/Makefile.am | 1 + + heartbeat/oraasm | 179 ++++++++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 181 insertions(+) + create mode 100755 heartbeat/oraasm + +diff --git a/doc/man/Makefile.am b/doc/man/Makefile.am +index 43a3f70..f5f64c8 100644 +--- a/doc/man/Makefile.am ++++ b/doc/man/Makefile.am +@@ -122,6 +122,7 @@ man_MANS = ocf_heartbeat_AoEtarget.7 \ + ocf_heartbeat_nfsnotify.7 \ + ocf_heartbeat_nfsserver.7 \ + ocf_heartbeat_nginx.7 \ ++ ocf_heartbeat_oraasm.7 \ + ocf_heartbeat_oracle.7 \ + ocf_heartbeat_oralsnr.7 \ + ocf_heartbeat_pgsql.7 \ +diff --git a/heartbeat/Makefile.am b/heartbeat/Makefile.am +index 91d4090..229db71 100644 +--- a/heartbeat/Makefile.am ++++ b/heartbeat/Makefile.am +@@ -119,6 +119,7 @@ ocf_SCRIPTS = AoEtarget \ + named \ + nfsnotify \ + nfsserver \ ++ oraasm \ + oracle \ + oralsnr \ + pingd \ +diff --git a/heartbeat/oraasm b/heartbeat/oraasm +new file mode 100755 +index 0000000..22b88ea +--- /dev/null ++++ b/heartbeat/oraasm +@@ -0,0 +1,179 @@ ++#!/bin/sh ++# ++# License: GNU General Public License (GPL) ++# (c) 2017 O. Albrigtsen ++# and Linux-HA contributors ++# ++# ----------------------------------------------------------------------------- ++# O C F R E S O U R C E S C R I P T S P E C I F I C A T I O N ++# ----------------------------------------------------------------------------- ++# ++# NAME ++# oraasm : OCF resource agent script for Oracle ASM ++# ++ ++# Initialization: ++: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat} ++. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs ++ ++# Defaults ++OCF_RESKEY_user_default="grid" ++ ++: ${OCF_RESKEY_user=${OCF_RESKEY_user_default}} ++ ++ ++oraasm_usage() { ++ cat < ++ ++ ++0.75 ++ ++OCF Resource script for Oracle ASM. It uses the ohasd init-script to manage a Oracle ASM Disk Group as a HA resource. ++Oracle ASM resource agent ++ ++ ++ ++ ++ Oracle Grid user ++ Oracle Grid user ++ ++ ++ ++ ++ ++The name of the Oracle Disk Group. ++If not specified, then the Disk Group along with its home should be listed in /etc/oratab. ++ ++ Oracle Disk Group ++ ++ ++ ++ ++The Oracle Grid home directory ++home ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++END ++} ++ ++oraasm_methods() { ++ cat <<-! ++ start ++ stop ++ status ++ monitor ++ validate-all ++ methods ++ meta-data ++ usage ++ ! ++} ++ ++oraasm_getconfig() { ++ [ x = "x$OCF_RESKEY_home" ] && ++ OCF_RESKEY_home=`awk -F: "/^+$OCF_RESKEY_diskgroup:/"'{print $2}' /etc/oratab` ++ PATH="$OCF_RESKEY_home/bin:$PATH" ++ ++ ORA_ENVF=`mktemp` ++ cat << EOF > $ORA_ENVF ++PATH="$OCF_RESKEY_home/bin:$PATH" ++EOF ++ chmod 644 $ORA_ENVF ++ trap "rm -f $ORA_ENVF" EXIT ++} ++ ++oraasm_start() { ++ # if resource is already running, no need to continue code after this. ++ if oraasm_monitor; then ++ ocf_log info "Oracle ASM is already running" ++ return $OCF_SUCCESS ++ fi ++ ++ ocf_run -q /etc/init.d/ohasd start ++ ++ while ! oraasm_monitor; do ++ sleep 1 ++ done ++ ++ return $OCF_SUCCESS ++} ++ ++oraasm_stop() { ++ oraasm_monitor ++ if [ $? -ne $OCF_SUCCESS ]; then ++ # Currently not running. Nothing to do. ++ ocf_log info "Oracle ASM is already stopped" ++ ++ return $OCF_SUCCESS ++ fi ++ ++ ocf_run -q /etc/init.d/ohasd stop ++ ++ # Wait for process to stop ++ while oraasm_monitor; do ++ sleep 1 ++ done ++ ++ return $OCF_SUCCESS ++} ++ ++oraasm_monitor() { ++ su - $OCF_RESKEY_user -c ". $ORA_ENVF; crsctl check has | grep -q \"CRS-4638\"" ++ case "$?" in ++ 0) ++ rc=$OCF_SUCCESS ++ ;; ++ 1) ++ rc=$OCF_NOT_RUNNING ++ ocf_log info "Oracle ASM is not running" ++ ;; ++ *) ++ rc=$OCF_ERR_GENERIC ++ ;; ++ esac ++ return $rc ++} ++ ++oraasm_status() { ++ rc=$(oraasm_monitor) ++ return $rc ++} ++ ++oraasm_validate_all() { ++ if [ x = "x$OCF_RESKEY_home" ]; then ++ ocf_exit_reason "home not set" ++ return $OCF_ERR_CONFIGURED ++ fi ++} ++ ++ ++OCF_REQUIRED_PARAMS="user diskgroup" ++OCF_REQUIRED_BINARIES="/etc/init.d/ohasd crsctl" ++ocf_rarun $* ++ ++# vim:tabstop=4:shiftwidth=4:textwidth=0:wrapmargin=0 diff --git a/SOURCES/bz1420565-pgsql-dont-use-crm_failcount.patch b/SOURCES/bz1420565-pgsql-dont-use-crm_failcount.patch new file mode 100644 index 00000000..e423934f --- /dev/null +++ b/SOURCES/bz1420565-pgsql-dont-use-crm_failcount.patch @@ -0,0 +1,64 @@ +diff -uNr a/heartbeat/pgsql b/heartbeat/pgsql +--- a/heartbeat/pgsql 2017-03-09 11:50:06.365145803 +0100 ++++ b/heartbeat/pgsql 2017-03-09 12:19:41.566177608 +0100 +@@ -966,8 +966,13 @@ + cmp_location=`printf "$master_baseline\n$my_master_baseline\n" |\ + sort | head -1` + if [ "$cmp_location" != "$my_master_baseline" ]; then ++ # We used to set the failcount to INF for the resource here in ++ # order to move the master to the other node. However, setting ++ # the failcount should be done only by the CRM and so this use ++ # got deprecated in pacemaker version 1.1.17. Now we do the ++ # "ban resource from the node". + ocf_exit_reason "My data is newer than new master's one. New master's location : $master_baseline" +- $CRM_FAILCOUNT -r $OCF_RESOURCE_INSTANCE -U $NODENAME -v INFINITY ++ exec_with_retry 0 $CRM_RESOURCE -B -r $OCF_RESOURCE_INSTANCE -N $NODENAME -Q + return $OCF_ERR_GENERIC + fi + fi +@@ -1526,6 +1531,36 @@ + wait $func_pid + } + ++# retry command when command doesn't return 0 ++# arg1 : count >= 0 (if arg1 is 0, it retries command in infinitum(1day)) ++# arg2..argN : command and args ++exec_with_retry() { ++ local count="86400" ++ local output ++ local rc ++ ++ if [ "$1" -ne 0 ]; then ++ count=$1 ++ fi ++ shift ++ ++ while [ $count -gt 0 ]; do ++ output=`$*` ++ rc=$? ++ if [ $rc -ne 0 ]; then ++ ocf_log warn "Retrying(remain $count). \"$*\" failed. rc=$rc. stdout=\"$output\"." ++ count=`expr $count - 1` ++ sleep 1 ++ else ++ printf "${output}" ++ return 0 ++ fi ++ done ++ ++ ocf_exit_reason "giving up executing \"$*\"" ++ return $rc ++} ++ + is_node_online() { + crm_mon -1 -n | tr '[A-Z]' '[a-z]' | grep -e "^node $1 " -e "^node $1:" | grep -q -v "offline" + } +@@ -1734,7 +1769,7 @@ + CRM_MASTER="${HA_SBIN_DIR}/crm_master -l reboot" + CRM_ATTR_REBOOT="${HA_SBIN_DIR}/crm_attribute -l reboot" + CRM_ATTR_FOREVER="${HA_SBIN_DIR}/crm_attribute -l forever" +- CRM_FAILCOUNT="${HA_SBIN_DIR}/crm_failcount" ++ CRM_RESOURCE="${HA_SBIN_DIR}/crm_resource" + + CAN_NOT_PROMOTE="-INFINITY" + CAN_PROMOTE="100" diff --git a/SOURCES/bz1427574-DB2-fix-HADR-DB2-V98-or-later.patch b/SOURCES/bz1427574-DB2-fix-HADR-DB2-V98-or-later.patch new file mode 100644 index 00000000..ed1a442a --- /dev/null +++ b/SOURCES/bz1427574-DB2-fix-HADR-DB2-V98-or-later.patch @@ -0,0 +1,68 @@ +From b5d3f7347ff423868d3735df377c649c3e81a12a Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Thu, 6 Apr 2017 11:36:44 +0200 +Subject: [PATCH] DB2: fix HADR support for DB2 V98+ + +--- + heartbeat/db2 | 16 +++++++++------- + 1 file changed, 9 insertions(+), 7 deletions(-) + +diff --git a/heartbeat/db2 b/heartbeat/db2 +index c522699..63de315 100755 +--- a/heartbeat/db2 ++++ b/heartbeat/db2 +@@ -650,7 +650,9 @@ db2_hadr_status() { + fi + + echo "$output" | +- awk '/^HADR is not active/ {print "Standard/Standalone"; exit; } ++ awk '/^\s+HADR_(ROLE|STATE) =/ {printf $3"/"} ++ /^\s+HADR_CONNECT_STATUS =/ {print $3; exit; } ++ /^HADR is not active/ {print "Standard/Standalone"; exit; } + /^Role *State */ {getline; printf "%s/%s\n", $1, $2; exit; }' + } + +@@ -680,7 +682,7 @@ db2_monitor() { + + # set master preference accordingly + case "$hadr" in +- Primary/*|Standard/*) ++ PRIMARY/*|Primary/*|Standard/*) + # perform a basic health check + CMD="if db2 connect to $db; + then +@@ -712,11 +714,11 @@ db2_monitor() { + ocf_is_ms && master_score -v 10000 -l reboot + ;; + +- Standby/*Peer) ++ STANDBY/PEER/*|Standby/*Peer) + master_score -v 8000 -l reboot + ;; + +- Standby/*) ++ STANDBY/*|Standby/*) + ocf_log warn "DB2 database $instance($db2node)/$db in status $hadr can never be promoted" + master_score -D -l reboot + ;; +@@ -755,17 +757,17 @@ db2_promote() { + return $OCF_SUCCESS + ;; + +- Primary/Peer) ++ PRIMARY/PEER/*|PRIMARY/REMOTE_CATCHUP/*|Primary/Peer) + # nothing to do, only update pacemaker's view + echo MASTER > $STATE_FILE + return $OCF_SUCCESS + ;; + +- Standby/Peer) ++ STANDBY/PEER/CONNECTED|Standby/Peer) + # must take over + ;; + +- Standby/DisconnectedPeer) ++ STANDBY/PEER/DISCONNECTED|Standby/DisconnectedPeer) + # must take over forced + force="by force peer window only" + ;; diff --git a/SOURCES/bz1427611-ocf_log-use-same-log-format-as-pacemaker.patch b/SOURCES/bz1427611-ocf_log-use-same-log-format-as-pacemaker.patch new file mode 100644 index 00000000..6ba9171c --- /dev/null +++ b/SOURCES/bz1427611-ocf_log-use-same-log-format-as-pacemaker.patch @@ -0,0 +1,39 @@ +From 75816393878bf063a8c3404b5c747868024e1097 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Wed, 1 Mar 2017 15:34:26 +0100 +Subject: [PATCH] ocf_log: use same log format as pacemaker + +--- + heartbeat/ocf-directories.in | 2 +- + heartbeat/ocf-shellfuncs.in | 2 +- + 2 files changed, 2 insertions(+), 2 deletions(-) + +diff --git a/heartbeat/ocf-directories.in b/heartbeat/ocf-directories.in +index 8d70776..d8df035 100644 +--- a/heartbeat/ocf-directories.in ++++ b/heartbeat/ocf-directories.in +@@ -13,7 +13,7 @@ exec_prefix=@exec_prefix@ + : ${HA_FIFO:=@localstatedir@/lib/heartbeat/fifo} + : ${HA_BIN:=@libexecdir@/heartbeat} + : ${HA_SBIN_DIR:=@sbindir@} +-: ${HA_DATEFMT:="%Y/%m/%d_%T "} ++: ${HA_DATEFMT:="%b %d %T "} + : ${HA_DEBUGLOG:=/dev/null} + : ${HA_RESOURCEDIR:=$HA_DIR/resource.d} + : ${HA_DOCDIR:=@datadir@/doc/heartbeat} +diff --git a/heartbeat/ocf-shellfuncs.in b/heartbeat/ocf-shellfuncs.in +index 2a3b875..87b2adf 100644 +--- a/heartbeat/ocf-shellfuncs.in ++++ b/heartbeat/ocf-shellfuncs.in +@@ -231,7 +231,7 @@ __ha_log() { + [ -n "$HA_LOGFILE" ] + then + : appending to $HA_LOGFILE +- echo "$HA_LOGTAG: "`hadate`"${*}" >> $HA_LOGFILE ++ echo `hadate`" $HA_LOGTAG: ${*}" >> $HA_LOGFILE + fi + if + [ -z "$HA_LOGFACILITY" -a -z "$HA_LOGFILE" ] && ! [ "$ignore_stderr" = "true" ] +-- +2.9.3 + diff --git a/SOURCES/bz1430304-NodeUtilization.patch b/SOURCES/bz1430304-NodeUtilization.patch new file mode 100644 index 00000000..3f90a69f --- /dev/null +++ b/SOURCES/bz1430304-NodeUtilization.patch @@ -0,0 +1,252 @@ +diff -uNr a/doc/man/Makefile.am b/doc/man/Makefile.am +--- a/doc/man/Makefile.am 2017-03-15 14:11:58.136058131 +0100 ++++ b/doc/man/Makefile.am 2017-03-15 14:31:58.181539045 +0100 +@@ -73,6 +73,7 @@ + ocf_heartbeat_MailTo.7 \ + ocf_heartbeat_ManageRAID.7 \ + ocf_heartbeat_ManageVE.7 \ ++ ocf_heartbeat_NodeUtilization.7 \ + ocf_heartbeat_nova-compute-wait.7 \ + ocf_heartbeat_NovaEvacuate.7 \ + ocf_heartbeat_Pure-FTPd.7 \ +diff -uNr a/heartbeat/Makefile.am b/heartbeat/Makefile.am +--- a/heartbeat/Makefile.am 2017-03-15 14:11:58.136058131 +0100 ++++ b/heartbeat/Makefile.am 2017-03-15 14:32:45.554873187 +0100 +@@ -95,6 +95,7 @@ + MailTo \ + ManageRAID \ + ManageVE \ ++ NodeUtilization \ + mysql \ + mysql-proxy \ + nagios \ +diff -uNr a/heartbeat/NodeUtilization b/heartbeat/NodeUtilization +--- a/heartbeat/NodeUtilization 1970-01-01 01:00:00.000000000 +0100 ++++ b/heartbeat/NodeUtilization 2017-03-15 14:29:18.141788491 +0100 +@@ -0,0 +1,226 @@ ++#!/bin/sh ++# ++# ++# NodeUtilization OCF Resource Agent ++# ++# Copyright (c) 2011 SUSE LINUX, John Shi ++# Copyright (c) 2016 SUSE LINUX, Kristoffer Gronlund ++# All Rights Reserved. ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of version 2 of the GNU General Public License as ++# published by the Free Software Foundation. ++# ++# This program is distributed in the hope that it would be useful, but ++# WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++# ++# Further, this software is distributed without any warranty that it is ++# free of the rightful claim of any third person regarding infringement ++# or the like. Any license provided herein, whether implied or ++# otherwise, applies only to this software file. Patent licenses, if ++# any, provided herein do not apply to combinations of this program with ++# other software, or any other product whatsoever. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write the Free Software Foundation, ++# Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. ++# ++####################################################################### ++# Initialization: ++ ++: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat} ++. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs ++ ++####################################################################### ++ ++NodeUtilization_meta_data() { ++ cat < ++ ++ ++1.0 ++ ++ ++The Node Utilization agent detects system parameters like available CPU, host ++memory and hypervisor memory availability, and adds them into the CIB for each ++node using crm_attribute. Run the agent as a clone resource to have it populate ++these parameters on each node. ++Note: Setting hv_memory only works with Xen at the moment, using the xl or xm ++command line tools. ++ ++Node Utilization ++ ++ ++ ++ ++If set, parameters will be updated if there are differences between the HA ++parameters and the system values when running the monitor action. ++If not set, the parameters will be set once when the resource instance starts. ++ ++Dynamically update parameters in monitor ++ ++ ++ ++ ++Enable setting node CPU utilization limit. ++Set node CPU utilization limit. ++ ++ ++ ++ ++Subtract this value when setting the CPU utilization parameter. ++CPU reservation. ++ ++ ++ ++ ++Enable setting available host memory. ++Set available host memory. ++ ++ ++ ++ ++Subtract this value when setting host memory utilization, in MB. ++Host memory reservation, in MB. ++ ++ ++ ++ ++Enable setting available hypervisor memory. ++Set available hypervisor memory. ++ ++ ++ ++ ++Subtract this value when setting hypervisor memory utilization, in MB. ++Hypervisor memory reservation, in MB. ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++END ++} ++ ++Host_Total_Memory() { ++ local xentool ++ ++ xentool=$(which xl 2> /dev/null || which xm 2> /dev/null) ++ ++ if [ -x $xentool ]; then ++ $xentool info | awk '/total_memory/{printf("%d\n",$3);exit(0)}' ++ else ++ ocf_log warn "Can only set hv_memory for Xen hypervisor" ++ echo "0" ++ fi ++} ++ ++ ++set_utilization() { ++ host_name="$(ocf_local_nodename)" ++ ++ if ocf_is_true "$OCF_RESKEY_utilization_cpu"; then ++ sys_cpu=$(( $(grep -c processor /proc/cpuinfo) - $OCF_RESKEY_utilization_cpu_reservation )) ++ uti_cpu=$(crm_attribute -Q -t nodes -U "$host_name" -z -n cpu 2>/dev/null) ++ ++ if [ "$sys_cpu" != "$uti_cpu" ]; then ++ if ! crm_attribute -t nodes -U "$host_name" -z -n cpu -v $sys_cpu; then ++ ocf_log err "Failed to set the cpu utilization attribute for $host_name using crm_attribute." ++ return 1 ++ fi ++ fi ++ fi ++ ++ if ocf_is_true "$OCF_RESKEY_utilization_host_memory"; then ++ sys_mem=$(( $(awk '/MemTotal/{printf("%d\n",$2/1024);exit(0)}' /proc/meminfo) - $OCF_RESKEY_utilization_host_memory_reservation )) ++ uti_mem=$(crm_attribute -Q -t nodes -U "$host_name" -z -n host_memory 2>/dev/null) ++ ++ if [ "$sys_mem" != "$uti_mem" ]; then ++ if ! crm_attribute -t nodes -U "$host_name" -z -n host_memory -v $sys_mem; then ++ ocf_log err "Failed to set the host_memory utilization attribute for $host_name using crm_attribute." ++ return 1 ++ fi ++ fi ++ fi ++ ++ if ocf_is_true "$OCF_RESKEY_utilization_hv_memory"; then ++ hv_mem=$(( $(Host_Total_Memory) - OCF_RESKEY_utilization_hv_memory_reservation )) ++ uti_mem=$(crm_attribute -Q -t nodes -U "$host_name" -z -n hv_memory 2>/dev/null) ++ ++ [ $hv_mem -lt 0 ] && hv_mem=0 ++ ++ if [ "$hv_mem" != "$uti_mem" ]; then ++ if ! crm_attribute -t nodes -U "$host_name" -z -n hv_memory -v $hv_mem; then ++ ocf_log err "Failed to set the hv_memory utilization attribute for $host_name using crm_attribute." ++ return 1 ++ fi ++ fi ++ fi ++} ++ ++NodeUtilization_usage() { ++ cat < +Date: Fri, 28 Oct 2016 13:37:45 +0200 +Subject: [PATCH 1/2] Medium: IPaddr2: add option to enable sending refresh arp + packets in monitor + +This commit introduces a new parameter: +OCF_RESKEY_arp_count_refresh_default (default: 0) + +This parameter allows to specify whether to send gratuitous ARP packets during +the monitoring of the resource, and how many. +This is to alleviate issues with potentially stuck switch ARP caches, +which can arise in case of split brain situations. Example: +- a two node cluster is interconnected directly as well as through a switch. + Node A is master, node B is slave +- communication between master and slave is severed (split brain) +- node B initializes the virtual IPs and sends gratuitous ARP packets +- the switch updated its ARP table to point to B +- node B dies (without node A noticing) +- node A never notices anything wrong +- the switch fails to notice that the virtual IP belongs to A +--- + heartbeat/IPaddr2 | 52 +++++++++++++++++++++++++++++++++++++--------------- + 1 file changed, 37 insertions(+), 15 deletions(-) + +diff --git a/heartbeat/IPaddr2 b/heartbeat/IPaddr2 +index b224ca5..c49d638 100755 +--- a/heartbeat/IPaddr2 ++++ b/heartbeat/IPaddr2 +@@ -76,6 +76,7 @@ OCF_RESKEY_clusterip_hash_default="sourceip-sourceport" + OCF_RESKEY_unique_clone_address_default=false + OCF_RESKEY_arp_interval_default=200 + OCF_RESKEY_arp_count_default=5 ++OCF_RESKEY_arp_count_refresh_default=0 + OCF_RESKEY_arp_bg_default=true + OCF_RESKEY_arp_mac_default="ffffffffffff" + +@@ -86,6 +87,7 @@ OCF_RESKEY_arp_mac_default="ffffffffffff" + : ${OCF_RESKEY_unique_clone_address=${OCF_RESKEY_unique_clone_address_default}} + : ${OCF_RESKEY_arp_interval=${OCF_RESKEY_arp_interval_default}} + : ${OCF_RESKEY_arp_count=${OCF_RESKEY_arp_count_default}} ++: ${OCF_RESKEY_arp_count_refresh=${OCF_RESKEY_arp_count_refresh_default}} + : ${OCF_RESKEY_arp_bg=${OCF_RESKEY_arp_bg_default}} + : ${OCF_RESKEY_arp_mac=${OCF_RESKEY_arp_mac_default}} + ####################################################################### +@@ -274,12 +276,22 @@ Specify the interval between unsolicited ARP packets in milliseconds. + + + +-Number of unsolicited ARP packets to send. ++Number of unsolicited ARP packets to send at resource initialization. + +-ARP packet count ++ARP packet count sent during initialization + + + ++ ++ ++Number of unsolicited ARP packets to send during resource monitoring. Doing ++so helps mitigate issues of stuck ARP caches resulting from split-brain ++situations. ++ ++ARP packet count sent during monitoring ++ ++ ++ + + + Whether or not to send the ARP packets in the background. +@@ -660,20 +672,25 @@ is_infiniband() { + # Run send_arp to note peers about new mac address + # + run_send_arp() { +- ARGS="-i $OCF_RESKEY_arp_interval -r $OCF_RESKEY_arp_count -p $SENDARPPIDFILE $NIC $OCF_RESKEY_ip auto not_used not_used" + if [ "x$IP_CIP" = "xyes" ] ; then + if [ x = "x$IF_MAC" ] ; then + MY_MAC=auto + else + MY_MAC=`echo ${IF_MAC} | sed -e 's/://g'` + fi +- ARGS="-i $OCF_RESKEY_arp_interval -r $OCF_RESKEY_arp_count -p $SENDARPPIDFILE $NIC $OCF_RESKEY_ip $MY_MAC not_used not_used" +- fi +- ocf_log info "$SENDARP $ARGS" +- if ocf_is_true $OCF_RESKEY_arp_bg; then +- ($SENDARP $ARGS || ocf_log err "Could not send gratuitous arps")& >&2 + else +- $SENDARP $ARGS || ocf_log err "Could not send gratuitous arps" ++ MY_MAC=auto ++ fi ++ [ "x$1" = "xrefresh" ] && ARP_COUNT=$OCF_RESKEY_arp_count_refresh \ ++ || ARP_COUNT=$OCF_RESKEY_arp_count ++ if [ $ARP_COUNT -ne 0 ] ; then ++ ARGS="-i $OCF_RESKEY_arp_interval -r $ARP_COUNT -p $SENDARPPIDFILE $NIC $OCF_RESKEY_ip $MY_MAC not_used not_used" ++ ocf_log info "$SENDARP $ARGS" ++ if ocf_is_true $OCF_RESKEY_arp_bg; then ++ ($SENDARP $ARGS || ocf_log err "Could not send gratuitous arps")& >&2 ++ else ++ $SENDARP $ARGS || ocf_log err "Could not send gratuitous arps" ++ fi + fi + } + +@@ -720,12 +737,16 @@ run_send_ua() { + # Run ipoibarping to note peers about new Infiniband address + # + run_send_ib_arp() { +- ARGS="-q -c $OCF_RESKEY_arp_count -U -I $NIC $OCF_RESKEY_ip" +- ocf_log info "ipoibarping $ARGS" +- if ocf_is_true $OCF_RESKEY_arp_bg; then +- (ipoibarping $ARGS || ocf_log err "Could not send gratuitous arps")& >&2 +- else +- ipoibarping $ARGS || ocf_log err "Could not send gratuitous arps" ++ [ "x$1" = "xrefresh" ] && ARP_COUNT=$OCF_RESKEY_arp_count_refresh \ ++ || ARP_COUNT=$OCF_RESKEY_arp_count ++ if [ $ARP_COUNT -ne 0 ] ; then ++ ARGS="-q -c $ARP_COUNT -U -I $NIC $OCF_RESKEY_ip" ++ ocf_log info "ipoibarping $ARGS" ++ if ocf_is_true $OCF_RESKEY_arp_bg; then ++ (ipoibarping $ARGS || ocf_log err "Could not send gratuitous arps")& >&2 ++ else ++ ipoibarping $ARGS || ocf_log err "Could not send gratuitous arps" ++ fi + fi + } + +@@ -946,6 +967,7 @@ ip_monitor() { + local ip_status=`ip_served` + case $ip_status in + ok) ++ $ARP_SEND_FUN refresh + return $OCF_SUCCESS + ;; + partial|no|partial2) + +From aa1db299f0b684fb814e6c31e96890868fa90e04 Mon Sep 17 00:00:00 2001 +From: Andrea Ieri +Date: Fri, 4 Nov 2016 15:37:15 +0100 +Subject: [PATCH 2/2] Low: IPaddr2: Log refresh arp packets at debug level + instead of info + +--- + heartbeat/IPaddr2 | 22 ++++++++++++++++------ + 1 file changed, 16 insertions(+), 6 deletions(-) + +diff --git a/heartbeat/IPaddr2 b/heartbeat/IPaddr2 +index c49d638..c9acf59 100755 +--- a/heartbeat/IPaddr2 ++++ b/heartbeat/IPaddr2 +@@ -681,11 +681,16 @@ run_send_arp() { + else + MY_MAC=auto + fi +- [ "x$1" = "xrefresh" ] && ARP_COUNT=$OCF_RESKEY_arp_count_refresh \ +- || ARP_COUNT=$OCF_RESKEY_arp_count ++ if [ "x$1" = "xrefresh" ] ; then ++ ARP_COUNT=$OCF_RESKEY_arp_count_refresh ++ LOGLEVEL=debug ++ else ++ ARP_COUNT=$OCF_RESKEY_arp_count ++ LOGLEVEL=info ++ fi + if [ $ARP_COUNT -ne 0 ] ; then + ARGS="-i $OCF_RESKEY_arp_interval -r $ARP_COUNT -p $SENDARPPIDFILE $NIC $OCF_RESKEY_ip $MY_MAC not_used not_used" +- ocf_log info "$SENDARP $ARGS" ++ ocf_log $LOGLEVEL "$SENDARP $ARGS" + if ocf_is_true $OCF_RESKEY_arp_bg; then + ($SENDARP $ARGS || ocf_log err "Could not send gratuitous arps")& >&2 + else +@@ -737,11 +742,16 @@ run_send_ua() { + # Run ipoibarping to note peers about new Infiniband address + # + run_send_ib_arp() { +- [ "x$1" = "xrefresh" ] && ARP_COUNT=$OCF_RESKEY_arp_count_refresh \ +- || ARP_COUNT=$OCF_RESKEY_arp_count ++ if [ "x$1" = "xrefresh" ] ; then ++ ARP_COUNT=$OCF_RESKEY_arp_count_refresh ++ LOGLEVEL=debug ++ else ++ ARP_COUNT=$OCF_RESKEY_arp_count ++ LOGLEVEL=info ++ fi + if [ $ARP_COUNT -ne 0 ] ; then + ARGS="-q -c $ARP_COUNT -U -I $NIC $OCF_RESKEY_ip" +- ocf_log info "ipoibarping $ARGS" ++ ocf_log $LOGLEVEL "ipoibarping $ARGS" + if ocf_is_true $OCF_RESKEY_arp_bg; then + (ipoibarping $ARGS || ocf_log err "Could not send gratuitous arps")& >&2 + else diff --git a/SOURCES/bz1435171-named-add-support-for-rndc-options.patch b/SOURCES/bz1435171-named-add-support-for-rndc-options.patch new file mode 100644 index 00000000..dd6894c3 --- /dev/null +++ b/SOURCES/bz1435171-named-add-support-for-rndc-options.patch @@ -0,0 +1,62 @@ +From b78c5e48568f97415de03f68d0c8b747229c4281 Mon Sep 17 00:00:00 2001 +From: Bas Couwenberg +Date: Wed, 22 Mar 2017 15:46:50 +0100 +Subject: [PATCH] Add support for rndc options in named resource agent. + +--- + heartbeat/named | 14 ++++++++++++-- + 1 file changed, 12 insertions(+), 2 deletions(-) + +diff --git a/heartbeat/named b/heartbeat/named +index 2118e0c..4856cdc 100755 +--- a/heartbeat/named ++++ b/heartbeat/named +@@ -25,6 +25,7 @@ OCF_RESKEY_named_pidfile_default="/var/run/named/named.pid" + OCF_RESKEY_named_rootdir_default="" + OCF_RESKEY_named_options_default="" + OCF_RESKEY_named_keytab_file_default="" ++OCF_RESKEY_rndc_options_default="" + OCF_RESKEY_monitor_request_default="localhost" + OCF_RESKEY_monitor_response_default="127.0.0.1" + OCF_RESKEY_monitor_ip_default="127.0.0.1" +@@ -38,6 +39,7 @@ OCF_RESKEY_monitor_ip_default="127.0.0.1" + : ${OCF_RESKEY_named_rootdir=${OCF_RESKEY_named_rootdir_default}} + : ${OCF_RESKEY_named_options=${OCF_RESKEY_named_options_default}} + : ${OCF_RESKEY_named_keytab_file=${OCF_RESKEY_named_keytab_file_default}} ++: ${OCF_RESKEY_rndc_options=${OCF_RESKEY_rndc_options_default}} + : ${OCF_RESKEY_monitor_request=${OCF_RESKEY_monitor_request_default}} + : ${OCF_RESKEY_monitor_response=${OCF_RESKEY_monitor_response_default}} + : ${OCF_RESKEY_monitor_ip=${OCF_RESKEY_monitor_ip_default}} +@@ -144,6 +146,14 @@ named service keytab file (for GSS-TSIG). + + + ++ ++ ++Options for rndc process if any. ++ ++rndc_options ++ ++ ++ + + + Request that shall be sent to named for monitoring. Usually an A record in DNS. +@@ -326,7 +336,7 @@ named_monitor() { + # + + named_reload() { +- $OCF_RESKEY_rndc reload >/dev/null || return $OCF_ERR_GENERIC ++ $OCF_RESKEY_rndc $OCF_RESKEY_rndc_options reload >/dev/null || return $OCF_ERR_GENERIC + + return $OCF_SUCCESS + } +@@ -396,7 +406,7 @@ named_stop () { + + named_status || return $OCF_SUCCESS + +- $OCF_RESKEY_rndc stop >/dev/null ++ $OCF_RESKEY_rndc $OCF_RESKEY_rndc_options stop >/dev/null + if [ $? -ne 0 ]; then + ocf_log info "rndc stop failed. Killing named." + kill `cat ${OCF_RESKEY_named_pidfile}` diff --git a/SOURCES/bz1435982-rabbitmq-cluster-pacemaker-remote.patch b/SOURCES/bz1435982-rabbitmq-cluster-pacemaker-remote.patch new file mode 100644 index 00000000..ad5f57b3 --- /dev/null +++ b/SOURCES/bz1435982-rabbitmq-cluster-pacemaker-remote.patch @@ -0,0 +1,92 @@ +From 51b03e5e892cd2446c84dc78e17b0ad3bdbe76d2 Mon Sep 17 00:00:00 2001 +From: Michele Baldessari +Date: Tue, 28 Mar 2017 16:21:52 +0200 +Subject: [PATCH] Allow the rabbitmq cluster to work on pacemaker remote nodes + +This was first observed via +https://bugzilla.redhat.com/show_bug.cgi?id=1435982. Due to the way +the resource agent looks for attrd entries, it will filter out any +node which does not have the @crmd=online attribute. This is the +case for pacemaker-remote nodes. To fix this we chose the more +conservative approach and only do an additional query when the first +one returned no entries. Note that this issue exhibits itself +when 'pcs status' reports rabbitmq started on a bunch of nodes: +Clone Set: rabbitmq-clone [rabbitmq] + Started: [ overcloud-rabbit-0 overcloud-rabbit-1 overcloud-rabbit-2 + +But the cluster_status command returns a single node: +[root@overcloud-rabbit-1 ~]# rabbitmqctl cluster_status +Cluster status of node 'rabbit@overcloud-rabbit-1' ... +[{nodes,[{disc,['rabbit@overcloud-rabbit-1']}]}, + {running_nodes,['rabbit@overcloud-rabbit-1']}, + {cluster_name,<<"rabbit@overcloud-rabbit-1.localdomain">>}, + {partitions,[]}, + {alarms,[{'rabbit@overcloud-rabbit-1',[]}]}] + +Also add some text in the help explaining that currently a mixture of +pacemaker-remote and pacemaker nodes is not supported. + +We tested this change on a pacemaker-remote only setup successfully: +Clone Set: rabbitmq-clone [rabbitmq] + Started: [ overcloud-rabbit-0 overcloud-rabbit-1 overcloud-rabbit-2 + +[root@overcloud-rabbit-0 ~]# rabbitmqctl cluster_status +Cluster status of node 'rabbit@overcloud-rabbit-0' ... +[{nodes,[{disc,['rabbit@overcloud-rabbit-0','rabbit@overcloud-rabbit-1', + 'rabbit@overcloud-rabbit-2']}]}, + {running_nodes,['rabbit@overcloud-rabbit-2','rabbit@overcloud-rabbit-1', + 'rabbit@overcloud-rabbit-0']}, + {cluster_name,<<"rabbit@overcloud-rabbit-0.localdomain">>}, + {partitions,[]}, + {alarms,[{'rabbit@overcloud-rabbit-2',[]}, + {'rabbit@overcloud-rabbit-1',[]}, + {'rabbit@overcloud-rabbit-0',[]}]}] + +Signed-Off-By: Michele Baldessari +Signed-Off-By: Damien Ciabrini +--- + heartbeat/rabbitmq-cluster | 24 ++++++++++++++++++++++-- + 1 file changed, 22 insertions(+), 2 deletions(-) + +diff --git a/heartbeat/rabbitmq-cluster b/heartbeat/rabbitmq-cluster +index 74378be..6a17590 100755 +--- a/heartbeat/rabbitmq-cluster ++++ b/heartbeat/rabbitmq-cluster +@@ -56,7 +56,9 @@ meta_data() { + 1.0 + + +-Starts cloned rabbitmq cluster instance ++Starts cloned rabbitmq cluster instance. NB: note that this RA ++cannot be spawned across a mix of pacemaker and pacemaker-remote nodes. ++Only on pacemaker *or* pacemaker-remote nodes exclusively. + + rabbitmq clustered + +@@ -111,7 +113,25 @@ rmq_local_node() + + rmq_join_list() + { +- cibadmin -Q --xpath "//node_state[@crmd='online']//nvpair[@name='$RMQ_CRM_ATTR_COOKIE']" | grep "$RMQ_CRM_ATTR_COOKIE" | sed -n -e "s/^.*value=.\(.*\)\".*$/\1/p" ++ local join_list=$(cibadmin -Q --xpath "//node_state[@crmd='online']//nvpair[@name='$RMQ_CRM_ATTR_COOKIE']" | grep "$RMQ_CRM_ATTR_COOKIE" | sed -n -e "s/^.*value=.\(.*\)\".*$/\1/p") ++ # If join_list is empty we want to check if there are any remote nodes ++ # where rabbitmq is allowed to run (i.e. nodes without the crmd=online selector) ++ if [ -z "$join_list" ]; then ++ # Get all the nodes written in the ATTR_COOKIE no matter if ++ # they are online or not. This will be one line per node like ++ # rabbit@overcloud-rabbit-0 ++ # rabbit@overcloud-rabbit-1 ++ # ... ++ local remote_join_list=$(cibadmin -Q --xpath "//node_state//nvpair[@name='$RMQ_CRM_ATTR_COOKIE']" | grep "$RMQ_CRM_ATTR_COOKIE" | sed -n -e "s/^.*value=.\(.*\)\".*$/\1/p") ++ # The following expression prepares a filter like '-e overcloud-rabbit-0 -e overcloud-rabbit-1 -e ...' ++ local filter=$(crm_mon -r --as-xml | xmllint --format --xpath "//nodes//node[@online='true' and @standby='false']/@name" - | xargs -n1 echo | awk -F= '{print "-e "$2}') ++ # export the intersection which gives us only the nodes that ++ # a) wrote their namein the cib attrd ++ # b) run on nodes where pacemaker_remote is enabled ++ join_list="$(echo $remote_join_list | grep $filter)" ++ fi ++ ++ echo $join_list + } + + rmq_write_nodename() diff --git a/SOURCES/bz1436189-sybase.patch b/SOURCES/bz1436189-sybase.patch new file mode 100644 index 00000000..7d992611 --- /dev/null +++ b/SOURCES/bz1436189-sybase.patch @@ -0,0 +1,920 @@ +diff -uNr a/doc/man/Makefile.am b/doc/man/Makefile.am +--- a/doc/man/Makefile.am 2017-08-30 15:55:08.646159027 +0200 ++++ b/doc/man/Makefile.am 2017-08-30 15:58:31.899477013 +0200 +@@ -140,6 +140,7 @@ + ocf_heartbeat_scsi2reservation.7 \ + ocf_heartbeat_sfex.7 \ + ocf_heartbeat_slapd.7 \ ++ ocf_heartbeat_sybaseASE.7 \ + ocf_heartbeat_symlink.7 \ + ocf_heartbeat_syslog-ng.7 \ + ocf_heartbeat_tomcat.7 \ +diff -uNr a/heartbeat/Makefile.am b/heartbeat/Makefile.am +--- a/heartbeat/Makefile.am 2017-08-30 15:55:08.646159027 +0200 ++++ b/heartbeat/Makefile.am 2017-08-30 15:58:31.899477013 +0200 +@@ -131,6 +131,7 @@ + SysInfo \ + scsi2reservation \ + sfex \ ++ sybaseASE \ + symlink \ + syslog-ng \ + tomcat \ +diff -uNr a/heartbeat/sybaseASE b/heartbeat/sybaseASE +--- a/heartbeat/sybaseASE 1970-01-01 01:00:00.000000000 +0100 ++++ b/heartbeat/sybaseASE 2017-08-30 14:51:24.000000000 +0200 +@@ -0,0 +1,894 @@ ++#!/bin/bash ++ ++# ++# Sybase Availability Agent for Red Hat Cluster v15.0.2 ++# Copyright (C) - 2007 ++# Sybase, Inc. All rights reserved. ++# ++# Sybase Availability Agent for Red Hat Cluster v15.0.2 is licensed ++# under the GNU General Public License Version 2. ++# ++# Author(s): ++# Jian-ping Hui ++# ++# Description: Service script for starting/stopping/monitoring \ ++# Sybase Adaptive Server on: \ ++# Red Hat Enterprise Linux 5 ES \ ++# Red Hat Enterprise Linux 5 AS ++# ++# NOTES: ++# ++# (1) Before running this script, we assume that user has installed ++# Sybase ASE 15.0.2 or higher version on the machine. Please ++# customize your configuration in /etc/cluster/cluster.conf according ++# to your actual environment. We assume the following files exist before ++# you start the service: ++# /$sybase_home/SYBASE.sh ++# /$sybase_home/$sybase_ase/install/RUN_$server_name ++# ++# (2) You can customize the interval value in the meta-data section if needed: ++# ++# ++# ++# ++# ++# ++# ++# ++# ++# ++# ++# ++# ++# The timeout value is not supported by Redhat in RHCS5.0. ++# ++# (3) This script should be put under /usr/share/cluster. Its owner should be "root" with ++# execution permission. ++# ++ ++####################################################################### ++# Initialization: ++ ++. /etc/init.d/functions ++: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat} ++. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs ++ ++####################################################################### ++ ++# Default timeouts when we aren't using the rgmanager wrapper ++if ! ocf_is_true "$OCF_RESKEY_is_rgmanager_wrapper"; then ++ if [ -z "$OCF_RESKEY_CRM_meta_timeout" ]; then ++ case $1 in ++ start|stop) OCF_RESKEY_CRM_meta_timeout=300000 ;; ++ *) OCF_RESKEY_CRM_meta_timeout=100000 ;; ++ esac ++ fi ++ default_timeout=$(((${OCF_RESKEY_CRM_meta_timeout}/1000) - 5)) ++ default_force_stop_timeout=$(((${OCF_RESKEY_CRM_meta_timeout}/1000) - 5)) ++ : ${OCF_RESKEY_shutdown_timeout=${default_force_stop_timeout}} ++ : ${OCF_RESKEY_deep_probe_timeout=${default_timeout}} ++ : ${OCF_RESKEY_start_timeout=${default_timeout}} ++fi ++ ++sybase_user_default="sybase" ++sybase_home_default="detect" ++ase_default="detect" ++ocs_default="detect" ++ ++: ${OCF_RESKEY_sybase_user=${sybase_user_default}} ++: ${OCF_RESKEY_sybase_ase=${ase_default}} ++: ${OCF_RESKEY_sybase_ocs=${ocs_default}} ++: ${OCF_RESKEY_sybase_home=${sybase_home_default}} ++ ++if [ "$OCF_RESKEY_sybase_home" = "detect" ]; then ++ if [ -d "/opt/sap" ]; then ++ OCF_RESKEY_sybase_home="/opt/sap" ++ elif [ -d "/opt/sybase" ]; then ++ OCF_RESKEY_sybase_home="/opt/sybase" ++ else ++ ocf_log err "sybaseASE: Unable to detect 'sybase_home'." ++ return $OCF_ERR_ARGS ++ fi ++fi ++ ++sybase_env="$OCF_RESKEY_sybase_home/SYBASE.env" ++ ++if [ "$OCF_RESKEY_sybase_ase" = "detect" ]; then ++ if [ -f "$sybase_env" ]; then ++ OCF_RESKEY_sybase_ase=$(grep "SYBASE_ASE" "$sybase_env" | cut -d= -f2) ++ else ++ ocf_log err "sybaseASE: Unable to detect 'sybase_ase'." ++ return $OCF_ERR_ARGS ++ fi ++fi ++ ++if [ "$OCF_RESKEY_sybase_ocs" = "detect" ]; then ++ if [ -f "$sybase_env" ]; then ++ OCF_RESKEY_sybase_ocs=$(grep "SYBASE_OCS" "$sybase_env" | cut -d= -f2) ++ else ++ ocf_log err "sybaseASE: Unable to detect 'sybase_ocs'." ++ return $OCF_ERR_ARGS ++ fi ++fi ++ ++ ++interfaces_file_default="${OCF_RESKEY_sybase_home}/interfaces" ++: ${OCF_RESKEY_interfaces_file=${interfaces_file_default}} ++ ++export LD_POINTER_GUARD=0 ++ ++####################################################################################### ++# Declare some variables we will use in the script. Please don't change their values. # ++####################################################################################### ++declare login_string="" ++declare RUNSERVER_SCRIPT=$OCF_RESKEY_sybase_home/$OCF_RESKEY_sybase_ase/install/RUN_$OCF_RESKEY_server_name ++declare CONSOLE_LOG=$OCF_RESKEY_sybase_home/$OCF_RESKEY_sybase_ase/install/$OCF_RESKEY_server_name.log ++ ++################################################################################################## ++# This function will be called by rgmanager to get the meta data of resource agent "sybaseASE". # ++# NEVER CHANGE ANYTHING IN THIS FUNCTION. ++################################################################################################## ++meta_data() ++{ ++ cat < ++ ++ ++ 1.0 ++ ++ ++ Sybase ASE Failover Instance ++ ++ ++ Sybase ASE Failover Instance ++ ++ ++ ++ ++ ++ The home directory of sybase products ++ ++ ++ SYBASE home directory ++ ++ ++ ++ ++ ++ ++ The directory name under sybase_home where ASE products are installed ++ ++ ++ SYBASE_ASE directory name ++ ++ ++ ++ ++ ++ ++ The directory name under sybase_home where OCS products are installed, i.e. ASE-15_0 ++ ++ ++ SYBASE_OCS directory name ++ ++ ++ ++ ++ ++ ++ The ASE server name which is configured for the HA service ++ ++ ++ ASE server name ++ ++ ++ ++ ++ ++ ++ The full path of interfaces file which is used to start/access the ASE server ++ ++ ++ Interfaces file ++ ++ ++ ++ ++ ++ ++ The user who can run ASE server ++ ++ ++ Sybase user ++ ++ ++ ++ ++ ++ ++ The database user required to login to isql. ++ ++ ++ Sybase user ++ ++ ++ ++ ++ ++ ++ The database user's password required to login to isql. ++ ++ ++ Sybase user ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++EOT ++} ++ ++ase_engine0_process() ++{ ++ sed -n -e '/engine 0/s/^.*os pid \([0-9]*\).*online$/\1/p' $CONSOLE_LOG ++} ++ ++ase_engine0_thread() ++{ ++ sed -n -e 's/.*Thread.*LWP \([0-9]*\).*online as engine 0.*/\1/p' $CONSOLE_LOG ++} ++ ++ase_engine_threadpool_pid() ++{ ++ sed -n -e 's/.*Adaptive Server is running as process id \([0-9]*\).*/\1/p' $CONSOLE_LOG ++} ++ ++ase_all_pids() ++{ ++ local PIDS=$(sed -n -e '/engine /s/^.*os pid \([0-9]*\).*online$/\1/p' $CONSOLE_LOG) ++ if [ -z "$PIDS" ]; then ++ #engines are running in a threadpool ++ PIDS=$(ase_engine_threadpool_pid) ++ fi ++ echo $PIDS ++} ++ ++################################################################################################## ++# Function Name: verify_all # ++# Parameter: None # ++# Return value: # ++# 0 SUCCESS # ++# OCF_ERR_ARGS Parameters are invalid # ++# Description: Do some validation on the user-configurable stuff at the beginning of the script. # ++################################################################################################## ++verify_all() ++{ ++ ocf_log debug "sybaseASE: Start 'verify_all'" ++ ++ check_binary "ksh" ++ ++ # Check if the parameter 'sybase_home' is set. ++ if [[ -z "$OCF_RESKEY_sybase_home" ]] ++ then ++ ocf_log err "sybaseASE: The parameter 'sybase_home' is not set." ++ return $OCF_ERR_ARGS ++ fi ++ ++ # Check if the parameter 'sybase_home' is a valid path. ++ if [[ ! -d $OCF_RESKEY_sybase_home ]] ++ then ++ ocf_log err "sybaseASE: The sybase_home '$OCF_RESKEY_sybase_home' doesn't exist." ++ return $OCF_ERR_ARGS ++ fi ++ ++ # Check if the script file SYBASE.sh exists ++ if [[ ! -f $OCF_RESKEY_sybase_home/SYBASE.sh ]] ++ then ++ ocf_log err "sybaseASE: The file $OCF_RESKEY_sybase_home/SYBASE.sh is required to run this script. Failed to run the script." ++ return $OCF_ERR_ARGS ++ fi ++ ++ # Check if the parameter 'sybase_ase' is set. ++ if [[ -z "$OCF_RESKEY_sybase_ase" ]] ++ then ++ ocf_log err "sybaseASE: The parameter 'sybase_ase' is not set." ++ return $OCF_ERR_ARGS ++ fi ++ ++ # Check if the directory /$OCF_RESKEY_sybase_home/$OCF_RESKEY_sybase_ase exists. ++ if [[ ! -d $OCF_RESKEY_sybase_home/$OCF_RESKEY_sybase_ase ]] ++ then ++ ocf_log err "sybaseASE: The directory '$OCF_RESKEY_sybase_home/$OCF_RESKEY_sybase_ase' doesn't exist." ++ return $OCF_ERR_ARGS ++ fi ++ ++ # Check if the parameter 'sybase_ocs' is set. ++ if [[ -z "$OCF_RESKEY_sybase_ocs" ]] ++ then ++ ocf_log err "sybaseASE: The parameter 'sybase_ocs' is not set." ++ return $OCF_ERR_ARGS ++ fi ++ ++ # Check if the directory /$OCF_RESKEY_sybase_home/$OCF_RESKEY_sybase_ocs exists. ++ if [[ ! -d $OCF_RESKEY_sybase_home/$OCF_RESKEY_sybase_ocs ]] ++ then ++ ocf_log err "sybaseASE: The directory '$OCF_RESKEY_sybase_home/$OCF_RESKEY_sybase_ocs' doesn't exist." ++ return $OCF_ERR_ARGS ++ fi ++ ++ # Check if the parameter 'server_name' is set. ++ if [[ -z "$OCF_RESKEY_server_name" ]] ++ then ++ ocf_log err "sybaseASE: The parameter 'server_name' is not set." ++ return $OCF_ERR_ARGS ++ fi ++ ++ # Check if the Run_server file exists. ++ if [[ ! -f $RUNSERVER_SCRIPT ]] ++ then ++ ocf_log err "sybaseASE: The file $RUNSERVER_SCRIPT doesn't exist. The sybase directory may be incorrect." ++ return $OCF_ERR_ARGS ++ fi ++ ++ # Check if the user 'sybase_user' exist ++ id -u $OCF_RESKEY_sybase_user ++ if [[ $? != 0 ]] ++ then ++ ocf_log err "sybaseASE: The user '$OCF_RESKEY_sybase_user' doesn't exist in the system." ++ return $OCF_ERR_ARGS ++ fi ++ ++ # Check if the parameter 'interfaces_file' is set ++ if [[ -z "$OCF_RESKEY_interfaces_file" ]] ++ then ++ ocf_log err "sybaseASE: The parameter 'interfaces_file' is not set." ++ return $OCF_ERR_ARGS ++ fi ++ ++ # Check if the file 'interfaces_file' exists ++ if [[ ! -f $OCF_RESKEY_interfaces_file ]] ++ then ++ ocf_log err "sybaseASE: The interfaces file '$OCF_RESKEY_interfaces_file' doesn't exist." ++ return $OCF_ERR_ARGS ++ fi ++ ++ # Check if the parameter 'db_user' is set ++ if [[ -z "$OCF_RESKEY_db_user" ]] ++ then ++ ocf_log err "sybaseASE: The parameter 'db_user' is not set." ++ return $OCF_ERR_ARGS ++ fi ++ ++ # Check if the parameter 'shutdown_timeout' is a valid value ++ if [[ $OCF_RESKEY_shutdown_timeout -eq 0 ]] ++ then ++ ocf_log err "sybaseASE: The parameter 'shutdown_timeout' is not set. Its value cannot be zero." ++ return $OCF_ERR_ARGS ++ fi ++ ++ # Check if the parameter 'start_timeout' is a valid value ++ if [[ $OCF_RESKEY_start_timeout -eq 0 ]] ++ then ++ ocf_log err "sybaseASE: The parameter 'start_timeout' is not set. Its value cannot be zero." ++ return $OCF_ERR_ARGS ++ fi ++ ++ # Check if the parameter 'deep_probe_timeout' is a valid value ++ if [[ $OCF_RESKEY_deep_probe_timeout -eq 0 ]] ++ then ++ ocf_log err "sybaseASE: The parameter 'deep_probe_timeout' is not set. Its value cannot be zero." ++ return $OCF_ERR_ARGS ++ fi ++ ++ ocf_log debug "sybaseASE: End 'verify_all' successfully." ++ ++ return $OCF_SUCCESS ++} ++ ++set_login_string() ++{ ++ tmpstring="" ++ login_sting="" ++ ++ login_string="-U$OCF_RESKEY_db_user -P$OCF_RESKEY_db_passwd" ++ return 0 ++} ++ ++############################################################################################## ++# Function name: ase_start # ++# Parameter: None # ++# Return value: # ++# 0 SUCCESS # ++# 1 FAIL # ++# Description: This function is used to start the ASE server in primary or secondary server. # ++############################################################################################## ++ase_start() ++{ ++ ocf_log debug "sybaseASE: Start 'ase_start'" ++ ++ # Check if the server is running. If yes, return SUCCESS directly. Otherwise, continue the start work. ++ ase_is_running ++ if [[ $? = 0 ]] ++ then ++ # The server is running. ++ ocf_log info "sybaseASE: Server is running. Start is success." ++ return $OCF_SUCCESS ++ fi ++ ++ # The server is not running. We need to start it. ++ # If the log file existed, delete it. ++ if [[ -f $CONSOLE_LOG ]] ++ then ++ rm -f $CONSOLE_LOG ++ fi ++ ++ ocf_log debug "sybaseASE: Starting '$OCF_RESKEY_server_name'..." ++ ++ # Run runserver script to start the server. Since this script will be run by root and ASE server ++ # needs to be run by another user, we need to change the user to sybase_user first. Then, run ++ # the script to start the server. ++ su $OCF_RESKEY_sybase_user -c ksh << EOF ++ # set required SYBASE environment by running SYBASE.sh. ++ . $OCF_RESKEY_sybase_home/SYBASE.sh ++ # Run the RUNSERVER_SCRIPT to start the server. ++ . $RUNSERVER_SCRIPT > $CONSOLE_LOG 2>&1 & ++EOF ++ ++ # Monitor every 1 seconds if the server has ++ # recovered, until RECOVERY_TIMEOUT. ++ t=0 ++ while [[ $t -le $OCF_RESKEY_start_timeout ]] ++ do ++ grep -s "Recovery complete." $CONSOLE_LOG > /dev/null 2>&1 ++ if [[ $? != 0 ]] ++ then ++ # The server has not completed the recovery. We need to continue to monitor the recovery ++ # process. ++ t=`expr $t + 1` ++ else ++ # The server has completed the recovery. ++ ocf_log info "sybaseASE: ASE server '$OCF_RESKEY_server_name' started successfully." ++ break ++ fi ++ sleep 1 ++ done ++ ++ # If $t is larger than start_timeout, it means the ASE server cannot start in given time. Otherwise, it ++ # means the ASE server has started successfully. ++ if [[ $t -gt $OCF_RESKEY_start_timeout ]] ++ then ++ # The server cannot start in specified time. We think the start is failed. ++ ocf_log err "sybaseASE: Failed to start ASE server '$OCF_RESKEY_server_name'. Please check the server error log $CONSOLE_LOG for possible problems." ++ return $OCF_ERR_GENERIC ++ fi ++ ++ ase_is_running ++ if [ $? -ne 0 ]; then ++ ocf_log err "sybaseASE: ase_start could not detect database initialized properly." ++ ++ return $OCF_ERR_GENERIC ++ fi ++ ocf_log debug "sybaseASE: End 'ase_start' successfully." ++ return $OCF_SUCCESS ++} ++ ++############################################################################################# ++# Function name: ase_stop # ++# Parameter: None # ++# Return value: # ++# 0 SUCCESS # ++# 1 FAIL # ++# Description: This function is used to stop the ASE server in primary or secondary server. # ++############################################################################################# ++ase_stop() ++{ ++ ocf_log debug "sybaseASE: Start 'ase_stop'" ++ ++ # Check if the ASE server is still running. ++ ase_is_running ++ if [[ $? != 0 ]] ++ then ++ # The ASE server is not running. We need not to shutdown it. ++ ocf_log info "sybaseASE: The dataserver $OCF_RESKEY_server_name is not running." ++ return $OCF_SUCCESS ++ fi ++ ++ set_login_string ++ ++ # Just in case things are hung, start a process that will wait for the ++ # timeout period, then kill any remaining porcesses. We'll need to ++ # monitor this process (set -m), so we can terminate it later if it is ++ # not needed. ++ set -m ++ kill_ase $OCF_RESKEY_shutdown_timeout & ++ KILL_PID=$! # If successful, we will also terminate watchdog process ++ ++ # Run "shutdown with nowait" from isql command line to shutdown the server ++ su $OCF_RESKEY_sybase_user -c ksh << EOF ++ # set required SYBASE environment by running SYBASE.sh. ++ . $OCF_RESKEY_sybase_home/SYBASE.sh ++ # Run "shutdown with nowait" to shutdown the server immediately. ++ (echo "use master" ; echo go ; echo "shutdown with nowait"; echo go) | \ ++ \$SYBASE/\$SYBASE_OCS/bin/isql $login_string -S$OCF_RESKEY_server_name -I$OCF_RESKEY_interfaces_file & ++EOF ++ ++ sleep 5 ++ ++ # Check if the server has been shut down successfully ++ t=0 ++ while [[ $t -lt $OCF_RESKEY_shutdown_timeout ]] ++ do ++ # Search "ueshutdown: exiting" in the server log. If found, it means the server has been shut down. ++ # Otherwise, we need to wait. ++ tail $CONSOLE_LOG | grep "ueshutdown: exiting" > /dev/null 2>&1 ++ if [[ $? != 0 ]] ++ then ++ # The shutdown is still in processing. Wait... ++ sleep 2 ++ t=`expr $t+2` ++ else ++ # The shutdown is success. ++ ocf_log info "sybaseASE: ASE server '$OCF_RESKEY_server_name' shutdown with isql successfully." ++ break ++ fi ++ done ++ ++ # If $t is larger than shutdown_timeout, it means the ASE server cannot be shut down in given time. We need ++ # to wait for the background kill process to kill the OS processes directly. ++ if [[ $t -ge $OCF_RESKEY_shutdown_timeout ]] ++ then ++ ocf_log err "sybaseASE: Shutdown of '$OCF_RESKEY_server_name' from isql failed. Server is either down or unreachable." ++ fi ++ ++ # Here, the ASE server has been shut down by isql command or killed by background process. We need to do ++ # further check to make sure all processes have gone away before saying shutdown is complete. This stops the ++ # other node from starting up the package before it has been stopped and the file system has been unmounted. ++ ++ # Get all processes ids from log file ++ declare -a ENGINE_ALL=$(ase_all_pids) ++ ++ typeset -i num_procs=${#ENGINE_ALL[@]} ++ ++ # We cannot find any process id from log file. It may be because the log file is corrupted or be deleted. ++ # In this case, we determine the shutdown is failed. ++ if [[ "${ENGINE_ALL[@]}" = "" ]] ++ then ++ ocf_log err "sybaseASE: Unable to find the process id from $CONSOLE_LOG." ++ ocf_log err "sybaseASE: Stop ASE server failed." ++ return $OCF_ERR_GENERIC ++ fi ++ ++ # Monitor the system processes to make sure all ASE related processes have gone away. ++ while true ++ do ++ # To every engine process, search it in system processes list. If it is not in the ++ # list, it means this process has gone away. Otherwise, we need to wait for it is ++ # killed by background process. ++ for i in ${ENGINE_ALL[@]} ++ do ++ ps -fu $OCF_RESKEY_sybase_user | awk '{print $2}' | grep $i | grep -v grep ++ if [[ $? != 0 ]] ++ then ++ ocf_log debug "sybaseASE: $i process has stopped." ++ c=0 ++ while (( c < $num_procs )) ++ do ++ if [[ ${ENGINE_ALL[$c]} = $i ]] ++ then ++ unset ENGINE_ALL[$c] ++ c=$num_procs ++ fi ++ (( c = c + 1 )) ++ done ++ fi ++ done ++ ++ # To here, all processes should have gone away. ++ if [[ ${ENGINE_ALL[@]} = "" ]] ++ then ++ # ++ # Looks like shutdown was successful, so kill the ++ # script to kill any hung processes, which we started earlier. ++ # Check to see if the script is still running. If jobs ++ # returns that the script is done, then we don't need to kill ++ # it. ++ # ++ job=$(jobs | grep -v Done) ++ if [[ ${job} != "" ]] ++ then ++ ocf_log debug "sybaseASE: Killing the kill_ase script." ++ ++ kill -15 $KILL_PID > /dev/null 2>&1 ++ fi ++ break ++ fi ++ sleep 5 ++ done ++ ++ ocf_log debug "sybaseASE: End 'ase_stop'." ++ ++ return $OCF_SUCCESS ++} ++ ++#################################################################################### ++# Function name: ase_is_running # ++# Parameter: None # ++# Return value: # ++# 0 ASE server is running # ++# 1 ASE server is not running or there are errors # ++# Description: This function is used to check if the ASE server is still running . # ++#################################################################################### ++ase_is_running() ++{ ++ local PID ++ local THREAD ++ # If the error log doesn't exist, we can say there is no ASE is running. ++ if [[ ! -f $CONSOLE_LOG ]] ++ then ++ ocf_log debug "could not find console log $CONSOLE_LOG" ++ return $OCF_NOT_RUNNING ++ fi ++ ++ # The error log file exists. Check if the engine 0 is alive. ++ PID=$(ase_engine0_process) ++ if [ -n "$PID" ]; then ++ kill -s 0 $PID > /dev/null 2>&1 ++ if [ $? -eq 0 ]; then ++ # The engine 0 is running. ++ ocf_log debug "Found engine 0 pid $PID to be running" ++ return $OCF_SUCCESS ++ fi ++ # The engine 0 is not running. ++ return $OCF_NOT_RUNNING ++ fi ++ ++ PID=$(ase_engine_threadpool_pid) ++ THREAD=$(ase_engine0_thread) ++ if [ -n "$PID" ] && [ -n "$THREAD" ]; then ++ ps -AL | grep -q "${PID}[[:space:]]*${THREAD} " ++ if [ $? -eq 0 ]; then ++ # engine 0 thread is running ++ ocf_log debug "Found engine 0 thread $THREAD in pid $PID to be running" ++ return $OCF_SUCCESS ++ fi ++ # The engine 0 is not running. ++ return $OCF_NOT_RUNNING ++ fi ++ return $OCF_ERR_GENERIC ++} ++ ++#################################################################################### ++# Function name: kill_ase # ++# Parameter: # ++# DELAY The seconds to wait before killing the ASE processes. 0 means # ++# kill the ASE processes immediately. # ++# Return value: None # ++# 1 ASE server is not running or there are errors # ++# Description: This function is used to check if the ASE server is still running . # ++#################################################################################### ++kill_ase() ++{ ++ ocf_log debug "sybaseASE: Start 'kill_ase'." ++ ++ DELAY=$1 ++ ++ # Wait for sometime before sending a kill signal. ++ t=0 ++ while [[ $t -lt $DELAY ]] ++ do ++ sleep 1 ++ t=`expr $t+1` ++ done ++ ++ # Get the process ids from log file ++ declare -a ENGINE_ALL=$(ase_all_pids) ++ ++ # If there is no process id found in the log file, we need not to continue. ++ if [[ "${ENGINE_ALL[@]}" = "" ]] ++ then ++ ocf_log err "sybaseASE: Unable to find the process id from $CONSOLE_LOG." ++ return $OCF_ERR_GENERIC ++ fi ++ ++ # Kill the datasever process(es) ++ for pid in ${ENGINE_ALL[@]} ++ do ++ kill -9 $pid > /dev/null 2>&1 ++ if [[ $? != 0 ]] ++ then ++ ocf_log info "sybaseASE: kill_ase function did NOT find process $pid running." ++ else ++ ocf_log info "sybaseASE: kill_ase function did find process $pid running. Sent SIGTERM." ++ fi ++ done ++ ++ ocf_log debug "sybaseASE: End 'kill_ase'." ++ return $OCF_SUCCESS ++} ++ ++##################################################################################### ++# Function name: ase_status # ++# Parameter: # ++# 0 Level 0 probe. In this level, we just check if engine 0 is alive # ++# 10 Level 10 probe. In this level, we need to probe if the ASE server # ++# still has response. # ++# Return value: # ++# 0 The server is still alive # ++# 1 The server is down # ++# Description: This function is used to check if the ASE server is still running. # ++##################################################################################### ++ase_status() ++{ ++ local rc ++ ocf_log debug "sybaseASE: Start 'ase_status'." ++ ++ # Step 1: Check if the engine 0 is alive ++ ase_is_running ++ rc=$? ++ if [ $rc -ne 0 ]; then ++ # ASE is down. Return fail to Pacemaker to trigger the failover process. ++ ocf_log err "sybaseASE: ASE server is down." ++ return $rc ++ fi ++ ++ # ASE process is still alive. ++ # Step2: If this is level 10 probe, We need to check if the ASE server still has response. ++ if [[ $1 -gt 0 ]] ++ then ++ ocf_log debug "sybaseASE: Need to run deep probe." ++ # Run deep probe ++ deep_probe ++ if [[ $? = 1 ]] ++ then ++ # Deep probe failed. This means the server has been down. ++ ocf_log err "sybaseASE: Deep probe found the ASE server is down." ++ return $OCF_ERR_GENERIC ++ fi ++ fi ++ ++ ocf_log debug "sybaseASE: End 'ase_status'." ++ ++ return $OCF_SUCCESS ++} ++ ++#################################################################################### ++# Function name: deep_probe # ++# Parameter: None # ++# Return value: # ++# 0 ASE server is alive # ++# 1 ASE server is down # ++# Description: This function is used to run deep probe to make sure the ASE server # ++# still has response. # ++#################################################################################### ++deep_probe() ++{ ++ declare -i rv ++ ++ ocf_log debug "sybaseASE: Start 'deep_probe'." ++ ++ # Declare two temporary files which will be used in this probe. ++ tmpfile1="$(mktemp /tmp/sybaseASE.1.XXXXXX)" ++ tmpfile2="$(mktemp /tmp/sybaseASE.2.XXXXXX)" ++ ++ set_login_string ++ ++ rm -f $tmpfile1 ++ rm -f $tmpfile2 ++ ++ # The login file is correct. We have gotten the login account and password from it. ++ # Run isql command in background. ++ su $OCF_RESKEY_sybase_user -c ksh << EOF ++ # set required SYBASE environment by running SYBASE.sh. ++ . $OCF_RESKEY_sybase_home/SYBASE.sh ++ # Run a very simple SQL statement to make sure the server is still ok. The output will be put to ++ # tmpfile1. ++ (echo "select 1"; echo "go") | ++ \$SYBASE/\$SYBASE_OCS/bin/isql $login_string -S$OCF_RESKEY_server_name -I$OCF_RESKEY_interfaces_file -t $OCF_RESKEY_deep_probe_timeout -e -o$tmpfile1 & ++ # Record the isql command process id to temporary file. If the isql is hung, we need this process id ++ # to kill the hung process. ++ echo \$! > $tmpfile2 ++EOF ++ ++ declare -i t=0 ++ ++ # Monitor the output file tmpfile1. ++ while [[ $t -lt $OCF_RESKEY_deep_probe_timeout ]] ++ do ++ # If the SQL statement is executed successfully, we will get the following output: ++ # 1> select 1 ++ # ++ # ----------- ++ # 1 ++ # ++ # (1 row affected) ++ # So, we determine if the execution is success by searching the keyword "(1 row affected)". ++ grep "(1 row affected)" $tmpfile1 ++ if [[ $? = 0 ]] ++ then ++ ocf_log debug "sybaseASE: Deep probe sucess." ++ break ++ else ++ sleep 1 ++ t=`expr $t+1` ++ fi ++ done ++ ++ # If $t is larger than deep_probe_timeout, it means the isql command line cannot finish in given time. ++ # This means the deep probe failed. We need to kill the isql process manually. ++ if [[ $t -ge $OCF_RESKEY_deep_probe_timeout ]] ++ then ++ ocf_log err "sybaseASE: Deep probe fail. The dataserver has no response." ++ ++ # Read the process id of isql process from tmpfile2 ++ pid=`cat $tmpfile2 | awk '{print $1}'` ++ ++ rm -f $tmpfile1 ++ rm -f $tmpfile2 ++ ++ # Kill the isql process directly. ++ kill -9 $pid ++ return 1 ++ fi ++ ++ rm -f $tmpfile1 ++ rm -f $tmpfile2 ++ ++ ocf_log debug "sybaseASE: End 'deep_probe'." ++ ++ return 0 ++} ++ ++############################# ++# Do some real work here... # ++############################# ++case $1 in ++ start) ++ verify_all || exit $OCF_ERR_GENERIC ++ ase_start ++ exit $? ++ ;; ++ stop) ++ verify_all || exit $OCF_ERR_GENERIC ++ ase_stop ++ exit $? ++ ;; ++ status | monitor) ++ verify_all || exit $OCF_ERR_GENERIC ++ ase_status $OCF_CHECK_LEVEL ++ exit $? ++ ;; ++ meta-data) ++ meta_data ++ exit $OCF_SUCCESS ++ ;; ++ validate-all) ++ verify_all ++ exit $? ++ ;; ++ *) ++ echo "Usage: $SCRIPT {start|stop|monitor|status|validate-all|meta-data}" ++ exit $OCF_ERR_UNIMPLEMENTED ++ ;; ++esac ++exit 0 ++ diff --git a/SOURCES/bz1445628-findif-improve-IPv6-NIC-detection.patch b/SOURCES/bz1445628-findif-improve-IPv6-NIC-detection.patch new file mode 100644 index 00000000..caeb02b7 --- /dev/null +++ b/SOURCES/bz1445628-findif-improve-IPv6-NIC-detection.patch @@ -0,0 +1,44 @@ +From 7629514ec332fbcb72c420683b1a1b5437ff60a6 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Fri, 15 Sep 2017 11:25:40 +0200 +Subject: [PATCH] findif: improve IPv6 NIC detection + +--- + heartbeat/findif.sh | 17 ++++++----------- + 1 file changed, 6 insertions(+), 11 deletions(-) + +diff --git a/heartbeat/findif.sh b/heartbeat/findif.sh +index a643da119..019098360 100644 +--- a/heartbeat/findif.sh ++++ b/heartbeat/findif.sh +@@ -233,6 +233,8 @@ findif() + fi + case $1 in + */*) : OK ;; ++ # "ip route" doesnt show netmask for IPv6 /128 ++ *:*:*) : OK ;; + *) + ocf_exit_reason "Unable to find cidr_netmask." + return $OCF_ERR_GENERIC ;; +@@ -240,17 +242,10 @@ findif() + fi + [ -z "$nic" ] && nic=$3 + [ -z "$netmask" ] && netmask=${1#*/} +- if [ $family = "inet" ] ; then +- if [ -z "$brdcast" ] ; then +- if [ -n "$7" ] ; then +- set -- `ip -o -f $family addr show | grep $7` +- [ "$5" = brd ] && brdcast=$6 +- fi +- fi +- else +- if [ -z "$OCF_RESKEY_nic" -a "$netmask" != "${1#*/}" ] ; then +- ocf_exit_reason "Unable to find nic, or netmask mismatch." +- return $OCF_ERR_GENERIC ++ if [ -z "$brdcast" ] ; then ++ if [ -n "$7" ] ; then ++ set -- `ip -o -f $family addr show | grep $7` ++ [ "$5" = brd ] && brdcast=$6 + fi + fi + echo "$nic netmask $netmask broadcast $brdcast" diff --git a/SOURCES/bz1445861-IPaddr2-IPv6-add-preferred_lft-parameter.patch b/SOURCES/bz1445861-IPaddr2-IPv6-add-preferred_lft-parameter.patch new file mode 100644 index 00000000..d8279d9d --- /dev/null +++ b/SOURCES/bz1445861-IPaddr2-IPv6-add-preferred_lft-parameter.patch @@ -0,0 +1,81 @@ +From 2918ab999cbcbe6bc04061dd070e5b0dd8465346 Mon Sep 17 00:00:00 2001 +From: Damien Ciabrini +Date: Wed, 26 Apr 2017 17:51:52 +0200 +Subject: [PATCH] IPaddr2: add option for specifying IPv6's preferred_lft + +This change allows setting the preferred_lft option when creating an +IPv6 address. This can be used to ensure that the created IP address +will not be used as a source address for routing. +--- + heartbeat/IPaddr2 | 23 +++++++++++++++++++++++ + 1 file changed, 23 insertions(+) + +diff --git a/heartbeat/IPaddr2 b/heartbeat/IPaddr2 +index 27b7208..2d2ba2c 100755 +--- a/heartbeat/IPaddr2 ++++ b/heartbeat/IPaddr2 +@@ -56,6 +56,7 @@ + # OCF_RESKEY_arp_count + # OCF_RESKEY_arp_bg + # OCF_RESKEY_arp_mac ++# OCF_RESKEY_preferred_lft + # + # OCF_RESKEY_CRM_meta_clone + # OCF_RESKEY_CRM_meta_clone_max +@@ -80,6 +81,7 @@ OCF_RESKEY_arp_count_refresh_default=0 + OCF_RESKEY_arp_bg_default=true + OCF_RESKEY_arp_mac_default="ffffffffffff" + OCF_RESKEY_run_arping_default=false ++OCF_RESKEY_preferred_lft_default="forever" + + : ${OCF_RESKEY_lvs_support=${OCF_RESKEY_lvs_support_default}} + : ${OCF_RESKEY_lvs_ipv6_addrlabel=${OCF_RESKEY_lvs_ipv6_addrlabel_default}} +@@ -92,6 +94,7 @@ OCF_RESKEY_run_arping_default=false + : ${OCF_RESKEY_arp_bg=${OCF_RESKEY_arp_bg_default}} + : ${OCF_RESKEY_arp_mac=${OCF_RESKEY_arp_mac_default}} + : ${OCF_RESKEY_run_arping=${OCF_RESKEY_run_arping_default}} ++: ${OCF_RESKEY_preferred_lft=${OCF_RESKEY_preferred_lft_default}} + ####################################################################### + + SENDARP=$HA_BIN/send_arp +@@ -350,6 +353,17 @@ Whether or not to run arping for IPv4 collision detection check. + + + ++ ++ ++For IPv6, set the preferred lifetime of the IP address. ++This can be used to ensure that the created IP address will not ++be used as a source address for routing. ++Expects a value as specified in section 5.5.4 of RFC 4862. ++ ++IPv6 preferred lifetime ++ ++ ++ + + + +@@ -590,6 +604,10 @@ add_interface () { + cmd="$cmd label $label" + msg="${msg} (with label $label)" + fi ++ if [ "$FAMILY" = "inet6" ] ;then ++ cmd="$cmd preferred_lft $OCF_RESKEY_preferred_lft" ++ msg="${msg} (with preferred_lft $OCF_RESKEY_preferred_lft)" ++ fi + + ocf_log info "$msg" + ocf_run $cmd || return $OCF_ERR_GENERIC +@@ -1076,6 +1094,11 @@ ip_validate() { + exit $OCF_ERR_CONFIGURED + fi + ++ if [ -z "$OCF_RESKEY_preferred_lft" ]; then ++ ocf_exit_reason "Empty value is invalid for OCF_RESKEY_preferred_lft" ++ exit $OCF_ERR_CONFIGURED ++ fi ++ + if [ -n "$IP_CIP" ]; then + + local valid=1 diff --git a/SOURCES/bz1449681-1-saphana-saphanatopology-update-0.152.21.patch b/SOURCES/bz1449681-1-saphana-saphanatopology-update-0.152.21.patch new file mode 100644 index 00000000..596d3a61 --- /dev/null +++ b/SOURCES/bz1449681-1-saphana-saphanatopology-update-0.152.21.patch @@ -0,0 +1,216 @@ +diff -uNr a/heartbeat/SAPHana b/heartbeat/SAPHana +--- a/heartbeat/SAPHana 2017-05-11 12:12:17.207213156 +0200 ++++ b/heartbeat/SAPHana 2017-05-11 12:19:44.846798058 +0200 +@@ -16,7 +16,7 @@ + # Support: linux@sap.com + # License: GNU General Public License (GPL) + # Copyright: (c) 2013,2014 SUSE Linux Products GmbH +-# (c) 2015-2016 SUSE Linux GmbH ++# (c) 2015-2017 SUSE Linux GmbH + # + # An example usage: + # See usage() function below for more details... +@@ -35,7 +35,7 @@ + ####################################################################### + # + # Initialization: +-SAPHanaVersion="0.152.17" ++SAPHanaVersion="0.152.21" + timeB=$(date '+%s') + + : ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat} +@@ -133,8 +133,8 @@ + function backup_global_and_nameserver() { + super_ocf_log info "FLOW $FUNCNAME ($*)" + local rc=0 +- cp /hana/shared/$SID/global/hdb/custom/config/global.ini /hana/shared/$SID/global/hdb/custom/config/global.ini.$(date +"%s") +- cp /hana/shared/$SID/global/hdb/custom/config/nameserver.ini /hana/shared/$SID/global/hdb/custom/config/nameserver.ini.$(date +"%s") ++ cp /hana/shared/${SID}/global/hdb/custom/config/global.ini /hana/shared/${SID}/global/hdb/custom/config/global.ini.$(date +"%s") ++ cp /hana/shared/${SID}/global/hdb/custom/config/nameserver.ini /hana/shared/${SID}/global/hdb/custom/config/nameserver.ini.$(date +"%s") + super_ocf_log info "FLOW $FUNCNAME rc=$rc" + return $rc + } +@@ -665,7 +665,7 @@ + # DONE: PRIO4: SAPVIRHOST might be different to NODENAME + # DONE: PRIO1: ASK: Is the output format of ListInstances fix? Could we take that as an API? Answer: Yes + # try to catch: Inst Info : LNX - 42 - lv9041 - 740, patch 36, changelist 1444691 +- # We rely on the following format: SID is word#4, SYSNR is work#6, vHost is word#8 ++ # We rely on the following format: SID is word#4, SYSNR is word#6, vHost is word#8 + if [ -e /usr/sap/hostctrl/exe/saphostctrl ]; then + vName=$(/usr/sap/hostctrl/exe/saphostctrl -function ListInstances \ + | awk '$4 == SID && $6 == SYSNR { print $8 }' SID=$SID SYSNR=$InstanceNr 2>/dev/null ) +@@ -713,27 +713,29 @@ + "[234]*:P:[^:]*:master .* 150" + "[015-9]*:P:[^:]*:master .* 90" + "[0-9]*:P:[^:]*:slave .* 60" +- "[0-9]*:P:[^:]*:\? .* 0" +- "[0-9]*:P:[^:]*:- .* 0" ++ "[234]*:P:[^:]*:[?:-] .* 0" ++ "[015-9]*:P:[^:]*:[?:-] .* -1" + "[234]*:S:[^:]*:master SOK 100" ++ "[234]*:S:[^:]*:master PRIM 100" + "[015-9]*:S:[^:]*:master SOK 80" + "[0-9]*:S:[^:]*:master SFAIL -INFINITY" + "[0-9]*:S:[^:]*:slave SOK 10" + "[0-9]*:S:[^:]*:slave SFAIL -INFINITY" +- "[0-9]*:S:[^:]*:\? .* 0" +- "[0-9]*:S:[^:]*:- .* 0" +- ".* .* -1" ++ "[234]*:S:[^:]*:[?:-] .* 0" ++ "[015-9]*:S:[^:]*:[?:-] .* -1" ++ ".* .* -1" + ) + SCORING_TABLE_PREFERRED_LOCAL_RESTART=( +- "[0-9]*:P:[^:]*:master .* 150" +- "[0-9]*:P:[^:]*:.* .* 140" ++ "[0-9]*:P:[^:]*:master .* 150" ++ "[0-9]*:P:[^:]*:.* .* 140" + "[0-9]*:S:[^:]*:master SOK 100" ++ "[0-9]*:S:[^:]*:master PRIM 100" + "[0-9]*:S:[^:]*:master SFAIL -INFINITY" + "[0-9]*:S:[^:]*:slave SOK 10" + "[0-9]*:S:[^:]*:slave SFAIL -INFINITY" +- "[0-9]*:S:[^:]*:\? .* 0" +- "[0-9]*:S:[^:]*:- .* 0" +- ".* .* -1" ++ "[015-9]*:S:[^:]*:[?:-] .* -1" ++ "[234]*:S:[^:]*:[?:-] .* -1" ++ ".* .* -1" + ) + SCORING_TABLE_PREFERRED_NEVER=( + "[234]*:P:[^:]*:master .* 150" +@@ -1030,7 +1032,7 @@ + # TODO: Limit the runtime of systemReplicationStatus.py + # SAP_CALL + # FULL_SR_STATUS=$(su - $sidadm -c "python $DIR_EXECUTABLE/python_support/systemReplicationStatus.py $siteParam" 2>/dev/null); srRc=$? +- FULL_SR_STATUS=$(HANA_CALL --timeout 60 --cmd "systemReplicationStatus.py" 2>/dev/null); srRc=$? ++ FULL_SR_STATUS=$(HANA_CALL --timeout 60 --cmd "systemReplicationStatus.py $siteParam" 2>/dev/null); srRc=$? + super_ocf_log info "DEC $FUNCNAME systemReplicationStatus.py (to site '$remSR_name')-> $srRc" + super_ocf_log info "FLOW $FUNCNAME systemReplicationStatus.py (to site '$remSR_name')-> $srRc" + # +@@ -2445,8 +2447,9 @@ + else + # + # neither MASTER nor SLAVE - This clone instance seams to be broken!! +- # +- rc=$OCF_ERR_GENERIC ++ # bsc#1027098 - do not stop SAP HANA if "only" HANA state is not correct ++ # Let next monitor find, if that HANA instance is available or not ++ rc=$OCF_SUCCESS; + fi + fi + rc=$? +diff -uNr a/heartbeat/SAPHanaTopology b/heartbeat/SAPHanaTopology +--- a/heartbeat/SAPHanaTopology 2017-05-11 12:12:17.205213176 +0200 ++++ b/heartbeat/SAPHanaTopology 2017-05-11 12:12:40.642982012 +0200 +@@ -14,7 +14,7 @@ + # Support: linux@sap.com + # License: GNU General Public License (GPL) + # Copyright: (c) 2014 SUSE Linux Products GmbH +-# (c) 2015-2016 SUSE Linux GmbH ++# (c) 2015-2017 SUSE Linux GmbH + # + # An example usage: + # See usage() function below for more details... +@@ -28,7 +28,7 @@ + ####################################################################### + # + # Initialization: +-SAPHanaVersion="0.152.17" ++SAPHanaVersion="0.152.21" + timeB=$(date '+%s') + + : ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat} +@@ -474,6 +474,7 @@ + ATTR_NAME_HANA_SRMODE=("hana_${sid}_srmode" "forever") + ATTR_NAME_HANA_VHOST=("hana_${sid}_vhost" "forever") + ATTR_NAME_HANA_STATUS=("hana_${sid}_status" "reboot") ++ ATTR_NAME_HANA_VERSION=("hana_${sid}_version" "reboot") + # + # new "central" attributes + # +@@ -531,7 +532,7 @@ + # hdbnsutil was a bit unstable in some tests so we recall the tool, if it fails to report the srmode + for chkMethod in hU hU hU gP ; do + # DONE: Limit the runtime of hdbnsutil. +- # TODO: Use getParameter.py if we get no answer ++ # DONE: Use getParameter.py if we get no answer + # SAP_CALL + #super_ocf_log debug "DBG2: hdbANSWER=$hdbANSWER" + #srmode=$(echo "$hdbANSWER" | awk -F= '/mode/ {print $2}') +@@ -602,7 +603,18 @@ + # currently having more than 2 HANA in a chain/star members IN the cluster is not allowed, the third must be external + if [ "$NODENAME" != "$n1" ]; then + hanaSite=$(get_hana_attribute ${n1} ${ATTR_NAME_HANA_SITE[@]}) +- hanaRemoteHost="$n1" ++ # ++ # only, if a hanaSite is found use that node - this allows majority makers ++ # ++ if [ -n "$hanaSite" ]; then ++ hanaRemoteHost=$(get_hana_attribute ${n1} ${ATTR_NAME_HANA_VHOST[@]}) ++ # ++ # only if vhost is NOT set use the nodename instead ++ # ++ if [ -z "$hanaRemoteHost" ]; then ++ hanaRemoteHost="$n1" ++ fi ++ fi + fi + done + super_ocf_log info "DEC: site=$site, mode=$srmode, hanaRemoteHost=$hanaRemoteHost - found by remote site ($hanaSite)" +@@ -700,7 +712,7 @@ + # TODO: PRIO3: move the string "$HA_RSCTMP/SAPHana/SAPTopologyON" to a variable + # TODO: PRIO3: move the file to the clusters tmp directory? + mkdir -p $HA_RSCTMP/SAPHana +- touch $HA_RSCTMP/SAPHana/SAPTopologyON ++ touch $HA_RSCTMP/SAPHana/SAPTopologyON.${SID} + if ! check_saphostagent; then + start_saphostagent + fi +@@ -722,7 +734,7 @@ + local output="" + local rc=0 + +- rm $HA_RSCTMP/SAPHana/SAPTopologyON ++ rm $HA_RSCTMP/SAPHana/SAPTopologyON.${SID} + rc=$OCF_SUCCESS + + super_ocf_log info "FLOW $FUNCNAME rc=$rc" +@@ -740,7 +752,7 @@ + super_ocf_log info "FLOW $FUNCNAME ($*)" + local rc=0 + +- if [ -f $HA_RSCTMP/SAPHana/SAPTopologyON ]; then ++ if [ -f $HA_RSCTMP/SAPHana/SAPTopologyON.${SID} ]; then + rc=$OCF_SUCCESS + else + rc=$OCF_NOT_RUNNING +@@ -845,6 +857,11 @@ + if ocf_is_probe; then + super_ocf_log debug "DBG2: PROBE ONLY" + sht_monitor; rc=$? ++ local hana_version=$(HANA_CALL --timeout 10 --cmd "HDB version" \ ++ | awk -F':' '$1==" version" {print $2}; ' | tr -d '[:space:]') ++ if [[ -n $hana_version ]]; then ++ set_hana_attribute "${NODENAME}" "$hana_version" ${ATTR_NAME_HANA_VERSION[@]} ++ fi + else + super_ocf_log debug "DBG2: REGULAR MONITOR" + if ! check_saphostagent; then +@@ -871,9 +888,13 @@ + super_ocf_log debug "DBG2: HANA IS STANDALONE" + sht_monitor; rc=$? + else +- hanaPrim="-" +- super_ocf_log warn "ACT: sht_monitor_clone: HANA_STATE_DEFECT" +- rc=$OCF_ERR_CONFIGURED ++ # bsc#1027098 Do not mark HANA instance as failed, if "only" the HANA state could not be detected ++ hanaPrim=$(get_hana_attribute ${NODENAME} ${ATTR_NAME_HANA_ROLES[@]} | awk -F: '{ print $2}') ++ if [ "$hanaPrim" = "" ]; then ++ hanaPrim="-" ++ fi ++ super_ocf_log warn "ACT: sht_monitor_clone: HANA_STATE_DEFECT (primary/secondary state could not be detected at this point of time)" ++ sht_monitor; rc=$? + fi + fi + # DONE: PRIO1: ASK: Is the output format of ListInstances fix? Could we take that as an API? diff --git a/SOURCES/bz1449681-2-saphana-saphanatopology-update-0.152.21.patch b/SOURCES/bz1449681-2-saphana-saphanatopology-update-0.152.21.patch new file mode 100644 index 00000000..75cde03b --- /dev/null +++ b/SOURCES/bz1449681-2-saphana-saphanatopology-update-0.152.21.patch @@ -0,0 +1,48 @@ +diff -uNr a/heartbeat/SAPHana b/heartbeat/SAPHana +--- a/heartbeat/SAPHana 2017-06-02 11:44:30.345894798 +0200 ++++ b/heartbeat/SAPHana 2017-06-02 11:45:15.622450739 +0200 +@@ -545,6 +545,9 @@ + read rolePatt syncPatt score <<< $scan + if grep "$rolePatt" <<< "$roles"; then + if grep "$syncPatt" <<< "$sync"; then ++ super_ocf_log info "SCORE: scoring_crm_master: roles($roles) are matching pattern ($rolePatt)" ++ super_ocf_log info "SCORE: scoring_crm_master: sync($sync) is matching syncPattern ($syncPatt)" ++ super_ocf_log info "SCORE: scoring_crm_master: set score $score" + skip=1 + myScore=$score + fi +@@ -1435,6 +1438,10 @@ + lpa_set_lpt $LPTloc $NODENAME + ;; + esac ++ if [ -z "$my_role" ]; then ++ my_role=$(get_hana_attribute ${NODENAME} ${ATTR_NAME_HANA_ROLES[@]}) ++ fi ++ super_ocf_log info "SCORE: saphana_start_primary: scoring_crm_master($my_role,$my_sync)" + scoring_crm_master "$my_role" "$my_sync" + ;; + register ) # process a REGISTER +@@ -2129,6 +2136,7 @@ + #super_ocf_log info "DEC: PreferSiteTakeover selected so decrease promotion score here" + my_role=$(get_hana_attribute ${NODENAME} ${ATTR_NAME_HANA_ROLES[@]}) + my_sync=$(get_hana_attribute ${NODENAME} ${ATTR_NAME_HANA_SYNC_STATUS[@]}) ++ super_ocf_log info "SCORE: saphana_monitor_primary: scoring_crm_master($my_role,$my_sync)" + scoring_crm_master "$my_role" "$my_sync" + rc=$OCF_FAILED_MASTER + fi +@@ -2191,6 +2199,7 @@ + ;; + esac + fi ++ super_ocf_log info "SCORE: saphana_monitor_primary: scoring_crm_master($my_role,$my_sync)" + scoring_crm_master "$my_role" "$my_sync" + fi + ;; +@@ -2301,6 +2310,7 @@ + super_ocf_log info "DEC: secondary with sync status SOK ==> possible takeover node" + my_role=$(get_hana_attribute ${NODENAME} ${ATTR_NAME_HANA_ROLES[@]}) + my_sync=$(get_hana_attribute ${NODENAME} ${ATTR_NAME_HANA_SYNC_STATUS[@]}) ++ super_ocf_log info "SCORE: saphana_monitor_secondary: scoring_crm_master($my_role,$my_sync)" + scoring_crm_master "$my_role" "$my_sync" + ;; + "SFAIL" ) # This is currently NOT a possible node to promote diff --git a/SOURCES/bz1451097-1-galera-fix-bootstrap-when-cluster-has-no-data.patch b/SOURCES/bz1451097-1-galera-fix-bootstrap-when-cluster-has-no-data.patch new file mode 100644 index 00000000..98e98bfe --- /dev/null +++ b/SOURCES/bz1451097-1-galera-fix-bootstrap-when-cluster-has-no-data.patch @@ -0,0 +1,140 @@ +From aa486941a7d980ded7a30e404a9d91620b19c47a Mon Sep 17 00:00:00 2001 +From: Damien Ciabrini +Date: Mon, 19 Dec 2016 14:13:21 +0100 +Subject: [PATCH] galera: allow names in wsrep_cluster_address to differ from + pacemaker nodes' names + +Add a new option cluster_host_map to the galera resource agent in case +names to be used in wsrep_cluster_address need to differ from names +used for the pacemaker nodes. (e.g. when galera names map to IP +from a specific network interface) +--- + heartbeat/galera | 71 +++++++++++++++++++++++++++++++++++++++++++++++++++----- + 1 file changed, 65 insertions(+), 6 deletions(-) + +diff --git a/heartbeat/galera b/heartbeat/galera +index fe2aa8a..45693ac 100755 +--- a/heartbeat/galera ++++ b/heartbeat/galera +@@ -208,13 +208,30 @@ The galera cluster address. This takes the form of: + gcomm://node,node,node + + Only nodes present in this node list will be allowed to start a galera instance. +-It is expected that the galera node names listed in this address match valid +-pacemaker node names. ++The galera node names listed in this address are expected to match valid ++pacemaker node names. If both names need to differ, you must provide a ++mapping in option cluster_host_map. + + Galera cluster address + + + ++ ++ ++A mapping of pacemaker node names to galera node names. ++ ++To be used when both pacemaker and galera names need to differ, ++(e.g. when galera names map to IP from a specific network interface) ++This takes the form of: ++pcmk1:node.1.galera;pcmk2:node.2.galera;pcmk3:node.3.galera ++ ++where the galera resource started on node pcmk1 would be named ++node.1.galera in the wsrep_cluster_address ++ ++Pacemaker to Galera name mapping ++ ++ ++ + + + Cluster check user. +@@ -454,6 +471,27 @@ greater_than_equal_long() + echo | awk -v n1="$1" -v n2="$2" '{if (n1>=n2) printf ("true"); else printf ("false");}' | grep -q "true" + } + ++galera_to_pcmk_name() ++{ ++ local galera=$1 ++ if [ -z "$OCF_RESKEY_cluster_host_map" ]; then ++ echo $galera ++ else ++ echo "$OCF_RESKEY_cluster_host_map" | tr ';' '\n' | tr -d ' ' | sed 's/:/ /' | awk -F' ' '$2=="'"$galera"'" {print $1;exit}' ++ fi ++} ++ ++pcmk_to_galera_name() ++{ ++ local pcmk=$1 ++ if [ -z "$OCF_RESKEY_cluster_host_map" ]; then ++ echo $pcmk ++ else ++ echo "$OCF_RESKEY_cluster_host_map" | tr ';' '\n' | tr -d ' ' | sed 's/:/ /' | awk -F' ' '$1=="'"$pcmk"'" {print $2;exit}' ++ fi ++} ++ ++ + detect_first_master() + { + local best_commit=0 +@@ -465,6 +503,14 @@ detect_first_master() + + # avoid selecting a recovered node as bootstrap if possible + for node in $(echo "$OCF_RESKEY_wsrep_cluster_address" | sed 's/gcomm:\/\///g' | tr -d ' ' | tr -s ',' ' '); do ++ local pcmk_node=$(galera_to_pcmk_name $node) ++ if [ -z "$pcmk_node" ]; then ++ ocf_log error "Could not determine pacemaker node from galera name <${node}>." ++ return ++ else ++ node=$pcmk_node ++ fi ++ + if is_no_grastate $node; then + nodes_recovered="$nodes_recovered $node" + else +@@ -783,10 +829,17 @@ galera_demote() + galera_start() + { + local rc ++ local galera_node ++ ++ galera_node=$(pcmk_to_galera_name $NODENAME) ++ if [ -z "$galera_node" ]; then ++ ocf_exit_reason "Could not determine galera name from pacemaker node <${NODENAME}>." ++ return $OCF_ERR_CONFIGURED ++ fi + +- echo $OCF_RESKEY_wsrep_cluster_address | grep -q $NODENAME ++ echo $OCF_RESKEY_wsrep_cluster_address | grep -q -F $galera_node + if [ $? -ne 0 ]; then +- ocf_exit_reason "local node <${NODENAME}> must be a member of the wsrep_cluster_address <${OCF_RESKEY_wsrep_cluster_address}>to start this galera instance" ++ ocf_exit_reason "local node <${NODENAME}> (galera node <${galera_node}>) must be a member of the wsrep_cluster_address <${OCF_RESKEY_wsrep_cluster_address}> to start this galera instance" + return $OCF_ERR_CONFIGURED + fi + +@@ -818,6 +871,7 @@ galera_start() + galera_monitor() + { + local rc ++ local galera_node + local status_loglevel="err" + + # Set loglevel to info during probe +@@ -857,10 +911,15 @@ galera_monitor() + fi + + # if we make it here, mysql is running. Check cluster status now. ++ galera_node=$(pcmk_to_galera_name $NODENAME) ++ if [ -z "$galera_node" ]; then ++ ocf_exit_reason "Could not determine galera name from pacemaker node <${NODENAME}>." ++ return $OCF_ERR_CONFIGURED ++ fi + +- echo $OCF_RESKEY_wsrep_cluster_address | grep -q $NODENAME ++ echo $OCF_RESKEY_wsrep_cluster_address | grep -q -F $galera_node + if [ $? -ne 0 ]; then +- ocf_exit_reason "local node <${NODENAME}> is started, but is not a member of the wsrep_cluster_address <${OCF_RESKEY_wsrep_cluster_address}>" ++ ocf_exit_reason "local node <${NODENAME}> (galera node <${galera_node}>) is started, but is not a member of the wsrep_cluster_address <${OCF_RESKEY_wsrep_cluster_address}>" + return $OCF_ERR_GENERIC + fi + diff --git a/SOURCES/bz1451097-2-galera-fix-bootstrap-when-cluster-has-no-data.patch b/SOURCES/bz1451097-2-galera-fix-bootstrap-when-cluster-has-no-data.patch new file mode 100644 index 00000000..b72c06d8 --- /dev/null +++ b/SOURCES/bz1451097-2-galera-fix-bootstrap-when-cluster-has-no-data.patch @@ -0,0 +1,50 @@ +From a05eb8673bd1d5d3d41f2ed39df2650b19681d08 Mon Sep 17 00:00:00 2001 +From: Damien Ciabrini +Date: Fri, 3 Mar 2017 15:31:30 +0100 +Subject: [PATCH] galera: fix the first bootstrap when cluster has no data + +The resource agent selects the first node to go into Master state +based on the biggest commit version found on each node. If case no +data were written yet into the galera cluster, the current node is +selected as a "fallback" node to bootstrap the cluster. + +The way the "fallback" node is selected is wrong because every node +takes a different decision, and this ultimately yields to 3 +single-node galera clusters being started. To fix that, let the +"fallback" node be the last one in the wsrep_cluster_address, so that +the selection algorithm yields coherent results across nodes. +--- + heartbeat/galera | 14 ++++++++++++-- + 1 file changed, 12 insertions(+), 2 deletions(-) + +diff --git a/heartbeat/galera b/heartbeat/galera +index decbaa2..475a8ba 100755 +--- a/heartbeat/galera ++++ b/heartbeat/galera +@@ -451,14 +451,24 @@ pcmk_to_galera_name() + detect_first_master() + { + local best_commit=0 +- local best_node="$NODENAME" + local last_commit=0 + local missing_nodes=0 + local nodes="" + local nodes_recovered="" ++ local all_nodes ++ local best_node_gcomm ++ local best_node ++ ++ all_nodes=$(echo "$OCF_RESKEY_wsrep_cluster_address" | sed 's/gcomm:\/\///g' | tr -d ' ' | tr -s ',' ' ') ++ best_node_gcomm=$(echo "$all_nodes" | sed 's/^.* \(.*\)$/\1/') ++ best_node=$(galera_to_pcmk_name $best_node_gcomm) ++ if [ -z "$best_node" ]; then ++ ocf_log error "Could not determine initial best node from galera name <${best_node_gcomm}>." ++ return ++ fi + + # avoid selecting a recovered node as bootstrap if possible +- for node in $(echo "$OCF_RESKEY_wsrep_cluster_address" | sed 's/gcomm:\/\///g' | tr -d ' ' | tr -s ',' ' '); do ++ for node in $all_nodes; do + local pcmk_node=$(galera_to_pcmk_name $node) + if [ -z "$pcmk_node" ]; then + ocf_log error "Could not determine pacemaker node from galera name <${node}>." diff --git a/SOURCES/bz1451097-3-galera-fix-bootstrap-when-cluster-has-no-data.patch b/SOURCES/bz1451097-3-galera-fix-bootstrap-when-cluster-has-no-data.patch new file mode 100644 index 00000000..2a9f52b7 --- /dev/null +++ b/SOURCES/bz1451097-3-galera-fix-bootstrap-when-cluster-has-no-data.patch @@ -0,0 +1,52 @@ +From a6b40d102e24134a3e5e99a63bd3636aebc2145a Mon Sep 17 00:00:00 2001 +From: Damien Ciabrini +Date: Thu, 13 Apr 2017 08:51:39 +0200 +Subject: [PATCH] galera: fix master target during promotion with + cluster_host_map + +When option cluster_host_map is in use, it is assumed that galera node +names map to pacemaker node names _because_ those galera names are not +part of the pacemaker cluster in the first place. + +This is not always the case (e.g. when using pacemaker bundles), so +fix accordingly. +--- + heartbeat/galera | 11 +++++++++-- + 1 file changed, 9 insertions(+), 2 deletions(-) + +diff --git a/heartbeat/galera b/heartbeat/galera +index 475a8ba..32c4222 100755 +--- a/heartbeat/galera ++++ b/heartbeat/galera +@@ -415,6 +415,13 @@ promote_everyone() + { + + for node in $(echo "$OCF_RESKEY_wsrep_cluster_address" | sed 's/gcomm:\/\///g' | tr -d ' ' | tr -s ',' ' '); do ++ local pcmk_node=$(galera_to_pcmk_name $node) ++ if [ -z "$pcmk_node" ]; then ++ ocf_log err "Could not determine pacemaker node from galera name <${node}>." ++ return ++ else ++ node=$pcmk_node ++ fi + + set_master_score $node + done +@@ -463,7 +470,7 @@ detect_first_master() + best_node_gcomm=$(echo "$all_nodes" | sed 's/^.* \(.*\)$/\1/') + best_node=$(galera_to_pcmk_name $best_node_gcomm) + if [ -z "$best_node" ]; then +- ocf_log error "Could not determine initial best node from galera name <${best_node_gcomm}>." ++ ocf_log err "Could not determine initial best node from galera name <${best_node_gcomm}>." + return + fi + +@@ -471,7 +478,7 @@ detect_first_master() + for node in $all_nodes; do + local pcmk_node=$(galera_to_pcmk_name $node) + if [ -z "$pcmk_node" ]; then +- ocf_log error "Could not determine pacemaker node from galera name <${node}>." ++ ocf_log err "Could not determine pacemaker node from galera name <${node}>." + return + else + node=$pcmk_node diff --git a/SOURCES/bz1451933-LVM-warn-when-cache-mode-not-writethrough.patch b/SOURCES/bz1451933-LVM-warn-when-cache-mode-not-writethrough.patch new file mode 100644 index 00000000..29be909d --- /dev/null +++ b/SOURCES/bz1451933-LVM-warn-when-cache-mode-not-writethrough.patch @@ -0,0 +1,59 @@ +From 30ac299da6a01a2f5f42fac6b3d35275ddc001e7 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Mon, 29 May 2017 14:38:48 +0200 +Subject: [PATCH] LVM: warn when cache mode is not writethrough + +--- + heartbeat/LVM | 17 ++--------------- + 1 file changed, 2 insertions(+), 15 deletions(-) + +diff --git a/heartbeat/LVM b/heartbeat/LVM +index 583b9a2bd..7ebedac6f 100755 +--- a/heartbeat/LVM ++++ b/heartbeat/LVM +@@ -29,8 +29,6 @@ + : ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat} + . ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs + +-OCF_RESKEY_check_writethrough_default="false" +- + ####################################################################### + + +@@ -108,14 +106,6 @@ logical volumes. + + + +- +- +-If set to true, check if cache_mode is set to writethrough. +- +-Check if cache_mode is set to writethrough +- +- +- + + + +@@ -593,10 +583,9 @@ LVM_validate_all() { + exit $OCF_ERR_GENERIC + fi + +- if ocf_is_true "$OCF_RESKEY_check_writethrough"; then ++ if lvs --noheadings -o segtype | grep -q "cache"; then + if ! lvs --noheadings -o cache_mode "$OCF_RESKEY_volgrpname" | grep -q "writethrough"; then +- ocf_exit_reason "LVM cache is not in writethrough mode." +- exit $OCF_ERR_CONFIGURED ++ ocf_log warn "LVM CACHE IS NOT IN WRITETHROUGH MODE. THIS IS NOT A SUPPORTED CONFIGURATION." + fi + fi + +@@ -707,8 +696,6 @@ if [ -n "$OCF_RESKEY_tag" ]; then + OUR_TAG=$OCF_RESKEY_tag + fi + +-: ${OCF_RESKEY_check_writethrough=${OCF_RESKEY_check_writethrough_default}} +- + # What kind of method was invoked? + case "$1" in + diff --git a/SOURCES/bz1452049-docker-create-directories.patch b/SOURCES/bz1452049-docker-create-directories.patch new file mode 100644 index 00000000..176af734 --- /dev/null +++ b/SOURCES/bz1452049-docker-create-directories.patch @@ -0,0 +1,49 @@ +From 7792db2967793e43a9272bcea3df10238c8cb806 Mon Sep 17 00:00:00 2001 +From: Andrew Beekhof +Date: Tue, 2 May 2017 12:11:34 +1000 +Subject: [PATCH] docker: Allow callers to specify a set of directories that + should be created if the don't exist + +--- + heartbeat/docker | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) + +diff --git a/heartbeat/docker b/heartbeat/docker +index b251924..bb10f36 100755 +--- a/heartbeat/docker ++++ b/heartbeat/docker +@@ -106,6 +106,15 @@ it has initialized. + + + ++ ++ ++A comma separated list of directories that the container is expecting to use. ++The agent will ensure they exist by running 'mkdir -p' ++ ++Required mount points ++ ++ ++ + + + Specifiy the full path of a command to launch within the container to check +@@ -263,8 +272,18 @@ docker_monitor() + monitor_cmd_exec + } + ++docker_create_mounts() { ++ oldIFS="$IFS" ++ IFS="," ++ for directory in $OCF_RESKEY_mount_points; do ++ mkdir -p "$directory" ++ done ++ IFS="$oldIFS" ++} ++ + docker_start() + { ++ docker_create_mounts + local run_opts="-d --name=${CONTAINER}" + # check to see if the container has already started + docker_simple_status diff --git a/SOURCES/bz1455305-VirtualDomain-fix-sed-migrate_options.patch b/SOURCES/bz1455305-VirtualDomain-fix-sed-migrate_options.patch new file mode 100644 index 00000000..9c7c1cae --- /dev/null +++ b/SOURCES/bz1455305-VirtualDomain-fix-sed-migrate_options.patch @@ -0,0 +1,22 @@ +From 43a6e76f6e685a35db9ddb23c651ab4eed0affae Mon Sep 17 00:00:00 2001 +From: Dejan Muhamedagic +Date: Thu, 29 Jan 2015 17:54:05 +0100 +Subject: [PATCH] Dev: VirtualDomain: fix sed expression + +--- + heartbeat/VirtualDomain | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/heartbeat/VirtualDomain b/heartbeat/VirtualDomain +index 17eb94afd..0f6b0bc4f 100755 +--- a/heartbeat/VirtualDomain ++++ b/heartbeat/VirtualDomain +@@ -664,7 +664,7 @@ VirtualDomain_Migrate_To() { + migrateuri=`echo "$migrate_opts" | + sed "s/.*--migrateuri=\([^ ]*\).*/\1/;s/%n/$target_node/g"` + migrate_opts=`echo "$migrate_opts" | +- sed "s/\(.*\)--migrateuri=[^ ]*\(.*\)/\1\3/"` ++ sed "s/\(.*\)--migrateuri=[^ ]*\(.*\)/\1\2/"` + else + migrateuri=`mk_migrateuri` + fi diff --git a/SOURCES/bz1457382-portblock-suppress-dd-output.patch b/SOURCES/bz1457382-portblock-suppress-dd-output.patch new file mode 100644 index 00000000..087b3a42 --- /dev/null +++ b/SOURCES/bz1457382-portblock-suppress-dd-output.patch @@ -0,0 +1,22 @@ +From 1e7921fe7b257973b4c27c30627e9bdb4b1a8ae2 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Fri, 7 Jul 2017 15:27:50 +0200 +Subject: [PATCH] portblock: dont log dd "0+0 records in/out" + +--- + heartbeat/portblock | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/heartbeat/portblock b/heartbeat/portblock +index 776ad17e4..a518f49fe 100755 +--- a/heartbeat/portblock ++++ b/heartbeat/portblock +@@ -253,7 +253,7 @@ save_tcp_connections() + netstat -tn |awk -F '[:[:space:]]+' ' + $8 == "ESTABLISHED" && $4 == "'$OCF_RESKEY_ip'" \ + {printf "%s:%s\t%s:%s\n", $4,$5, $6,$7}' | +- dd of="$statefile".new conv=fsync && ++ dd of="$statefile".new conv=fsync status=none && + mv "$statefile".new "$statefile" + else + netstat -tn |awk -F '[:[:space:]]+' ' diff --git a/SOURCES/bz1462802-systemd-tmpfiles.patch b/SOURCES/bz1462802-systemd-tmpfiles.patch new file mode 100644 index 00000000..6ebb047f --- /dev/null +++ b/SOURCES/bz1462802-systemd-tmpfiles.patch @@ -0,0 +1,59 @@ +diff -uNr a/configure.ac b/configure.ac +--- a/configure.ac 2017-09-01 15:04:40.575443547 +0200 ++++ b/configure.ac 2017-09-01 15:05:26.542004352 +0200 +@@ -80,6 +80,14 @@ + [AC_SUBST([systemdsystemunitdir], [$with_systemdsystemunitdir])]) + AM_CONDITIONAL([HAVE_SYSTEMD], [test "x$with_systemdsystemunitdir" != "xno"]) + ++AC_ARG_WITH([systemdtmpfilesdir], ++ AS_HELP_STRING([--with-systemdtmpfilesdir=DIR], [Directory for systemd tmp files]), ++ [], [with_systemdtmpfilesdir=$($PKGCONFIG --variable=tmpfilesdir systemd)]) ++ if test "x$with_systemdtmpfilesdir" != xno; then ++ AC_SUBST([systemdtmpfilesdir], [$with_systemdtmpfilesdir]) ++ fi ++AM_CONDITIONAL(HAVE_SYSTEMD, [test -n "$with_systemdtmpfilesdir" -a "x$with_systemdtmpfilesdir" != xno ]) ++ + dnl + dnl AM_INIT_AUTOMAKE([1.11.1 foreign dist-bzip2 dist-xz]) + dnl +diff -uNr a/resource-agents.spec.in b/resource-agents.spec.in +--- a/resource-agents.spec.in 2017-09-01 15:04:40.576443537 +0200 ++++ b/resource-agents.spec.in 2017-09-01 15:06:23.343461633 +0200 +@@ -174,6 +174,12 @@ + %configure \ + %{?conf_opt_rsctmpdir:%conf_opt_rsctmpdir} \ + %{conf_opt_fatal} \ ++%if %{defined _unitdir} ++ --with-systemdsystemunitdir=%{_unitdir} \ ++%endif ++%if %{defined _tmpfilesdir} ++ --with-systemdtmpfilesdir=%{_tmpfilesdir} \ ++%endif + --with-pkg-name=%{name} \ + --with-ras-set=%{rasset} + +@@ -234,6 +240,9 @@ + %if %{defined _unitdir} + %{_unitdir}/resource-agents-deps.target + %endif ++%if %{defined _tmpfilesdir} ++%{_tmpfilesdir}/%{name}.conf ++%endif + + %dir %{_datadir}/%{name} + %dir %{_datadir}/%{name}/ocft +diff -uNr a/systemd/Makefile.am b/systemd/Makefile.am +--- a/systemd/Makefile.am 2017-09-01 15:04:40.577443527 +0200 ++++ b/systemd/Makefile.am 2017-09-01 15:05:26.543004342 +0200 +@@ -20,4 +20,6 @@ + + if HAVE_SYSTEMD + dist_systemdsystemunit_DATA = resource-agents-deps.target ++ ++dist_systemdtmpfiles_DATA = resource-agents.conf + endif +diff -uNr a/systemd/resource-agents.conf b/systemd/resource-agents.conf +--- a/systemd/resource-agents.conf 1970-01-01 01:00:00.000000000 +0100 ++++ b/systemd/resource-agents.conf 2017-09-01 15:05:26.543004342 +0200 +@@ -0,0 +1 @@ ++d /var/run/resource-agents/ 1755 root root diff --git a/SOURCES/bz1465822-OCF-improve-locking.patch b/SOURCES/bz1465822-OCF-improve-locking.patch new file mode 100644 index 00000000..707db71f --- /dev/null +++ b/SOURCES/bz1465822-OCF-improve-locking.patch @@ -0,0 +1,185 @@ +From 738577dd30b782104057496bf01f09e28216892b Mon Sep 17 00:00:00 2001 +From: Dejan Muhamedagic +Date: Mon, 26 Jun 2017 15:56:01 +0200 +Subject: [PATCH 1/2] Medium: ocf-shellfuncs: improve locking (ocf_take_lock) + +This change improves locking by ocf_take_lock(). It uses mkdir(1) +to prevent two instances from creating the same directory (named +by the lock). + +The major difficulty is to prevent a race when a stale lock is +discovered. If two processes try to remove the stale lock at +about the same time, the one which runs slightly later can remove +the lock which just got created by the one which run slightly +earlier. The probability of this race is significantly reduced by +testing for stale lock twice with a random sleep in between. + +Though this change does not exclude a race entirely, it makes it +extremely improbable. In addition, stale locks are result of only +abnormal circumstances and occur seldom. + +The function providing random numbers has been modified to use +either /dev/urandom or awk (with the process pid as the seed). + +It was thoroughly tested with both stale lock simulation and +without, by running 64 instances of processes trying to get the +lock on a workstation with 4 cpus. +--- + heartbeat/ocf-shellfuncs.in | 74 ++++++++++++++++++++++++++++++++++----------- + 1 file changed, 57 insertions(+), 17 deletions(-) + +diff --git a/heartbeat/ocf-shellfuncs.in b/heartbeat/ocf-shellfuncs.in +index ebc221d5f..615f5b4b8 100644 +--- a/heartbeat/ocf-shellfuncs.in ++++ b/heartbeat/ocf-shellfuncs.in +@@ -72,10 +72,11 @@ ocf_is_root() { + } + + ocf_maybe_random() { +- local rnd="$RANDOM" +- # Something sane-ish in case a shell doesn't support $RANDOM +- [ -n "$rnd" ] || rnd=$$ +- echo $rnd ++ if test -c /dev/urandom; then ++ od -An -N4 -tu4 /dev/urandom | tr -d '[:space:]' ++ else ++ awk -v pid=$$ 'BEGIN{srand(pid); print rand()}' | sed 's/^.*[.]//' ++ fi + } + + # Portability comments: +@@ -465,24 +466,63 @@ ocf_pidfile_status() { + return 1 + } + +-ocf_take_lock() { +- local lockfile=$1 +- local rnd=$(ocf_maybe_random) ++# mkdir(1) based locking ++# first the directory is created with the name given as $1 ++# then a file named "pid" is created within that directory with ++# the process PID + +- sleep 0.$rnd +- while +- ocf_pidfile_status $lockfile +- do +- ocf_log info "Sleeping until $lockfile is released..." +- sleep 0.$rnd +- done +- echo $$ > $lockfile ++ocf_get_stale_pid() { ++ local piddir=$1 ++ local pid ++ [ -z "$piddir" ] && return 2 ++ pid=`cat $piddir/pid 2>/dev/null` ++ [ -z "$pid" ] && return 1 # no process ++ kill -0 $pid >/dev/null 2>&1 && return 1 # not stale ++ echo $pid + } + ++# There is a race when the following two functions to manage the ++# lock file (mk and rm) are invoked in parallel by different ++# instances. It is up to the caller to reduce probability of that ++# taking place (see ocf_take_lock() below). ++ ++ocf_mk_pid() { ++ mkdir $1 2>/dev/null && echo $$ > $1/pid ++} ++ocf_rm_pid() { ++ rm -f $1/pid ++ rmdir $1 2>/dev/null ++} ++ ++# Testing and subsequently removing a stale lock (containing the ++# process pid) is inherently difficult to do in such a way as to ++# prevent a race between creating a pid file and removing it and ++# its directory. We reduce the probability of that happening by ++# checking if the stale lock persists over a random period of ++# time. ++ ++ocf_take_lock() { ++ local lockdir=$1 ++ local rnd ++ local stale_pid ++ ++ # we don't want it too short, so strip leading zeros ++ rnd=$(ocf_maybe_random | sed 's/^0*//') ++ stale_pid=`ocf_get_stale_pid $lockdir` ++ if [ -n "$stale_pid" ]; then ++ sleep 0.$rnd ++ # remove "stale pid" only if it persists ++ [ "$stale_pid" = "`ocf_get_stale_pid $lockdir`" ] && ++ ocf_rm_pid $lockdir ++ fi ++ while ! ocf_mk_pid $lockdir; do ++ ocf_log info "Sleeping until $lockdir is released..." ++ sleep 0.$rnd ++ done ++} + + ocf_release_lock_on_exit() { +- local lockfile=$1 +- trap "rm -f $lockfile" EXIT ++ trap "ocf_rm_pid $1" EXIT + } + + # returns true if the CRM is currently running a probe. A probe is + +From 46e6f1d0e736e68c7a48c94083d7037e590365b4 Mon Sep 17 00:00:00 2001 +From: Dejan Muhamedagic +Date: Mon, 26 Jun 2017 20:29:06 +0200 +Subject: [PATCH 2/2] Dev: ocf-shellfuncs: handle empty lock directories + +--- + heartbeat/ocf-shellfuncs.in | 34 ++++++++++++++++++++++++++++------ + 1 file changed, 28 insertions(+), 6 deletions(-) + +diff --git a/heartbeat/ocf-shellfuncs.in b/heartbeat/ocf-shellfuncs.in +index 615f5b4b8..817b2a557 100644 +--- a/heartbeat/ocf-shellfuncs.in ++++ b/heartbeat/ocf-shellfuncs.in +@@ -470,15 +470,37 @@ ocf_pidfile_status() { + # first the directory is created with the name given as $1 + # then a file named "pid" is created within that directory with + # the process PID +- ++# stale locks are handled carefully, the inode of a directory ++# needs to match before and after test if the process is running ++# empty directories are also handled appropriately ++# we relax (sleep) occasionally to allow for other processes to ++# finish managing the lock in case they are in the middle of the ++# business ++ ++relax() { sleep 0.5; } + ocf_get_stale_pid() { +- local piddir=$1 +- local pid ++ local piddir pid dir_inode ++ ++ piddir="$1" + [ -z "$piddir" ] && return 2 ++ dir_inode="`ls -di $piddir 2>/dev/null`" ++ [ -z "$dir_inode" ] && return 1 + pid=`cat $piddir/pid 2>/dev/null` +- [ -z "$pid" ] && return 1 # no process +- kill -0 $pid >/dev/null 2>&1 && return 1 # not stale +- echo $pid ++ if [ -z "$pid" ]; then ++ # empty directory? ++ relax ++ if [ "$dir_inode" = "`ls -di $piddir 2>/dev/null`" ]; then ++ echo $dir_inode ++ else ++ return 1 ++ fi ++ elif kill -0 $pid >/dev/null 2>&1; then ++ return 1 ++ elif relax && [ -e "$piddir/pid" ] && [ "$dir_inode" = "`ls -di $piddir 2>/dev/null`" ]; then ++ echo $pid ++ else ++ return 1 ++ fi + } + + # There is a race when the following two functions to manage the diff --git a/SOURCES/bz1465827-mysql-fix-master-score-maintenance.patch b/SOURCES/bz1465827-mysql-fix-master-score-maintenance.patch new file mode 100644 index 00000000..ef4b0fda --- /dev/null +++ b/SOURCES/bz1465827-mysql-fix-master-score-maintenance.patch @@ -0,0 +1,121 @@ +From 7fe4d007da92381c692b5ae47cec7f63e06b1a6a Mon Sep 17 00:00:00 2001 +From: vaLentin chernoZemski +Date: Thu, 13 Oct 2016 13:17:59 +0300 +Subject: [PATCH 1/2] heartbeat/mysql - Fixed bug where crm_admin is never + called, leaving master scores to -1 in certain conditions. + + Consider the following scenario: + + - crm got mysql master slave resource configured without providing check_level and test_table in the config + - crm is put into maintenance mode + - mysql replication is adjusted automatically or by hand + - crm is restarted on all nodes + - crm resources are reprobed + - crm is put into live mode + - at this point all nodes are working as expected but NONE of them got any master-mysql score set thus defaulting to -1. monitor of the resource never called crm_master. + - master fails + - crm will refuse to elect any slaves with the following error + + failednode.com pengine: debug: master_color: mysql:0 master score: -1 + + When ms_mysql resource is configured master-mysql attribute/score for each node is not set by default thus returning -1. This translates to 'never promote this service as master on this machine' + + master-mysql should be set to positive value by the resource agent when RA decides that this machine is suitable for master. + + In the configuration set specified above if crm never did any operations on the mysql service such as start/stop/promote/demote score on particular node score remains -1 for that node. It just never called crm_master. + + When current master fails and new one needs to be promoted/elected crm is unable to choose new master with following error: + + failednode.com pengine: debug: master_color: mysql:1 master score: 0 ---> because node that hosts mysql:1 is down + failednode.com pengine: debug: master_color: mysql:0 master score: -1 --> because the current live node got initial default valule + + Respectively we fail to promote new master node for the particular service. + + failednode.com pengine: info: master_color: ms_mysql: Promoted 0 instances of a possible 1 to master + + When failover procedure is started crm calls resource agents (read ocfs 'init' script with action 'monitor' on all live nodes that host the have the particular master/slave resource started. + + This monitor operation is expected to return master-mysql scorenum here. But it did not due to specific conditions and configurations. + + To solve this issue we modified the mysql resource agent to always export master-mysql scores depending on the response if called with 'monitor'. + + Scores are exported by calling: + + crm_master -l reboot -v SCORE - if status is success. The higher the score, the better the chance to elect this node, + crm_master -l reboot -D - if monitor operation fails thus instructing the engine that the current node can not be used as master as it got some issues. +--- + heartbeat/mysql | 18 +++++++++++++++++- + 1 file changed, 17 insertions(+), 1 deletion(-) + +diff --git a/heartbeat/mysql b/heartbeat/mysql +index be914d3b2..707bff33c 100755 +--- a/heartbeat/mysql ++++ b/heartbeat/mysql +@@ -719,13 +719,22 @@ mysql_monitor() { + fi + + mysql_common_status $status_loglevel +- + rc=$? + + # TODO: check max connections error + + # If status returned an error, return that immediately + if [ $rc -ne $OCF_SUCCESS ]; then ++ if ( ocf_is_ms ); then ++ # This is a master slave setup but monitored host returned some errors. ++ # Immediately remove it from the pool of possible masters by erasing its master-mysql key ++ # When new mysql master election is started and node got no or negative master-mysql attribute the following is logged ++ # nodename.com pengine: debug: master_color: mysql:0 master score: -1 ++ # If there are NO nodes with positive vaule election of mysql master will fail with ++ # nodename.com pengine: info: master_color: ms_mysql: Promoted 0 instances of a possible 1 to master ++ $CRM_MASTER -D ++ fi ++ + return $rc + fi + +@@ -742,13 +751,20 @@ mysql_monitor() { + rc=$? + + if [ $rc -ne 0 ]; then ++ # We are master/slave and test failed. Delete master score for this node as it is considered unhealthy because of this particular failed check. ++ ocf_is_ms && $CRM_MASTER -D + ocf_exit_reason "Failed to select from $test_table"; + return $OCF_ERR_GENERIC; + fi ++ else ++ # In case no exnteded tests are enabled and we are in master/slave mode _always_ set the master score to 1 if we reached this point ++ ocf_is_ms && $CRM_MASTER -v 1 + fi + + if ocf_is_ms && ! get_read_only; then + ocf_log debug "MySQL monitor succeeded (master)"; ++ # Always set master score for the master ++ $CRM_MASTER -v 2 + return $OCF_RUNNING_MASTER + else + ocf_log debug "MySQL monitor succeeded"; + +From 8ba16bcd7ff23be983570df0afe447beabd1c682 Mon Sep 17 00:00:00 2001 +From: vaLentin chernoZemski +Date: Mon, 23 Jan 2017 10:46:52 +0200 +Subject: [PATCH 2/2] heartbeat/mysql - don't run ocf_is_ms check in a subshell + +--- + heartbeat/mysql | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/heartbeat/mysql b/heartbeat/mysql +index 707bff33c..9e779e4f9 100755 +--- a/heartbeat/mysql ++++ b/heartbeat/mysql +@@ -725,7 +725,7 @@ mysql_monitor() { + + # If status returned an error, return that immediately + if [ $rc -ne $OCF_SUCCESS ]; then +- if ( ocf_is_ms ); then ++ if ocf_is_ms ; then + # This is a master slave setup but monitored host returned some errors. + # Immediately remove it from the pool of possible masters by erasing its master-mysql key + # When new mysql master election is started and node got no or negative master-mysql attribute the following is logged diff --git a/SOURCES/bz1466187-SAPInstance-IS_ERS-parameter-for-ASCS-ERS-Netweaver.patch b/SOURCES/bz1466187-SAPInstance-IS_ERS-parameter-for-ASCS-ERS-Netweaver.patch new file mode 100644 index 00000000..bbadce18 --- /dev/null +++ b/SOURCES/bz1466187-SAPInstance-IS_ERS-parameter-for-ASCS-ERS-Netweaver.patch @@ -0,0 +1,73 @@ +From 2118e5324917938ee2e00926778cfe5159043165 Mon Sep 17 00:00:00 2001 +From: Fabian Herschel +Date: Thu, 27 Apr 2017 12:47:37 +0200 +Subject: [PATCH] Medium: SAPInstance: Add IS_ERS parameter (bsc#1036486) + +If IS_ERS is true, mark a per cluster attribute for a +specific ASCS/ERS pair describing which node is the +best place to failover a failed ASCS. +--- + heartbeat/SAPInstance | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) + +diff --git a/heartbeat/SAPInstance b/heartbeat/SAPInstance +index 49e60aa30..871cbcf3d 100755 +--- a/heartbeat/SAPInstance ++++ b/heartbeat/SAPInstance +@@ -31,6 +31,7 @@ + # OCF_RESKEY_POST_START_USEREXIT (optional, lists a script which can be executed after the resource is started) + # OCF_RESKEY_PRE_STOP_USEREXIT (optional, lists a script which can be executed before the resource is stopped) + # OCF_RESKEY_POST_STOP_USEREXIT (optional, lists a script which can be executed after the resource is stopped) ++# OCF_RESKEY_IS_ERS (needed for ENQ/REPL NW 740) + # + # TODO: - Option to shutdown sapstartsrv for non-active instances -> that means: do probes only with OS tools (sapinstance_status) + # - Option for better standalone enqueue server monitoring, using ensmon (test enque-deque) +@@ -195,6 +196,15 @@ The name of the SAP START profile. Specify this parameter, if you have changed t + Path to a post-start script + + ++ ++ Only used for ASCS/ERS SAP Netweaver installations without implementing a master/slave resource to ++ allow the ASCS to 'find' the ERS running on an other cluster node after a resource failure. This parameter should be set ++ to true 'only' for the ERS instance for implementations following the SAP NetWeaver 7.40 HA certification (NW-HA-CLU-740). This includes also ++ systems for NetWeaver less than 7.40, if you like to impelemnt the NW-HA-CLU-740 scenario. ++ ++ Mark SAPInstance as ERS instance ++ ++ + + + +@@ -342,6 +352,12 @@ sapinstance_init() { + currentSTART_PROFILE=$OCF_RESKEY_START_PROFILE + fi + ++ if [ -z "$OCF_RESKEY_IS_ERS" ]; then ++ is_ers="no" ++ else ++ is_ers="$OCF_RESKEY_IS_ERS" ++ fi ++ + if [ -z "$currentSTART_PROFILE" ] + then + SAPSTARTPROFILE="$DIR_PROFILE/START_${InstanceName}_${SAPVIRHOST}" +@@ -568,9 +584,11 @@ sapinstance_start() { + ocf_log info "SAP Instance $SID-$InstanceName started: $output" + rc=$OCF_SUCCESS + sapuserexit POST_START_USEREXIT "$OCF_RESKEY_POST_START_USEREXIT" ++ if ocf_is_true $is_ers; then crm_attribute -n runs_ers_${SID} -v 1 -l reboot; fi + else + ocf_log err "SAP Instance $SID-$InstanceName start failed: $output" + rc=$OCF_NOT_RUNNING ++ if ocf_is_true $is_ers; then crm_attribute -n runs_ers_${SID} -v 0 -l reboot; fi + fi + + return $rc +@@ -628,6 +646,7 @@ sapinstance_stop() { + fi + + sapuserexit POST_STOP_USEREXIT "$OCF_RESKEY_POST_STOP_USEREXIT" ++ if ocf_is_true $is_ers; then crm_attribute -n runs_ers_${SID} -v 0 -l reboot; fi + + return $rc + } diff --git a/SOURCES/bz1484473-ethmonitor-vlan-fix.patch b/SOURCES/bz1484473-ethmonitor-vlan-fix.patch new file mode 100644 index 00000000..066771f7 --- /dev/null +++ b/SOURCES/bz1484473-ethmonitor-vlan-fix.patch @@ -0,0 +1,25 @@ +From 5fae12629fcfbd00ef2433071d1c09503829624b Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Fri, 25 Aug 2017 13:03:10 +0200 +Subject: [PATCH] ethmonitor: fix for VLAN interfaces + +--- + heartbeat/ethmonitor | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/heartbeat/ethmonitor b/heartbeat/ethmonitor +index 81a7c0b75..6628c474d 100755 +--- a/heartbeat/ethmonitor ++++ b/heartbeat/ethmonitor +@@ -206,9 +206,9 @@ is_interface() { + # + # List interfaces but exclude FreeS/WAN ipsecN virtual interfaces + # +- local iface=`$IP2UTIL -o -f link addr show | grep " $1:" \ ++ local iface=`$IP2UTIL -o -f link addr show | grep " $1\(@[A-Za-z0-9\.]*\)\?:" \ + | cut -d ' ' -f2 | sort -u | grep -v '^ipsec[0-9][0-9]*$' \ +- | sed -e 's/:$//'` ++ | sed -e 's/\(@.*\)\?:$//'` + [ "$iface" != "" ] + } + diff --git a/SOURCES/bz1489734-1-support-per-host-per-bundle-attribs.patch b/SOURCES/bz1489734-1-support-per-host-per-bundle-attribs.patch new file mode 100644 index 00000000..aef9b6de --- /dev/null +++ b/SOURCES/bz1489734-1-support-per-host-per-bundle-attribs.patch @@ -0,0 +1,94 @@ +From 708e11c13ac25e1db5a4552db699a652f4e32353 Mon Sep 17 00:00:00 2001 +From: Michele Baldessari +Date: Thu, 7 Sep 2017 18:56:24 +0200 +Subject: [PATCH 1/2] Introduce helper functions for container-attribute-target + +In this change we introduce the ocf_attribute_target() function that helps +RAs decide where to store per-node attributes. The rationale is that +when an OCF resource runs in a bundle (e.g. rabbitmq-bundle-0) the +NODENAME will point to the bundle name and not to the physical node +running the bundle. Since a bundle can run on any cluster node, this +is not ideal in the situations in which an RA wants to remember on which +*host* a bundle was running (this is typically the case when there is no +shared storage) + +The way this new ocf_attribute_target() function works is the following: +A) When the meta-attr 'container-attribute-target' == 'host' and the + function is called without arguments it will return the physical + hostname the resource is running on. +B) When the meta-attr 'container-attribute-target' != 'host' and the + function is called without arguments it will return the NODENAME + (default) +C) When the meta-attr 'container-attribute-target' == 'host' and the + function is called with an argument it will return the physical + hostname on which the corresponding argument is running on. +D) When the meta-attr 'container-attribute-target' != 'host' and the + function is called with an argument it will return the NODENAME + (default) + +The basic idea is that if resources need to store per-host attributes +you will set the meta attribute 'container-attribute-target' equal to +host (the no-shared storage case). If resources need to store attributes +on a per-bundle basis (because they access data from shared-storage) +then no change is needed on meta attributes (this is the default +behaviour). + +Signed-off-by: Andrew Beekhof +Tested-by: Michele Baldessari +Tested-by: Damien Ciabrini +--- + heartbeat/ocf-shellfuncs.in | 38 ++++++++++++++++++++++++++++++++++++++ + 1 file changed, 38 insertions(+) + +diff --git a/heartbeat/ocf-shellfuncs.in b/heartbeat/ocf-shellfuncs.in +index 9b6b99f88a56..ddd6854e9487 100644 +--- a/heartbeat/ocf-shellfuncs.in ++++ b/heartbeat/ocf-shellfuncs.in +@@ -989,6 +989,44 @@ ocf_stop_trace() { + set +x + } + ++# Helper functions to map from nodename/bundle-name and physical hostname ++# list_index_for_word "node0 node1 node2 node3 node4 node5" node4 --> 5 ++# list_word_at_index "NA host1 host2 host3 host4 host5" 3 --> host2 ++ ++# list_index_for_word "node1 node2 node3 node4 node5" node7 --> "" ++# list_word_at_index "host1 host2 host3 host4 host5" 8 --> "" ++ ++# attribute_target node1 --> host1 ++list_index_for_word() { ++ echo $1 | tr ' ' '\n' | awk -v x="$2" '$0~x {print NR}' ++} ++ ++list_word_at_index() { ++ echo $1 | tr ' ' '\n' | awk -v n="$2" 'n == NR' ++} ++ ++ocf_attribute_target() { ++ if [ x$1 = x ]; then ++ if [ x$OCF_RESKEY_CRM_meta_container_attribute_target = xhost -a x$OCF_RESKEY_CRM_meta_physical_host != x ]; then ++ echo $OCF_RESKEY_CRM_meta_physical_host ++ else ++ echo $OCF_RESKEY_CRM_meta_on_node ++ fi ++ return ++ elif [ x"$OCF_RESKEY_CRM_meta_notify_all_uname" != x ]; then ++ index=$(list_index_for_word "$OCF_RESKEY_CRM_meta_notify_all_uname" $1) ++ mapping="" ++ if [ x$index != x ]; then ++ mapping=$(list_word_at_index "$OCF_RESKEY_CRM_meta_notify_all_hosts" $index) ++ fi ++ if [ x$mapping != x -a x$mapping != xNA ]; then ++ echo $mapping ++ return ++ fi ++ fi ++ echo $1 ++} ++ + __ocf_set_defaults "$@" + + : ${OCF_TRACE_RA:=$OCF_RESKEY_trace_ra} +-- +2.13.5 + diff --git a/SOURCES/bz1489734-2-support-per-host-per-bundle-attribs.patch b/SOURCES/bz1489734-2-support-per-host-per-bundle-attribs.patch new file mode 100644 index 00000000..fa163953 --- /dev/null +++ b/SOURCES/bz1489734-2-support-per-host-per-bundle-attribs.patch @@ -0,0 +1,146 @@ +From 9bd94137d77f770967d35db5de716590cfaf0435 Mon Sep 17 00:00:00 2001 +From: Michele Baldessari +Date: Thu, 7 Sep 2017 21:07:45 +0200 +Subject: [PATCH 2/2] Make use of ocf_attribute_target in rabbitmq/redis/galera + +Instead of using NODENAME directly use the newly-introduced +ocf_attribute_target function. This allows the operator to decide if an RA +running inside a bundle should use per-host properties or per-bundle +properties in a resource. This can be done by setting the meta-attribute +'container-attribute-target' to 'host' in the former case and leave the +defaults as is in the latter case. + +This change has been tested in the following scenarios (for rabbit/redis +and galera): +1) A deployment without bundles and without the container-attribute-target meta attr set. +2) A deployment with the resources running in bundles without the meta-attr set +3) A deployment with the resources running in bundles with the meta-attr set to 'host' + +Additionally we successfully tested restarting of each resource, banning +of each resource from a node and rebooting a cluster node hosting the +resource. + +Signed-off-by: Andrew Beekhof +Signed-off-by: Michele Baldessari +Signed-off-by: Damien Ciabrini +--- + heartbeat/galera | 16 +++++++++------- + heartbeat/rabbitmq-cluster | 4 ++-- + heartbeat/redis | 5 +++-- + 3 files changed, 14 insertions(+), 11 deletions(-) + +diff --git a/heartbeat/galera b/heartbeat/galera +index dc681a47079a..ab121a4be5a4 100755 +--- a/heartbeat/galera ++++ b/heartbeat/galera +@@ -68,6 +68,8 @@ + . ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs + . ${OCF_FUNCTIONS_DIR}/mysql-common.sh + ++NODENAME=$(ocf_attribute_target) ++ + # It is common for some galera instances to store + # check user that can be used to query status + # in this file +@@ -279,7 +281,7 @@ get_status_variable() + + set_bootstrap_node() + { +- local node=$1 ++ local node=$(ocf_attribute_target $1) + + ${HA_SBIN_DIR}/crm_attribute -N $node -l reboot --name "${INSTANCE_ATTR_NAME}-bootstrap" -v "true" + } +@@ -307,7 +309,7 @@ clear_no_grastate() + + is_no_grastate() + { +- local node=$1 ++ local node=$(ocf_attribute_target $1) + ${HA_SBIN_DIR}/crm_attribute -N $node -l reboot --name "${INSTANCE_ATTR_NAME}-no-grastate" -Q 2>/dev/null + } + +@@ -323,7 +325,7 @@ set_last_commit() + + get_last_commit() + { +- local node=$1 ++ local node=$(ocf_attribute_target $1) + + if [ -z "$node" ]; then + ${HA_SBIN_DIR}/crm_attribute -N $NODENAME -l reboot --name "${INSTANCE_ATTR_NAME}-last-committed" -Q 2>/dev/null +@@ -413,7 +415,7 @@ master_exists() + + clear_master_score() + { +- local node=$1 ++ local node=$(ocf_attribute_target $1) + if [ -z "$node" ]; then + $CRM_MASTER -D + else +@@ -423,7 +425,7 @@ clear_master_score() + + set_master_score() + { +- local node=$1 ++ local node=$(ocf_attribute_target $1) + + if [ -z "$node" ]; then + $CRM_MASTER -v 100 +@@ -542,7 +544,7 @@ detect_first_master() + + greater_than_equal_long "$last_commit" "$best_commit" + if [ $? -eq 0 ]; then +- best_node=$node ++ best_node=$(ocf_attribute_target $node) + best_commit=$last_commit + fi + +diff --git a/heartbeat/rabbitmq-cluster b/heartbeat/rabbitmq-cluster +index 1e78d9ecab98..362556d3f644 100755 +--- a/heartbeat/rabbitmq-cluster ++++ b/heartbeat/rabbitmq-cluster +@@ -37,7 +37,7 @@ RMQ_DATA_DIR="/var/lib/rabbitmq/mnesia" + RMQ_PID_DIR="/var/run/rabbitmq" + RMQ_PID_FILE="/var/run/rabbitmq/rmq.pid" + RMQ_LOG_DIR="/var/log/rabbitmq" +-NODENAME=$(ocf_local_nodename) ++NODENAME=$(ocf_attribute_target) + + # this attr represents the current active local rmq node name. + # when rmq stops or the node is fenced, this attr disappears +@@ -340,7 +340,7 @@ rmq_notify() { + + # forget each stopped rmq instance in the provided pcmk node in the list. + for node in $(echo "$node_list"); do +- local rmq_node="$(${HA_SBIN_DIR}/crm_attribute -N $node -l forever --query --name $RMQ_CRM_ATTR_COOKIE_LAST_KNOWN -q)" ++ local rmq_node="$(${HA_SBIN_DIR}/crm_attribute -N $(ocf_attribute_target $node) -l forever --query --name $RMQ_CRM_ATTR_COOKIE_LAST_KNOWN -q)" + if [ -z "$rmq_node" ]; then + ocf_log warn "Unable to map pcmk node $node to a known rmq node." + continue +diff --git a/heartbeat/redis b/heartbeat/redis +index 708ce84e6184..bc97f14096a6 100755 +--- a/heartbeat/redis ++++ b/heartbeat/redis +@@ -188,7 +188,8 @@ function last_known_master() + } + + function crm_master_reboot() { +- "${HA_SBIN_DIR}/crm_master" -l reboot "$@" ++ local node=$(ocf_attribute_target) ++ "${HA_SBIN_DIR}/crm_master" -N $node -l reboot "$@" + } + + function calculate_score() +@@ -545,7 +546,7 @@ function validate() { + fi + } + +-NODENAME=$(ocf_local_nodename) ++NODENAME=$(ocf_attribute_target) + if [ -f "$REDIS_CONFIG" ]; then + clientpasswd="$(cat $REDIS_CONFIG | sed -n -e 's/^\s*requirepass\s*\(.*\)\s*$/\1/p' | tail -n 1)" + fi +-- +2.13.5 + diff --git a/SOURCES/bz1496393-NovaEvacuate-Instance-HA-OSP12.patch b/SOURCES/bz1496393-NovaEvacuate-Instance-HA-OSP12.patch new file mode 100644 index 00000000..7d0c08ae --- /dev/null +++ b/SOURCES/bz1496393-NovaEvacuate-Instance-HA-OSP12.patch @@ -0,0 +1,183 @@ +diff -uNr a/heartbeat/NovaEvacuate b/heartbeat/NovaEvacuate +--- a/heartbeat/NovaEvacuate 2017-09-27 11:59:28.430326918 +0200 ++++ b/heartbeat/NovaEvacuate 2017-09-27 12:04:21.599608299 +0200 +@@ -77,6 +77,24 @@ + + + ++ ++ ++Region name for connecting to nova. ++ ++Region name ++ ++ ++ ++ ++ ++Explicitly allow client to perform "insecure" TLS (https) requests. ++The server's certificate will not be verified against any certificate authorities. ++This option should be used with caution. ++ ++Allow insecure TLS requests ++ ++ ++ + + + Disable shared storage recovery for instances. Use at your own risk! +@@ -85,6 +103,14 @@ + + + ++ ++ ++Enable extra logging from the evacuation process ++ ++Enable debug logging ++ ++ ++ + + + +@@ -143,16 +169,20 @@ + need_evacuate=0 + + case $state in +- "") ;; +- no) ocf_log debug "$node is either fine or already handled";; +- yes) need_evacuate=1;; ++ "") ++ ;; ++ no) ++ ocf_log debug "$node is either fine or already handled" ++ ;; ++ yes) need_evacuate=1 ++ ;; + *@*) + where=$(echo $state | awk -F@ '{print $1}') + when=$(echo $state | awk -F@ '{print $2}') + now=$(date +%s) + + if [ $(($now - $when)) -gt 60 ]; then +- ocf_log info "Processing partial evacuation of $node by $where at $when" ++ ocf_log info "Processing partial evacuation of $node by $where at $when" + need_evacuate=1 + else + # Give some time for any in-flight evacuations to either complete or fail +@@ -163,9 +193,15 @@ + esac + + if [ $need_evacuate = 1 ]; then +- ocf_log notice "Initiating evacuation of $node" ++ fence_agent="fence_compute" ++ ++ if have_binary fence_evacuate ++ then ++ fence_agent="fence_evacuate" ++ fi + +- fence_compute ${fence_options} -o status -n ${node} ++ ocf_log notice "Initiating evacuation of $node with $fence_agent" ++ $fence_agent ${fence_options} -o status -n ${node} + if [ $? = 1 ]; then + ocf_log info "Nova does not know about ${node}" + # Dont mark as no because perhaps nova is unavailable right now +@@ -177,7 +213,7 @@ + return $OCF_SUCCESS + fi + +- fence_compute ${fence_options} -o off -n $node ++ $fence_agent ${fence_options} -o off -n $node + rc=$? + + if [ $rc = 0 ]; then +@@ -211,7 +247,10 @@ + rc=$OCF_SUCCESS + fence_options="" + +- check_binary fence_compute ++ ++ if ! have_binary fence_evacuate; then ++ check_binary fence_compute ++ fi + + # Is the state directory writable? + state_dir=$(dirname $statefile) +@@ -250,12 +289,29 @@ + + fence_options="${fence_options} -t ${OCF_RESKEY_tenant_name}" + ++ if [ -n "${OCF_RESKEY_region_name}" ]; then ++ fence_options="${fence_options} \ ++ --region-name ${OCF_RESKEY_region_name}" ++ fi ++ ++ if [ -n "${OCF_RESKEY_insecure}" ]; then ++ if ocf_is_true "${OCF_RESKEY_insecure}"; then ++ fence_options="${fence_options} --insecure" ++ fi ++ fi ++ + if [ -n "${OCF_RESKEY_no_shared_storage}" ]; then + if ocf_is_true "${OCF_RESKEY_no_shared_storage}"; then + fence_options="${fence_options} --no-shared-storage" + fi + fi + ++ if [ -n "${OCF_RESKEY_verbose}" ]; then ++ if ocf_is_true "${OCF_RESKEY_verbose}"; then ++ fence_options="${fence_options} --verbose" ++ fi ++ fi ++ + if [ -n "${OCF_RESKEY_endpoint_type}" ]; then + case ${OCF_RESKEY_endpoint_type} in + adminURL|publicURL|internalURL) ;; +@@ -276,19 +332,32 @@ + statefile="${HA_RSCTMP}/${OCF_RESOURCE_INSTANCE}.active" + + case $__OCF_ACTION in +-start) evacuate_validate; evacuate_start;; +-stop) evacuate_stop;; +-monitor) evacuate_validate; evacuate_monitor;; +-meta-data) meta_data +- exit $OCF_SUCCESS +- ;; +-usage|help) evacuate_usage +- exit $OCF_SUCCESS +- ;; +-validate-all) exit $OCF_SUCCESS;; +-*) evacuate_usage +- exit $OCF_ERR_UNIMPLEMENTED +- ;; ++ start) ++ evacuate_validate ++ evacuate_start ++ ;; ++ stop) ++ evacuate_stop ++ ;; ++ monitor) ++ evacuate_validate ++ evacuate_monitor ++ ;; ++ meta-data) ++ meta_data ++ exit $OCF_SUCCESS ++ ;; ++ usage|help) ++ evacuate_usage ++ exit $OCF_SUCCESS ++ ;; ++ validate-all) ++ exit $OCF_SUCCESS ++ ;; ++ *) ++ evacuate_usage ++ exit $OCF_ERR_UNIMPLEMENTED ++ ;; + esac + rc=$? + ocf_log debug "${OCF_RESOURCE_INSTANCE} $__OCF_ACTION : $rc" diff --git a/SOURCES/bz1499677-galera-recover-from-empty-gvwstate.dat.patch b/SOURCES/bz1499677-galera-recover-from-empty-gvwstate.dat.patch new file mode 100644 index 00000000..0d6f6aa8 --- /dev/null +++ b/SOURCES/bz1499677-galera-recover-from-empty-gvwstate.dat.patch @@ -0,0 +1,40 @@ +From 8fef58405fbac15c0ea93f0d890b114c870de0cc Mon Sep 17 00:00:00 2001 +From: Damien Ciabrini +Date: Wed, 8 Nov 2017 15:19:33 +0100 +Subject: [PATCH] galera: recover from empty gvwstate.dat + +While running, a galera node keeps track of the last known state of +the cluster in a temporary file gvwstate.dat. This file is normally +deleted once a node is shutdown gracefully. + +Some ungraceful shutdowns can leave an empty gvwstate.dat on +disk. This will prevent galera to join the cluster if it is +configured to attempt PC recovery. Removing that file makes the +node fall back to the normal, unoptimized joining process next +time it is restarted. +--- + heartbeat/galera | 11 +++++++++++ + 1 file changed, 11 insertions(+) + +diff --git a/heartbeat/galera b/heartbeat/galera +index ab121a4be..ee8451427 100755 +--- a/heartbeat/galera ++++ b/heartbeat/galera +@@ -586,6 +586,17 @@ detect_last_commit() + local recovery_file_regex='s/.*WSREP\:.*position\s*recovery.*--log_error='\''\([^'\'']*\)'\''.*/\1/p' + local recovered_position_regex='s/.*WSREP\:\s*[R|r]ecovered\s*position.*\:\(.*\)\s*$/\1/p' + ++ # codership/galera#354 ++ # Some ungraceful shutdowns can leave an empty gvwstate.dat on ++ # disk. This will prevent galera to join the cluster if it is ++ # configured to attempt PC recovery. Removing that file makes the ++ # node fall back to the normal, unoptimized joining process. ++ if [ -f ${OCF_RESKEY_datadir}/gvwstate.dat ] && \ ++ [ ! -s ${OCF_RESKEY_datadir}/gvwstate.dat ]; then ++ ocf_log warn "empty ${OCF_RESKEY_datadir}/gvwstate.dat detected, removing it to prevent PC recovery failure at next restart" ++ rm -f ${OCF_RESKEY_datadir}/gvwstate.dat ++ fi ++ + ocf_log info "attempting to detect last commit version by reading ${OCF_RESKEY_datadir}/grastate.dat" + last_commit="$(cat ${OCF_RESKEY_datadir}/grastate.dat | sed -n 's/^seqno.\s*\(.*\)\s*$/\1/p')" + if [ -z "$last_commit" ] || [ "$last_commit" = "-1" ]; then diff --git a/SOURCES/bz1500352-amazon-aws-agents.patch b/SOURCES/bz1500352-amazon-aws-agents.patch new file mode 100644 index 00000000..c0945531 --- /dev/null +++ b/SOURCES/bz1500352-amazon-aws-agents.patch @@ -0,0 +1,867 @@ +diff -uNr a/doc/man/Makefile.am b/doc/man/Makefile.am +--- a/doc/man/Makefile.am 2018-02-21 13:07:56.172091057 +0100 ++++ b/doc/man/Makefile.am 2018-02-21 13:05:37.589245986 +0100 +@@ -99,6 +99,9 @@ + ocf_heartbeat_anything.7 \ + ocf_heartbeat_apache.7 \ + ocf_heartbeat_asterisk.7 \ ++ ocf_heartbeat_aws-vpc-move-ip.7 \ ++ ocf_heartbeat_awseip.7 \ ++ ocf_heartbeat_awsvip.7 \ + ocf_heartbeat_clvm.7 \ + ocf_heartbeat_conntrackd.7 \ + ocf_heartbeat_db2.7 \ +diff -uNr a/heartbeat/awseip b/heartbeat/awseip +--- a/heartbeat/awseip 1970-01-01 01:00:00.000000000 +0100 ++++ b/heartbeat/awseip 2018-02-21 13:08:21.112887254 +0100 +@@ -0,0 +1,278 @@ ++#!/bin/sh ++# ++# ++# Manage Elastic IP with Pacemaker ++# ++# ++# Copyright 2016 guessi ++# ++# Licensed under the Apache License, Version 2.0 (the "License"); ++# you may not use this file except in compliance with the License. ++# You may obtain a copy of the License at ++# ++# http://www.apache.org/licenses/LICENSE-2.0 ++# ++# Unless required by applicable law or agreed to in writing, software ++# distributed under the License is distributed on an "AS IS" BASIS, ++# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++# See the License for the specific language governing permissions and ++# limitations under the License. ++# ++# ++ ++# ++# Prerequisites: ++# ++# - preconfigured AWS CLI running environment (AccessKey, SecretAccessKey, etc.) ++# - a reserved secondary private IP address for EC2 instances high availablity ++# - IAM user role with the following permissions: ++# * DescribeInstances ++# * AssociateAddress ++# * DisassociateAddress ++# ++ ++####################################################################### ++# Initialization: ++ ++: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat} ++. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs ++ ++####################################################################### ++ ++# ++# Defaults ++# ++OCF_RESKEY_awscli_default="/usr/bin/aws" ++OCF_RESKEY_profile_default="default" ++OCF_RESKEY_api_delay_default="3" ++ ++: ${OCF_RESKEY_awscli=${OCF_RESKEY_awscli_default}} ++: ${OCF_RESKEY_profile=${OCF_RESKEY_profile_default}} ++: ${OCF_RESKEY_api_delay=${OCF_RESKEY_api_delay_default}} ++ ++meta_data() { ++ cat < ++ ++ ++1.0 ++ ++ ++Resource Agent for Amazon AWS Elastic IP Addresses. ++ ++It manages AWS Elastic IP Addresses with awscli. ++ ++Credentials needs to be setup by running "aws configure". ++ ++See https://aws.amazon.com/cli/ for more information about awscli. ++ ++Amazon AWS Elastic IP Address Resource Agent ++ ++ ++ ++ ++ ++command line tools for aws services ++ ++aws cli tools ++ ++ ++ ++ ++ ++Valid AWS CLI profile name (see ~/.aws/config and 'aws configure') ++ ++profile name ++ ++ ++ ++ ++ ++reserved elastic ip for ec2 instance ++ ++reserved elastic ip for ec2 instance ++ ++ ++ ++ ++ ++reserved allocation id for ec2 instance ++ ++reserved allocation id for ec2 instance ++ ++ ++ ++ ++ ++predefined private ip address for ec2 instance ++ ++predefined private ip address for ec2 instance ++ ++ ++ ++ ++ ++a short delay between API calls, to avoid sending API too quick ++ ++a short delay between API calls ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++END ++} ++ ++####################################################################### ++ ++awseip_usage() { ++ cat < ++# ++# Licensed under the Apache License, Version 2.0 (the "License"); ++# you may not use this file except in compliance with the License. ++# You may obtain a copy of the License at ++# ++# http://www.apache.org/licenses/LICENSE-2.0 ++# ++# Unless required by applicable law or agreed to in writing, software ++# distributed under the License is distributed on an "AS IS" BASIS, ++# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. ++# See the License for the specific language governing permissions and ++# limitations under the License. ++# ++# ++ ++# ++# Prerequisites: ++# ++# - preconfigured AWS CLI running environment (AccessKey, SecretAccessKey, etc.) ++# - a reserved secondary private IP address for EC2 instances high availablity ++# - IAM user role with the following permissions: ++# * DescribeInstances ++# * AssignPrivateIpAddresses ++# * UnassignPrivateIpAddresses ++# ++ ++####################################################################### ++# Initialization: ++ ++: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat} ++. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs ++ ++####################################################################### ++ ++# ++# Defaults ++# ++OCF_RESKEY_awscli_default="/usr/bin/aws" ++OCF_RESKEY_profile_default="default" ++OCF_RESKEY_api_delay_default="3" ++ ++: ${OCF_RESKEY_awscli=${OCF_RESKEY_awscli_default}} ++: ${OCF_RESKEY_profile=${OCF_RESKEY_profile_default}} ++: ${OCF_RESKEY_api_delay=${OCF_RESKEY_api_delay_default}} ++ ++meta_data() { ++ cat < ++ ++ ++1.0 ++ ++ ++Resource Agent for Amazon AWS Secondary Private IP Addresses. ++ ++It manages AWS Secondary Private IP Addresses with awscli. ++ ++Credentials needs to be setup by running "aws configure". ++ ++See https://aws.amazon.com/cli/ for more information about awscli. ++ ++Amazon AWS Secondary Private IP Address Resource Agent ++ ++ ++ ++ ++ ++command line tools for aws services ++ ++aws cli tools ++ ++ ++ ++ ++ ++Valid AWS CLI profile name (see ~/.aws/config and 'aws configure') ++ ++profile name ++ ++ ++ ++ ++ ++reserved secondary private ip for ec2 instance ++ ++reserved secondary private ip for ec2 instance ++ ++ ++ ++ ++ ++a short delay between API calls, to avoid sending API too quick ++ ++a short delay between API calls ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++END ++} ++ ++####################################################################### ++ ++awsvip_usage() { ++ cat < ++ ++ ++2.0 ++ ++Resource Agent to move IP addresses within a VPC of the Amazon Webservices EC2 ++by changing an entry in an specific routing table ++ ++Move IP within a APC of the AWS EC2 ++ ++ ++ ++ ++Path to command line tools for AWS ++ ++Path to AWS CLI tools ++ ++ ++ ++ ++ ++Valid AWS CLI profile name (see ~/.aws/config and 'aws configure') ++ ++profile name ++ ++ ++ ++ ++ ++VPC private IP address ++ ++VPC private IP ++ ++ ++ ++ ++ ++Name of the routing table, where the route for the IP address should be changed, i.e. rtb-... ++ ++routing table name ++ ++ ++ ++ ++ ++Name of the network interface, i.e. eth0 ++ ++network interface name ++ ++ ++ ++ ++ ++Enable enhanced monitoring using AWS API calls to check route table entry ++ ++Enhanced Monitoring ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++END ++} ++ ++ec2ip_validate() { ++ for cmd in aws ip curl; do ++ check_binary "$cmd" ++ done ++ ++ if [ -z "$OCF_RESKEY_profile" ]; then ++ ocf_exit_reason "profile parameter not set" ++ return $OCF_ERR_CONFIGURED ++ fi ++ ++ EC2_INSTANCE_ID="$(curl -s http://169.254.169.254/latest/meta-data/instance-id)" ++ ++ if [ -z "${EC2_INSTANCE_ID}" ]; then ++ ocf_exit_reason "Instance ID not found. Is this a EC2 instance?" ++ return $OCF_ERR_GENERIC ++ fi ++ ++ return $OCF_SUCCESS ++} ++ ++ec2ip_monitor() { ++ if ocf_is_true ${OCF_RESKEY_monapi} || [ "$__OCF_ACTION" = "start" ]; then ++ ocf_log info "monitor: check routing table (API call)" ++ cmd="$OCF_RESKEY_awscli --profile $OCF_RESKEY_profile --output text ec2 describe-route-tables --route-table-ids $OCF_RESKEY_routing_table" ++ ocf_log debug "executing command: $cmd" ++ ROUTE_TO_INSTANCE="$($cmd | grep $OCF_RESKEY_ip | awk '{ print $3 }')" ++ if [ -z "$ROUTE_TO_INSTANCE" ]; then ++ ROUTE_TO_INSTANCE="" ++ fi ++ ++ if [ "$EC2_INSTANCE_ID" != "$ROUTE_TO_INSTANCE" ];then ++ ocf_log warn "not routed to this instance ($EC2_INSTANCE_ID) but to instance $ROUTE_TO_INSTANCE" ++ return $OCF_NOT_RUNNING ++ fi ++ else ++ ocf_log debug "monitor: Enhanced Monitoring disabled - omitting API call" ++ fi ++ ++ cmd="ping -W 1 -c 1 $OCF_RESKEY_ip" ++ ocf_log debug "executing command: $cmd" ++ $cmd > /dev/null ++ if [ "$?" -gt 0 ]; then ++ ocf_log warn "IP $OCF_RESKEY_ip not locally reachable via ping on this system" ++ return $OCF_NOT_RUNNING ++ fi ++ ++ ocf_log debug "route in VPC and locally reachable" ++ return $OCF_SUCCESS ++} ++ ++ ++ec2ip_drop() { ++ cmd="ip addr delete ${OCF_RESKEY_ip}/32 dev $OCF_RESKEY_interface" ++ ocf_log debug "executing command: $cmd" ++ $cmd ++ rc=$? ++ if [ "$rc" -gt 0 ]; then ++ ocf_log warn "command failed, rc $rc" ++ return $OCF_ERR_GENERIC ++ fi ++ ++ return $OCF_SUCCESS ++} ++ ++ec2ip_get_and_configure() { ++ # Adjusting the routing table ++ cmd="$OCF_RESKEY_awscli --profile $OCF_RESKEY_profile ec2 replace-route --route-table-id $OCF_RESKEY_routing_table --destination-cidr-block ${OCF_RESKEY_ip}/32 --instance-id $EC2_INSTANCE_ID" ++ ocf_log debug "executing command: $cmd" ++ $cmd ++ rc=$? ++ if [ "$rc" != 0 ]; then ++ ocf_log warn "command failed, rc: $rc" ++ return $OCF_ERR_GENERIC ++ fi ++ ++ # Reconfigure the local ip address ++ ec2ip_drop ++ ip addr add "${OCF_RESKEY_ip}/32" dev $OCF_RESKEY_interface ++ rc=$? ++ if [ $rc != 0 ]; then ++ ocf_log warn "command failed, rc: $rc" ++ return $OCF_ERR_GENERIC ++ fi ++ ++ return $OCF_SUCCESS ++} ++ ++ec2ip_stop() { ++ ocf_log info "EC2: Bringing down IP address $OCF_RESKEY_ip" ++ ++ ec2ip_monitor ++ if [ $? = $OCF_NOT_RUNNING ]; then ++ ocf_log info "EC2: Address $OCF_RESKEY_ip already down" ++ return $OCF_SUCCESS ++ fi ++ ++ ec2ip_drop ++ if [ $? != $OCF_SUCCESS ]; then ++ return $OCF_ERR_GENERIC ++ fi ++ ++ ec2ip_monitor ++ if [ $? != $OCF_NOT_RUNNING ]; then ++ ocf_log error "EC2: Couldn't bring down IP address $OCF_RESKEY_ip on interface $OCF_RESKEY_interface." ++ return $OCF_ERR_GENERIC ++ fi ++ ++ ocf_log info "EC2: Successfully brought down $OCF_RESKEY_ip" ++ return $OCF_SUCCESS ++} ++ ++ec2ip_start() { ++ ocf_log info "EC2: Moving IP address $OCF_RESKEY_ip to this host by adjusting routing table $OCF_RESKEY_routing_table" ++ ++ ec2ip_monitor ++ if [ $? = $OCF_SUCCESS ]; then ++ ocf_log info "EC2: $OCF_RESKEY_ip already started" ++ return $OCF_SUCCESS ++ fi ++ ++ ocf_log info "EC2: Adjusting routing table and locally configuring IP address" ++ ec2ip_get_and_configure ++ rc=$? ++ if [ $rc != $OCF_SUCCESS ]; then ++ ocf_log error "Received $rc from 'aws'" ++ return $OCF_ERR_GENERIC ++ fi ++ ++ ec2ip_monitor ++ if [ $? != $OCF_SUCCESS ]; then ++ ocf_log error "EC2: IP address couldn't be configured on this host (IP: $OCF_RESKEY_ip, Interface: $OCF_RESKEY_interface)" ++ return $OCF_ERR_GENERIC ++ fi ++ ++ return $OCF_SUCCESS ++} ++ ++############################################################################### ++# ++# MAIN ++# ++############################################################################### ++ ++case $__OCF_ACTION in ++ meta-data) ++ metadata ++ exit $OCF_SUCCESS ++ ;; ++ usage|help) ++ echo $USAGE ++ exit $OCF_SUCCESS ++ ;; ++esac ++ ++if ! ocf_is_root; then ++ ocf_log err "You must be root for $__OCF_ACTION operation." ++ exit $OCF_ERR_PERM ++fi ++ ++ec2ip_validate ++ ++case $__OCF_ACTION in ++ start) ++ ec2ip_start;; ++ stop) ++ ec2ip_stop;; ++ monitor) ++ ec2ip_monitor;; ++ validate-all) ++ exit $?;; ++ *) ++ echo $USAGE ++ exit $OCF_ERR_UNIMPLEMENTED ++ ;; ++esac +diff -uNr a/heartbeat/Makefile.am b/heartbeat/Makefile.am +--- a/heartbeat/Makefile.am 2018-02-21 13:07:45.862175305 +0100 ++++ b/heartbeat/Makefile.am 2018-02-21 13:05:37.589245986 +0100 +@@ -64,6 +64,9 @@ + AoEtarget \ + apache \ + asterisk \ ++ aws-vpc-move-ip \ ++ awseip \ ++ awsvip \ + nginx \ + AudibleAlarm \ + clvm \ diff --git a/SOURCES/bz1504112-nfsserver-allow-stop-to-timeout.patch b/SOURCES/bz1504112-nfsserver-allow-stop-to-timeout.patch new file mode 100644 index 00000000..69a29eda --- /dev/null +++ b/SOURCES/bz1504112-nfsserver-allow-stop-to-timeout.patch @@ -0,0 +1,18 @@ +diff -uNr a/heartbeat/nfsserver b/heartbeat/nfsserver +--- a/heartbeat/nfsserver 2017-11-02 12:42:24.260248092 +0100 ++++ b/heartbeat/nfsserver 2017-11-02 12:43:12.494802422 +0100 +@@ -874,10 +874,10 @@ + if [ "$EXEC_MODE" -eq "2" ]; then + ocf_log info "Stop: threads" + tfn="/proc/fs/nfsd/threads" +- if [ -f "$tfn" ] && [ "$(cat $tfn)" -gt "0" ]; then +- ocf_exit_reason "NFS server failed to stop: /proc/fs/nfsd/threads" +- return $OCF_ERR_GENERIC +- fi ++ while [ -f "$tfn" ] && [ "$(cat $tfn)" -gt "0" ]; do ++ ocf_log err "NFS server failed to stop: /proc/fs/nfsd/threads" ++ sleep 1 ++ done + + nfs_exec stop rpc-statd > /dev/null 2>&1 + ocf_log info "Stop: rpc-statd" diff --git a/SOURCES/bz1508362-docker-improve-exit-reasons.patch b/SOURCES/bz1508362-docker-improve-exit-reasons.patch new file mode 100644 index 00000000..e4e0d7ab --- /dev/null +++ b/SOURCES/bz1508362-docker-improve-exit-reasons.patch @@ -0,0 +1,26 @@ +diff -uNr a/heartbeat/docker b/heartbeat/docker +--- a/heartbeat/docker 2017-11-01 13:57:09.742513891 +0100 ++++ b/heartbeat/docker 2017-11-01 13:59:20.632338967 +0100 +@@ -303,11 +303,21 @@ + # we already know at this point it wouldn't be running + remove_container + ocf_log info "running container $CONTAINER for the first time" +- ocf_run docker run $run_opts $OCF_RESKEY_image $OCF_RESKEY_run_cmd ++ output=`docker run $run_opts $OCF_RESKEY_image $OCF_RESKEY_run_cmd 2>&1` ++ rc=$? ++ ++ if [ $rc -ne 0 ]; then ++ reason=`echo $output | sed -e 's@See ./usr/bin.*@@' -e 's@.*Error response from daemon: @@' -e 's@[^\:]*:@@'` ++ ocf_exit_reason "$reason" ++ ocf_log err "$output" ++ ocf_run -info docker ps -a ++ return $OCF_ERR_GENERIC ++ fi + fi + + if [ $? -ne 0 ]; then + ocf_exit_reason "docker failed to launch container" ++ ocf_run -info docker ps -a + return $OCF_ERR_GENERIC + fi + diff --git a/SOURCES/bz1508366-docker-dont-ignore-stopped-containers.patch b/SOURCES/bz1508366-docker-dont-ignore-stopped-containers.patch new file mode 100644 index 00000000..7b43ed76 --- /dev/null +++ b/SOURCES/bz1508366-docker-dont-ignore-stopped-containers.patch @@ -0,0 +1,26 @@ +diff -uNr a/heartbeat/docker b/heartbeat/docker +--- a/heartbeat/docker 2017-11-01 13:46:00.935405714 +0100 ++++ b/heartbeat/docker 2017-11-01 13:54:20.896006649 +0100 +@@ -234,14 +234,16 @@ + + # retrieve the 'Running' attribute for the container + val=$(docker inspect --format {{.State.Running}} $CONTAINER 2>/dev/null) +- if [ $? -ne 0 ]; then +- #not running as a result of container not being found +- return $OCF_NOT_RUNNING ++ if [ $? -eq 0 ]; then ++ if ocf_is_true "$val"; then ++ # container exists and is running ++ return $OCF_SUCCESS ++ fi + fi + +- if ocf_is_true "$val"; then +- # container exists and is running +- return $OCF_SUCCESS ++ # Known but in a stopped state ++ if ! ocf_is_true "$OCF_RESKEY_reuse"; then ++ return $OCF_ERR_GENERIC + fi + + return $OCF_NOT_RUNNING diff --git a/SOURCES/bz1512580-CTDB-fix-probe.patch b/SOURCES/bz1512580-CTDB-fix-probe.patch new file mode 100644 index 00000000..207ca6f0 --- /dev/null +++ b/SOURCES/bz1512580-CTDB-fix-probe.patch @@ -0,0 +1,22 @@ +From 88a2513d0e97fe31c83151c05e10762fb5b4753a Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Fri, 1 Dec 2017 09:57:26 +0100 +Subject: [PATCH] CTDB: fix initial probe + +--- + heartbeat/CTDB | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/heartbeat/CTDB b/heartbeat/CTDB +index 709dbc8e9..09f5ecf5f 100755 +--- a/heartbeat/CTDB ++++ b/heartbeat/CTDB +@@ -706,6 +706,8 @@ ctdb_monitor() { + return $OCF_NOT_RUNNING + elif echo "$status" | grep -qs 'No such file or directory'; then + return $OCF_NOT_RUNNING ++ elif echo $status | grep -qs 'connect() failed'; then ++ return $OCF_NOT_RUNNING + else + ocf_exit_reason "CTDB status call failed: $status" + return $OCF_ERR_GENERIC diff --git a/SOURCES/bz1516180-db2-fix-hadr-promote-when-master-failed.patch b/SOURCES/bz1516180-db2-fix-hadr-promote-when-master-failed.patch new file mode 100644 index 00000000..6f248cca --- /dev/null +++ b/SOURCES/bz1516180-db2-fix-hadr-promote-when-master-failed.patch @@ -0,0 +1,31 @@ +From 051743955c4f1f5fe412875afba94edd2839008c Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Wed, 22 Nov 2017 12:25:41 +0100 +Subject: [PATCH] db2: fix HADR promote when master failed + +--- + heartbeat/db2 | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/heartbeat/db2 b/heartbeat/db2 +index 63de31582..b67363ec5 100755 +--- a/heartbeat/db2 ++++ b/heartbeat/db2 +@@ -617,7 +617,7 @@ db2_instance_status() { + if [ $pscount -ge 4 ]; then + return $OCF_SUCCESS; + elif [ $pscount -ge 1 ]; then +- return $OCF_GENERIC_ERR ++ return $OCF_ERR_GENERIC + fi + return $OCF_NOT_RUNNING + } +@@ -767,7 +767,7 @@ db2_promote() { + # must take over + ;; + +- STANDBY/PEER/DISCONNECTED|Standby/DisconnectedPeer) ++ STANDBY/PEER/DISCONNECTED|STANDBY/DISCONNECTED_PEER/DISCONNECTED|Standby/DisconnectedPeer) + # must take over forced + force="by force peer window only" + ;; diff --git a/SOURCES/bz1516435-azure-lb.patch b/SOURCES/bz1516435-azure-lb.patch new file mode 100644 index 00000000..354a65e4 --- /dev/null +++ b/SOURCES/bz1516435-azure-lb.patch @@ -0,0 +1,255 @@ +From 771b49a128100a986ee6508c998f296162f7c197 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Wed, 29 Nov 2017 15:09:06 +0100 +Subject: [PATCH] azure-lb: new resource agent + +--- + doc/man/Makefile.am | 1 + + heartbeat/Makefile.am | 1 + + heartbeat/azure-lb | 213 ++++++++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 215 insertions(+) + create mode 100755 heartbeat/azure-lb + +diff --git a/doc/man/Makefile.am b/doc/man/Makefile.am +index 03cdc8867..e3abdb5b7 100644 +--- a/doc/man/Makefile.am ++++ b/doc/man/Makefile.am +@@ -100,6 +100,7 @@ man_MANS = ocf_heartbeat_AoEtarget.7 \ + ocf_heartbeat_aws-vpc-move-ip.7 \ + ocf_heartbeat_awseip.7 \ + ocf_heartbeat_awsvip.7 \ ++ ocf_heartbeat_azure-lb.7 \ + ocf_heartbeat_clvm.7 \ + ocf_heartbeat_conntrackd.7 \ + ocf_heartbeat_db2.7 \ +diff --git a/heartbeat/Makefile.am b/heartbeat/Makefile.am +index 1fde5e905..1e441b9c1 100644 +--- a/heartbeat/Makefile.am ++++ b/heartbeat/Makefile.am +@@ -97,6 +97,7 @@ ocf_SCRIPTS = ClusterMon \ + aws-vpc-move-ip \ + awseip \ + awsvip \ ++ azure-lb \ + nginx \ + AudibleAlarm \ + clvm \ +diff --git a/heartbeat/azure-lb b/heartbeat/azure-lb +new file mode 100755 +index 000000000..f41e83c6d +--- /dev/null ++++ b/heartbeat/azure-lb +@@ -0,0 +1,213 @@ ++#!/bin/sh ++# ++ ++# License: GNU General Public License (GPL) ++# (c) 2017 O. Albrigtsen ++# and Linux-HA contributors ++# ++# ----------------------------------------------------------------------------- ++# O C F R E S O U R C E S C R I P T S P E C I F I C A T I O N ++# ----------------------------------------------------------------------------- ++# ++# NAME ++# azure-lb : OCF resource agent script for Azure Load Balancer ++# ++# Initialization: ++: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat} ++. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs ++ ++# Defaults ++OCF_RESKEY_nc_default="/usr/bin/nc" ++OCF_RESKEY_port_default="61000" ++ ++: ${OCF_RESKEY_nc=${OCF_RESKEY_nc_default}} ++: ${OCF_RESKEY_port=${OCF_RESKEY_port_default}} ++ ++process="$OCF_RESOURCE_INSTANCE" ++pidfile="/var/run/$OCF_RESOURCE_INSTANCE.pid" ++ ++ ++lb_usage() { ++ cat < ++ ++ ++1.0 ++ ++Resource agent to answer Azure Load Balancer health probe requests ++ ++Answers Azure Load Balancer health probe requests ++ ++ ++ ++ ++ ++The full name of the nc binary. ++ ++Full path name of the nc binary ++ ++ ++ ++ ++ ++Port to listen to. ++ ++Listen to port ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++END ++exit 0 ++} ++ ++getpid() { ++ grep -o '[0-9]*' $1 ++} ++ ++lb_monitor() { ++ if test -f "$pidfile"; then ++ if pid=`getpid $pidfile` && [ "$pid" ] && kill -s 0 $pid; then ++ return $OCF_SUCCESS ++ else ++ # pidfile w/o process means the process died ++ return $OCF_ERR_GENERIC ++ fi ++ else ++ return $OCF_NOT_RUNNING ++ fi ++} ++ ++lb_start() { ++ cmd="$OCF_RESKEY_nc -l -k $OCF_RESKEY_port" ++ if ! lb_monitor; then ++ ocf_log debug "Starting $process: $cmd" ++ # Execute the command as created above ++ eval "$cmd & echo \$!" > $pidfile ++ if lb_monitor; then ++ ocf_log debug "$process: $cmd started successfully, calling monitor" ++ lb_monitor ++ return $? ++ else ++ ocf_log err "$process: $cmd could not be started" ++ return $OCF_ERR_GENERIC ++ fi ++ else ++ # If already running, consider start successful ++ ocf_log debug "$process: $cmd is already running" ++ return $OCF_SUCCESS ++ fi ++} ++ ++lb_stop() { ++ local rc=$OCF_SUCCESS ++ ++ if [ -n "$OCF_RESKEY_CRM_meta_timeout" ]; then ++ # Allow 2/3 of the action timeout for the orderly shutdown ++ # (The origin unit is ms, hence the conversion) ++ stop_timeout=$((OCF_RESKEY_CRM_meta_timeout/1500)) ++ else ++ stop_timeout=10 ++ fi ++ ++ if lb_monitor; then ++ pid=`getpid $pidfile` ++ kill $pid ++ ++ i=0 ++ while [ $i -lt $stop_timeout ]; do ++ if ! lb_monitor; then ++ rm -f $pidfile ++ return $OCF_SUCCESS ++ fi ++ sleep 1 ++ i=$((i+1)) ++ done ++ ++ ocf_log warn "Stop with SIGTERM failed/timed out, now sending SIGKILL." ++ kill -s 9 $pid ++ while :; do ++ if ! lb_monitor; then ++ ocf_log warn "SIGKILL did the job." ++ rc=$OCF_SUCCESS ++ break ++ fi ++ ocf_log info "The job still hasn't stopped yet. Waiting..." ++ sleep 1 ++ done ++ fi ++ rm -f $pidfile ++ return $rc ++} ++ ++lb_validate() { ++ check_binary "$OCF_RESKEY_nc" ++ ++ if ! ocf_is_decimal "$OCF_RESKEY_port"; then ++ ocf_exit_reason "$OCF_RESKEY_port is not a valid port" ++ exit $OCF_ERR_CONFIGURED ++ fi ++ ++ return $OCF_SUCCESS ++} ++ ++############################################################################### ++# ++# MAIN ++# ++############################################################################### ++ ++case $__OCF_ACTION in ++ meta-data) ++ lb_metadata ++ exit $OCF_SUCCESS ++ ;; ++ usage|help) ++ lb_usage ++ exit $OCF_SUCCESS ++ ;; ++esac ++ ++if ! ocf_is_root; then ++ ocf_log err "You must be root for $__OCF_ACTION operation." ++ exit $OCF_ERR_PERM ++fi ++ ++case $__OCF_ACTION in ++ start) ++ lb_validate ++ lb_start;; ++ stop) ++ lb_stop;; ++ monitor) ++ lb_monitor;; ++ validate-all) ++ lb_validate;; ++ *) ++ echo $USAGE ++ exit $OCF_ERR_UNIMPLEMENTED ++ ;; ++esac ++ ++exit $? diff --git a/SOURCES/bz1520574-ocf_attribute_target-fallback-fix.patch b/SOURCES/bz1520574-ocf_attribute_target-fallback-fix.patch new file mode 100644 index 00000000..7225e55c --- /dev/null +++ b/SOURCES/bz1520574-ocf_attribute_target-fallback-fix.patch @@ -0,0 +1,35 @@ +From f0a7a64d644c604f84ec1668849e1cc5507a8ea8 Mon Sep 17 00:00:00 2001 +From: Damien Ciabrini +Date: Tue, 5 Dec 2017 10:43:10 +0100 +Subject: [PATCH] Fix fallback name for ocf_attribute_target + +For bundles, various resource agents now use ocf_attribute_target to +get the name of the pacemaker node to store attributes on. + +If a recent version of the resource agent is being run on a pacemaker +version which does not support bundles, ocf_attribute_target will +return an empty string as hostname. + +Provide a fallback path so the resource agent gets a valid name when +the resource is not containerized. +--- + heartbeat/ocf-shellfuncs.in | 6 +++++- + 1 file changed, 5 insertions(+), 1 deletion(-) + +diff --git a/heartbeat/ocf-shellfuncs.in b/heartbeat/ocf-shellfuncs.in +index ddd6854e9..2fa6f93f9 100644 +--- a/heartbeat/ocf-shellfuncs.in ++++ b/heartbeat/ocf-shellfuncs.in +@@ -1010,7 +1010,11 @@ ocf_attribute_target() { + if [ x$OCF_RESKEY_CRM_meta_container_attribute_target = xhost -a x$OCF_RESKEY_CRM_meta_physical_host != x ]; then + echo $OCF_RESKEY_CRM_meta_physical_host + else +- echo $OCF_RESKEY_CRM_meta_on_node ++ if [ x$OCF_RESKEY_CRM_meta_on_node != x ]; then ++ echo $OCF_RESKEY_CRM_meta_on_node ++ else ++ ocf_local_nodename ++ fi + fi + return + elif [ x"$OCF_RESKEY_CRM_meta_notify_all_uname" != x ]; then diff --git a/SOURCES/bz1523953-CTDB-detect-new-config-path.patch b/SOURCES/bz1523953-CTDB-detect-new-config-path.patch new file mode 100644 index 00000000..536b9eab --- /dev/null +++ b/SOURCES/bz1523953-CTDB-detect-new-config-path.patch @@ -0,0 +1,24 @@ +From 522328ba28d2e362bf09a7b771ca32206d2dfb02 Mon Sep 17 00:00:00 2001 +From: pablomh +Date: Fri, 8 Dec 2017 19:39:12 +0100 +Subject: [PATCH] Add new possible location for CTDB_SYSCONFIG + +When upgrading from Red Hat 7.3 to 7.4 the script stated that the location of the +configuration file had moved from /etc/sysconfig/ctdb to /etc/ctdb/ctdbd.conf. +--- + heartbeat/CTDB | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/heartbeat/CTDB b/heartbeat/CTDB +index 09f5ecf5f..1ee228e8b 100755 +--- a/heartbeat/CTDB ++++ b/heartbeat/CTDB +@@ -361,6 +361,8 @@ elif [ -f /etc/default/ctdb ]; then + CTDB_SYSCONFIG=/etc/default/ctdb + elif [ -f "$OCF_RESKEY_ctdb_config_dir/ctdb" ]; then + CTDB_SYSCONFIG=$OCF_RESKEY_ctdb_config_dir/ctdb ++elif [ -f "$OCF_RESKEY_ctdb_config_dir/ctdbd.conf" ]; then ++ CTDB_SYSCONFIG=$OCF_RESKEY_ctdb_config_dir/ctdbd.conf + fi + + # Backup paths diff --git a/SOURCES/bz1533168-NovaEvacuate-add-support-for-keystone-v3-authentication.patch b/SOURCES/bz1533168-NovaEvacuate-add-support-for-keystone-v3-authentication.patch new file mode 100644 index 00000000..43ad9fe2 --- /dev/null +++ b/SOURCES/bz1533168-NovaEvacuate-add-support-for-keystone-v3-authentication.patch @@ -0,0 +1,55 @@ +From 121ec00c8ea0f2e8b0c6336bd78fcb58b0bd490c Mon Sep 17 00:00:00 2001 +From: Andrew Beekhof +Date: Mon, 27 Nov 2017 13:35:18 +1100 +Subject: [PATCH] NovaEvacuate: Additional parameters for v3 keywstone + authentication + +Change-Id: I22d2733b17e5a6098b66c4644879b2e1255dbff5 +--- + heartbeat/NovaEvacuate | 26 +++++++++++++++++++++++++- + 1 file changed, 25 insertions(+), 1 deletion(-) + +diff --git a/heartbeat/NovaEvacuate b/heartbeat/NovaEvacuate +index b6dadce..ba19ca4 100644 +--- a/heartbeat/NovaEvacuate ++++ b/heartbeat/NovaEvacuate +@@ -65,7 +65,23 @@ Password for connecting to keystone in admin context + Tenant name for connecting to keystone in admin context. + Note that with Keystone V3 tenant names are only unique within a domain. + +-Tenant name ++Keystone v2 Tenant or v3 Project Name ++ ++ ++ ++ ++ ++User's domain name. Used when authenticating to Keystone. ++ ++Keystone v3 User Domain ++ ++ ++ ++ ++ ++Domain name containing project. Used when authenticating to Keystone. ++ ++Keystone v3 Project Domain + + + +@@ -289,6 +305,14 @@ evacuate_validate() { + + fence_options="${fence_options} -t ${OCF_RESKEY_tenant_name}" + ++ if [ -n "${OCF_RESKEY_user_domain}" ]; then ++ fence_options="${fence_options} -u ${OCF_RESKEY_user_domain}" ++ fi ++ ++ if [ -n "${OCF_RESKEY_project_domain}" ]; then ++ fence_options="${fence_options} -P ${OCF_RESKEY_project_domain}" ++ fi ++ + if [ -n "${OCF_RESKEY_region_name}" ]; then + fence_options="${fence_options} \ + --region-name ${OCF_RESKEY_region_name}" diff --git a/SOURCES/bz1536548-sap_redhat_cluster_connector-fix-unknown-gvi-function.patch b/SOURCES/bz1536548-sap_redhat_cluster_connector-fix-unknown-gvi-function.patch new file mode 100644 index 00000000..b661edcc --- /dev/null +++ b/SOURCES/bz1536548-sap_redhat_cluster_connector-fix-unknown-gvi-function.patch @@ -0,0 +1,106 @@ +diff -uNr a/sap_redhat_cluster_connector-6353d27/sap_redhat_cluster_connector b/sap_redhat_cluster_connector-6353d27/sap_redhat_cluster_connector +--- a/sap_redhat_cluster_connector-6353d27/sap_redhat_cluster_connector 2018-01-23 10:15:48.167424070 +0100 ++++ b/sap_redhat_cluster_connector-6353d27/sap_redhat_cluster_connector 2018-01-22 10:19:06.001422855 +0100 +@@ -41,6 +41,11 @@ + my $logident = "sap_redhat_cluster_connector"; + my $logoptions = "pid"; + my $logfacility = "LOG_USER"; ++my $protocolVersion=1; ++my $haProd="RHEL HA add-on"; ++my $haProdSAP="sap_redhat_cluster_connector"; ++my $haProdDoc="https://access.redhat.com/solutions/963123"; ++ + # + # open syslog + # +@@ -54,9 +59,10 @@ + where cmd could be: + help + init +- cpa --res RES --act ACT +- lsr --out FILE --sid SID --ino INO | --dbhost HOST --dbtype TYPE ++ gvi --out FILE ++ cpa --res RES --act ACT + fra --res RES --act ACT [ --nod NODE ] ++ lsr --out FILE --sid SID --ino INO | --dbhost HOST --dbtype TYPE + lsn --out FILE --res RES + "; + } +@@ -110,7 +116,7 @@ + + sub fire_resource_action { + my ($rsc, $act, $nod) = ("", "", ""); +- ($rsc, $act, $nod) = @_; ++ my ($rsc, $act, $nod) = @_; + my $rc=0; + my $sysconfig = "/etc/sysconfig/sap_redhat_cluster_connector"; + $nowstring = localtime; +@@ -349,10 +355,6 @@ + printf "%s : lsn()\n", $nowstring; + # TODO: check implemented action + ############################################################################################### +- ############################################################################################### +- ############################################################################################### +- ############################################################################################### +- ############################################################################################### + # + # 1. GET HOSTNAME WHERE FUNCTION WAS CALLED + # +@@ -452,6 +454,26 @@ + return $rc; + } + ++sub get_version_info($) ++{ ++ my ($outfile, $resource) = @_; ++ my $rc=0; ++ $nowstring = localtime; ++ printf "%s : gvi()\n", $nowstring; ++ if ( $outfile ne "" ) { ++ #HASCRIPTCO-VERS ++ ##HAPROD ++ ##HAPROD-SAP ++ ##HAPROD-DOC ++ open OUTFILE, ">$outfile"; ++ syslog("LOG_INFO", "gvi result: %s\n%s\n%s\n%s\n", $protocolVersion, $haProd, $haProdSAP, $haProdDoc); ++ printf OUTFILE "%s\n%s\n%s\n%s\n", $protocolVersion, $haProd, $haProdSAP, $haProdDoc; ++ close OUTFILE; ++ } else { ++ printf "%s\n%s\n%s\n%s\n", $protocolVersion, $haProd, $haProdSAP, $haProdDoc; ++ } ++ return $rc; ++} + + # + # "main" +@@ -492,7 +514,6 @@ + syslog("LOG_INFO", "lsr call (out=%s,sid=%s,ino=%s)", $out, $sid, $ino); + $return_code=list_sap_resources($out, $sid, $ino); + +- + } elsif ( $cmd eq "fra" ) { + open($DEBUG, ">>$logident" . ".log"); + *STDOUT=*$DEBUG; +@@ -518,6 +539,14 @@ + syslog("LOG_INFO", "lsn call (out=%s,res=%s)", $out, $res); + $return_code=list_sap_nodes($out, $res); + ++ } elsif ( $cmd eq "gvi" ) { ++ open($DEBUG, ">>$logident" . ".log"); ++ *STDOUT=*$DEBUG; ++ $result = GetOptions ("out=s" => \$out, ++ ) && ++ checkavail(($out)) || paramproblem(); ++ syslog("LOG_INFO", "gvi call (out=%s)", $out); ++ $return_code=get_version_info($out); + + } else { + open($DEBUG, ">>$logident" . ".log"); +@@ -530,7 +559,6 @@ + paramproblem() + } + +- syslog("LOG_INFO", "TEST END"); + closelog(); + exit $return_code; + # diff --git a/SOURCES/bz1543366-redis-add-support-for-tunneling-replication-traffic.patch b/SOURCES/bz1543366-redis-add-support-for-tunneling-replication-traffic.patch new file mode 100644 index 00000000..fa118957 --- /dev/null +++ b/SOURCES/bz1543366-redis-add-support-for-tunneling-replication-traffic.patch @@ -0,0 +1,160 @@ +From 273963331bd303f595e820ca6da17cd63f5514db Mon Sep 17 00:00:00 2001 +From: Damien Ciabrini +Date: Sat, 2 Dec 2017 11:53:56 +0100 +Subject: [PATCH] redis: add support for tunneling replication traffic + +Add parameters in the resource agent to assign specific redis port to +each pacemaker node. When redis slave wants to connect to a redis +master, it will instead connect to a tunnel host, on the port assigned +to the targeted redis master. + +This makes it possible for redis replication traffic to go through +pre-existing tunnels. This can be used to encrypt such traffic. +--- + heartbeat/redis | 89 +++++++++++++++++++++++++++++++++++++++++++++++++++++++-- + 1 file changed, 86 insertions(+), 3 deletions(-) + +diff --git a/heartbeat/redis b/heartbeat/redis +index fcd8c234..d9e29e2c 100755 +--- a/heartbeat/redis ++++ b/heartbeat/redis +@@ -38,6 +38,7 @@ + : ${OCF_RESKEY_pidfile_name:=redis-server.pid} + : ${OCF_RESKEY_socket_name:=redis.sock} + : ${OCF_RESKEY_port:=6379} ++: ${OCF_RESKEY_tunnel_host:=127.0.0.1} + + if [ -z "$OCF_RESKEY_config" ]; then + if [ -f "/etc/redis.conf" ]; then +@@ -156,6 +157,39 @@ Port for replication client to connect to on remote server + + + ++ ++ ++When replication traffic is tunnelled, this is the host to target ++to forward outgoing traffic to the redis master. The resource ++agent configures the redis slave to target the master via ++tunnel_host:tunnel_port. ++ ++Note that in order to enable replication traffic tunneling, ++parameter {tunnel_port_map} must be populated. ++ ++Tunnel host for replication traffic ++ ++ ++ ++ ++ ++A mapping of pacemaker node names to redis port number. ++ ++To be used when redis servers need to tunnel replication traffic. ++On every node where the redis resource is running, the redis server ++listens to a different port. Each redis server can access its peers ++for replication traffic via a tunnel accessible at {tunnel_host}:port. ++ ++The mapping the form of: ++pcmk1-name:port-for-redis1;pcmk2-name:port-for-redis2;pcmk3-name:port-for-redis3 ++ ++where the redis resource started on node pcmk1-name would listen on ++port port-for-redis1 ++ ++Mapping of Redis server name to redis port ++ ++ ++ + + + During redis cluster bootstrap, wait for the last known master to be +@@ -291,6 +325,8 @@ simple_status() { + + function monitor() { + local res ++ local master_name ++ local last_known_master_port + + simple_status + res=$? +@@ -334,14 +370,48 @@ redis_monitor() { + return $OCF_ERR_GENERIC + fi + if [[ "${info[master_host]}" != "$(last_known_master)" ]]; then +- ocf_log err "monitor: Slave mode current master does not match running master. current=${info[master_host]}, running=$(last_known_master)" +- return $OCF_ERR_GENERIC ++ if [ -n "${OCF_RESKEY_tunnel_port_map}" ]; then ++ master_name=$(port_to_redis_node ${info[master_port]}) ++ last_known_master_port=$(redis_node_to_port $(last_known_master)) ++ if [[ "${info[master_host]}" != "${OCF_RESKEY_tunnel_host}" ]] || ++ [[ "${info[master_port]}" != "${last_known_master_port}" ]]; then ++ ocf_log err "monitor: Slave mode current tunnelled connection to redis server does not match running master. tunnelled='${info[master_host]}:${info[master_port]} (${master_name})', running='$(last_known_master)'" ++ return $OCF_ERR_GENERIC ++ fi ++ else ++ ocf_log err "monitor: Slave mode current master does not match running master. current=${info[master_host]}, running=$(last_known_master)" ++ return $OCF_ERR_GENERIC ++ fi + fi + fi + fi + return $OCF_SUCCESS + } + ++redis_node_to_port() ++{ ++ local node=$1 ++ echo "$OCF_RESKEY_tunnel_port_map" | tr ';' '\n' | tr -d ' ' | sed 's/:/ /' | awk -F' ' '$1=="'"$node"'" {print $2;exit}' ++} ++ ++port_to_redis_node() ++{ ++ local port=$1 ++ echo "$OCF_RESKEY_tunnel_port_map" | tr ';' '\n' | tr -d ' ' | sed 's/:/ /' | awk -F' ' '$2=="'"$port"'" {print $1;exit}' ++} ++ ++get_tunnel_port_from_master() ++{ ++ local master_name=$1 ++ crm_attribute --node "$master_name" -l forever --name ${INSTANCE_ATTR_NAME}-tunnel-port --query -q 2>/dev/null ++} ++ ++get_master_from_tunnel_port() ++{ ++ local master_name=$1 ++ crm_attribute --node "$master_name" -l forever --name ${INSTANCE_ATTR_NAME}-tunnel-port --query -q 2>/dev/null ++} ++ + function check_dump_file() + { + if ! have_binary "$REDIS_CHECK_DUMP"; then +@@ -479,6 +549,7 @@ redis_promote() { + function demote() { + local master_host + local master_port ++ local tunnel_port + + # client kill is only supported in Redis 2.8.12 or greater + version=$(redis_client -v | awk '{print $NF}') +@@ -512,7 +583,19 @@ redis_demote() { + master_host="no-such-master" + fi + +- ocf_log info "demote: Setting master to '$master_host'" ++ if [ -n "${OCF_RESKEY_tunnel_port_map}" ]; then ++ # master_host can be the special marker "no-such-master" ++ # while a master is being selected. In this case, no ++ # tunnel port is returned, but this is not fatal. ++ tunnel_port=$(redis_node_to_port "$master_host") ++ if [ -n "$tunnel_port" ]; then ++ ocf_log info "demote: Setting master to '$master_host' via local tunnel '${OCF_RESKEY_tunnel_host}' on port '$tunnel_port'" ++ master_host="${OCF_RESKEY_tunnel_host}" ++ master_port="$tunnel_port" ++ fi ++ else ++ ocf_log info "demote: Setting master to '$master_host'" ++ fi + + redis_client slaveof "$master_host" "$master_port" + +-- +2.14.3 + diff --git a/SOURCES/bz1546083-galera-fix-temp-logfile-rights.patch b/SOURCES/bz1546083-galera-fix-temp-logfile-rights.patch new file mode 100644 index 00000000..dd5090ef --- /dev/null +++ b/SOURCES/bz1546083-galera-fix-temp-logfile-rights.patch @@ -0,0 +1,28 @@ +From 2754db9d03995e944a53e364f304bc7b0b24d75d Mon Sep 17 00:00:00 2001 +From: Damien Ciabrini +Date: Thu, 2 Mar 2017 18:41:50 +0100 +Subject: [PATCH] galera: fix permission of temporary log file for mariadb + 10.1.21+ + +Since MariaDB/server@8fcdd6b0ecbb966f4479856efe93a963a7a422f7, +mysqld_safe relies on a helper subprocess to write into log files. +This new logging mechanism expects log file to be writable by the +user configured to run mysqld. + +Fix the generation of temporary log file accordingly. +--- + heartbeat/galera | 1 + + 1 file changed, 1 insertion(+) + +diff --git a/heartbeat/galera b/heartbeat/galera +index 0cab9a464..decbaa257 100755 +--- a/heartbeat/galera ++++ b/heartbeat/galera +@@ -520,6 +520,7 @@ detect_last_commit() + last_commit="$(cat ${OCF_RESKEY_datadir}/grastate.dat | sed -n 's/^seqno.\s*\(.*\)\s*$/\1/p')" + if [ -z "$last_commit" ] || [ "$last_commit" = "-1" ]; then + local tmp=$(mktemp) ++ chown $OCF_RESKEY_user:$OCF_RESKEY_group $tmp + + # if we pass here because grastate.dat doesn't exist, + # try not to bootstrap from this node if possible diff --git a/SOURCES/bz773395-clvm-autoset-locking-type.patch b/SOURCES/bz773395-clvm-autoset-locking-type.patch new file mode 100644 index 00000000..c1ef716c --- /dev/null +++ b/SOURCES/bz773395-clvm-autoset-locking-type.patch @@ -0,0 +1,41 @@ +From 22203b45ef3c3a66512c60f2a2381cf5e490abf6 Mon Sep 17 00:00:00 2001 +From: David Vossel +Date: Mon, 4 Aug 2014 17:23:47 -0400 +Subject: [PATCH] High: clvm: automatically set lvm.conf's locking_type=3 + +lvm comes with a cli tool we can use to set/unset the +locking type. When clvmd is in use, it is safe to assume +that locking_type=3 (clustered locking) should be in use. +Otherwise there would be no reason to run the clvmd to begin +with. +--- + heartbeat/clvm | 6 ++++++ + 1 file changed, 6 insertions(+) + +diff --git a/heartbeat/clvm b/heartbeat/clvm +index 3e7701d..20bb40c 100644 +--- a/heartbeat/clvm ++++ b/heartbeat/clvm +@@ -86,6 +86,7 @@ DAEMON="clvmd" + CMIRROR="cmirrord" + DAEMON_PATH="${sbindir}/clvmd" + CMIRROR_PATH="${sbindir}/cmirrord" ++LVMCONF="${sbindir}/lvmconf" + LOCK_FILE="/var/lock/subsys/$DAEMON" + LVM_VGCHANGE=${sbindir}/vgchange + LVM_VGDISPLAY=${sbindir}/vgdisplay +@@ -342,6 +343,11 @@ clvmd_start() + return $?; + fi + ++ # autoset locking type to clusted when lvmconf tool is available ++ if [ -x "$LVMCONF" ]; then ++ $LVMCONF --enable-cluster > /dev/null 2>&1 ++ fi ++ + # if either of these fail, script will exit OCF_ERR_GENERIC + if ocf_is_true $OCF_RESKEY_with_cmirrord; then + start_process $CMIRROR_PATH +-- +1.8.4.2 + diff --git a/SOURCES/bz773399-netmast-error.patch b/SOURCES/bz773399-netmast-error.patch new file mode 100644 index 00000000..42ea2332 --- /dev/null +++ b/SOURCES/bz773399-netmast-error.patch @@ -0,0 +1,105 @@ +diff --git a/heartbeat/IPaddr2 b/heartbeat/IPaddr2 +index 2791ea0..74bdef1 100755 +--- a/heartbeat/IPaddr2 ++++ b/heartbeat/IPaddr2 +@@ -446,7 +446,7 @@ ip_init() { + ocf_log warn "[$FINDIF] failed" + exit $OCF_SUCCESS + else +- ocf_exit_reason "[$FINDIF] failed" ++ ocf_log err "[$FINDIF] failed" + exit $rc + fi + fi +diff --git a/heartbeat/findif.sh b/heartbeat/findif.sh +index 98649bf..6250a03 100644 +--- a/heartbeat/findif.sh ++++ b/heartbeat/findif.sh +@@ -75,26 +75,26 @@ findif_check_params() + if [ "$family" = "inet6" ] ; then + ipcheck_ipv6 $match + if [ $? = 1 ] ; then +- ocf_log err "IP address [$match] not valid." ++ ocf_exit_reason "IP address [$match] not valid." + return $OCF_ERR_CONFIGURED + fi + if [ -n "$nic" ] ; then + ifcheck_ipv6 $nic + if [ $? = 1 ] ; then +- ocf_log err "Unknown interface [$nic] No such device." ++ ocf_exit_reason "Unknown interface [$nic] No such device." + return $OCF_ERR_CONFIGURED + fi + else + echo $match | grep -qis '^fe80::' + if [ $? = 0 ] ; then +- ocf_log err "'nic' parameter is mandatory for a link local address [$match]." ++ ocf_exit_reason "'nic' parameter is mandatory for a link local address [$match]." + return $OCF_ERR_CONFIGURED + fi + fi + if [ -n "$netmask" ] ; then + prefixcheck $netmask 128 + if [ $? = 1 ] ; then +- ocf_log err "Invalid netmask specification [$netmask]." ++ ocf_exit_reason "Invalid netmask specification [$netmask]." + return $OCF_ERR_CONFIGURED + fi + fi +@@ -102,27 +102,27 @@ findif_check_params() + # family = inet + ipcheck_ipv4 $match + if [ $? = 1 ] ; then +- ocf_log err "IP address [$match] not valid." ++ ocf_exit_reason "IP address [$match] not valid." + return $OCF_ERR_CONFIGURED + fi + if [ -n "$nic" ] ; then + ifcheck_ipv4 $nic + if [ $? = 1 ] ; then +- ocf_log err "Unknown interface [$nic] No such device." ++ ocf_exit_reason "Unknown interface [$nic] No such device." + return $OCF_ERR_CONFIGURED + fi + fi + if [ -n "$netmask" ] ; then + prefixcheck $netmask 32 + if [ $? = 1 ] ; then +- ocf_log err "Invalid netmask specification [$netmask]." ++ ocf_exit_reason "Invalid netmask specification [$netmask]." + return $OCF_ERR_CONFIGURED + fi + fi + if [ -n "$brdcast" ] ; then + ipcheck_ipv4 $brdcast + if [ $? = 1 ] ; then +- ocf_log err "Invalid broadcast address [$brdcast]." ++ ocf_exit_reason "Invalid broadcast address [$brdcast]." + return $OCF_ERR_CONFIGURED + fi + fi +@@ -166,13 +166,13 @@ findif() + fi + if [ -z "$nic" -o -z "$netmask" ] ; then + if [ $# = 0 ] ; then +- ocf_log err "Unable to find nic or netmask." ++ ocf_exit_reason "Unable to find nic or netmask." + return $OCF_ERR_GENERIC + fi + case $1 in + */*) : OK ;; + *) +- ocf_log err "Unable to find cidr_netmask." ++ ocf_exit_reason "Unable to find cidr_netmask." + return $OCF_ERR_GENERIC ;; + esac + fi +@@ -187,7 +187,7 @@ findif() + fi + else + if [ -z "$OCF_RESKEY_nic" -a "$netmask" != "${1#*/}" ] ; then +- ocf_log err "Unable to find nic, or netmask mismatch." ++ ocf_exit_reason "Unable to find nic, or netmask mismatch." + return $OCF_ERR_GENERIC + fi + fi diff --git a/SOURCES/bz799065-apache-simple-monitor.patch b/SOURCES/bz799065-apache-simple-monitor.patch new file mode 100644 index 00000000..8bccd70b --- /dev/null +++ b/SOURCES/bz799065-apache-simple-monitor.patch @@ -0,0 +1,118 @@ +From d2b7ff7208a7ad65cc8298eef4c4d32549c31d7b Mon Sep 17 00:00:00 2001 +From: David Vossel +Date: Tue, 10 Sep 2013 21:16:40 -0500 +Subject: [PATCH] Low: apache: Allow basic server request monitoring without + requiring server-status to be enabled + +By default, the apache agent attempts to detect the location +of the server-status url and retrieve the contents of that URL. +If no regex is set, all this agent does is verify some sort +of html file exists at the server-status url. Essentially in +the default use-case, the agent is just verifying that the agent +can successfully request something from the webserver. + +Requiring the user to enable the server-status feature +just to verify a request/response from the server shouldn't be +necessary. This patch allows the agent to fall back to +doing a basic http header request of the website's index +if the server-status check fails during a monitor... This will +only occur in the very basic use-case where a user has +not defined any statusurls, regex patterns, or custom test cases. +--- + heartbeat/apache | 54 ++++++++++++++++++++++++++++++++++++++++++++++----- + heartbeat/http-mon.sh | 9 +++++++++ + 2 files changed, 58 insertions(+), 5 deletions(-) + +diff --git a/heartbeat/apache b/heartbeat/apache +index 1369804..fac2a53 100755 +--- a/heartbeat/apache ++++ b/heartbeat/apache +@@ -308,16 +308,60 @@ apache_monitor_10() { + return $OCF_ERR_GENERIC + fi + } ++ ++# If the user has not provided any basic monitoring ++# information, allow the agent to verify the server is ++# healthy and capable of processing requests by requesting ++# the http header of website's index ++attempt_index_monitor_request() { ++ local indexpage="" ++ ++ if [ -n "$OCF_RESKEY_client" ]; then ++ if [ "$OCF_RESKEY_client" != "curl" ]; then ++ return 1; ++ fi ++ fi ++ if [ -n "$OCF_RESKEY_testregex" ]; then ++ return 1; ++ fi ++ if [ -n "$OCF_RESKEY_testregex10" ]; then ++ return 1; ++ fi ++ if [ -n "$OCF_RESKEY_testurl" ]; then ++ return 1; ++ fi ++ if [ -n "$OCF_RESKEY_statusurl" ]; then ++ return 1; ++ fi ++ if [ -n "$OCF_RESKEY_testconffile" ]; then ++ return 1; ++ fi ++ ++ indexpage=$(buildlocalurl) ++ ++ request_url_header $indexpage > /dev/null 2>&1 ++ if [ $? -ne 0 ]; then ++ return $OCF_ERR_GENERIC ++ fi ++ ocf_log info "Successfully retrieved http header at $indexpage" ++ return 0 ++} ++ + apache_monitor_basic() { + if ${ourhttpclient}_func "$STATUSURL" | grep -Ei "$TESTREGEX" > /dev/null + then + return $OCF_SUCCESS +- else +- if ! ocf_is_probe; then +- ocf_log err "Failed to access httpd status page." +- fi +- return $OCF_ERR_GENERIC + fi ++ ++ attempt_index_monitor_request ++ if [ $? -eq 0 ]; then ++ return $OCF_SUCCESS ++ fi ++ ++ if ! ocf_is_probe; then ++ ocf_log err "Failed to access httpd status page." ++ fi ++ return $OCF_ERR_GENERIC + } + apache_monitor() { + silent_status +diff --git a/heartbeat/http-mon.sh b/heartbeat/http-mon.sh +index d7b6182..fac19ef 100644 +--- a/heartbeat/http-mon.sh ++++ b/heartbeat/http-mon.sh +@@ -24,6 +24,15 @@ fi + WGETOPTS="-O- -q -L --no-proxy --bind-address=$bind_address" + CURLOPTS="-o - -Ss -L --interface lo $curl_ipv6_opts" + ++request_url_header() { ++ which curl >/dev/null 2>&1 ++ if [ $? -ne 0 ]; then ++ return 1 ++ fi ++ ++ curl -IL --connect-timeout 5 --interface lo $curl_ipv6_opts "$1" ++} ++ + # + # run the http client + # +-- +1.8.1 + diff --git a/SOURCES/bz884164-multi-lib-fixes.patch b/SOURCES/bz884164-multi-lib-fixes.patch new file mode 100644 index 00000000..e33710b3 --- /dev/null +++ b/SOURCES/bz884164-multi-lib-fixes.patch @@ -0,0 +1,53 @@ +diff --git a/heartbeat/Makefile.am b/heartbeat/Makefile.am +index 3a05974..777c6b1 100644 +--- a/heartbeat/Makefile.am ++++ b/heartbeat/Makefile.am +@@ -25,7 +25,7 @@ EXTRA_DIST = $(ocf_SCRIPTS) $(ocfcommon_DATA) \ + + INCLUDES = -I$(top_srcdir)/include -I$(top_srcdir)/linux-ha + +-halibdir = $(libdir)/heartbeat ++halibdir = $(libexecdir)/heartbeat + + ocfdir = $(OCF_RA_DIR_PREFIX)/heartbeat + +diff --git a/heartbeat/ocf-directories.in b/heartbeat/ocf-directories.in +index 26004a3..6e0a9d5 100644 +--- a/heartbeat/ocf-directories.in ++++ b/heartbeat/ocf-directories.in +@@ -11,7 +11,7 @@ exec_prefix=@exec_prefix@ + : ${HA_RSCTMP:=@HA_RSCTMPDIR@} + : ${HA_RSCTMP_OLD:=@HA_VARRUNDIR@/heartbeat/rsctmp} + : ${HA_FIFO:=@localstatedir@/lib/heartbeat/fifo} +-: ${HA_BIN:=@libdir@/heartbeat} ++: ${HA_BIN:=@libexecdir@/heartbeat} + : ${HA_SBIN_DIR:=@sbindir@} + : ${HA_DATEFMT:="%Y/%m/%d_%T "} + : ${HA_DEBUGLOG:=/dev/null} +diff --git a/resource-agents.spec.in b/resource-agents.spec.in +index c306398..e9f0688 100644 +--- a/resource-agents.spec.in ++++ b/resource-agents.spec.in +@@ -255,7 +255,7 @@ rm -rf %{buildroot} + %dir %{_sysconfdir}/ha.d + %{_sysconfdir}/ha.d/shellfuncs + +-%{_libdir}/heartbeat ++%{_libexecdir}/heartbeat + + %post -n resource-agents + if [ $1 = 2 ]; then +diff --git a/tools/Makefile.am b/tools/Makefile.am +index 971db1c..3205bbd 100644 +--- a/tools/Makefile.am ++++ b/tools/Makefile.am +@@ -23,7 +23,7 @@ SUBDIRS = ocft + + INCLUDES = -I$(top_builddir)/include -I$(top_srcdir)/include + +-halibdir = $(libdir)/heartbeat ++halibdir = $(libexecdir)/heartbeat + + EXTRA_DIST = ocf-tester.8 sfex_init.8 + + diff --git a/SOURCES/bz917681-VirtualDomain-heartbeat-updates.patch b/SOURCES/bz917681-VirtualDomain-heartbeat-updates.patch new file mode 100644 index 00000000..522cb868 --- /dev/null +++ b/SOURCES/bz917681-VirtualDomain-heartbeat-updates.patch @@ -0,0 +1,247 @@ +diff --git a/heartbeat/VirtualDomain b/heartbeat/VirtualDomain +index 50c1eaa..6582a16 100755 +--- a/heartbeat/VirtualDomain ++++ b/heartbeat/VirtualDomain +@@ -18,13 +18,11 @@ + + # Defaults + OCF_RESKEY_force_stop_default=0 +-OCF_RESKEY_hypervisor_default="$(virsh --quiet uri)" + OCF_RESKEY_autoset_utilization_cpu_default="true" + OCF_RESKEY_autoset_utilization_hv_memory_default="true" + OCF_RESKEY_migrateport_default=$(( 49152 + $(ocf_maybe_random) % 64 )) + + : ${OCF_RESKEY_force_stop=${OCF_RESKEY_force_stop_default}} +-: ${OCF_RESKEY_hypervisor=${OCF_RESKEY_hypervisor_default}} + : ${OCF_RESKEY_autoset_utilization_cpu=${OCF_RESKEY_autoset_utilization_cpu_default}} + : ${OCF_RESKEY_autoset_utilization_hv_memory=${OCF_RESKEY_autoset_utilization_hv_memory_default}} + : ${OCF_RESKEY_migrateport=${OCF_RESKEY_migrateport_default}} +@@ -67,9 +65,10 @@ for this virtual domain. + + Hypervisor URI to connect to. See the libvirt documentation for + details on supported URI formats. The default is system dependent. ++Determine your systems default uri by running 'virsh --quiet uri' + + Hypervisor URI +- ++ + + + +@@ -206,52 +205,18 @@ update_utilization() { + # Set options to be passed to virsh: + VIRSH_OPTIONS="--connect=${OCF_RESKEY_hypervisor} --quiet" + +-# A state file where we record the domain name: +-STATEFILE="${HA_RSCTMP}/VirtualDomain-${OCF_RESOURCE_INSTANCE}.state" +- +-VirtualDomain_Define() { +- local virsh_output +- local domain_name +- # Note: passing in the domain name from outside the script is +- # intended for testing and debugging purposes only. Don't do this +- # in production, instead let the script figure out the domain name +- # from the config file. You have been warned. +- if [ -z "$DOMAIN_NAME" ]; then +- # Spin until we have a domain name +- while true; do +- virsh_output=$( (virsh ${VIRSH_OPTIONS} define ${OCF_RESKEY_config}) 2>&1) +- domain_name=`echo "$virsh_output" | sed -n -e 's/Domain \(.*\) defined from .*$/\1/p'` +- if [ -n "$domain_name" ]; then +- break; +- fi +- domain_name=`echo $virsh_output | sed -n -e "s/.* '\(.*\)' already exists .*/\1/p"` +- if [ -n "$domain_name" ]; then +- break; +- fi +- ocf_log debug "Domain not defined yet, probably unable to connect to hypervisor. Retrying." +- sleep 1 +- done +- echo "$domain_name" > $STATEFILE +- ocf_log info "Domain name \"$domain_name\" saved to $STATEFILE." +- else +- ocf_log warn "Domain name ${DOMAIN_NAME} already defined, overriding configuration file ${OCF_RESKEY_config}. You should do this for testing only." +- fi +-} +- +-VirtualDomain_Cleanup_Statefile() { +- rm -f $STATEFILE || ocf_log warn "Failed to remove $STATEFILE during $__OCF_ACTION." +-} +- + VirtualDomain_Status() { + local try=0 + rc=$OCF_ERR_GENERIC + status="no state" + while [ "$status" = "no state" ]; do + try=$(($try + 1 )) +- status="`virsh $VIRSH_OPTIONS domstate $DOMAIN_NAME`" ++ status="`virsh $VIRSH_OPTIONS domstate $DOMAIN_NAME 2>&1`" + case "$status" in +- "shut off") +- # shut off: domain is defined, but not started ++ *"error:"*"Domain not found"*|"shut off") ++ # shut off: domain is defined, but not started, will not happen if ++ # domain is created but not defined ++ # Domain not found: domain is not defined and thus not started + ocf_log debug "Virtual domain $DOMAIN_NAME is currently $status." + rc=$OCF_NOT_RUNNING + ;; +@@ -264,7 +229,7 @@ VirtualDomain_Status() { + ocf_log debug "Virtual domain $DOMAIN_NAME is currently $status." + rc=$OCF_SUCCESS + ;; +- ""|"no state") ++ ""|*"Failed to reconnect to the hypervisor"*|"no state") + # Empty string may be returned when virsh does not + # receive a reply from libvirtd. + # "no state" may occur when the domain is currently +@@ -314,7 +279,7 @@ VirtualDomain_Start() { + return $OCF_ERR_GENERIC + fi + +- virsh $VIRSH_OPTIONS start ${DOMAIN_NAME} ++ virsh $VIRSH_OPTIONS create ${OCF_RESKEY_config} + rc=$? + if [ $rc -ne 0 ]; then + ocf_log error "Failed to start virtual domain ${DOMAIN_NAME}." +@@ -327,11 +292,33 @@ VirtualDomain_Start() { + return $OCF_SUCCESS + } + ++force_stop() ++{ ++ local out ex ++ local status ++ ++ ocf_log info "Issuing forced shutdown (destroy) request for domain ${DOMAIN_NAME}." ++ out=$(virsh $VIRSH_OPTIONS destroy ${DOMAIN_NAME} 2>&1) ++ ex=$? ++ echo >&2 "$out" ++ case $ex$out in ++ *"error:"*"domain is not running"*|*"error:"*"Domain not found"*) ++ : ;; # unexpected path to the intended outcome, all is well ++ [!0]*) ++ return $OCF_ERR_GENERIC ;; ++ 0*) ++ while [ $status != $OCF_NOT_RUNNING ]; do ++ VirtualDomain_Status ++ status=$? ++ done ;; ++ esac ++ return $OCF_SUCCESS ++} ++ + VirtualDomain_Stop() { + local i + local status + local shutdown_timeout +- local out ex + local needshutdown=1 + + VirtualDomain_Status +@@ -341,7 +328,8 @@ VirtualDomain_Stop() { + $OCF_SUCCESS) + if ocf_is_true $OCF_RESKEY_force_stop; then + # if force stop, don't bother attempting graceful shutdown. +- break; ++ force_stop ++ return $? + fi + + ocf_log info "Issuing graceful shutdown request for domain ${DOMAIN_NAME}." +@@ -370,9 +358,7 @@ VirtualDomain_Stop() { + status=$? + case $status in + $OCF_NOT_RUNNING) +- # This was a graceful shutdown. Clean +- # up and return. +- VirtualDomain_Cleanup_Statefile ++ # This was a graceful shutdown. + return $OCF_SUCCESS + ;; + $OCF_SUCCESS) +@@ -393,27 +379,11 @@ VirtualDomain_Stop() { + ocf_log info "Domain $DOMAIN_NAME already stopped." + return $OCF_SUCCESS + esac ++ + # OK. Now if the above graceful shutdown hasn't worked, kill + # off the domain with destroy. If that too does not work, + # have the LRM time us out. +- ocf_log info "Issuing forced shutdown (destroy) request for domain ${DOMAIN_NAME}." +- out=$(virsh $VIRSH_OPTIONS destroy ${DOMAIN_NAME} 2>&1) +- ex=$? +- echo >&2 "$out" +- # unconditionally clean up. +- VirtualDomain_Cleanup_Statefile +- case $ex$out in +- *"error:"*"domain is not running"*) +- : ;; # unexpected path to the intended outcome, all is well +- [!0]*) +- return $OCF_ERR_GENERIC ;; +- 0*) +- while [ $status != $OCF_NOT_RUNNING ]; do +- VirtualDomain_Status +- status=$? +- done ;; +- esac +- return $OCF_SUCCESS ++ force_stop + } + + VirtualDomain_Migrate_To() { +@@ -469,7 +439,6 @@ VirtualDomain_Migrate_To() { + return $OCF_ERR_GENERIC + else + ocf_log info "$DOMAIN_NAME: live migration to ${target_node} succeeded." +- VirtualDomain_Cleanup_Statefile + return $OCF_SUCCESS + fi + else +@@ -561,12 +530,15 @@ case $1 in + ;; + esac + ++OCF_RESKEY_hypervisor_default="$(virsh --quiet uri)" ++: ${OCF_RESKEY_hypervisor=${OCF_RESKEY_hypervisor_default}} ++ + # Everything except usage and meta-data must pass the validate test + VirtualDomain_Validate_All || exit $? + + # During a probe, it is permissible for the config file to not be + # readable (it might be on shared storage not available during the +-# probe). In that case, VirtualDomain_Define can't work and we're ++# probe). In that case, we're + # unable to get the domain name. Thus, we also can't check whether the + # domain is running. The only thing we can do here is to assume that + # it is not running. +@@ -575,21 +547,10 @@ if [ ! -r $OCF_RESKEY_config ]; then + [ "$__OCF_ACTION" = "stop" ] && exit $OCF_SUCCESS + fi + +-# Define the domain on startup, and re-define whenever someone deleted +-# the state file, or touched the config. +-if [ ! -e $STATEFILE ] || [ $OCF_RESKEY_config -nt $STATEFILE ]; then +- VirtualDomain_Define +-fi +-# By now, we should definitely be able to read from the state file. +-# If not, something went wrong. +-if [ ! -r $STATEFILE ]; then +- ocf_log err "$STATEFILE not found or unreadable. This is unexpected. Cannot determine domain name." +- exit $OCF_ERR_GENERIC +-fi +-# Finally, retrieve the domain name from the state file. +-DOMAIN_NAME=`cat $STATEFILE 2>/dev/null` ++# Retrieve the domain name from the xml file. ++DOMAIN_NAME=`egrep '.*.*$' ${OCF_RESKEY_config} | sed -e 's/.*\(.*\)<\/name>$/\1/' 2>/dev/null` + if [ -z $DOMAIN_NAME ]; then +- ocf_log err "$STATEFILE is empty. This is unexpected. Cannot determine domain name." ++ ocf_log err "This is unexpected. Cannot determine domain name." + exit $OCF_ERR_GENERIC + fi + +@@ -620,3 +581,4 @@ case $1 in + ;; + esac + exit $? ++ diff --git a/SOURCES/bz917681-VirtualDomain-heartbeat-updates_v2.patch b/SOURCES/bz917681-VirtualDomain-heartbeat-updates_v2.patch new file mode 100644 index 00000000..e4bf6ac0 --- /dev/null +++ b/SOURCES/bz917681-VirtualDomain-heartbeat-updates_v2.patch @@ -0,0 +1,36 @@ +From 34994edfb713cfda496b31ce9da3f893960caa1c Mon Sep 17 00:00:00 2001 +From: David Vossel +Date: Mon, 7 Oct 2013 19:33:42 -0500 +Subject: [PATCH] High: VirtualDomain: Fix ability to use default libvirt hypervisor without explicitly setting agent attribute + +--- + heartbeat/VirtualDomain | 6 +++--- + 1 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/heartbeat/VirtualDomain b/heartbeat/VirtualDomain +index 04b4390..f7ed100 100755 +--- a/heartbeat/VirtualDomain ++++ b/heartbeat/VirtualDomain +@@ -202,9 +202,6 @@ update_utilization() { + fi + } + +-# Set options to be passed to virsh: +-VIRSH_OPTIONS="--connect=${OCF_RESKEY_hypervisor} --quiet" +- + VirtualDomain_Status() { + local try=0 + rc=$OCF_ERR_GENERIC +@@ -533,6 +530,9 @@ esac + OCF_RESKEY_hypervisor_default="$(virsh --quiet uri)" + : ${OCF_RESKEY_hypervisor=${OCF_RESKEY_hypervisor_default}} + ++# Set options to be passed to virsh: ++VIRSH_OPTIONS="--connect=${OCF_RESKEY_hypervisor} --quiet" ++ + # Everything except usage and meta-data must pass the validate test + VirtualDomain_Validate_All || exit $? + +-- +1.7.1 + diff --git a/SOURCES/bz917681-ipv6-send_ua-fix.patch b/SOURCES/bz917681-ipv6-send_ua-fix.patch new file mode 100644 index 00000000..eb99bb6e --- /dev/null +++ b/SOURCES/bz917681-ipv6-send_ua-fix.patch @@ -0,0 +1,743 @@ +From 72d9c7dbb01afb26faf141fbec17e2af70ea729c Mon Sep 17 00:00:00 2001 +From: David Vossel +Date: Mon, 4 Nov 2013 15:03:23 -0600 +Subject: [PATCH] High: IPv6addr: Split send_ua utility out of IPv6addr.c source so it can be re-used in IPaddr2 without requiring cluster-glue. + +--- + configure.ac | 3 +- + doc/man/Makefile.am | 2 +- + heartbeat/IPv6addr.c | 198 +++----------------------------------------- + heartbeat/IPv6addr_utils.c | 147 ++++++++++++++++++++++++++++++++ + heartbeat/Makefile.am | 14 ++- + heartbeat/send_ua.c | 127 ++++++++++++++++++++++++++++ + include/IPv6addr.h | 58 +++++++++++++ + include/Makefile.am | 2 +- + 8 files changed, 356 insertions(+), 195 deletions(-) + create mode 100644 heartbeat/IPv6addr_utils.c + create mode 100644 heartbeat/send_ua.c + create mode 100644 include/IPv6addr.h + +diff --git a/configure.ac b/configure.ac +index f88a20f..ac669d8 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -714,7 +714,8 @@ AM_CONDITIONAL(USE_LIBNET, test "x$libnet_version" != "xnone" ) + dnl ************************************************************************ + dnl * Check for netinet/icmp6.h to enable the IPv6addr resource agent + AC_CHECK_HEADERS(netinet/icmp6.h,[],[],[#include ]) +-AM_CONDITIONAL(USE_IPV6ADDR, test "$ac_cv_header_netinet_icmp6_h" = yes && test "$ac_cv_header_heartbeat_glue_config_h" = yes) ++AM_CONDITIONAL(USE_IPV6ADDR_AGENT, test "$ac_cv_header_netinet_icmp6_h" = yes && test "$ac_cv_header_heartbeat_glue_config_h" = yes) ++AM_CONDITIONAL(IPV6ADDR_COMPATIBLE, test "$ac_cv_header_netinet_icmp6_h" = yes) + + dnl ======================================================================== + dnl Compiler flags +diff --git a/doc/man/Makefile.am b/doc/man/Makefile.am +index 347c145..3bf569a 100644 +--- a/doc/man/Makefile.am ++++ b/doc/man/Makefile.am +@@ -134,7 +134,7 @@ man_MANS = ocf_heartbeat_AoEtarget.7 \ + ocf_heartbeat_vmware.7 \ + ocf_heartbeat_zabbixserver.7 + +-if USE_IPV6ADDR ++if USE_IPV6ADDR_AGENT + man_MANS += ocf_heartbeat_IPv6addr.7 + endif + +diff --git a/heartbeat/IPv6addr.c b/heartbeat/IPv6addr.c +index fab59f5..7c1d20d 100644 +--- a/heartbeat/IPv6addr.c ++++ b/heartbeat/IPv6addr.c +@@ -86,6 +86,7 @@ + */ + + #include ++#include + + #include + #include +@@ -134,9 +135,7 @@ + #define OCF_ERR_CONFIGURED 6 + #define OCF_NOT_RUNNING 7 + +-const char* IF_INET6 = "/proc/net/if_inet6"; + const char* APP_NAME = "IPv6addr"; +-const char* APP_NAME_SUA = "send_ua"; + + const char* START_CMD = "start"; + const char* STOP_CMD = "stop"; +@@ -148,12 +147,8 @@ const char* RELOAD_CMD = "reload"; + const char* META_DATA_CMD = "meta-data"; + const char* VALIDATE_CMD = "validate-all"; + +-char BCAST_ADDR[] = "ff02::1"; +-const int UA_REPEAT_COUNT = 5; + const int QUERY_COUNT = 5; + +-#define HWADDR_LEN 6 /* mac address length */ +- + struct in6_ifreq { + struct in6_addr ifr6_addr; + uint32_t ifr6_prefixlen; +@@ -169,7 +164,6 @@ static int meta_data_addr6(void); + + + static void usage(const char* self); +-static void usage_send_ua(const char* self); + int write_pid_file(const char *pid_file); + int create_pid_directory(const char *pid_file); + static void byebye(int nsig); +@@ -181,7 +175,6 @@ static char* get_if(struct in6_addr* addr_target, int* plen_target, char* prov_i + static int assign_addr6(struct in6_addr* addr6, int prefix_len, char* if_name); + static int unassign_addr6(struct in6_addr* addr6, int prefix_len, char* if_name); + int is_addr6_available(struct in6_addr* addr6); +-static int send_ua(struct in6_addr* src_ip, char* if_name); + + int + main(int argc, char* argv[]) +@@ -190,40 +183,11 @@ main(int argc, char* argv[]) + char* ipv6addr; + char* cidr_netmask; + int ret; +- int count = UA_REPEAT_COUNT; +- int interval = 1000; /* default 1000 msec */ +- int senduaflg = 0; +- int ch; +- int i; + char* cp; + char* prov_ifname = NULL; + int prefix_len = -1; + struct in6_addr addr6; + +- /* Check binary name */ +- if (strcmp(basename(argv[0]), APP_NAME_SUA) == 0) { +- senduaflg = 1; +- if (argc < 4) { +- usage_send_ua(argv[0]); +- return OCF_ERR_ARGS; +- } +- while ((ch = getopt(argc, argv, "h?c:i:")) != EOF) { +- switch(ch) { +- case 'c': /* count option */ +- count = atoi(optarg); +- break; +- case 'i': /* interval option */ +- interval = atoi(optarg); +- break; +- case 'h': +- case '?': +- default: +- usage_send_ua(argv[0]); +- return OCF_ERR_ARGS; +- } +- } +- } +- + /* Check the count of parameters first */ + if (argc < 2) { + usage(argv[0]); +@@ -235,11 +199,7 @@ main(int argc, char* argv[]) + signal(SIGTERM, byebye); + + /* open system log */ +- if (senduaflg) { +- cl_log_set_entity(APP_NAME_SUA); +- } else { +- cl_log_set_entity(APP_NAME); +- } ++ cl_log_set_entity(APP_NAME); + cl_log_set_facility(LOG_DAEMON); + + /* the meta-data dont need any parameter */ +@@ -248,12 +208,9 @@ main(int argc, char* argv[]) + return OCF_SUCCESS; + } + +- if (senduaflg) { +- ipv6addr = argv[optind]; +- } else { +- /* check the OCF_RESKEY_ipv6addr parameter, should be an IPv6 address */ +- ipv6addr = getenv("OCF_RESKEY_ipv6addr"); +- } ++ /* check the OCF_RESKEY_ipv6addr parameter, should be an IPv6 address */ ++ ipv6addr = getenv("OCF_RESKEY_ipv6addr"); ++ + if (ipv6addr == NULL) { + cl_log(LOG_ERR, "Please set OCF_RESKEY_ipv6addr to the IPv6 address you want to manage."); + usage(argv[0]); +@@ -271,12 +228,9 @@ main(int argc, char* argv[]) + *cp=0; + } + +- if (senduaflg) { +- cidr_netmask = argv[optind+1]; +- } else { +- /* get provided netmask (optional) */ +- cidr_netmask = getenv("OCF_RESKEY_cidr_netmask"); +- } ++ /* get provided netmask (optional) */ ++ cidr_netmask = getenv("OCF_RESKEY_cidr_netmask"); ++ + if (cidr_netmask != NULL) { + if ((atol(cidr_netmask) < 0) || (atol(cidr_netmask) > 128)) { + cl_log(LOG_ERR, "Invalid prefix_len [%s], " +@@ -294,12 +248,9 @@ main(int argc, char* argv[]) + prefix_len = 0; + } + +- if (senduaflg) { +- prov_ifname = argv[optind+2]; +- } else { +- /* get provided interface name (optional) */ +- prov_ifname = getenv("OCF_RESKEY_nic"); +- } ++ /* get provided interface name (optional) */ ++ prov_ifname = getenv("OCF_RESKEY_nic"); ++ + if (inet_pton(AF_INET6, ipv6addr, &addr6) <= 0) { + cl_log(LOG_ERR, "Invalid IPv6 address [%s]", ipv6addr); + usage(argv[0]); +@@ -312,15 +263,6 @@ main(int argc, char* argv[]) + return OCF_ERR_GENERIC; + } + +- if (senduaflg) { +- /* Send unsolicited advertisement packet to neighbor */ +- for (i = 0; i < count; i++) { +- send_ua(&addr6, prov_ifname); +- usleep(interval * 1000); +- } +- return OCF_SUCCESS; +- } +- + /* create the pid file so we can make sure that only one IPv6addr + * for this address is running + */ +@@ -467,118 +409,6 @@ monitor_addr6(struct in6_addr* addr6, int prefix_len) + return OCF_NOT_RUNNING; + } + +-/* Send an unsolicited advertisement packet +- * Please refer to rfc4861 / rfc3542 +- */ +-int +-send_ua(struct in6_addr* src_ip, char* if_name) +-{ +- int status = -1; +- int fd; +- +- int ifindex; +- int hop; +- struct ifreq ifr; +- u_int8_t *payload = NULL; +- int payload_size; +- struct nd_neighbor_advert *na; +- struct nd_opt_hdr *opt; +- struct sockaddr_in6 src_sin6; +- struct sockaddr_in6 dst_sin6; +- +- if ((fd = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) == -1) { +- cl_log(LOG_ERR, "socket(IPPROTO_ICMPV6) failed: %s", +- strerror(errno)); +- return status; +- } +- /* set the outgoing interface */ +- ifindex = if_nametoindex(if_name); +- if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, +- &ifindex, sizeof(ifindex)) < 0) { +- cl_log(LOG_ERR, "setsockopt(IPV6_MULTICAST_IF) failed: %s", +- strerror(errno)); +- goto err; +- } +- /* set the hop limit */ +- hop = 255; /* 255 is required. see rfc4861 7.1.2 */ +- if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, +- &hop, sizeof(hop)) < 0) { +- cl_log(LOG_ERR, "setsockopt(IPV6_MULTICAST_HOPS) failed: %s", +- strerror(errno)); +- goto err; +- } +- +- /* set the source address */ +- memset(&src_sin6, 0, sizeof(src_sin6)); +- src_sin6.sin6_family = AF_INET6; +- src_sin6.sin6_addr = *src_ip; +- src_sin6.sin6_port = 0; +- if (IN6_IS_ADDR_LINKLOCAL(&src_sin6.sin6_addr) || +- IN6_IS_ADDR_MC_LINKLOCAL(&src_sin6.sin6_addr)) { +- src_sin6.sin6_scope_id = ifindex; +- } +- +- if (bind(fd, (struct sockaddr *)&src_sin6, sizeof(src_sin6)) < 0) { +- cl_log(LOG_ERR, "bind() failed: %s", strerror(errno)); +- goto err; +- } +- +- +- /* get the hardware address */ +- memset(&ifr, 0, sizeof(ifr)); +- strncpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name) - 1); +- if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) { +- cl_log(LOG_ERR, "ioctl(SIOCGIFHWADDR) failed: %s", strerror(errno)); +- goto err; +- } +- +- /* build a neighbor advertisement message */ +- payload_size = sizeof(struct nd_neighbor_advert) +- + sizeof(struct nd_opt_hdr) + HWADDR_LEN; +- payload = memalign(sysconf(_SC_PAGESIZE), payload_size); +- if (!payload) { +- cl_log(LOG_ERR, "malloc for payload failed"); +- goto err; +- } +- memset(payload, 0, payload_size); +- +- /* Ugly typecast from ia64 hell! */ +- na = (struct nd_neighbor_advert *)((void *)payload); +- na->nd_na_type = ND_NEIGHBOR_ADVERT; +- na->nd_na_code = 0; +- na->nd_na_cksum = 0; /* calculated by kernel */ +- na->nd_na_flags_reserved = ND_NA_FLAG_OVERRIDE; +- na->nd_na_target = *src_ip; +- +- /* options field; set the target link-layer address */ +- opt = (struct nd_opt_hdr *)(payload + sizeof(struct nd_neighbor_advert)); +- opt->nd_opt_type = ND_OPT_TARGET_LINKADDR; +- opt->nd_opt_len = 1; /* The length of the option in units of 8 octets */ +- memcpy(payload + sizeof(struct nd_neighbor_advert) +- + sizeof(struct nd_opt_hdr), +- &ifr.ifr_hwaddr.sa_data, HWADDR_LEN); +- +- /* sending an unsolicited neighbor advertisement to all */ +- memset(&dst_sin6, 0, sizeof(dst_sin6)); +- dst_sin6.sin6_family = AF_INET6; +- inet_pton(AF_INET6, BCAST_ADDR, &dst_sin6.sin6_addr); /* should not fail */ +- +- if (sendto(fd, payload, payload_size, 0, +- (struct sockaddr *)&dst_sin6, sizeof(dst_sin6)) +- != payload_size) { +- cl_log(LOG_ERR, "sendto(%s) failed: %s", +- if_name, strerror(errno)); +- goto err; +- } +- +- status = 0; +- +-err: +- close(fd); +- free(payload); +- return status; +-} +- + /* find the network interface associated with an address */ + char* + scan_if(struct in6_addr* addr_target, int* plen_target, int use_mask, char* prov_ifname) +@@ -822,12 +652,6 @@ static void usage(const char* self) + return; + } + +-static void usage_send_ua(const char* self) +-{ +- printf("usage: %s [-i[=Interval]] [-c[=Count]] [-h] IPv6-Address Prefix Interface\n",self); +- return; +-} +- + /* Following code is copied from send_arp.c, linux-HA project. */ + void + byebye(int nsig) +diff --git a/heartbeat/IPv6addr_utils.c b/heartbeat/IPv6addr_utils.c +new file mode 100644 +index 0000000..7672b70 +--- /dev/null ++++ b/heartbeat/IPv6addr_utils.c +@@ -0,0 +1,147 @@ ++ ++/* ++ * This program manages IPv6 address with OCF Resource Agent standard. ++ * ++ * Author: Huang Zhen ++ * Copyright (c) 2004 International Business Machines ++ * ++ * This library 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 ++ * of the License, or (at your option) any later version. ++ * ++ * This library 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 program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ */ ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include /* for inet_pton */ ++#include /* for if_nametoindex */ ++#include ++#include ++#include ++#include ++ ++/* Send an unsolicited advertisement packet ++ * Please refer to rfc4861 / rfc3542 ++ */ ++int ++send_ua(struct in6_addr* src_ip, char* if_name) ++{ ++ int status = -1; ++ int fd; ++ ++ int ifindex; ++ int hop; ++ struct ifreq ifr; ++ u_int8_t *payload = NULL; ++ int payload_size; ++ struct nd_neighbor_advert *na; ++ struct nd_opt_hdr *opt; ++ struct sockaddr_in6 src_sin6; ++ struct sockaddr_in6 dst_sin6; ++ ++ if ((fd = socket(AF_INET6, SOCK_RAW, IPPROTO_ICMPV6)) == -1) { ++ printf("ERROR: socket(IPPROTO_ICMPV6) failed: %s", ++ strerror(errno)); ++ return status; ++ } ++ /* set the outgoing interface */ ++ ifindex = if_nametoindex(if_name); ++ if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_IF, ++ &ifindex, sizeof(ifindex)) < 0) { ++ printf("ERROR: setsockopt(IPV6_MULTICAST_IF) failed: %s", ++ strerror(errno)); ++ goto err; ++ } ++ /* set the hop limit */ ++ hop = 255; /* 255 is required. see rfc4861 7.1.2 */ ++ if (setsockopt(fd, IPPROTO_IPV6, IPV6_MULTICAST_HOPS, ++ &hop, sizeof(hop)) < 0) { ++ printf("ERROR: setsockopt(IPV6_MULTICAST_HOPS) failed: %s", ++ strerror(errno)); ++ goto err; ++ } ++ ++ /* set the source address */ ++ memset(&src_sin6, 0, sizeof(src_sin6)); ++ src_sin6.sin6_family = AF_INET6; ++ src_sin6.sin6_addr = *src_ip; ++ src_sin6.sin6_port = 0; ++ if (IN6_IS_ADDR_LINKLOCAL(&src_sin6.sin6_addr) || ++ IN6_IS_ADDR_MC_LINKLOCAL(&src_sin6.sin6_addr)) { ++ src_sin6.sin6_scope_id = ifindex; ++ } ++ ++ if (bind(fd, (struct sockaddr *)&src_sin6, sizeof(src_sin6)) < 0) { ++ printf("ERROR: bind() failed: %s", strerror(errno)); ++ goto err; ++ } ++ ++ ++ /* get the hardware address */ ++ memset(&ifr, 0, sizeof(ifr)); ++ strncpy(ifr.ifr_name, if_name, sizeof(ifr.ifr_name) - 1); ++ if (ioctl(fd, SIOCGIFHWADDR, &ifr) < 0) { ++ printf("ERROR: ioctl(SIOCGIFHWADDR) failed: %s", strerror(errno)); ++ goto err; ++ } ++ ++ /* build a neighbor advertisement message */ ++ payload_size = sizeof(struct nd_neighbor_advert) ++ + sizeof(struct nd_opt_hdr) + HWADDR_LEN; ++ payload = memalign(sysconf(_SC_PAGESIZE), payload_size); ++ if (!payload) { ++ printf("ERROR: malloc for payload failed"); ++ goto err; ++ } ++ memset(payload, 0, payload_size); ++ ++ /* Ugly typecast from ia64 hell! */ ++ na = (struct nd_neighbor_advert *)((void *)payload); ++ na->nd_na_type = ND_NEIGHBOR_ADVERT; ++ na->nd_na_code = 0; ++ na->nd_na_cksum = 0; /* calculated by kernel */ ++ na->nd_na_flags_reserved = ND_NA_FLAG_OVERRIDE; ++ na->nd_na_target = *src_ip; ++ ++ /* options field; set the target link-layer address */ ++ opt = (struct nd_opt_hdr *)(payload + sizeof(struct nd_neighbor_advert)); ++ opt->nd_opt_type = ND_OPT_TARGET_LINKADDR; ++ opt->nd_opt_len = 1; /* The length of the option in units of 8 octets */ ++ memcpy(payload + sizeof(struct nd_neighbor_advert) ++ + sizeof(struct nd_opt_hdr), ++ &ifr.ifr_hwaddr.sa_data, HWADDR_LEN); ++ ++ /* sending an unsolicited neighbor advertisement to all */ ++ memset(&dst_sin6, 0, sizeof(dst_sin6)); ++ dst_sin6.sin6_family = AF_INET6; ++ inet_pton(AF_INET6, BCAST_ADDR, &dst_sin6.sin6_addr); /* should not fail */ ++ ++ if (sendto(fd, payload, payload_size, 0, ++ (struct sockaddr *)&dst_sin6, sizeof(dst_sin6)) ++ != payload_size) { ++ printf("ERROR: sendto(%s) failed: %s", ++ if_name, strerror(errno)); ++ goto err; ++ } ++ ++ status = 0; ++ ++err: ++ close(fd); ++ free(payload); ++ return status; ++} +diff --git a/heartbeat/Makefile.am b/heartbeat/Makefile.am +index 0ce1c13..3393640 100644 +--- a/heartbeat/Makefile.am ++++ b/heartbeat/Makefile.am +@@ -32,19 +32,23 @@ ocfdir = $(OCF_RA_DIR_PREFIX)/heartbeat + dtddir = $(datadir)/$(PACKAGE_NAME) + dtd_DATA = ra-api-1.dtd + +-if USE_IPV6ADDR ++if USE_IPV6ADDR_AGENT + ocf_PROGRAMS = IPv6addr +-halib_PROGRAMS = send_ua + else + ocf_PROGRAMS = ++endif ++ ++if IPV6ADDR_COMPATIBLE ++halib_PROGRAMS = send_ua ++else + halib_PROGRAMS = + endif + +-IPv6addr_SOURCES = IPv6addr.c +-send_ua_SOURCES = IPv6addr.c ++IPv6addr_SOURCES = IPv6addr.c IPv6addr_utils.c ++send_ua_SOURCES = send_ua.c IPv6addr_utils.c + + IPv6addr_LDADD = -lplumb $(LIBNETLIBS) +-send_ua_LDADD = -lplumb $(LIBNETLIBS) ++send_ua_LDADD = $(LIBNETLIBS) + + ocf_SCRIPTS = ClusterMon \ + CTDB \ +diff --git a/heartbeat/send_ua.c b/heartbeat/send_ua.c +new file mode 100644 +index 0000000..ef5357b +--- /dev/null ++++ b/heartbeat/send_ua.c +@@ -0,0 +1,127 @@ ++ ++/* ++ * This program manages IPv6 address with OCF Resource Agent standard. ++ * ++ * Author: Huang Zhen ++ * Copyright (c) 2004 International Business Machines ++ * ++ * This library 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 ++ * of the License, or (at your option) any later version. ++ * ++ * This library 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 program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ */ ++ ++#include ++ ++#include ++#include ++#include ++#include ++#include ++#include /* for inet_pton */ ++#include /* for if_nametoindex */ ++#include ++#include ++#include ++#include ++ ++static void usage_send_ua(const char* self); ++static void byebye(int nsig); ++ ++int ++main(int argc, char* argv[]) ++{ ++ char* ipv6addr; ++ int count = UA_REPEAT_COUNT; ++ int interval = 1000; /* default 1000 msec */ ++ int ch; ++ int i; ++ char* cp; ++ char* prov_ifname = NULL; ++ struct in6_addr addr6; ++ ++ /* Check binary name */ ++ if (argc < 4) { ++ usage_send_ua(argv[0]); ++ return OCF_ERR_ARGS; ++ } ++ while ((ch = getopt(argc, argv, "h?c:i:")) != EOF) { ++ switch(ch) { ++ case 'c': /* count option */ ++ count = atoi(optarg); ++ break; ++ case 'i': /* interval option */ ++ interval = atoi(optarg); ++ break; ++ case 'h': ++ case '?': ++ default: ++ usage_send_ua(argv[0]); ++ return OCF_ERR_ARGS; ++ } ++ } ++ ++ /* set termination signal */ ++ siginterrupt(SIGTERM, 1); ++ signal(SIGTERM, byebye); ++ ++ ipv6addr = argv[optind]; ++ ++ if (ipv6addr == NULL) { ++ printf("ERROR: Please set OCF_RESKEY_ipv6addr to the IPv6 address you want to manage."); ++ usage_send_ua(argv[0]); ++ return OCF_ERR_ARGS; ++ } ++ ++ /* legacy option */ ++ if ((cp = strchr(ipv6addr, '/'))) { ++ *cp=0; ++ } ++ ++ prov_ifname = argv[optind+2]; ++ ++ if (inet_pton(AF_INET6, ipv6addr, &addr6) <= 0) { ++ printf("ERROR: Invalid IPv6 address [%s]", ipv6addr); ++ usage_send_ua(argv[0]); ++ return OCF_ERR_ARGS; ++ } ++ ++ /* Check whether this system supports IPv6 */ ++ if (access(IF_INET6, R_OK)) { ++ printf("ERROR: No support for INET6 on this system."); ++ return OCF_ERR_GENERIC; ++ } ++ ++ /* Send unsolicited advertisement packet to neighbor */ ++ for (i = 0; i < count; i++) { ++ send_ua(&addr6, prov_ifname); ++ usleep(interval * 1000); ++ } ++ ++ return OCF_SUCCESS; ++} ++ ++static void usage_send_ua(const char* self) ++{ ++ printf("usage: %s [-i[=Interval]] [-c[=Count]] [-h] IPv6-Address Prefix Interface\n",self); ++ return; ++} ++ ++/* Following code is copied from send_arp.c, linux-HA project. */ ++void ++byebye(int nsig) ++{ ++ (void)nsig; ++ /* Avoid an "error exit" log message if we're killed */ ++ exit(0); ++} ++ +diff --git a/include/IPv6addr.h b/include/IPv6addr.h +new file mode 100644 +index 0000000..720edf9 +--- /dev/null ++++ b/include/IPv6addr.h +@@ -0,0 +1,58 @@ ++/* ++ * This program manages IPv6 address with OCF Resource Agent standard. ++ * ++ * Author: Huang Zhen ++ * Copyright (c) 2004 International Business Machines ++ * ++ * This library 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 ++ * of the License, or (at your option) any later version. ++ * ++ * This library 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 program; if not, write to the Free Software ++ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ++ */ ++ ++#ifndef OCF_IPV6_HELPER_H ++#define OCF_IPV6_HELPER_H ++#include ++#include ++/* ++0 No error, action succeeded completely ++1 generic or unspecified error (current practice) ++ The "monitor" operation shall return this for a crashed, hung or ++ otherwise non-functional resource. ++2 invalid or excess argument(s) ++ Likely error code for validate-all, if the instance parameters ++ do not validate. Any other action is free to also return this ++ exit status code for this case. ++3 unimplemented feature (for example, "reload") ++4 user had insufficient privilege ++5 program is not installed ++6 program is not configured ++7 program is not running ++8 resource is running in "master" mode and fully operational ++9 resource is in "master" mode but in a failed state ++*/ ++#define OCF_SUCCESS 0 ++#define OCF_ERR_GENERIC 1 ++#define OCF_ERR_ARGS 2 ++#define OCF_ERR_UNIMPLEMENTED 3 ++#define OCF_ERR_PERM 4 ++#define OCF_ERR_INSTALLED 5 ++#define OCF_ERR_CONFIGURED 6 ++#define OCF_NOT_RUNNING 7 ++ ++#define HWADDR_LEN 6 /* mac address length */ ++#define UA_REPEAT_COUNT 5 ++#define BCAST_ADDR "ff02::1" ++#define IF_INET6 "/proc/net/if_inet6" ++ ++int send_ua(struct in6_addr* src_ip, char* if_name); ++#endif +diff --git a/include/Makefile.am b/include/Makefile.am +index 5381ce0..6f46ec3 100644 +--- a/include/Makefile.am ++++ b/include/Makefile.am +@@ -21,4 +21,4 @@ MAINTAINERCLEANFILES = Makefile.in config.h.in config.h.in~ + idir=$(includedir)/heartbeat + i_HEADERS = agent_config.h + +-noinst_HEADERS = config.h ++noinst_HEADERS = config.h IPv6addr.h +-- +1.7.1 + diff --git a/SOURCES/bz917681-ocft_fedora_supported_test_cases.patch b/SOURCES/bz917681-ocft_fedora_supported_test_cases.patch new file mode 100644 index 00000000..4a5c648a --- /dev/null +++ b/SOURCES/bz917681-ocft_fedora_supported_test_cases.patch @@ -0,0 +1,7215 @@ +From 01587177c39423763f0ad7bbcc55adf22685d706 Mon Sep 17 00:00:00 2001 +From: David Vossel +Date: Wed, 6 Nov 2013 16:39:06 -0600 +Subject: [PATCH] fedora ocft + +--- + configure.ac | 9 + + tools/ocft/Filesystem | 110 -------------- + tools/ocft/IPaddr2 | 127 ---------------- + tools/ocft/IPaddr2v4 | 323 ---------------------------------------- + tools/ocft/IPaddr2v6 | 250 ------------------------------- + tools/ocft/IPsrcaddr | 63 -------- + tools/ocft/IPv6addr | 150 ------------------- + tools/ocft/LVM | 86 ----------- + tools/ocft/MailTo | 57 ------- + tools/ocft/Makefile.am | 67 ++++++--- + tools/ocft/Raid1 | 146 ------------------ + tools/ocft/SendArp | 74 --------- + tools/ocft/Xinetd | 56 ------- + tools/ocft/apache | 63 -------- + tools/ocft/db2 | 164 -------------------- + tools/ocft/default/Filesystem | 110 ++++++++++++++ + tools/ocft/default/IPaddr2 | 137 +++++++++++++++++ + tools/ocft/default/IPaddr2v4 | 323 ++++++++++++++++++++++++++++++++++++++++ + tools/ocft/default/IPaddr2v6 | 250 +++++++++++++++++++++++++++++++ + tools/ocft/default/IPsrcaddr | 63 ++++++++ + tools/ocft/default/IPv6addr | 150 +++++++++++++++++++ + tools/ocft/default/LVM | 86 +++++++++++ + tools/ocft/default/MailTo | 57 +++++++ + tools/ocft/default/Raid1 | 146 ++++++++++++++++++ + tools/ocft/default/SendArp | 74 +++++++++ + tools/ocft/default/Xinetd | 56 +++++++ + tools/ocft/default/apache | 63 ++++++++ + tools/ocft/default/db2 | 164 ++++++++++++++++++++ + tools/ocft/default/drbd.linbit | 183 +++++++++++++++++++++++ + tools/ocft/default/exportfs | 74 +++++++++ + tools/ocft/default/iscsi | 82 ++++++++++ + tools/ocft/default/jboss | 83 ++++++++++ + tools/ocft/default/mysql | 77 ++++++++++ + tools/ocft/default/mysql-proxy | 83 ++++++++++ + tools/ocft/default/named | 69 +++++++++ + tools/ocft/default/nfsserver | 75 +++++++++ + tools/ocft/default/oracle | 81 ++++++++++ + tools/ocft/default/pgsql | 71 +++++++++ + tools/ocft/default/portblock | 69 +++++++++ + tools/ocft/default/postfix | 102 +++++++++++++ + tools/ocft/default/tomcat | 73 +++++++++ + tools/ocft/drbd.linbit | 183 ----------------------- + tools/ocft/fedora/Filesystem | 110 ++++++++++++++ + tools/ocft/fedora/IPaddr2v4 | 323 ++++++++++++++++++++++++++++++++++++++++ + tools/ocft/fedora/IPaddr2v6 | 250 +++++++++++++++++++++++++++++++ + tools/ocft/fedora/IPsrcaddr | 61 ++++++++ + tools/ocft/fedora/SendArp | 73 +++++++++ + tools/ocft/fedora/Xinetd | 62 ++++++++ + tools/ocft/fedora/apache | 81 ++++++++++ + tools/ocft/fedora/mysql | 76 ++++++++++ + tools/ocft/fedora/nfsserver | 74 +++++++++ + tools/ocft/fedora/pgsql | 72 +++++++++ + tools/ocft/fedora/tomcat | 72 +++++++++ + tools/ocft/iscsi | 82 ---------- + tools/ocft/mysql | 77 ---------- + tools/ocft/mysql-proxy | 83 ---------- + tools/ocft/named | 69 --------- + tools/ocft/nfsserver | 75 --------- + tools/ocft/oracle | 81 ---------- + tools/ocft/pgsql | 71 --------- + tools/ocft/portblock | 69 --------- + tools/ocft/postfix | 102 ------------- + 62 files changed, 4108 insertions(+), 2584 deletions(-) + delete mode 100644 tools/ocft/Filesystem + delete mode 100644 tools/ocft/IPaddr2 + delete mode 100644 tools/ocft/IPaddr2v4 + delete mode 100644 tools/ocft/IPaddr2v6 + delete mode 100644 tools/ocft/IPsrcaddr + delete mode 100644 tools/ocft/IPv6addr + delete mode 100644 tools/ocft/LVM + delete mode 100644 tools/ocft/MailTo + delete mode 100644 tools/ocft/Raid1 + delete mode 100644 tools/ocft/SendArp + delete mode 100644 tools/ocft/Xinetd + delete mode 100644 tools/ocft/apache + delete mode 100644 tools/ocft/db2 + create mode 100644 tools/ocft/default/Filesystem + create mode 100644 tools/ocft/default/IPaddr2 + create mode 100644 tools/ocft/default/IPaddr2v4 + create mode 100644 tools/ocft/default/IPaddr2v6 + create mode 100644 tools/ocft/default/IPsrcaddr + create mode 100644 tools/ocft/default/IPv6addr + create mode 100644 tools/ocft/default/LVM + create mode 100644 tools/ocft/default/MailTo + create mode 100644 tools/ocft/default/Raid1 + create mode 100644 tools/ocft/default/SendArp + create mode 100644 tools/ocft/default/Xinetd + create mode 100644 tools/ocft/default/apache + create mode 100644 tools/ocft/default/db2 + create mode 100644 tools/ocft/default/drbd.linbit + create mode 100644 tools/ocft/default/exportfs + create mode 100644 tools/ocft/default/iscsi + create mode 100644 tools/ocft/default/jboss + create mode 100644 tools/ocft/default/mysql + create mode 100644 tools/ocft/default/mysql-proxy + create mode 100644 tools/ocft/default/named + create mode 100644 tools/ocft/default/nfsserver + create mode 100644 tools/ocft/default/oracle + create mode 100644 tools/ocft/default/pgsql + create mode 100644 tools/ocft/default/portblock + create mode 100644 tools/ocft/default/postfix + create mode 100644 tools/ocft/default/tomcat + delete mode 100644 tools/ocft/drbd.linbit + create mode 100644 tools/ocft/fedora/Filesystem + create mode 100644 tools/ocft/fedora/IPaddr2v4 + create mode 100644 tools/ocft/fedora/IPaddr2v6 + create mode 100644 tools/ocft/fedora/IPsrcaddr + create mode 100644 tools/ocft/fedora/SendArp + create mode 100644 tools/ocft/fedora/Xinetd + create mode 100644 tools/ocft/fedora/apache + create mode 100644 tools/ocft/fedora/mysql + create mode 100644 tools/ocft/fedora/nfsserver + create mode 100644 tools/ocft/fedora/pgsql + create mode 100644 tools/ocft/fedora/tomcat + delete mode 100644 tools/ocft/iscsi + delete mode 100644 tools/ocft/mysql + delete mode 100644 tools/ocft/mysql-proxy + delete mode 100644 tools/ocft/named + delete mode 100644 tools/ocft/nfsserver + delete mode 100644 tools/ocft/oracle + delete mode 100644 tools/ocft/pgsql + delete mode 100644 tools/ocft/portblock + delete mode 100644 tools/ocft/postfix + +diff --git a/configure.ac b/configure.ac +index d2d58cf..15344e0 100644 +--- a/configure.ac ++++ b/configure.ac +@@ -28,6 +28,7 @@ AC_USE_SYSTEM_EXTENSIONS + CRM_DTD_VERSION="1.0" + + PKG_FEATURES="" ++OCFT_TEST_CASES="default" + + AC_CONFIG_AUX_DIR(.) + AC_CANONICAL_HOST +@@ -56,6 +57,14 @@ AC_ARG_WITH(pkg-name, + [ --with-pkg-name=name Override package name (if you're a packager needing to pretend) ], + [ PACKAGE_NAME="$withval" ]) + ++ ++AC_ARG_WITH(ocft-cases, ++ [ --with-ocft-cases=cases Set which ocft test cases to install. ], ++ [ OCFT_TEST_CASES="$withval" ]) ++ ++AM_CONDITIONAL(OCFT_FEDORA_CASES, test "x$OCFT_TEST_CASES" = "xfedora" ) ++AM_CONDITIONAL(OCFT_DEFAULT_CASES, test "x$OCFT_TEST_CASES" = "xdefault" ) ++ + dnl + dnl AM_INIT_AUTOMAKE([1.11.1 foreign dist-bzip2 dist-xz]) + dnl +diff --git a/tools/ocft/Filesystem b/tools/ocft/Filesystem +deleted file mode 100644 +index 75203d7..0000000 +--- a/tools/ocft/Filesystem ++++ /dev/null +@@ -1,110 +0,0 @@ +-# Filesystem +-# by dejan@suse.de on +-# Tue Feb 15 18:50:04 CET 2011 +- +-CONFIG +- Agent Filesystem +- AgentRoot /usr/lib/ocf/resource.d/heartbeat +- HangTimeout 20 +- +-VARIABLE +- OCFT_fs=/var/run/resource-agents/ocft-Filesystem-fs +- OCFT_loop=/dev/loop7 +- OCFT_dir=/var/run/resource-agents/ocft-Filesystem-mnt +- +-SETUP-AGENT +- losetup $OCFT_loop 2>/dev/null && exit 1 +- rmdir $OCFT_dir 2>/dev/null || true +- mkdir $OCFT_dir +- dd if=/dev/zero of=$OCFT_fs bs=1 count=0 seek=16M 2>/dev/null +- mke2fs -j -Fq -m 0 $OCFT_fs +- losetup $OCFT_loop $OCFT_fs +- +-CLEANUP-AGENT +- rmdir $OCFT_dir +- rm $OCFT_fs +- losetup -d $OCFT_loop +- +-CASE-BLOCK required_args +- Env OCF_RESKEY_device=$OCFT_loop +- Env OCF_RESKEY_fstype=ext3 +- Env OCF_RESKEY_directory=$OCFT_dir +- +-CASE-BLOCK default_status +- AgentRun stop +- +-CASE-BLOCK prepare +- Include required_args +- Include default_status +- +-CASE "check base env" +- Include prepare +- AgentRun start OCF_SUCCESS +- +-CASE "check base env: invalid 'OCF_RESKEY_device'" +- Include prepare +- Env OCF_RESKEY_device=/dev/no_such_device +- AgentRun start OCF_ERR_INSTALLED +- +-CASE "check base env: unset 'OCF_RESKEY_device'" +- Include prepare +- Unenv OCF_RESKEY_device +- AgentRun start OCF_ERR_CONFIGURED +- +-CASE "normal start" +- Include prepare +- AgentRun start OCF_SUCCESS +- +-CASE "normal stop" +- Include prepare +- AgentRun start +- AgentRun stop OCF_SUCCESS +- +-CASE "double start" +- Include prepare +- AgentRun start +- AgentRun start OCF_SUCCESS +- +-CASE "double stop" +- Include prepare +- AgentRun stop OCF_SUCCESS +- +-CASE "monitor when running" +- Include prepare +- AgentRun start +- AgentRun monitor OCF_SUCCESS +- +-CASE "monitor when not running" +- Include prepare +- AgentRun monitor OCF_NOT_RUNNING +- +-CASE "monitor depth 10 when running" +- Include prepare +- AgentRun start +- Env OCF_CHECK_LEVEL=10 +- AgentRun monitor OCF_SUCCESS +- +-CASE "monitor depth 20 with running" +- Include prepare +- AgentRun start +- Env OCF_CHECK_LEVEL=20 +- AgentRun monitor OCF_SUCCESS +- +-CASE "start insert failure (remove device)" +- Include prepare +- Bash losetup -d $OCFT_loop +- BashAtExit losetup $OCFT_loop $OCFT_fs +- AgentRun start OCF_ERR_GENERIC +- +-CASE "monitor depth 20 insert failure (r/o fs)" +- Include prepare +- AgentRun start +- Bash mount -o remount,ro $OCFT_dir +- BashAtExit mount -o remount,rw $OCFT_dir +- Env OCF_CHECK_LEVEL=20 +- AgentRun monitor OCF_ERR_GENERIC +- +-CASE "unimplemented command" +- Include prepare +- AgentRun no_cmd OCF_ERR_UNIMPLEMENTED +- +diff --git a/tools/ocft/IPaddr2 b/tools/ocft/IPaddr2 +deleted file mode 100644 +index bfa8283..0000000 +--- a/tools/ocft/IPaddr2 ++++ /dev/null +@@ -1,127 +0,0 @@ +-# IPaddr2 +- +-CONFIG +- Agent IPaddr2 +- AgentRoot /usr/lib/ocf/resource.d/heartbeat +- HangTimeout 20 +- +-SETUP-AGENT +- ip addr add 192.168.144.1/24 dev eth0 brd 192.168.144.255 +- +-CLEANUP-AGENT +- ip addr del 192.168.144.1/24 dev eth0 +- +-CASE-BLOCK required_args +- Env OCF_RESKEY_ip=192.168.144.2 +- +-CASE-BLOCK check_iflabel_assigned +- Bash ip -4 -o addr show eth0 | grep -w 192.168.144.2/24 | grep -w eth0:iflabel >/dev/null # checking iflabel was assigned correctly +- +-CASE-BLOCK check_iflabel_removed +- Bash ! ip -4 -o addr show eth0 | grep -w 192.168.144.2/24 | grep -w eth0:iflabel >/dev/null # checking iflabel was removed correctly +- +-CASE-BLOCK default_status +- AgentRun stop +- +-CASE-BLOCK prepare +- Include required_args +- Include default_status +- +-CASE "check base env" +- Include prepare +- AgentRun start OCF_SUCCESS +- +-CASE "check base env: unset 'OCF_RESKEY_ip'" +- Include prepare +- Unenv OCF_RESKEY_ip +- AgentRun start OCF_ERR_CONFIGURED +- +-CASE "check base env: set invalid 'OCF_RESKEY_ip'" +- Include prepare +- Env OCF_RESKEY_ip=not_ip_address +- AgentRun start OCF_ERR_CONFIGURED +- +-CASE "check base env: set 'OCF_RESKEY_cidr_netmask'" +- Include prepare +- Env OCF_RESKEY_cidr_netmask=24 +- AgentRun start OCF_SUCCESS +- +-CASE "check base env: set invalid 'OCF_RESKEY_cidr_netmask'" +- Include prepare +- Env OCF_RESKEY_cidr_netmask=not_netmask +- AgentRun start OCF_ERR_CONFIGURED +- +-CASE "check base env: set 'OCF_RESKEY_broadcast'" +- Include prepare +- Env OCF_RESKEY_broadcast=192.168.144.255 +- AgentRun start OCF_SUCCESS +- +-CASE "check base env: set invalid 'OCF_RESKEY_broadcast'" +- Include prepare +- Env OCF_RESKEY_broadcast=not_broadcast +- AgentRun start OCF_ERR_CONFIGURED +- +-CASE "check base env: set 'OCF_RESKEY_nic'" +- Include prepare +- Env OCF_RESKEY_nic=eth0 +- AgentRun start OCF_SUCCESS +- +-CASE "check base env: set invalid 'OCF_RESKEY_nic'" +- Include prepare +- Env OCF_RESKEY_nic=not_nic +- AgentRun start OCF_ERR_CONFIGURED +- +-CASE "normal start" +- Include prepare +- AgentRun start OCF_SUCCESS +- +-CASE "normal stop" +- Include prepare +- AgentRun start +- AgentRun stop OCF_SUCCESS +- +-CASE "double start" +- Include prepare +- AgentRun start +- AgentRun start OCF_SUCCESS +- +-CASE "double stop" +- Include prepare +- AgentRun stop OCF_SUCCESS +- +-CASE "monitor with running" +- Include prepare +- AgentRun start +- AgentRun monitor OCF_SUCCESS +- +-CASE "monitor with not running" +- Include prepare +- AgentRun monitor OCF_NOT_RUNNING +- +-CASE "unimplemented command" +- Include prepare +- AgentRun no_cmd OCF_ERR_UNIMPLEMENTED +- +-CASE "Attachment to loopback interface" +- Env OCF_RESKEY_ip=127.0.0.3 +- AgentRun start OCF_SUCCESS +- AgentRun monitor OCF_SUCCESS +- AgentRun stop OCF_SUCCESS +- +-CASE "check additional env: set 'OCF_RESKEY_iflabel'" +- Include prepare +- Env OCF_RESKEY_nic=eth0 +- Env OCF_RESKEY_iflabel=iflabel +- AgentRun start OCF_SUCCESS +- Include check_iflabel_assigned +- AgentRun stop OCF_SUCCESS +- Include check_iflabel_removed +- +-# This is deprecated but still supported for the compatibility. +-CASE "check additional env: specify iflabel in 'OCF_RESKEY_nic'" +- Include prepare +- Env OCF_RESKEY_nic=eth0:iflabel +- AgentRun start OCF_SUCCESS +- Include check_iflabel_assigned +- AgentRun stop OCF_SUCCESS +- Include check_iflabel_removed +diff --git a/tools/ocft/IPaddr2v4 b/tools/ocft/IPaddr2v4 +deleted file mode 100644 +index 4d37168..0000000 +--- a/tools/ocft/IPaddr2v4 ++++ /dev/null +@@ -1,323 +0,0 @@ +-# IPaddr2v4 +- +-# Note: This test case uses two NICs(eth0, eth1) and +-# a IPv4 address prefix (192.168.144.0/24). +-# Adjust them according to your environment at VARIABLE section if needed. +- +-CONFIG +- Agent IPaddr2 +- AgentRoot /usr/lib/ocf/resource.d/heartbeat +- HangTimeout 20 +- +-VARIABLE +- OCFT_target_ip=192.168.144.2 +- OCFT_target_nic=eth0 +- OCFT_target_prefix=24 +- OCFT_target_netaddr=192.168.144.1/$OCFT_target_prefix +- OCFT_target_brd=192.168.144.255 +- OCFT_wrong_ip=192.168.120.1 +- OCFT_force_nic=eth1 +- OCFT_force_prefix=16 +- OCFT_force_prefix2=28 +- OCFT_force_brd=192.168.255.255 +- +-SETUP-AGENT +- ip addr add $OCFT_target_netaddr dev $OCFT_target_nic brd $OCFT_target_brd +- +-CLEANUP-AGENT +- ip addr del $OCFT_target_netaddr dev $OCFT_target_nic +- +-CASE-BLOCK required_args +- Env OCF_RESKEY_ip=$OCFT_target_ip +- Env OCFT_check_ip=$OCFT_target_ip +- Env OCFT_check_prefix=$OCFT_target_prefix +- Env OCFT_check_nic=$OCFT_target_nic +- +-CASE-BLOCK check_ip_assigned +- Bash ip -4 -o addr show $OCFT_check_nic | grep -w $OCFT_check_ip/$OCFT_check_prefix >/dev/null # checking if the IPv4 address was assigned correctly +- +-CASE-BLOCK check_ip_removed +- Bash ! ip -4 -o addr show $OCFT_check_nic | grep -w $OCFT_check_ip/$OCFT_check_prefix >/dev/null # checking if the IPv4 address was removed correctly +- +-CASE-BLOCK base_ip_assigned +- Bash ip addr add $OCFT_target_netaddr dev $OCFT_target_nic brd $OCFT_target_brd +- +-CASE-BLOCK base_ip_removed +- Bash ip addr del $OCFT_target_netaddr dev $OCFT_target_nic +- +-CASE-BLOCK default_status +- AgentRun stop +- +-CASE-BLOCK prepare +- Include required_args +- Include default_status +- +-# CASE No.0 +-# +-CASE "normal start" +- Include prepare +- AgentRun start OCF_SUCCESS +- Include check_ip_assigned +- +-# CASE No.1 +-# +-CASE "normal stop" +- Include prepare +- AgentRun start +- AgentRun stop OCF_SUCCESS +- Include check_ip_removed +- +-# CASE No.2 +-# +-CASE "double start" +- Include prepare +- AgentRun start +- AgentRun start OCF_SUCCESS +- +-# CASE No.3 +-# +-CASE "double stop" +- Include prepare +- AgentRun stop OCF_SUCCESS +- +-# CASE No.4 +-# +-CASE "monitor with running" +- Include prepare +- AgentRun start +- AgentRun monitor OCF_SUCCESS +- +-# CASE No.5 +-# +-CASE "monitor with not running" +- Include prepare +- AgentRun monitor OCF_NOT_RUNNING +- +-# CASE No.6 +-# Note: this result is different from IPaddr2 in 3.9.3. +-# IPaddr2 succeeds if the ip matched based on the netmask of the subnet +-# or fails if it did not match to any. +-# Recommended to always specify both nic, cidr_netmask, and broadcast when you needed. +-# IPaddr2 in 3.9.3 was using a wrong subnet mask (constant of 32) in this case. +-# +-CASE "params with nic, no cidr_netmask" +- Include prepare +- Env OCF_RESKEY_nic=$OCFT_target_nic +- AgentRun start OCF_SUCCESS +- Include check_ip_assigned +- AgentRun monitor OCF_SUCCESS +- AgentRun stop OCF_SUCCESS +- Include check_ip_removed +- +-# CASE No.7 +-# +-CASE "params with nic, cidr_netmask" +- Include prepare +- Env OCF_RESKEY_nic=$OCFT_target_nic +- Env OCF_RESKEY_cidr_netmask=$OCFT_target_prefix +- AgentRun start OCF_SUCCESS +- Include check_ip_assigned +- AgentRun monitor OCF_SUCCESS +- AgentRun stop OCF_SUCCESS +- Include check_ip_removed +- +-# CASE No.8 +-# +-CASE "error params with wrong ip" +- Include prepare +- Env OCF_RESKEY_ip=$OCFT_wrong_ip +- AgentRun start OCF_ERR_GENERIC +- +-# CASE No.9 +-# Note: this result is different from IPaddr2 in 3.9.3. +-# IPaddr2 fails when it could not determine the correct subnet mask. +-# When it could not get base ip, it becomes the error. +-# Recommended to always specify both nic, cidr_netmask, and broadcast when you needed. +-# IPaddr2 in 3.9.3 was using a wrong subnet mask (constant of 32) in this case. +-# +-CASE "params with force nic" +- Include prepare +- Env OCF_RESKEY_nic=$OCFT_force_nic +- Env OCFT_check_nic=$OCFT_force_nic +- AgentRun start OCF_ERR_GENERIC +- Include check_ip_removed +- Unenv OCF_RESKEY_nic +- +-# CASE No.10 +-# Note: this result is different from IPaddr2 in 3.9.3. +-# IPaddr2 fails when it could not determine the broadcast. +-# Recommended to always specify both nic, cidr_netmask, and broadcast when you needed. +-# IPaddr2 in 3.9.3 succeeded but it's considered ambiguous. +-# +-CASE "params with force cidr_netmask (base netmask > assigned netmask)" +- Include prepare +- Env OCF_RESKEY_cidr_netmask=$OCFT_force_prefix +- Env OCFT_check_prefix=$OCFT_force_prefix +- AgentRun start OCF_ERR_GENERIC +- Include check_ip_removed +- +-# CASE No.11 +-# Note: this result is different from IPaddr2 in 3.9.3. +-# IPaddr2 succeeds but the broadcast is not set. +-# This is because findif.sh can not calculate a broadcast from a netmask. +-# Recommended to always specify both nic, cidr_netmask, and broadcast when you needed. +-# IPaddr2 in 3.9.3 succeeded with using a calculated broadcast. +-# +-CASE "force to use the specified nic and cidr_netmask" +- Include prepare +- Env OCF_RESKEY_nic=$OCFT_force_nic +- Env OCF_RESKEY_cidr_netmask=$OCFT_force_prefix +- Env OCFT_check_nic=$OCFT_force_nic +- Env OCFT_check_prefix=$OCFT_force_prefix +- AgentRun start OCF_SUCCESS +- AgentRun stop OCF_SUCCESS +- Include check_ip_removed +- Unenv OCF_RESKEY_cidr_netmask +- +- +-# CASE No.12 +-# Note: this result is different from IPaddr2 in 3.9.3. +-# IPaddr2 fails when it could not determine the correct subnet mask. +-# When it could not get base ip, it becomes the error. +-# Recommended to always specify both nic, cidr_netmask, and broadcast when you needed. +-# IPaddr2 in 3.9.3 was using a wrong subnet mask (constant of 32) in this case. +-# +-CASE "error params with wrong ip and nic (not exist base_ip)" +- Include prepare +- Include base_ip_removed +- Env OCF_RESKEY_nic=$OCFT_target_nic +- Env OCFT_check_nic=$OCFT_target_nic +- AgentRun start OCF_ERR_GENERIC +- Include check_ip_removed +- Include base_ip_assigned +- +-# CASE No.13 +-# +-CASE "params with cidr_netmask" +- Include prepare +- Env OCF_RESKEY_cidr_netmask=$OCFT_target_prefix +- AgentRun start OCF_SUCCESS +- Include check_ip_assigned +- AgentRun monitor OCF_SUCCESS +- AgentRun stop OCF_SUCCESS +- Include check_ip_removed +- +-# CASE No.14 +-# Note: this result is different from IPaddr2 in 3.9.3. +-# IPaddr2 does not override the broadcast by cidr_netmask. +-# Recommended to always specify both nic, cidr_netmask, and broadcast when you needed. +-# IPaddr2 in 3.9.3 overrode the broadcast calculated by cidr_netmask. +-# +-CASE "params with force cidr_netmask (base netmask < assigned netmask)" +- Include prepare +- Env OCF_RESKEY_cidr_netmask=$OCFT_force_prefix2 +- Env OCFT_check_prefix=$OCFT_force_prefix2 +- AgentRun start OCF_SUCCESS +- Include check_ip_assigned +- AgentRun monitor OCF_SUCCESS +- AgentRun stop OCF_SUCCESS +- Include check_ip_removed +- +-# CASE No.15 +-# Note: this result is different from IPaddr2 in 3.9.3. +-# IPaddr2 fails when it could not determine the broadcast. +-# Recommended to always specify both nic, cidr_netmask, and broadcast when you needed. +-# IPaddr2 in 3.9.3 succeeded but it's considered ambiguous. +-# +-CASE "error params with wrong ip and cidr_netmask (not exist base_ip)" +- Include prepare +- Include base_ip_removed +- Env OCF_RESKEY_cidr_netmask=$OCFT_target_prefix +- AgentRun start OCF_ERR_GENERIC +- Include base_ip_assigned +- +-# CASE No.16 +-# Note: this result is different from IPaddr2 in 3.9.3. +-# IPaddr2 succeeds but the broadcast is not set. +-# This is because findif.sh can not calculate a broadcast from a netmask. +-# Recommended to always specify both nic, cidr_netmask, and broadcast when you needed. +-# IPaddr2 in 3.9.3 succeeded with using a calculated broadcast. +-# +-CASE "force to use the specified nic and cidr_netmask" +- Include prepare +- Env OCF_RESKEY_nic=$OCFT_force_nic +- Env OCF_RESKEY_cidr_netmask=$OCFT_force_prefix2 +- Env OCFT_check_prefix=$OCFT_force_prefix2 +- Env OCFT_check_nic=$OCFT_force_nic +- AgentRun start OCF_SUCCESS +- AgentRun stop OCF_SUCCESS +- Include check_ip_removed +- +-# CASE No.17 +-# Note: this result is different from IPaddr2 in 3.9.3. +-# IPaddr2 succeeds but the broadcast is not set. +-# This is because findif.sh can not calculate a broadcast from a netmask. +-# Recommended to always specify both nic, cidr_netmask, and broadcast when you needed. +-# IPaddr2 in 3.9.3 succeeded with using a calculated broadcast. +-# +-CASE "force to use the specified nic and cidr_netmask (not exist base_ip)" +- Include prepare +- Include base_ip_removed +- Env OCF_RESKEY_nic=$OCFT_force_nic +- Env OCF_RESKEY_cidr_netmask=$OCFT_force_prefix2 +- Env OCFT_check_prefix=$OCFT_force_prefix2 +- Env OCFT_check_nic=$OCFT_force_nic +- AgentRun start OCF_SUCCESS +- AgentRun stop OCF_SUCCESS +- Unenv OCF_RESKEY_nic +- Unenv OCF_RESKEY_cidr_netmask +- Include base_ip_assigned +- +-# CASE No.18 +-# +-CASE "params with broadcast, no nic, no cidr_netmask" +- Include prepare +- Env OCF_RESKEY_broadcast=$OCFT_force_brd +- AgentRun start OCF_SUCCESS +- Include check_ip_assigned +- AgentRun monitor OCF_SUCCESS +- AgentRun stop OCF_SUCCESS +- Include check_ip_removed +- +-# CASE No.19 +-# +-CASE "params with broadcast, no nic, no cidr_netmask" +- Include prepare +- Include base_ip_removed +- Env OCF_RESKEY_broadcast=$OCFT_force_brd +- AgentRun start OCF_ERR_GENERIC +- Include base_ip_assigned +- +-# CASE No.20 +-# +-CASE "force to use the specified nic and cidr_netmask" +- Include prepare +- Env OCF_RESKEY_nic=$OCFT_force_nic +- Env OCF_RESKEY_cidr_netmask=$OCFT_force_prefix +- Env OCF_RESKEY_broadcast=$OCFT_force_brd +- Env OCFT_check_nic=$OCFT_force_nic +- Env OCFT_check_prefix=$OCFT_force_prefix +- AgentRun start OCF_SUCCESS +- Include check_ip_assigned +- AgentRun monitor OCF_SUCCESS +- AgentRun stop OCF_SUCCESS +- Include check_ip_removed +- Unenv OCF_RESKEY_cidr_netmask +- +-# CASE No.21 +-# +-CASE "force to use the specified nic and cidr_netmask" +- Include prepare +- Include base_ip_removed +- Env OCF_RESKEY_nic=$OCFT_force_nic +- Env OCF_RESKEY_cidr_netmask=$OCFT_force_prefix2 +- Env OCF_RESKEY_broadcast=$OCFT_target_brd +- Env OCFT_check_nic=$OCFT_force_nic +- Env OCFT_check_prefix=$OCFT_force_prefix2 +- AgentRun start OCF_SUCCESS +- Include check_ip_assigned +- AgentRun monitor OCF_SUCCESS +- AgentRun stop OCF_SUCCESS +- Include check_ip_removed +- Include base_ip_assigned +- +diff --git a/tools/ocft/IPaddr2v6 b/tools/ocft/IPaddr2v6 +deleted file mode 100644 +index d24d890..0000000 +--- a/tools/ocft/IPaddr2v6 ++++ /dev/null +@@ -1,250 +0,0 @@ +-# IPaddr2v6 +- +-# Note: This test case uses two NICs(eth0, eth1) and +-# a IPv6 address prefix (2001:db8::/32, RFC3849). +-# Adjust them according to your environment at VARIABLE section if needed. +- +-CONFIG +- Agent IPaddr2 +- AgentRoot /usr/lib/ocf/resource.d/heartbeat +- HangTimeout 20 +- +-VARIABLE +- OCFT_target_ip=2001:db8:1234::2 +- OCFT_target_nic=eth0 +- OCFT_target_prefix=64 +- OCFT_target_netaddr=2001:db8:1234::1/$OCFT_target_prefix +- OCFT_target_linklocal=fe80::2 +- OCFT_wrong_ip=2001:db8:5678::2 +- OCFT_force_nic=eth1 +- OCFT_force_prefix=80 +- OCFT_force_prefix2=48 +- +-SETUP-AGENT +- ip addr add $OCFT_target_netaddr dev $OCFT_target_nic +- +-CLEANUP-AGENT +- ip addr del $OCFT_target_netaddr dev $OCFT_target_nic +- +-CASE-BLOCK required_args +- Env OCF_RESKEY_ip=$OCFT_target_ip +- Env OCFT_check_ip=$OCFT_target_ip +- Env OCFT_check_prefix=$OCFT_target_prefix +- Env OCFT_check_nic=$OCFT_target_nic +- +-CASE-BLOCK check_ip_assigned +- Bash ip -6 -o addr show $OCFT_check_nic | grep -w $OCFT_check_ip/$OCFT_check_prefix >/dev/null # checking if the IPv6 address was assigned correctly +- +-CASE-BLOCK check_ip_removed +- Bash ! ip -6 -o addr show $OCFT_check_nic | grep -w $OCFT_check_ip/$OCFT_check_prefix >/dev/null # checking if the IPv6 address was removed correctly +- +-CASE-BLOCK base_ip_assigned +- Bash ip addr add $OCFT_target_netaddr dev $OCFT_target_nic +- +-CASE-BLOCK base_ip_removed +- Bash ip addr del $OCFT_target_netaddr dev $OCFT_target_nic +- +-CASE-BLOCK default_status +- AgentRun stop +- +-CASE-BLOCK prepare +- Include required_args +- Include default_status +- +-# CASE No.0 +-# +-CASE "normal start" +- Include prepare +- AgentRun start OCF_SUCCESS +- Include check_ip_assigned +- +-# CASE No.1 +-# +-CASE "normal stop" +- Include prepare +- AgentRun start OCF_SUCCESS +- AgentRun stop OCF_SUCCESS +- Include check_ip_removed +- +-# CASE No.2 +-# +-CASE "double start" +- Include prepare +- AgentRun start +- AgentRun start OCF_SUCCESS +- +-# CASE No.3 +-# +-CASE "double stop" +- Include prepare +- AgentRun stop OCF_SUCCESS +- +-# CASE No.4 +-# +-CASE "monitor with running" +- Include prepare +- AgentRun start +- AgentRun monitor OCF_SUCCESS +- +-# CASE No.5 +-# +-CASE "monitor with not running" +- Include prepare +- AgentRun monitor OCF_NOT_RUNNING +- +-# CASE No.6 +-# +-CASE "error params with wrong ip" +- Include prepare +- Env OCF_RESKEY_ip=$OCFT_wrong_ip +- AgentRun start OCF_ERR_GENERIC +- +-# CASE No.7 +-# +-CASE "error params with no nic for a link-local IPv6 address" +- Include prepare +- Env OCF_RESKEY_ip=$OCFT_target_linklocal +- Env OCFT_check_ip=$OCFT_target_linklocal +- # nic is mandatory for a link-local address +- AgentRun start OCF_ERR_CONFIGURED +- +-# CASE No.8 +-# +-CASE "params with nic, no cidr_netmask" +- Include prepare +- Env OCF_RESKEY_nic=$OCFT_target_nic +- AgentRun start OCF_SUCCESS +- Include check_ip_assigned +- AgentRun monitor OCF_SUCCESS +- AgentRun stop OCF_SUCCESS +- Include check_ip_removed +- +-# CASE No.9 +-# +-CASE "normal usage for a link-local IPv6 address, params with nic" +- Include prepare +- Env OCF_RESKEY_ip=$OCFT_target_linklocal +- Env OCFT_check_ip=$OCFT_target_linklocal +- # nic is mandatory for a link-local address +- Env OCF_RESKEY_nic=$OCFT_target_nic +- Env OCFT_check_nic=$OCFT_target_nic +- AgentRun start OCF_SUCCESS +- Include check_ip_assigned +- AgentRun stop OCF_SUCCESS +- Include check_ip_removed +- +-# CASE No.10 +-# +-CASE "error params with wrong ip and nic (not exist base_ip)" +- Include prepare +- Include base_ip_removed +- Env OCF_RESKEY_nic=$OCFT_target_nic +- Env OCFT_check_nic=$OCFT_target_nic +- AgentRun start OCF_ERR_GENERIC +- Include check_ip_removed +- Include base_ip_assigned +- +-# CASE No.11 +-# +-CASE "params with force nic" +- Include prepare +- Env OCF_RESKEY_nic=$OCFT_force_nic +- Env OCFT_check_nic=$OCFT_force_nic +- AgentRun start OCF_ERR_GENERIC +- Include check_ip_removed +- Unenv OCF_RESKEY_nic +- +-# CASE No.12 +-# +-CASE "params with force cidr_netmask" +- Include prepare +- Env OCF_RESKEY_cidr_netmask=$OCFT_target_prefix +- Env OCFT_check_prefix=$OCFT_target_prefix +- AgentRun start OCF_SUCCESS +- Include check_ip_assigned +- AgentRun stop OCF_SUCCESS +- Include check_ip_removed +- +-# CASE No.13 +-# +-CASE "params with force cidr_netmask (base netmask < assigned netmask)" +- Include prepare +- Env OCF_RESKEY_cidr_netmask=$OCFT_force_prefix +- Env OCFT_check_prefix=$OCFT_force_prefix +- AgentRun start OCF_ERR_GENERIC +- Include check_ip_removed +- +-# CASE No.14 +-# +-CASE "params with force cidr_netmask (base netmask > assigned netmask)" +- Include prepare +- Env OCF_RESKEY_cidr_netmask=$OCFT_force_prefix2 +- Env OCFT_check_prefix=$OCFT_force_prefix2 +- AgentRun start OCF_ERR_GENERIC +- Include check_ip_removed +- +-# CASE No.15 +-# +-CASE "params with cidr_netmask" +- Include prepare +- Include base_ip_removed +- Env OCF_RESKEY_cidr_netmask=$OCFT_target_prefix +- Env OCFT_check_prefix=$OCFT_target_prefix +- AgentRun start OCF_ERR_GENERIC +- Include base_ip_assigned +- +-# CASE No.16 +-# +-CASE "params with nic, cidr_netmask" +- Include prepare +- Env OCF_RESKEY_nic=$OCFT_target_nic +- Env OCF_RESKEY_cidr_netmask=$OCFT_target_prefix +- Env OCFT_check_nic=$OCFT_target_nic +- Env OCFT_check_prefix=$OCFT_target_prefix +- AgentRun start OCF_SUCCESS +- Include check_ip_assigned +- AgentRun stop OCF_SUCCESS +- Include check_ip_removed +- +-# CASE No.17 +-# +-CASE "force to use the specified nic and cidr_netmask (base netmask < assigned netmask)" +- Include prepare +- Env OCF_RESKEY_nic=$OCFT_force_nic +- Env OCF_RESKEY_cidr_netmask=$OCFT_force_prefix +- Env OCFT_check_nic=$OCFT_force_nic +- Env OCFT_check_prefix=$OCFT_force_prefix +- AgentRun start OCF_SUCCESS +- Include check_ip_assigned +- AgentRun stop OCF_SUCCESS +- Include check_ip_removed +- +-# CASE No.18 +-# This use case is now valid. It was not allowed until v3.9.2. +-# +-CASE "force to use the specified nic and cidr_netmask (base netmask > assigned netmask)" +- Include prepare +- Env OCF_RESKEY_nic=$OCFT_force_nic +- Env OCF_RESKEY_cidr_netmask=$OCFT_force_prefix2 +- Env OCFT_check_nic=$OCFT_force_nic +- Env OCFT_check_prefix=$OCFT_force_prefix2 +- AgentRun start OCF_SUCCESS +- Include check_ip_assigned +- AgentRun stop OCF_SUCCESS +- Include check_ip_removed +- +-# CASE No.19 +-# +-CASE "force to use the specified nic and cidr_netmask (base netmask > assigned netmask)" +- Include prepare +- Include base_ip_removed +- Env OCF_RESKEY_nic=$OCFT_force_nic +- Env OCF_RESKEY_cidr_netmask=$OCFT_force_prefix2 +- Env OCFT_check_nic=$OCFT_force_nic +- Env OCFT_check_prefix=$OCFT_force_prefix2 +- AgentRun start OCF_SUCCESS +- Include check_ip_assigned +- AgentRun stop OCF_SUCCESS +- Include check_ip_removed +- Include base_ip_assigned +- +diff --git a/tools/ocft/IPsrcaddr b/tools/ocft/IPsrcaddr +deleted file mode 100644 +index d95142e..0000000 +--- a/tools/ocft/IPsrcaddr ++++ /dev/null +@@ -1,63 +0,0 @@ +-# IPsrcaddr +- +-CONFIG +- Agent IPsrcaddr +- AgentRoot /usr/lib/ocf/resource.d/heartbeat +- InstallPackage iproute2 +- HangTimeout 20 +- +-CASE-BLOCK required_args +- Env OCF_RESKEY_ipaddress= # put here your IP +- Env OCF_RESKEY_cidr_netmask= # and the netmask +- +-CASE-BLOCK default_status +- AgentRun stop +- +-CASE-BLOCK prepare +- Include required_args +- Include default_status +- +-CASE "check base env" +- Include prepare +- AgentRun start OCF_SUCCESS +- +-CASE "check base env: unset 'OCF_RESKEY_ipaddress'" +- Include prepare +- Unenv OCF_RESKEY_ipaddress +- AgentRun start OCF_ERR_CONFIGURED +- +-CASE "check base env: set invalid 'OCF_RESKEY_ipaddress'" +- Include prepare +- Env OCF_RESKEY_ipaddress=not_ip_address +- AgentRun start OCF_ERR_CONFIGURED +- +-CASE "normal start" +- Include prepare +- AgentRun start OCF_SUCCESS +- +-CASE "normal stop" +- Include prepare +- AgentRun start +- AgentRun stop OCF_SUCCESS +- +-CASE "double start" +- Include prepare +- AgentRun start +- AgentRun start OCF_SUCCESS +- +-CASE "double stop" +- Include prepare +- AgentRun stop OCF_SUCCESS +- +-CASE "monitor with running" +- Include prepare +- AgentRun start +- AgentRun monitor OCF_SUCCESS +- +-CASE "monitor with not running" +- Include prepare +- AgentRun monitor OCF_NOT_RUNNING +- +-CASE "unimplemented command" +- Include prepare +- AgentRun no_cmd OCF_ERR_UNIMPLEMENTED +diff --git a/tools/ocft/IPv6addr b/tools/ocft/IPv6addr +deleted file mode 100644 +index 36a9642..0000000 +--- a/tools/ocft/IPv6addr ++++ /dev/null +@@ -1,150 +0,0 @@ +-# IPv6addr +- +-# Note: This test case uses two NICs(eth0, eth1) and +-# a IPv6 address prefix (2001:db8::/32, RFC3849). +-# Adjust them according to your environment at VARIABLE section if needed. +- +-CONFIG +- Agent IPv6addr +- AgentRoot /usr/lib/ocf/resource.d/heartbeat +- HangTimeout 20 +- +-VARIABLE +- OCFT_target_ipv6addr=2001:db8:1234::2 +- OCFT_target_nic=eth0 +- OCFT_target_prefix=64 +- OCFT_target_netaddr=2001:db8:1234::1/$OCFT_target_prefix +- OCFT_target_linklocal=fe80::2 +- OCFT_wrong_ipv6addr=2001:db8:5678::2 +- OCFT_force_nic=eth1 +- OCFT_force_prefix=80 +- +-SETUP-AGENT +- ip addr add $OCFT_target_netaddr dev $OCFT_target_nic +- +-CLEANUP-AGENT +- ip addr del $OCFT_target_netaddr dev $OCFT_target_nic +- +-CASE-BLOCK required_args +- Env OCF_RESKEY_ipv6addr=$OCFT_target_ipv6addr +- Env OCFT_check_ipv6addr=$OCFT_target_ipv6addr +- Env OCFT_check_prefix=$OCFT_target_prefix +- Env OCFT_check_nic=$OCFT_target_nic +- +-CASE-BLOCK check_ip_assigned +- Bash ip -6 -o addr show $OCFT_check_nic | grep -w $OCFT_check_ipv6addr/$OCFT_check_prefix >/dev/null # checking if the IPv6 address was assigned correctly +- +-CASE-BLOCK check_ip_removed +- Bash ! ip -6 -o addr show $OCFT_check_nic | grep -w $OCFT_check_ipv6addr/$OCFT_check_prefix >/dev/null # checking if the IPv6 address was removed correctly +- +-CASE-BLOCK default_status +- AgentRun stop +- +-CASE-BLOCK prepare +- Include required_args +- Include default_status +- +- +-CASE "normal start" +- Include prepare +- AgentRun start OCF_SUCCESS +- Include check_ip_assigned +- +-CASE "normal stop" +- Include prepare +- AgentRun start +- AgentRun stop OCF_SUCCESS +- Include check_ip_removed +- +-CASE "double start" +- Include prepare +- AgentRun start +- AgentRun start OCF_SUCCESS +- +-CASE "double stop" +- Include prepare +- AgentRun stop OCF_SUCCESS +- +-CASE "monitor with running" +- Include prepare +- AgentRun start +- AgentRun monitor OCF_SUCCESS +- +-CASE "monitor with not running" +- Include prepare +- AgentRun monitor OCF_NOT_RUNNING +- +-CASE "params with nic, no cidr_netmask" +- Include prepare +- Env OCF_RESKEY_nic=$OCFT_target_nic +- AgentRun start OCF_SUCCESS +- Include check_ip_assigned +- AgentRun monitor OCF_SUCCESS +- AgentRun stop OCF_SUCCESS +- Include check_ip_removed +- +-CASE "params with nic, cidr_netmask" +- Include prepare +- Env OCF_RESKEY_nic=$OCFT_target_nic +- Env OCF_RESKEY_cidr_netmask=$OCFT_target_prefix +- AgentRun start OCF_SUCCESS +- Include check_ip_assigned +- AgentRun monitor OCF_SUCCESS +- AgentRun stop OCF_SUCCESS +- Include check_ip_removed +- +-CASE "normal usage for a link-local IPv6 address" +- Include prepare +- Env OCF_RESKEY_ipv6addr=$OCFT_target_linklocal +- Env OCFT_check_ipv6addr=$OCFT_target_linklocal +- # nic is mandatory for a link-local address +- Env OCF_RESKEY_nic=$OCFT_target_nic +- AgentRun start OCF_SUCCESS +- Include check_ip_assigned +- AgentRun monitor OCF_SUCCESS +- AgentRun stop OCF_SUCCESS +- Include check_ip_removed +- +-CASE "error start for a link-local IPv6 address when no nic" +- Include prepare +- Env OCF_RESKEY_ipv6addr=$OCFT_target_linklocal +- # nic is mandatory for a link-local address +- Unenv OCF_RESKEY_nic +- AgentRun start OCF_ERR_GENERIC +- Include check_ip_removed +- +-CASE "error params with wrong ipv6addr" +- Include prepare +- Env OCF_RESKEY_ipv6addr=$OCFT_wrong_ipv6addr +- AgentRun start OCF_ERR_GENERIC +- +-# Note: this result is different from IPaddr2/findif +-# IPaddr2 succeeds if the ip matched based on the netmask of the subnet +-# or fails if it did not match to any. +-# Recommended to always specify both nic and cidr_netmask when you needed. +-CASE "error params with wrong cidr_netmask" +- Include prepare +- Env OCF_RESKEY_cidr_netmask=$OCFT_force_prefix +- AgentRun start OCF_ERR_GENERIC +- +-# Note: this result is different from IPaddr2/findif +-# IPaddr2 succeeds but it uses /32 as a guessed cidr_netmask which +-# does not seem to be expected. +-# Recommended to always specify both nic and cidr_netmask when you needed. +-CASE "error params with wrong nic" +- Include prepare +- Env OCF_RESKEY_nic=$OCFT_force_nic +- AgentRun start OCF_ERR_GENERIC +- +-# Note: This use case is now valid. It was not allowed until v3.9.2. +-CASE "force to use the specified nic and cidr_netmask" +- Include prepare +- Env OCF_RESKEY_nic=$OCFT_force_nic +- Env OCF_RESKEY_cidr_netmask=$OCFT_force_prefix +- Env OCFT_check_nic=$OCFT_force_nic +- Env OCFT_check_prefix=$OCFT_force_prefix +- AgentRun start OCF_SUCCESS +- Include check_ip_assigned +- AgentRun monitor OCF_SUCCESS +- AgentRun stop OCF_SUCCESS +- Include check_ip_removed +diff --git a/tools/ocft/LVM b/tools/ocft/LVM +deleted file mode 100644 +index 4bd2b22..0000000 +--- a/tools/ocft/LVM ++++ /dev/null +@@ -1,86 +0,0 @@ +-# LVM +-# by dejan@suse.de on +-# Wed Feb 16 13:15:01 CET 2011 +- +-CONFIG +- Agent LVM +- AgentRoot /usr/lib/ocf/resource.d/heartbeat +- HangTimeout 20 +- +-VARIABLE +- OCFT_pv=/var/run/resource-agents/ocft-LVM-pv +- OCFT_vg=ocft-vg +- OCFT_lv=ocft-lv +- OCFT_loop=/dev/loop7 +- +-SETUP-AGENT +- losetup $OCFT_loop 2>/dev/null && exit 1 +- dd if=/dev/zero of=$OCFT_pv bs=1 count=0 seek=16M 2>/dev/null +- losetup $OCFT_loop $OCFT_pv +- pvcreate $OCFT_loop +- vgcreate -s 4K $OCFT_vg $OCFT_loop +- lvcreate -n $OCFT_lv -L 600K $OCFT_vg +- +-CLEANUP-AGENT +- vgchange -an $OCFT_vg +- lvremove -f /dev/$OCFT_vg/$OCFT_lv +- vgremove -f $OCFT_vg +- pvremove $OCFT_loop +- losetup -d $OCFT_loop +- rm $OCFT_pv +- +-CASE-BLOCK required_args +- Env OCF_RESKEY_volgrpname=$OCFT_vg +- +-CASE-BLOCK default_status +- AgentRun stop +- +-CASE-BLOCK prepare +- Include required_args +- Include default_status +- +-CASE "check base env" +- Include prepare +- AgentRun start OCF_SUCCESS +- +-CASE "check base env: invalid 'OCF_RESKEY_volgrpname'" +- Include prepare +- Env OCF_RESKEY_volgrpname=/dev/no_such_device +- AgentRun start OCF_ERR_GENERIC +- +-CASE "check base env: unset 'OCF_RESKEY_volgrpname'" +- Include prepare +- Unenv OCF_RESKEY_volgrpname +- AgentRun start OCF_ERR_CONFIGURED +- +-CASE "normal start" +- Include prepare +- AgentRun start OCF_SUCCESS +- +-CASE "normal stop" +- Include prepare +- AgentRun start +- AgentRun stop OCF_SUCCESS +- +-CASE "double start" +- Include prepare +- AgentRun start +- AgentRun start OCF_SUCCESS +- +-CASE "double stop" +- Include prepare +- AgentRun stop OCF_SUCCESS +- +-CASE "monitor when running" +- Include prepare +- AgentRun start +- AgentRun monitor OCF_SUCCESS +- +-CASE "monitor when not running" +- Include prepare +- AgentRun monitor OCF_NOT_RUNNING +- +-CASE "unimplemented command" +- Include prepare +- AgentRun no_cmd OCF_ERR_UNIMPLEMENTED +- +diff --git a/tools/ocft/MailTo b/tools/ocft/MailTo +deleted file mode 100644 +index 8754035..0000000 +--- a/tools/ocft/MailTo ++++ /dev/null +@@ -1,57 +0,0 @@ +-# MailTo +- +-CONFIG +- Agent MailTo +- AgentRoot /usr/lib/ocf/resource.d/heartbeat +- InstallPackage mailx +- HangTimeout 20 +- +-CASE-BLOCK required_args +- Env OCF_RESKEY_email=root@localhost +- +-CASE-BLOCK default_status +- AgentRun stop +- +-CASE-BLOCK prepare +- Include required_args +- Include default_status +- +-CASE "check base env" +- Include prepare +- AgentRun start OCF_SUCCESS +- +-CASE "check base env: unset 'OCF_RESKEY_email'" +- Include prepare +- Unenv OCF_RESKEY_email +- AgentRun start OCF_ERR_CONFIGURED +- +-CASE "normal start" +- Include prepare +- AgentRun start OCF_SUCCESS +- +-CASE "normal stop" +- Include prepare +- AgentRun start +- AgentRun stop OCF_SUCCESS +- +-CASE "double start" +- Include prepare +- AgentRun start +- AgentRun start OCF_SUCCESS +- +-CASE "double stop" +- Include prepare +- AgentRun stop OCF_SUCCESS +- +-CASE "monitor with running" +- Include prepare +- AgentRun start +- AgentRun monitor OCF_SUCCESS +- +-CASE "monitor with not running" +- Include prepare +- AgentRun monitor OCF_NOT_RUNNING +- +-CASE "unimplemented command" +- Include prepare +- AgentRun no_cmd OCF_ERR_UNIMPLEMENTED +diff --git a/tools/ocft/Makefile.am b/tools/ocft/Makefile.am +index 733e487..9eab648 100644 +--- a/tools/ocft/Makefile.am ++++ b/tools/ocft/Makefile.am +@@ -22,29 +22,50 @@ EXTRA_DIST = $(ocftcfgs_DATA) $(ocft_DATA) + sbin_SCRIPTS = ocft + + ocftcfgsdir = $(datadir)/$(PACKAGE_NAME)/ocft/configs +-ocftcfgs_DATA = apache \ +- IPaddr2 \ +- IPaddr2v4 \ +- IPaddr2v6 \ +- IPv6addr \ +- Filesystem \ +- LVM \ +- Raid1 \ +- IPsrcaddr \ +- MailTo \ +- mysql \ +- mysql-proxy \ +- pgsql \ +- db2 \ +- oracle \ +- drbd.linbit \ +- nfsserver \ +- portblock \ +- iscsi \ +- named \ +- postfix \ +- Xinetd \ +- SendArp ++ ++ocftcfgs_DATA = ++if OCFT_FEDORA_CASES ++ocftcfgs_DATA += fedora/Filesystem \ ++ fedora/IPaddr2v4 \ ++ fedora/IPaddr2v6 \ ++ fedora/IPsrcaddr \ ++ fedora/SendArp \ ++ fedora/Xinetd \ ++ fedora/apache \ ++ fedora/mysql \ ++ fedora/nfsserver \ ++ fedora/pgsql \ ++ fedora/tomcat ++endif ++ ++if OCFT_DEFAULT_CASES ++ocftcfgs_DATA += default/apache \ ++ default/IPaddr2 \ ++ default/IPaddr2v4 \ ++ default/IPaddr2v6 \ ++ default/IPv6addr \ ++ default/Filesystem \ ++ default/LVM \ ++ default/Raid1 \ ++ default/IPsrcaddr \ ++ default/MailTo \ ++ default/jboss \ ++ default/mysql \ ++ default/mysql-proxy \ ++ default/pgsql \ ++ default/db2 \ ++ default/oracle \ ++ default/drbd.linbit \ ++ default/exportfs \ ++ default/nfsserver \ ++ default/portblock \ ++ default/iscsi \ ++ default/named \ ++ default/postfix \ ++ default/tomcat \ ++ default/Xinetd \ ++ default/SendArp ++endif + + ocftdir = $(datadir)/$(PACKAGE_NAME)/ocft + ocft_DATA = README \ +diff --git a/tools/ocft/Raid1 b/tools/ocft/Raid1 +deleted file mode 100644 +index 1c239c8..0000000 +--- a/tools/ocft/Raid1 ++++ /dev/null +@@ -1,146 +0,0 @@ +-# Raid1 +-# by dejan@suse.de on +-# Fri Aug 24 17:01:40 CEST 2012 +- +-CONFIG +- Agent Raid1 +- AgentRoot /usr/lib/ocf/resource.d/heartbeat +- InstallPackage mdadm +- HangTimeout 20 +- +-VARIABLE +- OCFT_disk0=/var/run/resource-agents/ocft-Raid1-disk0 +- OCFT_disk1=/var/run/resource-agents/ocft-Raid1-disk1 +- OCFT_disk2=/var/run/resource-agents/ocft-Raid1-disk2 +- OCFT_disk3=/var/run/resource-agents/ocft-Raid1-disk3 +- OCFT_raidconf=/var/run/resource-agents/ocft-mdadm.conf +- OCFT_raiddev=/dev/md8 +- OCFT_raiddev2=/dev/md9 +- OCFT_loop0=/dev/loop6 +- OCFT_loop1=/dev/loop7 +- OCFT_loop2=/dev/loop4 +- OCFT_loop3=/dev/loop5 +- +-SETUP-AGENT +- losetup $OCFT_loop0 2>/dev/null && exit 1 +- losetup $OCFT_loop1 2>/dev/null && exit 1 +- losetup $OCFT_loop2 2>/dev/null && exit 1 +- losetup $OCFT_loop3 2>/dev/null && exit 1 +- dd if=/dev/zero of=$OCFT_disk0 bs=1 count=0 seek=16M 2>/dev/null +- dd if=/dev/zero of=$OCFT_disk1 bs=1 count=0 seek=16M 2>/dev/null +- dd if=/dev/zero of=$OCFT_disk2 bs=1 count=0 seek=16M 2>/dev/null +- dd if=/dev/zero of=$OCFT_disk3 bs=1 count=0 seek=16M 2>/dev/null +- losetup $OCFT_loop0 $OCFT_disk0 +- losetup $OCFT_loop1 $OCFT_disk1 +- losetup $OCFT_loop2 $OCFT_disk2 +- losetup $OCFT_loop3 $OCFT_disk3 +- mdadm --create $OCFT_raiddev -l 0 --raid-devices=2 $OCFT_loop0 $OCFT_loop1 +- mdadm --create $OCFT_raiddev2 -l 0 --raid-devices=2 $OCFT_loop2 $OCFT_loop3 +- echo DEVICE $OCFT_loop0 $OCFT_loop1 > $OCFT_raidconf +- echo DEVICE $OCFT_loop2 $OCFT_loop3 >> $OCFT_raidconf +- echo ARRAY $OCFT_raiddev devices=$OCFT_loop0,$OCFT_loop1 >> $OCFT_raidconf +- echo ARRAY $OCFT_raiddev2 devices=$OCFT_loop2,$OCFT_loop3 >> $OCFT_raidconf +- +-CLEANUP-AGENT +- mdadm --zero-superblock $OCFT_loop0 +- mdadm --zero-superblock $OCFT_loop1 +- mdadm --zero-superblock $OCFT_loop2 +- mdadm --zero-superblock $OCFT_loop3 +- mdadm --remove $OCFT_raiddev 2>/dev/null +- mdadm --remove $OCFT_raiddev2 2>/dev/null +- losetup -d $OCFT_loop0 +- losetup -d $OCFT_loop1 +- losetup -d $OCFT_loop2 +- losetup -d $OCFT_loop3 +- rm $OCFT_disk0 $OCFT_disk1 $OCFT_raidconf +- rm $OCFT_disk2 $OCFT_disk3 +- +-CASE-BLOCK required_args +- Env OCF_RESKEY_raidconf=$OCFT_raidconf +- Env OCF_RESKEY_raiddev=$OCFT_raiddev +- +-CASE-BLOCK default_status +- AgentRun stop +- +-CASE-BLOCK prepare +- Include required_args +- Include default_status +- +-CASE-BLOCK prepare_auto +- Include required_args +- Env OCF_RESKEY_raiddev="auto" +- Include default_status +- +-CASE-BLOCK prepare_multiple +- Include required_args +- Env OCF_RESKEY_raiddev="$OCFT_raiddev $OCFT_raiddev2" +- Include default_status +- +-CASE "check base env" +- Include prepare +- AgentRun start OCF_SUCCESS +- +-CASE "check base env: invalid 'OCF_RESKEY_raiddev'" +- Include prepare +- Env OCF_RESKEY_raiddev=/dev/no_such_device +- AgentRun start OCF_ERR_GENERIC +- +-CASE "check base env: unset 'OCF_RESKEY_raiddev'" +- Include prepare +- Unenv OCF_RESKEY_raiddev +- AgentRun start OCF_ERR_CONFIGURED +- +-CASE "normal start" +- Include prepare +- AgentRun start OCF_SUCCESS +- +-CASE "normal stop" +- Include prepare +- AgentRun start +- AgentRun stop OCF_SUCCESS +- +-CASE "double start" +- Include prepare +- AgentRun start +- AgentRun start OCF_SUCCESS +- +-CASE "double stop" +- Include prepare +- AgentRun stop OCF_SUCCESS +- +-CASE "monitor when running" +- Include prepare +- AgentRun start +- AgentRun monitor OCF_SUCCESS +- +-CASE "monitor when not running" +- Include prepare +- AgentRun monitor OCF_NOT_RUNNING +- +-CASE "normal start (auto)" +- Include prepare_auto +- AgentRun start OCF_SUCCESS +- AgentRun monitor OCF_SUCCESS +- +-CASE "normal stop (auto)" +- Include prepare_auto +- AgentRun start +- AgentRun stop OCF_SUCCESS +- AgentRun monitor OCF_NOT_RUNNING +- +-CASE "normal start (multiple)" +- Include prepare +- AgentRun start OCF_SUCCESS +- AgentRun monitor OCF_SUCCESS +- +-CASE "normal stop (multiple)" +- Include prepare +- Env OCF_RESKEY_raiddev="$OCFT_raiddev $OCFT_raiddev2" +- AgentRun start +- AgentRun stop OCF_SUCCESS +- AgentRun monitor OCF_NOT_RUNNING +- +-CASE "unimplemented command" +- Include prepare +- AgentRun no_cmd OCF_ERR_UNIMPLEMENTED +- +diff --git a/tools/ocft/SendArp b/tools/ocft/SendArp +deleted file mode 100644 +index 7880388..0000000 +--- a/tools/ocft/SendArp ++++ /dev/null +@@ -1,74 +0,0 @@ +-# SendArp +- +-CONFIG +- Agent SendArp +- AgentRoot /usr/lib/ocf/resource.d/heartbeat +- InstallPackage resource-agents +- HangTimeout 15 +- +-CASE-BLOCK required_args +- Env OCF_RESKEY_ip=127.0.0.1 +- Env OCF_RESKEY_nic=lo +- Env OCF_RESKEY_background=false +- +-CASE-BLOCK default_status +- AgentRun stop +- +-CASE-BLOCK prepare +- Include required_args +- Include default_status +- +-CASE "check base env" +- Include prepare +- AgentRun start OCF_SUCCESS +- +-CASE "check base env: unset 'OCF_RESKEY_ip'" +- Include prepare +- Unenv OCF_RESKEY_ip +- AgentRun start OCF_ERR_CONFIGURED +- +-CASE "check base env: set invalid 'OCF_RESKEY_ip'" +- Include prepare +- Env OCF_RESKEY_ip=not_ip_address +- AgentRun start OCF_ERR_GENERIC +- +-CASE "check base env: unset 'OCF_RESKEY_nic'" +- Include prepare +- Unenv OCF_RESKEY_nic +- AgentRun start OCF_ERR_CONFIGURED +- +-CASE "check base env: set invalid 'OCF_RESKEY_nic'" +- Include prepare +- Env OCF_RESKEY_nic=not_nic +- AgentRun start OCF_ERR_GENERIC +- +-CASE "normal start" +- Include prepare +- AgentRun start OCF_SUCCESS +- +-CASE "normal stop" +- Include prepare +- AgentRun start +- AgentRun stop OCF_SUCCESS +- +-CASE "double start" +- Include prepare +- AgentRun start +- AgentRun start OCF_SUCCESS +- +-CASE "double stop" +- Include prepare +- AgentRun stop OCF_SUCCESS +- +-CASE "monitor with running" +- Include prepare +- AgentRun start +- AgentRun monitor OCF_SUCCESS +- +-CASE "monitor with not running" +- Include prepare +- AgentRun monitor OCF_NOT_RUNNING +- +-CASE "unimplemented command" +- Include prepare +- AgentRun no_cmd OCF_ERR_UNIMPLEMENTED +diff --git a/tools/ocft/Xinetd b/tools/ocft/Xinetd +deleted file mode 100644 +index ba9c85c..0000000 +--- a/tools/ocft/Xinetd ++++ /dev/null +@@ -1,56 +0,0 @@ +-# Xinetd +- +-CONFIG +- Agent Xinetd +- AgentRoot /usr/lib/ocf/resource.d/heartbeat +- InstallPackage xinetd +- +-CASE-BLOCK required_args +- Env OCF_RESKEY_service=discard +- +-CASE-BLOCK default_status +- AgentRun stop +- +-CASE-BLOCK prepare +- Include required_args +- Include default_status +- +-CASE "check base env" +- Include prepare +- AgentRun start OCF_SUCCESS +- +-CASE "check base env: unset 'OCF_RESKEY_protocol'" +- Include prepare +- Unenv OCF_RESKEY_service +- AgentRun start OCF_ERR_CONFIGURED +- +-CASE "normal start" +- Include prepare +- AgentRun start OCF_SUCCESS +- +-CASE "normal stop" +- Include prepare +- AgentRun start +- AgentRun stop OCF_SUCCESS +- +-CASE "double start" +- Include prepare +- AgentRun start +- AgentRun start OCF_SUCCESS +- +-CASE "double stop" +- Include prepare +- AgentRun stop OCF_SUCCESS +- +-CASE "monitor with running" +- Include prepare +- AgentRun start +- AgentRun monitor OCF_SUCCESS +- +-CASE "monitor with not running" +- Include prepare +- AgentRun monitor OCF_NOT_RUNNING +- +-CASE "unimplemented command" +- Include prepare +- AgentRun no_cmd OCF_ERR_UNIMPLEMENTED +diff --git a/tools/ocft/apache b/tools/ocft/apache +deleted file mode 100644 +index 797412d..0000000 +--- a/tools/ocft/apache ++++ /dev/null +@@ -1,63 +0,0 @@ +-# apache +-# make sure that your apache configuration loads mod_status +- +-CONFIG +- Agent apache +- AgentRoot /usr/lib/ocf/resource.d/heartbeat +- InstallPackage apache2 +- HangTimeout 20 +- +-SETUP-AGENT +- /etc/init.d/apache2 start +- /etc/init.d/apache2 stop +- +-CASE-BLOCK default_status +- AgentRun stop +- +-CASE-BLOCK prepare +- Include default_status +- +-CASE "check base env" +- Include prepare +- AgentRun start OCF_SUCCESS +- +-CASE "check base env: set non-existing OCF_RESKEY_statusurl" +- Include prepare +- Env OCF_RESKEY_statusurl="yoyoyoyo" +- AgentRun start OCF_ERR_CONFIGURED +- +-CASE "check base env: set non-existing OCF_RESKEY_configfile" +- Include prepare +- Env OCF_RESKEY_configfile="/yoyoyoyo/nosuchfile" +- AgentRun start OCF_ERR_INSTALLED +- +-CASE "normal start" +- Include prepare +- AgentRun start OCF_SUCCESS +- +-CASE "normal stop" +- Include prepare +- AgentRun start +- AgentRun stop OCF_SUCCESS +- +-CASE "double start" +- Include prepare +- AgentRun start +- AgentRun start OCF_SUCCESS +- +-CASE "double stop" +- Include prepare +- AgentRun stop OCF_SUCCESS +- +-CASE "running monitor" +- Include prepare +- AgentRun start +- AgentRun monitor OCF_SUCCESS +- +-CASE "not running monitor" +- Include prepare +- AgentRun monitor OCF_NOT_RUNNING +- +-CASE "unimplemented command" +- Include prepare +- AgentRun no_cmd OCF_ERR_UNIMPLEMENTED +diff --git a/tools/ocft/db2 b/tools/ocft/db2 +deleted file mode 100644 +index 7013a99..0000000 +--- a/tools/ocft/db2 ++++ /dev/null +@@ -1,164 +0,0 @@ +-# db2 +-# +-# This test assumes a db2 ESE instance with two partions and a database. +-# Default is instance=db2inst1, database=ocft +-# adapt this in set_testenv below +-# +-# Simple steps to generate a test environment (if you don't have one): +-# +-# A virtual machine with 1200MB RAM is sufficient +-# +-# - download an eval version of DB2 server from IBM +-# - create an user "db2inst1" in group "db2inst1" +-# +-# As root +-# - install DB2 software in some location +-# - create instance +-# cd /instance +-# ./db2icrt -s ese -u db2inst1 db2inst1 +-# - adapt profile of db2inst1 as instructed by db2icrt +-# +-# As db2inst1 +-# # allow to run with small memory footprint +-# db2set DB2_FCM_SETTINGS=FCM_MAXIMIZE_SET_SIZE:FALSE +-# db2start +-# db2start dbpartitionnum 1 add dbpartitionnum hostname $(uname -n) port 1 without tablespaces +-# db2stop +-# db2start +-# db2 create database ocft +-# Done +-# In order to install a real cluster refer to http://www.linux-ha.org/wiki/db2_(resource_agent) +- +-CONFIG +- Agent db2 +- AgentRoot /usr/lib/ocf/resource.d/heartbeat +- HangTimeout 40 +- +-SETUP-AGENT +- # nothing +- +-CASE-BLOCK set_testenv +- Env OCFT_instance=db2inst1 +- Env OCFT_db=ocft +- +-CASE-BLOCK crm_setting +- Env OCF_RESKEY_instance=$OCFT_instance +- Env OCF_RESKEY_CRM_meta_timeout=30000 +- +-CASE-BLOCK default_status +- AgentRun stop +- +-CASE-BLOCK prepare +- Include set_testenv +- Include crm_setting +- Include default_status +- +-CASE "check base env" +- Include prepare +- AgentRun start OCF_SUCCESS +- +-CASE "check base env: invalid 'OCF_RESKEY_instance'" +- Include prepare +- Env OCF_RESKEY_instance=no_such +- AgentRun start OCF_ERR_INSTALLED +- +-CASE "invalid instance config" +- Include prepare +- Bash eval mv ~$OCFT_instance/sqllib ~$OCFT_instance/sqllib- +- BashAtExit eval mv ~$OCFT_instance/sqllib- ~$OCFT_instance/sqllib +- AgentRun start OCF_ERR_INSTALLED +- +-CASE "unimplemented command" +- Include prepare +- AgentRun no_cmd OCF_ERR_UNIMPLEMENTED +- +-CASE "normal start" +- Include prepare +- AgentRun start OCF_SUCCESS +- +-CASE "normal stop" +- Include prepare +- AgentRun start +- AgentRun stop OCF_SUCCESS +- +-CASE "double start" +- Include prepare +- AgentRun start +- AgentRun start OCF_SUCCESS +- +-CASE "double stop" +- Include prepare +- AgentRun stop OCF_SUCCESS +- +-CASE "started: monitor" +- Include prepare +- AgentRun start +- AgentRun monitor OCF_SUCCESS +- +-CASE "not started: monitor" +- Include prepare +- AgentRun monitor OCF_NOT_RUNNING +- +-CASE "killed instance: monitor" +- Include prepare +- AgentRun start OCF_SUCCESS +- AgentRun monitor OCF_SUCCESS +- BashAtExit rm /tmp/ocft-helper1 +- Bash echo "su $OCFT_instance -c '. ~$OCFT_instance/sqllib/db2profile; db2nkill 0 >/dev/null 2>&1'" > /tmp/ocft-helper1 +- Bash sh -x /tmp/ocft-helper1 +- AgentRun monitor OCF_NOT_RUNNING +- +-CASE "overload param instance by admin" +- Include prepare +- Env OCF_RESKEY_instance=no_such +- Env OCF_RESKEY_admin=$OCFT_instance +- AgentRun start OCF_SUCCESS +- +-CASE "check start really activates db" +- Include prepare +- AgentRun start OCF_SUCCESS +- +- BashAtExit rm /tmp/ocft-helper2 +- Bash echo "su $OCFT_instance -c '. ~$OCFT_instance/sqllib/db2profile; db2 get snapshot for database on $OCFT_db>/dev/null'" > /tmp/ocft-helper2 +- Bash sh -x /tmp/ocft-helper2 +- +-CASE "multipartion test" +- Include prepare +- AgentRun start OCF_SUCCESS +- AgentRun monitor OCF_SUCCESS +- +- # start does not start partion 1 +- Env OCF_RESKEY_dbpartitionnum=1 +- AgentRun monitor OCF_NOT_RUNNING +- +- # now start 1 +- AgentRun start OCF_SUCCESS +- AgentRun monitor OCF_SUCCESS +- +- # now stop 1 +- AgentRun stop OCF_SUCCESS +- AgentRun monitor OCF_NOT_RUNNING +- +- # does not affect 0 +- Env OCF_RESKEY_dbpartitionnum=0 +- AgentRun monitor OCF_SUCCESS +- +-# fault injection does not work on the 1.0.4 client due to a hardcoded path +-CASE "simulate hanging db2stop (not meaningful for 1.0.4 agent)" +- Include prepare +- AgentRun start OCF_SUCCESS +- Bash [ ! -f /usr/local/bin/db2stop ] +- BashAtExit rm /usr/local/bin/db2stop +- Bash echo -e "#!/bin/sh\necho fake db2stop\nsleep 10000" > /usr/local/bin/db2stop +- Bash chmod +x /usr/local/bin/db2stop +- AgentRun stop OCF_SUCCESS +- +-# fault injection does not work on the 1.0.4 client due to a hardcoded path +-CASE "simulate not stopping db2stop (not meaningful for 1.0.4 agent)" +- Include prepare +- AgentRun start OCF_SUCCESS +- Bash [ ! -f /usr/local/bin/db2stop ] +- BashAtExit rm /usr/local/bin/db2stop +- Bash echo -e "#!/bin/sh\necho fake db2stop\nexit 0" > /usr/local/bin/db2stop +- Bash chmod +x /usr/local/bin/db2stop +- AgentRun stop OCF_SUCCESS +diff --git a/tools/ocft/default/Filesystem b/tools/ocft/default/Filesystem +new file mode 100644 +index 0000000..75203d7 +--- /dev/null ++++ b/tools/ocft/default/Filesystem +@@ -0,0 +1,110 @@ ++# Filesystem ++# by dejan@suse.de on ++# Tue Feb 15 18:50:04 CET 2011 ++ ++CONFIG ++ Agent Filesystem ++ AgentRoot /usr/lib/ocf/resource.d/heartbeat ++ HangTimeout 20 ++ ++VARIABLE ++ OCFT_fs=/var/run/resource-agents/ocft-Filesystem-fs ++ OCFT_loop=/dev/loop7 ++ OCFT_dir=/var/run/resource-agents/ocft-Filesystem-mnt ++ ++SETUP-AGENT ++ losetup $OCFT_loop 2>/dev/null && exit 1 ++ rmdir $OCFT_dir 2>/dev/null || true ++ mkdir $OCFT_dir ++ dd if=/dev/zero of=$OCFT_fs bs=1 count=0 seek=16M 2>/dev/null ++ mke2fs -j -Fq -m 0 $OCFT_fs ++ losetup $OCFT_loop $OCFT_fs ++ ++CLEANUP-AGENT ++ rmdir $OCFT_dir ++ rm $OCFT_fs ++ losetup -d $OCFT_loop ++ ++CASE-BLOCK required_args ++ Env OCF_RESKEY_device=$OCFT_loop ++ Env OCF_RESKEY_fstype=ext3 ++ Env OCF_RESKEY_directory=$OCFT_dir ++ ++CASE-BLOCK default_status ++ AgentRun stop ++ ++CASE-BLOCK prepare ++ Include required_args ++ Include default_status ++ ++CASE "check base env" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ ++CASE "check base env: invalid 'OCF_RESKEY_device'" ++ Include prepare ++ Env OCF_RESKEY_device=/dev/no_such_device ++ AgentRun start OCF_ERR_INSTALLED ++ ++CASE "check base env: unset 'OCF_RESKEY_device'" ++ Include prepare ++ Unenv OCF_RESKEY_device ++ AgentRun start OCF_ERR_CONFIGURED ++ ++CASE "normal start" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ ++CASE "normal stop" ++ Include prepare ++ AgentRun start ++ AgentRun stop OCF_SUCCESS ++ ++CASE "double start" ++ Include prepare ++ AgentRun start ++ AgentRun start OCF_SUCCESS ++ ++CASE "double stop" ++ Include prepare ++ AgentRun stop OCF_SUCCESS ++ ++CASE "monitor when running" ++ Include prepare ++ AgentRun start ++ AgentRun monitor OCF_SUCCESS ++ ++CASE "monitor when not running" ++ Include prepare ++ AgentRun monitor OCF_NOT_RUNNING ++ ++CASE "monitor depth 10 when running" ++ Include prepare ++ AgentRun start ++ Env OCF_CHECK_LEVEL=10 ++ AgentRun monitor OCF_SUCCESS ++ ++CASE "monitor depth 20 with running" ++ Include prepare ++ AgentRun start ++ Env OCF_CHECK_LEVEL=20 ++ AgentRun monitor OCF_SUCCESS ++ ++CASE "start insert failure (remove device)" ++ Include prepare ++ Bash losetup -d $OCFT_loop ++ BashAtExit losetup $OCFT_loop $OCFT_fs ++ AgentRun start OCF_ERR_GENERIC ++ ++CASE "monitor depth 20 insert failure (r/o fs)" ++ Include prepare ++ AgentRun start ++ Bash mount -o remount,ro $OCFT_dir ++ BashAtExit mount -o remount,rw $OCFT_dir ++ Env OCF_CHECK_LEVEL=20 ++ AgentRun monitor OCF_ERR_GENERIC ++ ++CASE "unimplemented command" ++ Include prepare ++ AgentRun no_cmd OCF_ERR_UNIMPLEMENTED ++ +diff --git a/tools/ocft/default/IPaddr2 b/tools/ocft/default/IPaddr2 +new file mode 100644 +index 0000000..1cf81bf +--- /dev/null ++++ b/tools/ocft/default/IPaddr2 +@@ -0,0 +1,137 @@ ++# IPaddr2 ++ ++CONFIG ++ Agent IPaddr2 ++ AgentRoot /usr/lib/ocf/resource.d/heartbeat ++ HangTimeout 20 ++ ++SETUP-AGENT ++ ip addr add 192.168.144.1/24 dev eth0 brd 192.168.144.255 ++ ++CLEANUP-AGENT ++ ip addr del 192.168.144.1/24 dev eth0 ++ ++CASE-BLOCK required_args ++ Env OCF_RESKEY_ip=192.168.144.2 ++ ++CASE-BLOCK check_iflabel_assigned ++ Bash ip -4 -o addr show eth0 | grep -w 192.168.144.2/24 | grep -w eth0:iflabel >/dev/null # checking iflabel was assigned correctly ++ ++CASE-BLOCK check_iflabel_removed ++ Bash ! ip -4 -o addr show eth0 | grep -w 192.168.144.2/24 | grep -w eth0:iflabel >/dev/null # checking iflabel was removed correctly ++ ++CASE-BLOCK default_status ++ AgentRun stop ++ ++CASE-BLOCK prepare ++ Include required_args ++ Include default_status ++ ++CASE "check base env" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ ++CASE "check base env: unset 'OCF_RESKEY_ip'" ++ Include prepare ++ Unenv OCF_RESKEY_ip ++ AgentRun start OCF_ERR_CONFIGURED ++ ++CASE "check base env: set invalid 'OCF_RESKEY_ip'" ++ Include prepare ++ Env OCF_RESKEY_ip=not_ip_address ++ AgentRun start OCF_ERR_CONFIGURED ++ ++CASE "check base env: set 'OCF_RESKEY_cidr_netmask'" ++ Include prepare ++ Env OCF_RESKEY_cidr_netmask=24 ++ AgentRun start OCF_SUCCESS ++ ++CASE "check base env: set invalid 'OCF_RESKEY_cidr_netmask'" ++ Include prepare ++ Env OCF_RESKEY_cidr_netmask=not_netmask ++ AgentRun start OCF_ERR_CONFIGURED ++ ++CASE "check base env: set 'OCF_RESKEY_broadcast'" ++ Include prepare ++ Env OCF_RESKEY_broadcast=192.168.144.255 ++ AgentRun start OCF_SUCCESS ++ ++CASE "check base env: set invalid 'OCF_RESKEY_broadcast'" ++ Include prepare ++ Env OCF_RESKEY_broadcast=not_broadcast ++ AgentRun start OCF_ERR_CONFIGURED ++ ++CASE "check base env: set 'OCF_RESKEY_nic'" ++ Include prepare ++ Env OCF_RESKEY_nic=eth0 ++ AgentRun start OCF_SUCCESS ++ ++CASE "check base env: set invalid 'OCF_RESKEY_nic'" ++ Include prepare ++ Env OCF_RESKEY_nic=not_nic ++ AgentRun start OCF_ERR_CONFIGURED ++ AgentRun validate-all OCF_ERR_CONFIGURED ++ ++CASE "normal start" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ ++CASE "normal stop" ++ Include prepare ++ AgentRun start ++ AgentRun stop OCF_SUCCESS ++ ++CASE "double start" ++ Include prepare ++ AgentRun start ++ AgentRun start OCF_SUCCESS ++ ++CASE "double stop" ++ Include prepare ++ AgentRun stop OCF_SUCCESS ++ ++CASE "monitor with running" ++ Include prepare ++ AgentRun start ++ AgentRun monitor OCF_SUCCESS ++ ++CASE "monitor with not running" ++ Include prepare ++ AgentRun monitor OCF_NOT_RUNNING ++ ++CASE "unimplemented command" ++ Include prepare ++ AgentRun no_cmd OCF_ERR_UNIMPLEMENTED ++ ++CASE "Attachment to loopback interface" ++ Env OCF_RESKEY_ip=127.0.0.3 ++ AgentRun start OCF_SUCCESS ++ AgentRun monitor OCF_SUCCESS ++ AgentRun stop OCF_SUCCESS ++ ++CASE "check additional env: set 'OCF_RESKEY_iflabel'" ++ Include prepare ++ Env OCF_RESKEY_nic=eth0 ++ Env OCF_RESKEY_iflabel=iflabel ++ AgentRun start OCF_SUCCESS ++ Include check_iflabel_assigned ++ AgentRun stop OCF_SUCCESS ++ Include check_iflabel_removed ++ ++# This is deprecated but still supported for the compatibility. ++CASE "check additional env: specify iflabel in 'OCF_RESKEY_nic'" ++ Include prepare ++ Env OCF_RESKEY_nic=eth0:iflabel ++ AgentRun start OCF_SUCCESS ++ Include check_iflabel_assigned ++ AgentRun stop OCF_SUCCESS ++ Include check_iflabel_removed ++ ++# monitor should return OCF_ERR_GENERIC rather than OCF_ERR_CONFIGURED ++# when the specified OCF_RESKEY_nic is disappeard by a failure. ++# This has been changed as of 3.9.6. ++CASE "monitor failure when 'OCF_RESKEY_nic' is disappeared" ++ Include prepare ++ Env OCF_RESKEY_nic=ethDisappear ++ Env OCF_RESKEY_CRM_meta_interval=10 # not in probe ++ AgentRun monitor OCF_ERR_GENERIC +diff --git a/tools/ocft/default/IPaddr2v4 b/tools/ocft/default/IPaddr2v4 +new file mode 100644 +index 0000000..4d37168 +--- /dev/null ++++ b/tools/ocft/default/IPaddr2v4 +@@ -0,0 +1,323 @@ ++# IPaddr2v4 ++ ++# Note: This test case uses two NICs(eth0, eth1) and ++# a IPv4 address prefix (192.168.144.0/24). ++# Adjust them according to your environment at VARIABLE section if needed. ++ ++CONFIG ++ Agent IPaddr2 ++ AgentRoot /usr/lib/ocf/resource.d/heartbeat ++ HangTimeout 20 ++ ++VARIABLE ++ OCFT_target_ip=192.168.144.2 ++ OCFT_target_nic=eth0 ++ OCFT_target_prefix=24 ++ OCFT_target_netaddr=192.168.144.1/$OCFT_target_prefix ++ OCFT_target_brd=192.168.144.255 ++ OCFT_wrong_ip=192.168.120.1 ++ OCFT_force_nic=eth1 ++ OCFT_force_prefix=16 ++ OCFT_force_prefix2=28 ++ OCFT_force_brd=192.168.255.255 ++ ++SETUP-AGENT ++ ip addr add $OCFT_target_netaddr dev $OCFT_target_nic brd $OCFT_target_brd ++ ++CLEANUP-AGENT ++ ip addr del $OCFT_target_netaddr dev $OCFT_target_nic ++ ++CASE-BLOCK required_args ++ Env OCF_RESKEY_ip=$OCFT_target_ip ++ Env OCFT_check_ip=$OCFT_target_ip ++ Env OCFT_check_prefix=$OCFT_target_prefix ++ Env OCFT_check_nic=$OCFT_target_nic ++ ++CASE-BLOCK check_ip_assigned ++ Bash ip -4 -o addr show $OCFT_check_nic | grep -w $OCFT_check_ip/$OCFT_check_prefix >/dev/null # checking if the IPv4 address was assigned correctly ++ ++CASE-BLOCK check_ip_removed ++ Bash ! ip -4 -o addr show $OCFT_check_nic | grep -w $OCFT_check_ip/$OCFT_check_prefix >/dev/null # checking if the IPv4 address was removed correctly ++ ++CASE-BLOCK base_ip_assigned ++ Bash ip addr add $OCFT_target_netaddr dev $OCFT_target_nic brd $OCFT_target_brd ++ ++CASE-BLOCK base_ip_removed ++ Bash ip addr del $OCFT_target_netaddr dev $OCFT_target_nic ++ ++CASE-BLOCK default_status ++ AgentRun stop ++ ++CASE-BLOCK prepare ++ Include required_args ++ Include default_status ++ ++# CASE No.0 ++# ++CASE "normal start" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ Include check_ip_assigned ++ ++# CASE No.1 ++# ++CASE "normal stop" ++ Include prepare ++ AgentRun start ++ AgentRun stop OCF_SUCCESS ++ Include check_ip_removed ++ ++# CASE No.2 ++# ++CASE "double start" ++ Include prepare ++ AgentRun start ++ AgentRun start OCF_SUCCESS ++ ++# CASE No.3 ++# ++CASE "double stop" ++ Include prepare ++ AgentRun stop OCF_SUCCESS ++ ++# CASE No.4 ++# ++CASE "monitor with running" ++ Include prepare ++ AgentRun start ++ AgentRun monitor OCF_SUCCESS ++ ++# CASE No.5 ++# ++CASE "monitor with not running" ++ Include prepare ++ AgentRun monitor OCF_NOT_RUNNING ++ ++# CASE No.6 ++# Note: this result is different from IPaddr2 in 3.9.3. ++# IPaddr2 succeeds if the ip matched based on the netmask of the subnet ++# or fails if it did not match to any. ++# Recommended to always specify both nic, cidr_netmask, and broadcast when you needed. ++# IPaddr2 in 3.9.3 was using a wrong subnet mask (constant of 32) in this case. ++# ++CASE "params with nic, no cidr_netmask" ++ Include prepare ++ Env OCF_RESKEY_nic=$OCFT_target_nic ++ AgentRun start OCF_SUCCESS ++ Include check_ip_assigned ++ AgentRun monitor OCF_SUCCESS ++ AgentRun stop OCF_SUCCESS ++ Include check_ip_removed ++ ++# CASE No.7 ++# ++CASE "params with nic, cidr_netmask" ++ Include prepare ++ Env OCF_RESKEY_nic=$OCFT_target_nic ++ Env OCF_RESKEY_cidr_netmask=$OCFT_target_prefix ++ AgentRun start OCF_SUCCESS ++ Include check_ip_assigned ++ AgentRun monitor OCF_SUCCESS ++ AgentRun stop OCF_SUCCESS ++ Include check_ip_removed ++ ++# CASE No.8 ++# ++CASE "error params with wrong ip" ++ Include prepare ++ Env OCF_RESKEY_ip=$OCFT_wrong_ip ++ AgentRun start OCF_ERR_GENERIC ++ ++# CASE No.9 ++# Note: this result is different from IPaddr2 in 3.9.3. ++# IPaddr2 fails when it could not determine the correct subnet mask. ++# When it could not get base ip, it becomes the error. ++# Recommended to always specify both nic, cidr_netmask, and broadcast when you needed. ++# IPaddr2 in 3.9.3 was using a wrong subnet mask (constant of 32) in this case. ++# ++CASE "params with force nic" ++ Include prepare ++ Env OCF_RESKEY_nic=$OCFT_force_nic ++ Env OCFT_check_nic=$OCFT_force_nic ++ AgentRun start OCF_ERR_GENERIC ++ Include check_ip_removed ++ Unenv OCF_RESKEY_nic ++ ++# CASE No.10 ++# Note: this result is different from IPaddr2 in 3.9.3. ++# IPaddr2 fails when it could not determine the broadcast. ++# Recommended to always specify both nic, cidr_netmask, and broadcast when you needed. ++# IPaddr2 in 3.9.3 succeeded but it's considered ambiguous. ++# ++CASE "params with force cidr_netmask (base netmask > assigned netmask)" ++ Include prepare ++ Env OCF_RESKEY_cidr_netmask=$OCFT_force_prefix ++ Env OCFT_check_prefix=$OCFT_force_prefix ++ AgentRun start OCF_ERR_GENERIC ++ Include check_ip_removed ++ ++# CASE No.11 ++# Note: this result is different from IPaddr2 in 3.9.3. ++# IPaddr2 succeeds but the broadcast is not set. ++# This is because findif.sh can not calculate a broadcast from a netmask. ++# Recommended to always specify both nic, cidr_netmask, and broadcast when you needed. ++# IPaddr2 in 3.9.3 succeeded with using a calculated broadcast. ++# ++CASE "force to use the specified nic and cidr_netmask" ++ Include prepare ++ Env OCF_RESKEY_nic=$OCFT_force_nic ++ Env OCF_RESKEY_cidr_netmask=$OCFT_force_prefix ++ Env OCFT_check_nic=$OCFT_force_nic ++ Env OCFT_check_prefix=$OCFT_force_prefix ++ AgentRun start OCF_SUCCESS ++ AgentRun stop OCF_SUCCESS ++ Include check_ip_removed ++ Unenv OCF_RESKEY_cidr_netmask ++ ++ ++# CASE No.12 ++# Note: this result is different from IPaddr2 in 3.9.3. ++# IPaddr2 fails when it could not determine the correct subnet mask. ++# When it could not get base ip, it becomes the error. ++# Recommended to always specify both nic, cidr_netmask, and broadcast when you needed. ++# IPaddr2 in 3.9.3 was using a wrong subnet mask (constant of 32) in this case. ++# ++CASE "error params with wrong ip and nic (not exist base_ip)" ++ Include prepare ++ Include base_ip_removed ++ Env OCF_RESKEY_nic=$OCFT_target_nic ++ Env OCFT_check_nic=$OCFT_target_nic ++ AgentRun start OCF_ERR_GENERIC ++ Include check_ip_removed ++ Include base_ip_assigned ++ ++# CASE No.13 ++# ++CASE "params with cidr_netmask" ++ Include prepare ++ Env OCF_RESKEY_cidr_netmask=$OCFT_target_prefix ++ AgentRun start OCF_SUCCESS ++ Include check_ip_assigned ++ AgentRun monitor OCF_SUCCESS ++ AgentRun stop OCF_SUCCESS ++ Include check_ip_removed ++ ++# CASE No.14 ++# Note: this result is different from IPaddr2 in 3.9.3. ++# IPaddr2 does not override the broadcast by cidr_netmask. ++# Recommended to always specify both nic, cidr_netmask, and broadcast when you needed. ++# IPaddr2 in 3.9.3 overrode the broadcast calculated by cidr_netmask. ++# ++CASE "params with force cidr_netmask (base netmask < assigned netmask)" ++ Include prepare ++ Env OCF_RESKEY_cidr_netmask=$OCFT_force_prefix2 ++ Env OCFT_check_prefix=$OCFT_force_prefix2 ++ AgentRun start OCF_SUCCESS ++ Include check_ip_assigned ++ AgentRun monitor OCF_SUCCESS ++ AgentRun stop OCF_SUCCESS ++ Include check_ip_removed ++ ++# CASE No.15 ++# Note: this result is different from IPaddr2 in 3.9.3. ++# IPaddr2 fails when it could not determine the broadcast. ++# Recommended to always specify both nic, cidr_netmask, and broadcast when you needed. ++# IPaddr2 in 3.9.3 succeeded but it's considered ambiguous. ++# ++CASE "error params with wrong ip and cidr_netmask (not exist base_ip)" ++ Include prepare ++ Include base_ip_removed ++ Env OCF_RESKEY_cidr_netmask=$OCFT_target_prefix ++ AgentRun start OCF_ERR_GENERIC ++ Include base_ip_assigned ++ ++# CASE No.16 ++# Note: this result is different from IPaddr2 in 3.9.3. ++# IPaddr2 succeeds but the broadcast is not set. ++# This is because findif.sh can not calculate a broadcast from a netmask. ++# Recommended to always specify both nic, cidr_netmask, and broadcast when you needed. ++# IPaddr2 in 3.9.3 succeeded with using a calculated broadcast. ++# ++CASE "force to use the specified nic and cidr_netmask" ++ Include prepare ++ Env OCF_RESKEY_nic=$OCFT_force_nic ++ Env OCF_RESKEY_cidr_netmask=$OCFT_force_prefix2 ++ Env OCFT_check_prefix=$OCFT_force_prefix2 ++ Env OCFT_check_nic=$OCFT_force_nic ++ AgentRun start OCF_SUCCESS ++ AgentRun stop OCF_SUCCESS ++ Include check_ip_removed ++ ++# CASE No.17 ++# Note: this result is different from IPaddr2 in 3.9.3. ++# IPaddr2 succeeds but the broadcast is not set. ++# This is because findif.sh can not calculate a broadcast from a netmask. ++# Recommended to always specify both nic, cidr_netmask, and broadcast when you needed. ++# IPaddr2 in 3.9.3 succeeded with using a calculated broadcast. ++# ++CASE "force to use the specified nic and cidr_netmask (not exist base_ip)" ++ Include prepare ++ Include base_ip_removed ++ Env OCF_RESKEY_nic=$OCFT_force_nic ++ Env OCF_RESKEY_cidr_netmask=$OCFT_force_prefix2 ++ Env OCFT_check_prefix=$OCFT_force_prefix2 ++ Env OCFT_check_nic=$OCFT_force_nic ++ AgentRun start OCF_SUCCESS ++ AgentRun stop OCF_SUCCESS ++ Unenv OCF_RESKEY_nic ++ Unenv OCF_RESKEY_cidr_netmask ++ Include base_ip_assigned ++ ++# CASE No.18 ++# ++CASE "params with broadcast, no nic, no cidr_netmask" ++ Include prepare ++ Env OCF_RESKEY_broadcast=$OCFT_force_brd ++ AgentRun start OCF_SUCCESS ++ Include check_ip_assigned ++ AgentRun monitor OCF_SUCCESS ++ AgentRun stop OCF_SUCCESS ++ Include check_ip_removed ++ ++# CASE No.19 ++# ++CASE "params with broadcast, no nic, no cidr_netmask" ++ Include prepare ++ Include base_ip_removed ++ Env OCF_RESKEY_broadcast=$OCFT_force_brd ++ AgentRun start OCF_ERR_GENERIC ++ Include base_ip_assigned ++ ++# CASE No.20 ++# ++CASE "force to use the specified nic and cidr_netmask" ++ Include prepare ++ Env OCF_RESKEY_nic=$OCFT_force_nic ++ Env OCF_RESKEY_cidr_netmask=$OCFT_force_prefix ++ Env OCF_RESKEY_broadcast=$OCFT_force_brd ++ Env OCFT_check_nic=$OCFT_force_nic ++ Env OCFT_check_prefix=$OCFT_force_prefix ++ AgentRun start OCF_SUCCESS ++ Include check_ip_assigned ++ AgentRun monitor OCF_SUCCESS ++ AgentRun stop OCF_SUCCESS ++ Include check_ip_removed ++ Unenv OCF_RESKEY_cidr_netmask ++ ++# CASE No.21 ++# ++CASE "force to use the specified nic and cidr_netmask" ++ Include prepare ++ Include base_ip_removed ++ Env OCF_RESKEY_nic=$OCFT_force_nic ++ Env OCF_RESKEY_cidr_netmask=$OCFT_force_prefix2 ++ Env OCF_RESKEY_broadcast=$OCFT_target_brd ++ Env OCFT_check_nic=$OCFT_force_nic ++ Env OCFT_check_prefix=$OCFT_force_prefix2 ++ AgentRun start OCF_SUCCESS ++ Include check_ip_assigned ++ AgentRun monitor OCF_SUCCESS ++ AgentRun stop OCF_SUCCESS ++ Include check_ip_removed ++ Include base_ip_assigned ++ +diff --git a/tools/ocft/default/IPaddr2v6 b/tools/ocft/default/IPaddr2v6 +new file mode 100644 +index 0000000..d24d890 +--- /dev/null ++++ b/tools/ocft/default/IPaddr2v6 +@@ -0,0 +1,250 @@ ++# IPaddr2v6 ++ ++# Note: This test case uses two NICs(eth0, eth1) and ++# a IPv6 address prefix (2001:db8::/32, RFC3849). ++# Adjust them according to your environment at VARIABLE section if needed. ++ ++CONFIG ++ Agent IPaddr2 ++ AgentRoot /usr/lib/ocf/resource.d/heartbeat ++ HangTimeout 20 ++ ++VARIABLE ++ OCFT_target_ip=2001:db8:1234::2 ++ OCFT_target_nic=eth0 ++ OCFT_target_prefix=64 ++ OCFT_target_netaddr=2001:db8:1234::1/$OCFT_target_prefix ++ OCFT_target_linklocal=fe80::2 ++ OCFT_wrong_ip=2001:db8:5678::2 ++ OCFT_force_nic=eth1 ++ OCFT_force_prefix=80 ++ OCFT_force_prefix2=48 ++ ++SETUP-AGENT ++ ip addr add $OCFT_target_netaddr dev $OCFT_target_nic ++ ++CLEANUP-AGENT ++ ip addr del $OCFT_target_netaddr dev $OCFT_target_nic ++ ++CASE-BLOCK required_args ++ Env OCF_RESKEY_ip=$OCFT_target_ip ++ Env OCFT_check_ip=$OCFT_target_ip ++ Env OCFT_check_prefix=$OCFT_target_prefix ++ Env OCFT_check_nic=$OCFT_target_nic ++ ++CASE-BLOCK check_ip_assigned ++ Bash ip -6 -o addr show $OCFT_check_nic | grep -w $OCFT_check_ip/$OCFT_check_prefix >/dev/null # checking if the IPv6 address was assigned correctly ++ ++CASE-BLOCK check_ip_removed ++ Bash ! ip -6 -o addr show $OCFT_check_nic | grep -w $OCFT_check_ip/$OCFT_check_prefix >/dev/null # checking if the IPv6 address was removed correctly ++ ++CASE-BLOCK base_ip_assigned ++ Bash ip addr add $OCFT_target_netaddr dev $OCFT_target_nic ++ ++CASE-BLOCK base_ip_removed ++ Bash ip addr del $OCFT_target_netaddr dev $OCFT_target_nic ++ ++CASE-BLOCK default_status ++ AgentRun stop ++ ++CASE-BLOCK prepare ++ Include required_args ++ Include default_status ++ ++# CASE No.0 ++# ++CASE "normal start" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ Include check_ip_assigned ++ ++# CASE No.1 ++# ++CASE "normal stop" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ AgentRun stop OCF_SUCCESS ++ Include check_ip_removed ++ ++# CASE No.2 ++# ++CASE "double start" ++ Include prepare ++ AgentRun start ++ AgentRun start OCF_SUCCESS ++ ++# CASE No.3 ++# ++CASE "double stop" ++ Include prepare ++ AgentRun stop OCF_SUCCESS ++ ++# CASE No.4 ++# ++CASE "monitor with running" ++ Include prepare ++ AgentRun start ++ AgentRun monitor OCF_SUCCESS ++ ++# CASE No.5 ++# ++CASE "monitor with not running" ++ Include prepare ++ AgentRun monitor OCF_NOT_RUNNING ++ ++# CASE No.6 ++# ++CASE "error params with wrong ip" ++ Include prepare ++ Env OCF_RESKEY_ip=$OCFT_wrong_ip ++ AgentRun start OCF_ERR_GENERIC ++ ++# CASE No.7 ++# ++CASE "error params with no nic for a link-local IPv6 address" ++ Include prepare ++ Env OCF_RESKEY_ip=$OCFT_target_linklocal ++ Env OCFT_check_ip=$OCFT_target_linklocal ++ # nic is mandatory for a link-local address ++ AgentRun start OCF_ERR_CONFIGURED ++ ++# CASE No.8 ++# ++CASE "params with nic, no cidr_netmask" ++ Include prepare ++ Env OCF_RESKEY_nic=$OCFT_target_nic ++ AgentRun start OCF_SUCCESS ++ Include check_ip_assigned ++ AgentRun monitor OCF_SUCCESS ++ AgentRun stop OCF_SUCCESS ++ Include check_ip_removed ++ ++# CASE No.9 ++# ++CASE "normal usage for a link-local IPv6 address, params with nic" ++ Include prepare ++ Env OCF_RESKEY_ip=$OCFT_target_linklocal ++ Env OCFT_check_ip=$OCFT_target_linklocal ++ # nic is mandatory for a link-local address ++ Env OCF_RESKEY_nic=$OCFT_target_nic ++ Env OCFT_check_nic=$OCFT_target_nic ++ AgentRun start OCF_SUCCESS ++ Include check_ip_assigned ++ AgentRun stop OCF_SUCCESS ++ Include check_ip_removed ++ ++# CASE No.10 ++# ++CASE "error params with wrong ip and nic (not exist base_ip)" ++ Include prepare ++ Include base_ip_removed ++ Env OCF_RESKEY_nic=$OCFT_target_nic ++ Env OCFT_check_nic=$OCFT_target_nic ++ AgentRun start OCF_ERR_GENERIC ++ Include check_ip_removed ++ Include base_ip_assigned ++ ++# CASE No.11 ++# ++CASE "params with force nic" ++ Include prepare ++ Env OCF_RESKEY_nic=$OCFT_force_nic ++ Env OCFT_check_nic=$OCFT_force_nic ++ AgentRun start OCF_ERR_GENERIC ++ Include check_ip_removed ++ Unenv OCF_RESKEY_nic ++ ++# CASE No.12 ++# ++CASE "params with force cidr_netmask" ++ Include prepare ++ Env OCF_RESKEY_cidr_netmask=$OCFT_target_prefix ++ Env OCFT_check_prefix=$OCFT_target_prefix ++ AgentRun start OCF_SUCCESS ++ Include check_ip_assigned ++ AgentRun stop OCF_SUCCESS ++ Include check_ip_removed ++ ++# CASE No.13 ++# ++CASE "params with force cidr_netmask (base netmask < assigned netmask)" ++ Include prepare ++ Env OCF_RESKEY_cidr_netmask=$OCFT_force_prefix ++ Env OCFT_check_prefix=$OCFT_force_prefix ++ AgentRun start OCF_ERR_GENERIC ++ Include check_ip_removed ++ ++# CASE No.14 ++# ++CASE "params with force cidr_netmask (base netmask > assigned netmask)" ++ Include prepare ++ Env OCF_RESKEY_cidr_netmask=$OCFT_force_prefix2 ++ Env OCFT_check_prefix=$OCFT_force_prefix2 ++ AgentRun start OCF_ERR_GENERIC ++ Include check_ip_removed ++ ++# CASE No.15 ++# ++CASE "params with cidr_netmask" ++ Include prepare ++ Include base_ip_removed ++ Env OCF_RESKEY_cidr_netmask=$OCFT_target_prefix ++ Env OCFT_check_prefix=$OCFT_target_prefix ++ AgentRun start OCF_ERR_GENERIC ++ Include base_ip_assigned ++ ++# CASE No.16 ++# ++CASE "params with nic, cidr_netmask" ++ Include prepare ++ Env OCF_RESKEY_nic=$OCFT_target_nic ++ Env OCF_RESKEY_cidr_netmask=$OCFT_target_prefix ++ Env OCFT_check_nic=$OCFT_target_nic ++ Env OCFT_check_prefix=$OCFT_target_prefix ++ AgentRun start OCF_SUCCESS ++ Include check_ip_assigned ++ AgentRun stop OCF_SUCCESS ++ Include check_ip_removed ++ ++# CASE No.17 ++# ++CASE "force to use the specified nic and cidr_netmask (base netmask < assigned netmask)" ++ Include prepare ++ Env OCF_RESKEY_nic=$OCFT_force_nic ++ Env OCF_RESKEY_cidr_netmask=$OCFT_force_prefix ++ Env OCFT_check_nic=$OCFT_force_nic ++ Env OCFT_check_prefix=$OCFT_force_prefix ++ AgentRun start OCF_SUCCESS ++ Include check_ip_assigned ++ AgentRun stop OCF_SUCCESS ++ Include check_ip_removed ++ ++# CASE No.18 ++# This use case is now valid. It was not allowed until v3.9.2. ++# ++CASE "force to use the specified nic and cidr_netmask (base netmask > assigned netmask)" ++ Include prepare ++ Env OCF_RESKEY_nic=$OCFT_force_nic ++ Env OCF_RESKEY_cidr_netmask=$OCFT_force_prefix2 ++ Env OCFT_check_nic=$OCFT_force_nic ++ Env OCFT_check_prefix=$OCFT_force_prefix2 ++ AgentRun start OCF_SUCCESS ++ Include check_ip_assigned ++ AgentRun stop OCF_SUCCESS ++ Include check_ip_removed ++ ++# CASE No.19 ++# ++CASE "force to use the specified nic and cidr_netmask (base netmask > assigned netmask)" ++ Include prepare ++ Include base_ip_removed ++ Env OCF_RESKEY_nic=$OCFT_force_nic ++ Env OCF_RESKEY_cidr_netmask=$OCFT_force_prefix2 ++ Env OCFT_check_nic=$OCFT_force_nic ++ Env OCFT_check_prefix=$OCFT_force_prefix2 ++ AgentRun start OCF_SUCCESS ++ Include check_ip_assigned ++ AgentRun stop OCF_SUCCESS ++ Include check_ip_removed ++ Include base_ip_assigned ++ +diff --git a/tools/ocft/default/IPsrcaddr b/tools/ocft/default/IPsrcaddr +new file mode 100644 +index 0000000..d95142e +--- /dev/null ++++ b/tools/ocft/default/IPsrcaddr +@@ -0,0 +1,63 @@ ++# IPsrcaddr ++ ++CONFIG ++ Agent IPsrcaddr ++ AgentRoot /usr/lib/ocf/resource.d/heartbeat ++ InstallPackage iproute2 ++ HangTimeout 20 ++ ++CASE-BLOCK required_args ++ Env OCF_RESKEY_ipaddress= # put here your IP ++ Env OCF_RESKEY_cidr_netmask= # and the netmask ++ ++CASE-BLOCK default_status ++ AgentRun stop ++ ++CASE-BLOCK prepare ++ Include required_args ++ Include default_status ++ ++CASE "check base env" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ ++CASE "check base env: unset 'OCF_RESKEY_ipaddress'" ++ Include prepare ++ Unenv OCF_RESKEY_ipaddress ++ AgentRun start OCF_ERR_CONFIGURED ++ ++CASE "check base env: set invalid 'OCF_RESKEY_ipaddress'" ++ Include prepare ++ Env OCF_RESKEY_ipaddress=not_ip_address ++ AgentRun start OCF_ERR_CONFIGURED ++ ++CASE "normal start" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ ++CASE "normal stop" ++ Include prepare ++ AgentRun start ++ AgentRun stop OCF_SUCCESS ++ ++CASE "double start" ++ Include prepare ++ AgentRun start ++ AgentRun start OCF_SUCCESS ++ ++CASE "double stop" ++ Include prepare ++ AgentRun stop OCF_SUCCESS ++ ++CASE "monitor with running" ++ Include prepare ++ AgentRun start ++ AgentRun monitor OCF_SUCCESS ++ ++CASE "monitor with not running" ++ Include prepare ++ AgentRun monitor OCF_NOT_RUNNING ++ ++CASE "unimplemented command" ++ Include prepare ++ AgentRun no_cmd OCF_ERR_UNIMPLEMENTED +diff --git a/tools/ocft/default/IPv6addr b/tools/ocft/default/IPv6addr +new file mode 100644 +index 0000000..36a9642 +--- /dev/null ++++ b/tools/ocft/default/IPv6addr +@@ -0,0 +1,150 @@ ++# IPv6addr ++ ++# Note: This test case uses two NICs(eth0, eth1) and ++# a IPv6 address prefix (2001:db8::/32, RFC3849). ++# Adjust them according to your environment at VARIABLE section if needed. ++ ++CONFIG ++ Agent IPv6addr ++ AgentRoot /usr/lib/ocf/resource.d/heartbeat ++ HangTimeout 20 ++ ++VARIABLE ++ OCFT_target_ipv6addr=2001:db8:1234::2 ++ OCFT_target_nic=eth0 ++ OCFT_target_prefix=64 ++ OCFT_target_netaddr=2001:db8:1234::1/$OCFT_target_prefix ++ OCFT_target_linklocal=fe80::2 ++ OCFT_wrong_ipv6addr=2001:db8:5678::2 ++ OCFT_force_nic=eth1 ++ OCFT_force_prefix=80 ++ ++SETUP-AGENT ++ ip addr add $OCFT_target_netaddr dev $OCFT_target_nic ++ ++CLEANUP-AGENT ++ ip addr del $OCFT_target_netaddr dev $OCFT_target_nic ++ ++CASE-BLOCK required_args ++ Env OCF_RESKEY_ipv6addr=$OCFT_target_ipv6addr ++ Env OCFT_check_ipv6addr=$OCFT_target_ipv6addr ++ Env OCFT_check_prefix=$OCFT_target_prefix ++ Env OCFT_check_nic=$OCFT_target_nic ++ ++CASE-BLOCK check_ip_assigned ++ Bash ip -6 -o addr show $OCFT_check_nic | grep -w $OCFT_check_ipv6addr/$OCFT_check_prefix >/dev/null # checking if the IPv6 address was assigned correctly ++ ++CASE-BLOCK check_ip_removed ++ Bash ! ip -6 -o addr show $OCFT_check_nic | grep -w $OCFT_check_ipv6addr/$OCFT_check_prefix >/dev/null # checking if the IPv6 address was removed correctly ++ ++CASE-BLOCK default_status ++ AgentRun stop ++ ++CASE-BLOCK prepare ++ Include required_args ++ Include default_status ++ ++ ++CASE "normal start" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ Include check_ip_assigned ++ ++CASE "normal stop" ++ Include prepare ++ AgentRun start ++ AgentRun stop OCF_SUCCESS ++ Include check_ip_removed ++ ++CASE "double start" ++ Include prepare ++ AgentRun start ++ AgentRun start OCF_SUCCESS ++ ++CASE "double stop" ++ Include prepare ++ AgentRun stop OCF_SUCCESS ++ ++CASE "monitor with running" ++ Include prepare ++ AgentRun start ++ AgentRun monitor OCF_SUCCESS ++ ++CASE "monitor with not running" ++ Include prepare ++ AgentRun monitor OCF_NOT_RUNNING ++ ++CASE "params with nic, no cidr_netmask" ++ Include prepare ++ Env OCF_RESKEY_nic=$OCFT_target_nic ++ AgentRun start OCF_SUCCESS ++ Include check_ip_assigned ++ AgentRun monitor OCF_SUCCESS ++ AgentRun stop OCF_SUCCESS ++ Include check_ip_removed ++ ++CASE "params with nic, cidr_netmask" ++ Include prepare ++ Env OCF_RESKEY_nic=$OCFT_target_nic ++ Env OCF_RESKEY_cidr_netmask=$OCFT_target_prefix ++ AgentRun start OCF_SUCCESS ++ Include check_ip_assigned ++ AgentRun monitor OCF_SUCCESS ++ AgentRun stop OCF_SUCCESS ++ Include check_ip_removed ++ ++CASE "normal usage for a link-local IPv6 address" ++ Include prepare ++ Env OCF_RESKEY_ipv6addr=$OCFT_target_linklocal ++ Env OCFT_check_ipv6addr=$OCFT_target_linklocal ++ # nic is mandatory for a link-local address ++ Env OCF_RESKEY_nic=$OCFT_target_nic ++ AgentRun start OCF_SUCCESS ++ Include check_ip_assigned ++ AgentRun monitor OCF_SUCCESS ++ AgentRun stop OCF_SUCCESS ++ Include check_ip_removed ++ ++CASE "error start for a link-local IPv6 address when no nic" ++ Include prepare ++ Env OCF_RESKEY_ipv6addr=$OCFT_target_linklocal ++ # nic is mandatory for a link-local address ++ Unenv OCF_RESKEY_nic ++ AgentRun start OCF_ERR_GENERIC ++ Include check_ip_removed ++ ++CASE "error params with wrong ipv6addr" ++ Include prepare ++ Env OCF_RESKEY_ipv6addr=$OCFT_wrong_ipv6addr ++ AgentRun start OCF_ERR_GENERIC ++ ++# Note: this result is different from IPaddr2/findif ++# IPaddr2 succeeds if the ip matched based on the netmask of the subnet ++# or fails if it did not match to any. ++# Recommended to always specify both nic and cidr_netmask when you needed. ++CASE "error params with wrong cidr_netmask" ++ Include prepare ++ Env OCF_RESKEY_cidr_netmask=$OCFT_force_prefix ++ AgentRun start OCF_ERR_GENERIC ++ ++# Note: this result is different from IPaddr2/findif ++# IPaddr2 succeeds but it uses /32 as a guessed cidr_netmask which ++# does not seem to be expected. ++# Recommended to always specify both nic and cidr_netmask when you needed. ++CASE "error params with wrong nic" ++ Include prepare ++ Env OCF_RESKEY_nic=$OCFT_force_nic ++ AgentRun start OCF_ERR_GENERIC ++ ++# Note: This use case is now valid. It was not allowed until v3.9.2. ++CASE "force to use the specified nic and cidr_netmask" ++ Include prepare ++ Env OCF_RESKEY_nic=$OCFT_force_nic ++ Env OCF_RESKEY_cidr_netmask=$OCFT_force_prefix ++ Env OCFT_check_nic=$OCFT_force_nic ++ Env OCFT_check_prefix=$OCFT_force_prefix ++ AgentRun start OCF_SUCCESS ++ Include check_ip_assigned ++ AgentRun monitor OCF_SUCCESS ++ AgentRun stop OCF_SUCCESS ++ Include check_ip_removed +diff --git a/tools/ocft/default/LVM b/tools/ocft/default/LVM +new file mode 100644 +index 0000000..4bd2b22 +--- /dev/null ++++ b/tools/ocft/default/LVM +@@ -0,0 +1,86 @@ ++# LVM ++# by dejan@suse.de on ++# Wed Feb 16 13:15:01 CET 2011 ++ ++CONFIG ++ Agent LVM ++ AgentRoot /usr/lib/ocf/resource.d/heartbeat ++ HangTimeout 20 ++ ++VARIABLE ++ OCFT_pv=/var/run/resource-agents/ocft-LVM-pv ++ OCFT_vg=ocft-vg ++ OCFT_lv=ocft-lv ++ OCFT_loop=/dev/loop7 ++ ++SETUP-AGENT ++ losetup $OCFT_loop 2>/dev/null && exit 1 ++ dd if=/dev/zero of=$OCFT_pv bs=1 count=0 seek=16M 2>/dev/null ++ losetup $OCFT_loop $OCFT_pv ++ pvcreate $OCFT_loop ++ vgcreate -s 4K $OCFT_vg $OCFT_loop ++ lvcreate -n $OCFT_lv -L 600K $OCFT_vg ++ ++CLEANUP-AGENT ++ vgchange -an $OCFT_vg ++ lvremove -f /dev/$OCFT_vg/$OCFT_lv ++ vgremove -f $OCFT_vg ++ pvremove $OCFT_loop ++ losetup -d $OCFT_loop ++ rm $OCFT_pv ++ ++CASE-BLOCK required_args ++ Env OCF_RESKEY_volgrpname=$OCFT_vg ++ ++CASE-BLOCK default_status ++ AgentRun stop ++ ++CASE-BLOCK prepare ++ Include required_args ++ Include default_status ++ ++CASE "check base env" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ ++CASE "check base env: invalid 'OCF_RESKEY_volgrpname'" ++ Include prepare ++ Env OCF_RESKEY_volgrpname=/dev/no_such_device ++ AgentRun start OCF_ERR_GENERIC ++ ++CASE "check base env: unset 'OCF_RESKEY_volgrpname'" ++ Include prepare ++ Unenv OCF_RESKEY_volgrpname ++ AgentRun start OCF_ERR_CONFIGURED ++ ++CASE "normal start" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ ++CASE "normal stop" ++ Include prepare ++ AgentRun start ++ AgentRun stop OCF_SUCCESS ++ ++CASE "double start" ++ Include prepare ++ AgentRun start ++ AgentRun start OCF_SUCCESS ++ ++CASE "double stop" ++ Include prepare ++ AgentRun stop OCF_SUCCESS ++ ++CASE "monitor when running" ++ Include prepare ++ AgentRun start ++ AgentRun monitor OCF_SUCCESS ++ ++CASE "monitor when not running" ++ Include prepare ++ AgentRun monitor OCF_NOT_RUNNING ++ ++CASE "unimplemented command" ++ Include prepare ++ AgentRun no_cmd OCF_ERR_UNIMPLEMENTED ++ +diff --git a/tools/ocft/default/MailTo b/tools/ocft/default/MailTo +new file mode 100644 +index 0000000..8754035 +--- /dev/null ++++ b/tools/ocft/default/MailTo +@@ -0,0 +1,57 @@ ++# MailTo ++ ++CONFIG ++ Agent MailTo ++ AgentRoot /usr/lib/ocf/resource.d/heartbeat ++ InstallPackage mailx ++ HangTimeout 20 ++ ++CASE-BLOCK required_args ++ Env OCF_RESKEY_email=root@localhost ++ ++CASE-BLOCK default_status ++ AgentRun stop ++ ++CASE-BLOCK prepare ++ Include required_args ++ Include default_status ++ ++CASE "check base env" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ ++CASE "check base env: unset 'OCF_RESKEY_email'" ++ Include prepare ++ Unenv OCF_RESKEY_email ++ AgentRun start OCF_ERR_CONFIGURED ++ ++CASE "normal start" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ ++CASE "normal stop" ++ Include prepare ++ AgentRun start ++ AgentRun stop OCF_SUCCESS ++ ++CASE "double start" ++ Include prepare ++ AgentRun start ++ AgentRun start OCF_SUCCESS ++ ++CASE "double stop" ++ Include prepare ++ AgentRun stop OCF_SUCCESS ++ ++CASE "monitor with running" ++ Include prepare ++ AgentRun start ++ AgentRun monitor OCF_SUCCESS ++ ++CASE "monitor with not running" ++ Include prepare ++ AgentRun monitor OCF_NOT_RUNNING ++ ++CASE "unimplemented command" ++ Include prepare ++ AgentRun no_cmd OCF_ERR_UNIMPLEMENTED +diff --git a/tools/ocft/default/Raid1 b/tools/ocft/default/Raid1 +new file mode 100644 +index 0000000..1c239c8 +--- /dev/null ++++ b/tools/ocft/default/Raid1 +@@ -0,0 +1,146 @@ ++# Raid1 ++# by dejan@suse.de on ++# Fri Aug 24 17:01:40 CEST 2012 ++ ++CONFIG ++ Agent Raid1 ++ AgentRoot /usr/lib/ocf/resource.d/heartbeat ++ InstallPackage mdadm ++ HangTimeout 20 ++ ++VARIABLE ++ OCFT_disk0=/var/run/resource-agents/ocft-Raid1-disk0 ++ OCFT_disk1=/var/run/resource-agents/ocft-Raid1-disk1 ++ OCFT_disk2=/var/run/resource-agents/ocft-Raid1-disk2 ++ OCFT_disk3=/var/run/resource-agents/ocft-Raid1-disk3 ++ OCFT_raidconf=/var/run/resource-agents/ocft-mdadm.conf ++ OCFT_raiddev=/dev/md8 ++ OCFT_raiddev2=/dev/md9 ++ OCFT_loop0=/dev/loop6 ++ OCFT_loop1=/dev/loop7 ++ OCFT_loop2=/dev/loop4 ++ OCFT_loop3=/dev/loop5 ++ ++SETUP-AGENT ++ losetup $OCFT_loop0 2>/dev/null && exit 1 ++ losetup $OCFT_loop1 2>/dev/null && exit 1 ++ losetup $OCFT_loop2 2>/dev/null && exit 1 ++ losetup $OCFT_loop3 2>/dev/null && exit 1 ++ dd if=/dev/zero of=$OCFT_disk0 bs=1 count=0 seek=16M 2>/dev/null ++ dd if=/dev/zero of=$OCFT_disk1 bs=1 count=0 seek=16M 2>/dev/null ++ dd if=/dev/zero of=$OCFT_disk2 bs=1 count=0 seek=16M 2>/dev/null ++ dd if=/dev/zero of=$OCFT_disk3 bs=1 count=0 seek=16M 2>/dev/null ++ losetup $OCFT_loop0 $OCFT_disk0 ++ losetup $OCFT_loop1 $OCFT_disk1 ++ losetup $OCFT_loop2 $OCFT_disk2 ++ losetup $OCFT_loop3 $OCFT_disk3 ++ mdadm --create $OCFT_raiddev -l 0 --raid-devices=2 $OCFT_loop0 $OCFT_loop1 ++ mdadm --create $OCFT_raiddev2 -l 0 --raid-devices=2 $OCFT_loop2 $OCFT_loop3 ++ echo DEVICE $OCFT_loop0 $OCFT_loop1 > $OCFT_raidconf ++ echo DEVICE $OCFT_loop2 $OCFT_loop3 >> $OCFT_raidconf ++ echo ARRAY $OCFT_raiddev devices=$OCFT_loop0,$OCFT_loop1 >> $OCFT_raidconf ++ echo ARRAY $OCFT_raiddev2 devices=$OCFT_loop2,$OCFT_loop3 >> $OCFT_raidconf ++ ++CLEANUP-AGENT ++ mdadm --zero-superblock $OCFT_loop0 ++ mdadm --zero-superblock $OCFT_loop1 ++ mdadm --zero-superblock $OCFT_loop2 ++ mdadm --zero-superblock $OCFT_loop3 ++ mdadm --remove $OCFT_raiddev 2>/dev/null ++ mdadm --remove $OCFT_raiddev2 2>/dev/null ++ losetup -d $OCFT_loop0 ++ losetup -d $OCFT_loop1 ++ losetup -d $OCFT_loop2 ++ losetup -d $OCFT_loop3 ++ rm $OCFT_disk0 $OCFT_disk1 $OCFT_raidconf ++ rm $OCFT_disk2 $OCFT_disk3 ++ ++CASE-BLOCK required_args ++ Env OCF_RESKEY_raidconf=$OCFT_raidconf ++ Env OCF_RESKEY_raiddev=$OCFT_raiddev ++ ++CASE-BLOCK default_status ++ AgentRun stop ++ ++CASE-BLOCK prepare ++ Include required_args ++ Include default_status ++ ++CASE-BLOCK prepare_auto ++ Include required_args ++ Env OCF_RESKEY_raiddev="auto" ++ Include default_status ++ ++CASE-BLOCK prepare_multiple ++ Include required_args ++ Env OCF_RESKEY_raiddev="$OCFT_raiddev $OCFT_raiddev2" ++ Include default_status ++ ++CASE "check base env" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ ++CASE "check base env: invalid 'OCF_RESKEY_raiddev'" ++ Include prepare ++ Env OCF_RESKEY_raiddev=/dev/no_such_device ++ AgentRun start OCF_ERR_GENERIC ++ ++CASE "check base env: unset 'OCF_RESKEY_raiddev'" ++ Include prepare ++ Unenv OCF_RESKEY_raiddev ++ AgentRun start OCF_ERR_CONFIGURED ++ ++CASE "normal start" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ ++CASE "normal stop" ++ Include prepare ++ AgentRun start ++ AgentRun stop OCF_SUCCESS ++ ++CASE "double start" ++ Include prepare ++ AgentRun start ++ AgentRun start OCF_SUCCESS ++ ++CASE "double stop" ++ Include prepare ++ AgentRun stop OCF_SUCCESS ++ ++CASE "monitor when running" ++ Include prepare ++ AgentRun start ++ AgentRun monitor OCF_SUCCESS ++ ++CASE "monitor when not running" ++ Include prepare ++ AgentRun monitor OCF_NOT_RUNNING ++ ++CASE "normal start (auto)" ++ Include prepare_auto ++ AgentRun start OCF_SUCCESS ++ AgentRun monitor OCF_SUCCESS ++ ++CASE "normal stop (auto)" ++ Include prepare_auto ++ AgentRun start ++ AgentRun stop OCF_SUCCESS ++ AgentRun monitor OCF_NOT_RUNNING ++ ++CASE "normal start (multiple)" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ AgentRun monitor OCF_SUCCESS ++ ++CASE "normal stop (multiple)" ++ Include prepare ++ Env OCF_RESKEY_raiddev="$OCFT_raiddev $OCFT_raiddev2" ++ AgentRun start ++ AgentRun stop OCF_SUCCESS ++ AgentRun monitor OCF_NOT_RUNNING ++ ++CASE "unimplemented command" ++ Include prepare ++ AgentRun no_cmd OCF_ERR_UNIMPLEMENTED ++ +diff --git a/tools/ocft/default/SendArp b/tools/ocft/default/SendArp +new file mode 100644 +index 0000000..7880388 +--- /dev/null ++++ b/tools/ocft/default/SendArp +@@ -0,0 +1,74 @@ ++# SendArp ++ ++CONFIG ++ Agent SendArp ++ AgentRoot /usr/lib/ocf/resource.d/heartbeat ++ InstallPackage resource-agents ++ HangTimeout 15 ++ ++CASE-BLOCK required_args ++ Env OCF_RESKEY_ip=127.0.0.1 ++ Env OCF_RESKEY_nic=lo ++ Env OCF_RESKEY_background=false ++ ++CASE-BLOCK default_status ++ AgentRun stop ++ ++CASE-BLOCK prepare ++ Include required_args ++ Include default_status ++ ++CASE "check base env" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ ++CASE "check base env: unset 'OCF_RESKEY_ip'" ++ Include prepare ++ Unenv OCF_RESKEY_ip ++ AgentRun start OCF_ERR_CONFIGURED ++ ++CASE "check base env: set invalid 'OCF_RESKEY_ip'" ++ Include prepare ++ Env OCF_RESKEY_ip=not_ip_address ++ AgentRun start OCF_ERR_GENERIC ++ ++CASE "check base env: unset 'OCF_RESKEY_nic'" ++ Include prepare ++ Unenv OCF_RESKEY_nic ++ AgentRun start OCF_ERR_CONFIGURED ++ ++CASE "check base env: set invalid 'OCF_RESKEY_nic'" ++ Include prepare ++ Env OCF_RESKEY_nic=not_nic ++ AgentRun start OCF_ERR_GENERIC ++ ++CASE "normal start" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ ++CASE "normal stop" ++ Include prepare ++ AgentRun start ++ AgentRun stop OCF_SUCCESS ++ ++CASE "double start" ++ Include prepare ++ AgentRun start ++ AgentRun start OCF_SUCCESS ++ ++CASE "double stop" ++ Include prepare ++ AgentRun stop OCF_SUCCESS ++ ++CASE "monitor with running" ++ Include prepare ++ AgentRun start ++ AgentRun monitor OCF_SUCCESS ++ ++CASE "monitor with not running" ++ Include prepare ++ AgentRun monitor OCF_NOT_RUNNING ++ ++CASE "unimplemented command" ++ Include prepare ++ AgentRun no_cmd OCF_ERR_UNIMPLEMENTED +diff --git a/tools/ocft/default/Xinetd b/tools/ocft/default/Xinetd +new file mode 100644 +index 0000000..ba9c85c +--- /dev/null ++++ b/tools/ocft/default/Xinetd +@@ -0,0 +1,56 @@ ++# Xinetd ++ ++CONFIG ++ Agent Xinetd ++ AgentRoot /usr/lib/ocf/resource.d/heartbeat ++ InstallPackage xinetd ++ ++CASE-BLOCK required_args ++ Env OCF_RESKEY_service=discard ++ ++CASE-BLOCK default_status ++ AgentRun stop ++ ++CASE-BLOCK prepare ++ Include required_args ++ Include default_status ++ ++CASE "check base env" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ ++CASE "check base env: unset 'OCF_RESKEY_protocol'" ++ Include prepare ++ Unenv OCF_RESKEY_service ++ AgentRun start OCF_ERR_CONFIGURED ++ ++CASE "normal start" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ ++CASE "normal stop" ++ Include prepare ++ AgentRun start ++ AgentRun stop OCF_SUCCESS ++ ++CASE "double start" ++ Include prepare ++ AgentRun start ++ AgentRun start OCF_SUCCESS ++ ++CASE "double stop" ++ Include prepare ++ AgentRun stop OCF_SUCCESS ++ ++CASE "monitor with running" ++ Include prepare ++ AgentRun start ++ AgentRun monitor OCF_SUCCESS ++ ++CASE "monitor with not running" ++ Include prepare ++ AgentRun monitor OCF_NOT_RUNNING ++ ++CASE "unimplemented command" ++ Include prepare ++ AgentRun no_cmd OCF_ERR_UNIMPLEMENTED +diff --git a/tools/ocft/default/apache b/tools/ocft/default/apache +new file mode 100644 +index 0000000..e939044 +--- /dev/null ++++ b/tools/ocft/default/apache +@@ -0,0 +1,63 @@ ++# apache ++# make sure that your apache configuration loads mod_status ++ ++CONFIG ++ Agent apache ++ AgentRoot /usr/lib/ocf/resource.d/heartbeat ++ InstallPackage apache2 ++ HangTimeout 20 ++ ++SETUP-AGENT ++ /etc/init.d/apache2 start ++ /etc/init.d/apache2 stop ++ ++CASE-BLOCK default_status ++ AgentRun stop ++ ++CASE-BLOCK prepare ++ Include default_status ++ ++CASE "check base env" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ ++CASE "check base env: set non-existing OCF_RESKEY_statusurl" ++ Include prepare ++ Env OCF_RESKEY_statusurl="yoyoyoyo" ++ AgentRun start OCF_ERR_CONFIGURED ++ ++CASE "check base env: set non-existing OCF_RESKEY_configfile" ++ Include prepare ++ Env OCF_RESKEY_configfile="/yoyoyoyo/nosuchfile" ++ AgentRun start OCF_ERR_INSTALLED ++ ++CASE "normal start" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ ++CASE "normal stop" ++ Include prepare ++ AgentRun start ++ AgentRun stop OCF_SUCCESS ++ ++CASE "double start" ++ Include prepare ++ AgentRun start ++ AgentRun start OCF_SUCCESS ++ ++CASE "double stop" ++ Include prepare ++ AgentRun stop OCF_SUCCESS ++ ++CASE "running monitor" ++ Include prepare ++ AgentRun start ++ AgentRun monitor OCF_SUCCESS ++ ++CASE "not running monitor" ++ Include prepare ++ AgentRun monitor OCF_NOT_RUNNING ++ ++CASE "unimplemented command" ++ Include prepare ++ AgentRun no_cmd OCF_ERR_UNIMPLEMENTED +diff --git a/tools/ocft/default/db2 b/tools/ocft/default/db2 +new file mode 100644 +index 0000000..7013a99 +--- /dev/null ++++ b/tools/ocft/default/db2 +@@ -0,0 +1,164 @@ ++# db2 ++# ++# This test assumes a db2 ESE instance with two partions and a database. ++# Default is instance=db2inst1, database=ocft ++# adapt this in set_testenv below ++# ++# Simple steps to generate a test environment (if you don't have one): ++# ++# A virtual machine with 1200MB RAM is sufficient ++# ++# - download an eval version of DB2 server from IBM ++# - create an user "db2inst1" in group "db2inst1" ++# ++# As root ++# - install DB2 software in some location ++# - create instance ++# cd /instance ++# ./db2icrt -s ese -u db2inst1 db2inst1 ++# - adapt profile of db2inst1 as instructed by db2icrt ++# ++# As db2inst1 ++# # allow to run with small memory footprint ++# db2set DB2_FCM_SETTINGS=FCM_MAXIMIZE_SET_SIZE:FALSE ++# db2start ++# db2start dbpartitionnum 1 add dbpartitionnum hostname $(uname -n) port 1 without tablespaces ++# db2stop ++# db2start ++# db2 create database ocft ++# Done ++# In order to install a real cluster refer to http://www.linux-ha.org/wiki/db2_(resource_agent) ++ ++CONFIG ++ Agent db2 ++ AgentRoot /usr/lib/ocf/resource.d/heartbeat ++ HangTimeout 40 ++ ++SETUP-AGENT ++ # nothing ++ ++CASE-BLOCK set_testenv ++ Env OCFT_instance=db2inst1 ++ Env OCFT_db=ocft ++ ++CASE-BLOCK crm_setting ++ Env OCF_RESKEY_instance=$OCFT_instance ++ Env OCF_RESKEY_CRM_meta_timeout=30000 ++ ++CASE-BLOCK default_status ++ AgentRun stop ++ ++CASE-BLOCK prepare ++ Include set_testenv ++ Include crm_setting ++ Include default_status ++ ++CASE "check base env" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ ++CASE "check base env: invalid 'OCF_RESKEY_instance'" ++ Include prepare ++ Env OCF_RESKEY_instance=no_such ++ AgentRun start OCF_ERR_INSTALLED ++ ++CASE "invalid instance config" ++ Include prepare ++ Bash eval mv ~$OCFT_instance/sqllib ~$OCFT_instance/sqllib- ++ BashAtExit eval mv ~$OCFT_instance/sqllib- ~$OCFT_instance/sqllib ++ AgentRun start OCF_ERR_INSTALLED ++ ++CASE "unimplemented command" ++ Include prepare ++ AgentRun no_cmd OCF_ERR_UNIMPLEMENTED ++ ++CASE "normal start" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ ++CASE "normal stop" ++ Include prepare ++ AgentRun start ++ AgentRun stop OCF_SUCCESS ++ ++CASE "double start" ++ Include prepare ++ AgentRun start ++ AgentRun start OCF_SUCCESS ++ ++CASE "double stop" ++ Include prepare ++ AgentRun stop OCF_SUCCESS ++ ++CASE "started: monitor" ++ Include prepare ++ AgentRun start ++ AgentRun monitor OCF_SUCCESS ++ ++CASE "not started: monitor" ++ Include prepare ++ AgentRun monitor OCF_NOT_RUNNING ++ ++CASE "killed instance: monitor" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ AgentRun monitor OCF_SUCCESS ++ BashAtExit rm /tmp/ocft-helper1 ++ Bash echo "su $OCFT_instance -c '. ~$OCFT_instance/sqllib/db2profile; db2nkill 0 >/dev/null 2>&1'" > /tmp/ocft-helper1 ++ Bash sh -x /tmp/ocft-helper1 ++ AgentRun monitor OCF_NOT_RUNNING ++ ++CASE "overload param instance by admin" ++ Include prepare ++ Env OCF_RESKEY_instance=no_such ++ Env OCF_RESKEY_admin=$OCFT_instance ++ AgentRun start OCF_SUCCESS ++ ++CASE "check start really activates db" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ ++ BashAtExit rm /tmp/ocft-helper2 ++ Bash echo "su $OCFT_instance -c '. ~$OCFT_instance/sqllib/db2profile; db2 get snapshot for database on $OCFT_db>/dev/null'" > /tmp/ocft-helper2 ++ Bash sh -x /tmp/ocft-helper2 ++ ++CASE "multipartion test" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ AgentRun monitor OCF_SUCCESS ++ ++ # start does not start partion 1 ++ Env OCF_RESKEY_dbpartitionnum=1 ++ AgentRun monitor OCF_NOT_RUNNING ++ ++ # now start 1 ++ AgentRun start OCF_SUCCESS ++ AgentRun monitor OCF_SUCCESS ++ ++ # now stop 1 ++ AgentRun stop OCF_SUCCESS ++ AgentRun monitor OCF_NOT_RUNNING ++ ++ # does not affect 0 ++ Env OCF_RESKEY_dbpartitionnum=0 ++ AgentRun monitor OCF_SUCCESS ++ ++# fault injection does not work on the 1.0.4 client due to a hardcoded path ++CASE "simulate hanging db2stop (not meaningful for 1.0.4 agent)" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ Bash [ ! -f /usr/local/bin/db2stop ] ++ BashAtExit rm /usr/local/bin/db2stop ++ Bash echo -e "#!/bin/sh\necho fake db2stop\nsleep 10000" > /usr/local/bin/db2stop ++ Bash chmod +x /usr/local/bin/db2stop ++ AgentRun stop OCF_SUCCESS ++ ++# fault injection does not work on the 1.0.4 client due to a hardcoded path ++CASE "simulate not stopping db2stop (not meaningful for 1.0.4 agent)" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ Bash [ ! -f /usr/local/bin/db2stop ] ++ BashAtExit rm /usr/local/bin/db2stop ++ Bash echo -e "#!/bin/sh\necho fake db2stop\nexit 0" > /usr/local/bin/db2stop ++ Bash chmod +x /usr/local/bin/db2stop ++ AgentRun stop OCF_SUCCESS +diff --git a/tools/ocft/default/drbd.linbit b/tools/ocft/default/drbd.linbit +new file mode 100644 +index 0000000..4cc5519 +--- /dev/null ++++ b/tools/ocft/default/drbd.linbit +@@ -0,0 +1,183 @@ ++# linbit: drbd ++ ++CONFIG ++ Agent drbd ++ AgentRoot /usr/lib/ocf/resource.d/linbit ++ InstallPackage drbd ++ HangTimeout 20 ++ ++VARIABLE ++ DRBDCONF=/tmp/ocft_drbd_tmp.conf ++ ++ # should be this machine's hostname/ip, please modify it by yourself. ++ NAME_1=HOSTNAME1 ++ IP_1=IP_ADDRESS1 ++ ++ # the block device just for test, please modify it by yourself. ++ DISK_1=/dev/DEVICE1 ++ ++ PORT_1=5735 ++ DEVICE_1=/dev/drbd0 ++ ++ #################################################################### ++ ++ # please modify it by yourself. ++ NAME_2=HOSTNAME2 ++ IP_2=IP_ADDRESS2 ++ ++ # the block device just for test, please modify it by yourself. ++ DISK_2=/dev/DEVICE2 ++ ++ PORT_2=5735 ++ DEVICE_2=/dev/drbd0 ++ ++ ++ ++SETUP-AGENT ++ cat >$DRBDCONF </dev/null 2>&1 ++ if [ $? -eq 255 ]; then ++ $DRBDADM create-md ocft0 ++ fi ++ ++ # start drbd ++ $DRBDADM up ocft0 ++ ++ # UpToDate ++ if [ "$HOST" = "$NAME_1" ]; then ++ $DRBDADM wait-connect ocft0 ++ echo "drbd Syncing .." ++ $DRBDADM primary --force ocft0 ++ while true; do ++ CSTATE=$($DRBDADM cstate ocft0) ++ DSTATE=$($DRBDADM dstate ocft0) ++ if [ "$CSTATE" = "Connected" -a "$DSTATE" = "UpToDate/UpToDate" ]; then ++ break ++ else ++ sleep 3 ++ fi ++ done ++ echo "done" ++ fi ++ ++CLEANUP-AGENT ++ drbdadm -c $DRBDCONF down ocft0 ++ rm -f $DRBDCONF ++ ++CASE-BLOCK required_args ++ Env OCF_RESKEY_drbdconf=$DRBDCONF ++ Env OCF_RESKEY_drbd_resource=ocft0 ++ Env OCF_RESKEY_CRM_meta_notify=true ++ Env OCF_RESKEY_CRM_meta_clone_max=2 ++ ++CASE-BLOCK default_status ++ AgentRun stop ++ ++CASE-BLOCK prepare ++ Include required_args ++ Include default_status ++ ++CASE "check base env" ++ Include required_args ++ AgentRun validate-all OCF_SUCCESS ++ ++CASE "normal start" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ ++CASE "normal stop" ++ Include prepare ++ AgentRun start ++ AgentRun stop OCF_SUCCESS ++ ++CASE "wrong path of config file" ++ Include prepare ++ Env OCF_RESKEY_drbdconf=no_such_file ++ AgentRun start OCF_ERR_INSTALLED ++ ++CASE "wrong resource name" ++ Include prepare ++ Env OCF_RESKEY_drbd_resource=no_such_src ++ # OCF_RESKEY_drbd_resource is a required parameter in agent meta-data, ++ # if wrong, I think the agent should return OCF_ERR_CONFIGURED. ++ AgentRun start OCF_ERR_CONFIGURED ++ ++CASE "double start" ++ Include prepare ++ AgentRun start ++ AgentRun start OCF_SUCCESS ++ ++CASE "double stop" ++ Include prepare ++ AgentRun stop OCF_SUCCESS ++ ++CASE "running monitor" ++ Include prepare ++ AgentRun start ++ AgentRun monitor OCF_SUCCESS ++ ++CASE "not running monitor" ++ Include prepare ++ AgentRun monitor OCF_NOT_RUNNING ++ ++CASE "Primary/Secondary monitor" ++ Include prepare ++ AgentRun start ++ AgentRun promote ++ AgentRun monitor OCF_RUNNING_MASTER ++ AgentRun demote ++ AgentRun monitor OCF_SUCCESS ++ ++CASE "unimplemented command" ++ Include prepare ++ AgentRun no_cmd OCF_ERR_UNIMPLEMENTED ++ ++CASE "try to 'promote' in single-primary mode" ++ Include prepare ++ Include@$IP_2 prepare ++ ++ # start drbd ++ AgentRun start ++ AgentRun@$IP_2 start ++ ++ # promote local drbd first ++ AgentRun promote OCF_SUCCESS ++ ++ # demote local drbd prepare for remote drbd promote ++ AgentRun demote ++ # remote drbd promote ++ AgentRun@$IP_2 promote OCF_SUCCESS ++ ++ # promote fails, because remote drbd promote first. ++ AgentRun promote OCF_ERR_GENERIC +diff --git a/tools/ocft/default/exportfs b/tools/ocft/default/exportfs +new file mode 100644 +index 0000000..c83520d +--- /dev/null ++++ b/tools/ocft/default/exportfs +@@ -0,0 +1,74 @@ ++# exportfs ++# ++# ++ ++CONFIG ++ Agent exportfs ++ AgentRoot /usr/lib/ocf/resource.d/heartbeat ++ HangTimeout 40 ++ ++SETUP-AGENT ++ # nothing ++ ++CASE-BLOCK set_testenv ++ Env OCF_RESKEY_directory=/usr ++ Env OCF_RESKEY_fsid=105 ++ Env OCF_RESKEY_clientspec="*" ++ Env OCF_RESKEY_CRM_meta_timeout=30000 ++ ++CASE-BLOCK default_status ++ AgentRun stop ++ ++CASE-BLOCK prepare ++ Include set_testenv ++ Include default_status ++ ++CASE "check base env" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ ++CASE "check base env: no 'OCF_RESKEY_fsid'" ++ Include prepare ++ Env OCF_RESKEY_fsid= ++ AgentRun start OCF_ERR_CONFIGURED ++ ++CASE "check base env: invalid 'OCF_RESKEY_directory'" ++ Include prepare ++ Env OCF_RESKEY_directory=/no_such ++ AgentRun start OCF_ERR_INSTALLED ++ ++CASE "unimplemented command" ++ Include prepare ++ AgentRun no_cmd OCF_ERR_UNIMPLEMENTED ++ ++CASE "normal start" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ ++CASE "normal stop" ++ Include prepare ++ AgentRun start ++ AgentRun stop OCF_SUCCESS ++ ++CASE "double start" ++ Include prepare ++ AgentRun start ++ AgentRun start OCF_SUCCESS ++ ++CASE "double stop" ++ Include prepare ++ AgentRun stop OCF_SUCCESS ++ ++CASE "stop with no env" ++ Include prepare ++ Env OCF_RESKEY_directory=/no_such ++ AgentRun stop OCF_SUCCESS ++ ++CASE "started: monitor" ++ Include prepare ++ AgentRun start ++ AgentRun monitor OCF_SUCCESS ++ ++CASE "not started: monitor" ++ Include prepare ++ AgentRun monitor OCF_NOT_RUNNING +diff --git a/tools/ocft/default/iscsi b/tools/ocft/default/iscsi +new file mode 100644 +index 0000000..c1325a1 +--- /dev/null ++++ b/tools/ocft/default/iscsi +@@ -0,0 +1,82 @@ ++# iscsi ++ ++CONFIG ++ Agent iscsi ++ AgentRoot /usr/lib/ocf/resource.d/heartbeat ++ InstallPackage open-iscsi ++ InstallPackage iscsitarget ++ HangTimeout 20 ++ ++VARIABLE ++ OCFT_disk=/var/run/resource-agents/ocft-iscsi ++ OCFT_target="iqn.2011-03.ocft.localhost:disk0" ++ OCFT_portal="127.0.0.1:3260" ++ ++SETUP-AGENT ++ dd if=/dev/zero of=$OCFT_disk bs=1024k count=1 2>/dev/null ++ echo Target $OCFT_target >> /etc/ietd.conf ++ echo " Lun 0 Path=$OCFT_disk,Type=fileio" >> /etc/ietd.conf ++ /etc/init.d/iscsitarget start ++ /etc/init.d/open-iscsi start ++ /etc/init.d/iscsitarget restart ++ ++CLEANUP-AGENT ++ rm -f $OCFT_disk ++ sed -i "/^Target $OCFT_target/,+1d" /etc/ietd.conf ++ ++CASE-BLOCK required_args ++ Env OCF_RESKEY_portal=$OCFT_portal ++ Env OCF_RESKEY_target=$OCFT_target ++ ++CASE-BLOCK default_status ++ AgentRun stop ++ ++CASE-BLOCK prepare ++ Include required_args ++ Include default_status ++ ++CASE "check base env" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ ++CASE "check base env: invalid 'OCF_RESKEY_portal'" ++ Include prepare ++ Unenv OCF_RESKEY_portal ++ AgentRun start OCF_ERR_CONFIGURED ++ ++CASE "check base env: unset 'OCF_RESKEY_target'" ++ Include prepare ++ Unenv OCF_RESKEY_target ++ AgentRun start OCF_ERR_CONFIGURED ++ ++CASE "normal start" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ ++CASE "normal stop" ++ Include prepare ++ AgentRun start ++ AgentRun stop OCF_SUCCESS ++ ++CASE "double start" ++ Include prepare ++ AgentRun start ++ AgentRun start OCF_SUCCESS ++ ++CASE "double stop" ++ Include prepare ++ AgentRun stop OCF_SUCCESS ++ ++CASE "monitor when running" ++ Include prepare ++ AgentRun start ++ AgentRun monitor OCF_SUCCESS ++ ++CASE "monitor when not running" ++ Include prepare ++ AgentRun monitor OCF_NOT_RUNNING ++ ++CASE "unimplemented command" ++ Include prepare ++ AgentRun no_cmd OCF_ERR_UNIMPLEMENTED ++ +diff --git a/tools/ocft/default/jboss b/tools/ocft/default/jboss +new file mode 100644 +index 0000000..bc99d8f +--- /dev/null ++++ b/tools/ocft/default/jboss +@@ -0,0 +1,83 @@ ++# jboss ++# ++# NOTE: Clean up $jboss_home/standalone/log before running this test ++# otherwise creating the pid/log files may fail ++# in the test case with a different user. ++ ++CONFIG ++ Agent jboss ++ AgentRoot /usr/lib/ocf/resource.d/heartbeat ++ HangTimeout 120 ++ ++# Note : Change setting by a version of JBoss. ++# ++VARIABLE ++ # JBoss5 Environment require ++# jboss_version=5 ++# jboss_home=/opt/jboss5/current ++# java_home=/usr/lib/jvm/java-1.6.0-openjdk.x86_64 ++# user=jboss5 ++ # JBoss6 Environment require ++ jboss_version=6 ++ jboss_home=/opt/jboss6/current ++ java_home=/usr/lib/jvm/java-1.7.0-openjdk.x86_64 ++ user=jboss6 ++ ++CASE-BLOCK required_args_jboss ++ Env OCF_RESKEY_jboss_home=${jboss_home} ++ Env OCF_RESKEY_java_home=${java_home} ++ Env OCF_RESKEY_jboss_version=${jboss_version} ++ Env OCF_RESKEY_user=${user} ++ ++CASE-BLOCK args_clear ++ Unenv OCF_RESKEY_jboss_home ++ Unenv OCF_RESKEY_java_home ++ Unenv OCF_RESKEY_jboss_version ++ Unenv OCF_RESKEY_user ++ ++CASE-BLOCK default_status ++ AgentRun stop ++ ++CASE-BLOCK prepare_jboss ++ Include required_args_jboss ++ Include default_status ++ ++# Test CASE ++# ++CASE "normal start jboss require_args (user:user)" ++ Include prepare_jboss ++ AgentRun start OCF_SUCCESS ++ AgentRun monitor OCF_SUCCESS ++ AgentRun stop OCF_SUCCESS ++ AgentRun monitor OCF_NOT_RUNNING ++ Include args_clear ++ ++CASE "normal start jboss require_args (user:root)" ++ Include prepare_jboss ++ Unenv OCF_RESKEY_user ++ AgentRun start OCF_SUCCESS ++ AgentRun monitor OCF_SUCCESS ++ AgentRun stop OCF_SUCCESS ++ AgentRun monitor OCF_NOT_RUNNING ++ Include args_clear ++ ++CASE "error start jboss no jboss_home" ++ Include prepare_jboss ++ Unenv OCF_RESKEY_jboss_home ++ AgentRun start OCF_ERR_INSTALLED ++ Include args_clear ++ ++CASE "error start jboss no java_home" ++ Include prepare_jboss ++ Unenv OCF_RESKEY_java_home ++ AgentRun start OCF_ERR_INSTALLED ++ Include args_clear ++ ++CASE "error start jboss no java command" ++ Include prepare_jboss ++ Env OCF_RESKEY_java_home=/var ++ AgentRun start OCF_ERR_INSTALLED ++ AgentRun stop OCF_SUCCESS ++ AgentRun monitor OCF_NOT_RUNNING ++ Include args_clear ++ +diff --git a/tools/ocft/default/mysql b/tools/ocft/default/mysql +new file mode 100644 +index 0000000..27fcb58 +--- /dev/null ++++ b/tools/ocft/default/mysql +@@ -0,0 +1,77 @@ ++# mysql ++ ++CONFIG ++ Agent mysql ++ AgentRoot /usr/lib/ocf/resource.d/heartbeat ++ InstallPackage mariadb ++ InstallPackage mariadb-server ++ HangTimeout 20 ++ ++SETUP-AGENT ++ /etc/init.d/mysql start ++ /etc/init.d/mysql stop ++ ++CASE-BLOCK crm_setting ++ Env OCF_RESKEY_CRM_meta_timeout=15000 ++ ++CASE-BLOCK default_status ++ AgentRun stop ++ ++CASE-BLOCK prepare ++ Include crm_setting ++ Include default_status ++ ++CASE "check base env" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ ++CASE "check base env: invalid 'OCF_RESKEY_binary'" ++ Include prepare ++ Env OCF_RESKEY_binary=no_such ++ AgentRun start OCF_ERR_INSTALLED ++ ++CASE "normal start" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ ++CASE "normal stop" ++ Include prepare ++ AgentRun start ++ AgentRun stop OCF_SUCCESS ++ ++CASE "double start" ++ Include prepare ++ AgentRun start ++ AgentRun start OCF_SUCCESS ++ ++CASE "double stop" ++ Include prepare ++ AgentRun stop OCF_SUCCESS ++ ++CASE "running monitor" ++ Include prepare ++ AgentRun start ++ AgentRun monitor OCF_SUCCESS ++ ++CASE "not running monitor" ++ Include prepare ++ AgentRun monitor OCF_NOT_RUNNING ++ ++CASE "check lib file" ++ Include prepare ++ Bash chmod u-w /var/lib/mysql ++ BashAtExit chmod u+w /var/lib/mysql ++ AgentRun start OCF_ERR_PERM ++ ++CASE "unimplemented command" ++ Include prepare ++ AgentRun no_cmd OCF_ERR_UNIMPLEMENTED ++ ++CASE "non-existent user" ++ Include prepare ++ Env OCF_RESKEY_user=no_user ++ AgentRun start OCF_ERR_INSTALLED ++ ++CASE "invalid user" ++ Include prepare ++ Env OCF_RESKEY_user=nobody ++ AgentRun start OCF_ERR_PERM +diff --git a/tools/ocft/default/mysql-proxy b/tools/ocft/default/mysql-proxy +new file mode 100644 +index 0000000..e16d52b +--- /dev/null ++++ b/tools/ocft/default/mysql-proxy +@@ -0,0 +1,83 @@ ++# mysql-proxy ++# by r.bhatia@ipax.at ++# ++# test cases (to implement): ++# ++# * /usr/sbin/ocf-tester -n mp -o binary="/usr/sbin/mysql-proxy" -o defaults_file="" -o parameters="--proxy-skip-profiling" \ ++# -o admin_address="127.0.0.1:4041" -o admin_username="root" -o admin_password="la" -o admin_lua_script="/usr/lib/mysql-proxy/lua/admin.lua" \ ++# -o proxy_backend_addresses="192.168.100.200:42006" -o proxy_address="/var/run/mysqld/mysqld.sock" /usr/lib/ocf/resource.d/heartbeat/mysql-proxy ++# ++# * OCF_CHECK_LEVEL 20 check ++ ++CONFIG ++ Agent mysql-proxy ++ AgentRoot /usr/lib/ocf/resource.d/heartbeat/ ++ InstallPackage mysql-proxy ++ HangTimeout 20 ++ ++SETUP-AGENT ++ # nothing ++ ++CASE-BLOCK crm_setting ++ Env OCF_RESKEY_CRM_meta_timeout=15000 ++ Env OCF_RESKEY_binary=/tmp/mysql-proxy ++ Env OCF_RESKEY_admin_username=root ++ Env OCF_RESKEY_admin_password=test123 ++ Env OCF_RESKEY_admin_lua_script=/usr/lib/mysql-proxy/lua/admin.lua ++ ++CASE-BLOCK default_status ++ AgentRun stop ++ ++CASE-BLOCK prepare ++ Bash [ ! -x /tmp/mysql-proxy ] && ln -s `which mysql-proxy` /tmp/mysql-proxy || true ++ Include crm_setting ++ ++CASE-BLOCK teardown ++ AgentRun stop ++ BashAtExit rm -f /tmp/mysql-proxy ++ ++CASE "check base env" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ Include teardown ++ ++CASE "check base env: invalid 'OCF_RESKEY_binary'" ++ Include prepare ++ Env OCF_RESKEY_binary=no_such ++ AgentRun start OCF_ERR_INSTALLED ++ BashAtExit rm -f /tmp/mysql-proxy ++ ++CASE "normal start" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ Include teardown ++ ++CASE "normal stop" ++ Include prepare ++ AgentRun start ++ AgentRun stop OCF_SUCCESS ++ Include teardown ++ ++CASE "double start" ++ Include prepare ++ AgentRun start ++ AgentRun start OCF_SUCCESS ++ Include teardown ++ ++CASE "double stop" ++ Include prepare ++ AgentRun stop OCF_SUCCESS ++ ++CASE "running monitor" ++ Include prepare ++ AgentRun start ++ AgentRun monitor OCF_SUCCESS ++ Include teardown ++ ++CASE "not running monitor" ++ Include prepare ++ AgentRun monitor OCF_NOT_RUNNING ++ ++CASE "unimplemented command" ++ Include prepare ++ AgentRun no_cmd OCF_ERR_UNIMPLEMENTED +diff --git a/tools/ocft/default/named b/tools/ocft/default/named +new file mode 100644 +index 0000000..90a4351 +--- /dev/null ++++ b/tools/ocft/default/named +@@ -0,0 +1,69 @@ ++#named ++ ++# To work properly this test requires that standard bind and bin-utils ++# packages installed. ++ ++CONFIG ++ Agent named ++ AgentRoot /usr/lib/ocf/resource.d/heartbeat ++ InstallPackage bind ++ InstallPackage bind-utils ++ ++SETUP-AGENT ++ /etc/init.d/named start ++ /etc/init.d/named stop ++ ++CASE-BLOCK crm_setting ++ Env OCF_RESKEY_CRM_meta_timeout=15000 ++ ++CASE-BLOCK default_status ++ AgentRun stop ++ ++CASE-BLOCK prepare ++ Include crm_setting ++ Include default_status ++ ++CASE "check base env" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ ++CASE "check base env: invalid 'OCF_RESKEY_named'" ++ Include prepare ++ Env OCF_RESKEY_named=no_such ++ AgentRun start OCF_ERR_INSTALLED ++ ++CASE "normal start" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ ++CASE "normal stop" ++ Include prepare ++ AgentRun start ++ AgentRun stop OCF_SUCCESS ++ ++CASE "double start" ++ Include prepare ++ AgentRun start ++ AgentRun start OCF_SUCCESS ++ ++CASE "double stop" ++ Include prepare ++ AgentRun stop OCF_SUCCESS ++ ++CASE "running monitor" ++ Include prepare ++ AgentRun start ++ AgentRun monitor OCF_SUCCESS ++ ++CASE "not running monitor" ++ Include prepare ++ AgentRun monitor OCF_NOT_RUNNING ++ ++CASE "unimplemented command" ++ Include prepare ++ AgentRun no_cmd OCF_ERR_UNIMPLEMENTED ++ ++CASE "non-existent user" ++ Include prepare ++ Env OCF_RESKEY_named_user=no_user ++ AgentRun start OCF_ERR_INSTALLED +diff --git a/tools/ocft/default/nfsserver b/tools/ocft/default/nfsserver +new file mode 100644 +index 0000000..cd73164 +--- /dev/null ++++ b/tools/ocft/default/nfsserver +@@ -0,0 +1,75 @@ ++# nfsserver ++ ++CONFIG ++ Agent nfsserver ++ AgentRoot /usr/lib/ocf/resource.d/heartbeat ++ InstallPackage nfs-kernel-server ++ HangTimeout 20 ++ ++CASE-BLOCK required_args ++ Env OCF_RESKEY_nfs_init_script=/etc/init.d/nfsserver ++ Env OCF_RESKEY_nfs_ip=127.0.0.1 ++ Env OCF_RESKEY_nfs_shared_infodir=/var/lib/nfs ++ Env OCF_RESKEY_nfs_notify_cmd=/usr/sbin/sm-notify ++ ++CASE-BLOCK default_status ++ AgentRun stop ++ ++CASE-BLOCK prepare ++ Include required_args ++ Include default_status ++ ++CASE "check base env" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ ++CASE "check base env: invalid 'OCF_RESKEY_nfs_init_script'" ++ Include prepare ++ Env OCF_RESKEY_nfs_init_script=no_such_script ++ AgentRun start OCF_ERR_INSTALLED ++ ++CASE "check base env: unset 'OCF_RESKEY_nfs_ip'" ++ Include prepare ++ Unenv OCF_RESKEY_nfs_ip ++ AgentRun start OCF_ERR_CONFIGURED ++ ++CASE "check base env: unset 'OCF_RESKEY_nfs_shared_infodir'" ++ Include prepare ++ Unenv OCF_RESKEY_nfs_shared_infodir ++ AgentRun start OCF_ERR_CONFIGURED ++ ++CASE "check base env: invalid 'OCF_RESKEY_nfs_notify_cmd'" ++ Include prepare ++ Env OCF_RESKEY_nfs_notify_cmd=no_such_program ++ AgentRun start OCF_ERR_INSTALLED ++ ++CASE "normal start" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ ++CASE "normal stop" ++ Include prepare ++ AgentRun start ++ AgentRun stop OCF_SUCCESS ++ ++CASE "double start" ++ Include prepare ++ AgentRun start ++ AgentRun start OCF_SUCCESS ++ ++CASE "double stop" ++ Include prepare ++ AgentRun stop OCF_SUCCESS ++ ++CASE "monitor with running" ++ Include prepare ++ AgentRun start ++ AgentRun monitor OCF_SUCCESS ++ ++CASE "monitor with not running" ++ Include prepare ++ AgentRun monitor OCF_NOT_RUNNING ++ ++CASE "unimplemented command" ++ Include prepare ++ AgentRun no_cmd OCF_ERR_UNIMPLEMENTED +diff --git a/tools/ocft/default/oracle b/tools/ocft/default/oracle +new file mode 100644 +index 0000000..6f145c7 +--- /dev/null ++++ b/tools/ocft/default/oracle +@@ -0,0 +1,81 @@ ++# oracle ++# (based on db2) ++# ++# Created on an SLE11SP2 running oracle 11g ++# database sid is orcl ++# adapt this in set_testenv below ++# TODO: need oracle expert to break it, then test it ++# ++ ++CONFIG ++ Agent oracle ++ AgentRoot /usr/lib/ocf/resource.d/heartbeat ++ HangTimeout 40 ++ ++SETUP-AGENT ++ # nothing ++ ++CASE-BLOCK set_testenv ++ Env OCFT_sid=orcl ++ ++CASE-BLOCK crm_setting ++ Env OCF_RESKEY_sid=$OCFT_sid ++ Env OCF_RESKEY_CRM_meta_timeout=30000 ++ ++CASE-BLOCK default_status ++ AgentRun stop ++ ++CASE-BLOCK prepare ++ Include set_testenv ++ Include crm_setting ++ Include default_status ++ ++CASE "check base env" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ ++CASE "check base env: no 'OCF_RESKEY_sid'" ++ Include prepare ++ Env OCF_RESKEY_sid= ++ AgentRun start OCF_ERR_CONFIGURED ++ ++CASE "check base env: invalid 'OCF_RESKEY_home'" ++ Include prepare ++ Env OCF_RESKEY_home=/no_such ++ AgentRun start OCF_ERR_INSTALLED ++ ++CASE "unimplemented command" ++ Include prepare ++ AgentRun no_cmd OCF_ERR_UNIMPLEMENTED ++ ++CASE "normal start" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ ++CASE "normal stop" ++ Include prepare ++ AgentRun start ++ AgentRun stop OCF_SUCCESS ++ ++CASE "double start" ++ Include prepare ++ AgentRun start ++ AgentRun start OCF_SUCCESS ++ ++CASE "double stop" ++ Include prepare ++ AgentRun stop OCF_SUCCESS ++ ++CASE "started: monitor" ++ Include prepare ++ AgentRun start ++ AgentRun monitor OCF_SUCCESS ++ ++CASE "not started: monitor" ++ Include prepare ++ AgentRun monitor OCF_NOT_RUNNING ++ ++CASE "try different ipcrm method" ++ Include prepare ++ Env OCF_RESKEY_ipcrm=none ++ AgentRun start OCF_SUCCESS +diff --git a/tools/ocft/default/pgsql b/tools/ocft/default/pgsql +new file mode 100644 +index 0000000..9944b09 +--- /dev/null ++++ b/tools/ocft/default/pgsql +@@ -0,0 +1,71 @@ ++# pgsql ++ ++CONFIG ++ Agent pgsql ++ AgentRoot /usr/lib/ocf/resource.d/heartbeat ++ InstallPackage postgresql-server ++ HangTimeout 20 ++ ++SETUP-AGENT ++ /etc/init.d/postgresql start ++ /etc/init.d/postgresql stop ++ ++CASE-BLOCK crm_setting ++ Env OCF_RESKEY_CRM_meta_timeout=15000 ++ ++CASE-BLOCK default_status ++ AgentRun stop ++ ++CASE-BLOCK prepare ++ Include crm_setting ++ Include default_status ++ ++CASE "check base env" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ ++CASE "check base env: invalid 'OCF_RESKEY_pgctl'" ++ Include prepare ++ Env OCF_RESKEY_pgctl=no_such ++ AgentRun start OCF_ERR_INSTALLED ++ ++CASE "normal start" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ ++CASE "normal stop" ++ Include prepare ++ AgentRun start ++ AgentRun stop OCF_SUCCESS ++ ++CASE "double start" ++ Include prepare ++ AgentRun start ++ AgentRun start OCF_SUCCESS ++ ++CASE "double stop" ++ Include prepare ++ AgentRun stop OCF_SUCCESS ++ ++CASE "running monitor" ++ Include prepare ++ AgentRun start ++ AgentRun monitor OCF_SUCCESS ++ ++CASE "not running monitor" ++ Include prepare ++ AgentRun monitor OCF_NOT_RUNNING ++ ++CASE "unimplemented command" ++ Include prepare ++ AgentRun no_cmd OCF_ERR_UNIMPLEMENTED ++ ++CASE "non-existent user" ++ Include prepare ++ Env OCF_RESKEY_pgdba=no_user ++ AgentRun start OCF_ERR_INSTALLED ++ ++CASE "invalid user" ++ Include prepare ++ Env OCF_RESKEY_pgdba=nobody ++ AgentRun start OCF_ERR_PERM +diff --git a/tools/ocft/default/portblock b/tools/ocft/default/portblock +new file mode 100644 +index 0000000..3475c63 +--- /dev/null ++++ b/tools/ocft/default/portblock +@@ -0,0 +1,69 @@ ++# portblock ++ ++CONFIG ++ Agent portblock ++ AgentRoot /usr/lib/ocf/resource.d/heartbeat ++ InstallPackage iptables ++ HangTimeout 15 ++ ++CASE-BLOCK required_args ++ Env OCF_RESKEY_protocol=tcp ++ Env OCF_RESKEY_portno=80 ++ Env OCF_RESKEY_action=block ++ ++CASE-BLOCK default_status ++ AgentRun stop ++ ++CASE-BLOCK prepare ++ Include required_args ++ Include default_status ++ ++CASE "check base env" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ ++CASE "check base env: unset 'OCF_RESKEY_protocol'" ++ Include prepare ++ Unenv OCF_RESKEY_protocol ++ AgentRun start OCF_ERR_CONFIGURED ++ ++CASE "check base env: unset 'OCF_RESKEY_portno'" ++ Include prepare ++ Unenv OCF_RESKEY_portno ++ AgentRun start OCF_ERR_CONFIGURED ++ ++CASE "check base env: unset 'OCF_RESKEY_action'" ++ Include prepare ++ Unenv OCF_RESKEY_action ++ AgentRun start OCF_ERR_CONFIGURED ++ ++CASE "normal start" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ ++CASE "normal stop" ++ Include prepare ++ AgentRun start ++ AgentRun stop OCF_SUCCESS ++ ++CASE "double start" ++ Include prepare ++ AgentRun start ++ AgentRun start OCF_SUCCESS ++ ++CASE "double stop" ++ Include prepare ++ AgentRun stop OCF_SUCCESS ++ ++CASE "monitor with running" ++ Include prepare ++ AgentRun start ++ AgentRun monitor OCF_SUCCESS ++ ++CASE "monitor with not running" ++ Include prepare ++ AgentRun monitor OCF_NOT_RUNNING ++ ++CASE "unimplemented command" ++ Include prepare ++ AgentRun no_cmd OCF_ERR_UNIMPLEMENTED +diff --git a/tools/ocft/default/postfix b/tools/ocft/default/postfix +new file mode 100644 +index 0000000..f17e968 +--- /dev/null ++++ b/tools/ocft/default/postfix +@@ -0,0 +1,102 @@ ++# postfix ++# by r.bhatia@ipax.at ++# ++# test cases (to implement): ++# ++# * /usr/sbin/ocf-tester -n post1 /usr/lib/ocf/resource.d/heartbeat/postfix; echo $? -> DONE ++# * /usr/sbin/ocf-tester -n post2 -o binary="/usr/sbin/postfix" \ ++# -o config_dir="" /usr/lib/ocf/resource.d/heartbeat/postfix; echo $? -> DONE ++# * /usr/sbin/ocf-tester -n post3 -o binary="/usr/sbin/postfix" \ ++# -o config_dir="/etc/postfix" /usr/lib/ocf/resource.d/heartbeat/postfix; echo $? -> DONE ++# * /usr/sbin/ocf-tester -n post4 -o binary="/usr/sbin/postfix" \ ++# -o config_dir="/root/postfix/" /usr/lib/ocf/resource.d/heartbeat/postfix; echo $? ++ ++CONFIG ++ Agent postfix ++ AgentRoot /usr/lib/ocf/resource.d/heartbeat ++ InstallPackage postfix ++ HangTimeout 20 ++ ++SETUP-AGENT ++ # nothing ++ ++CASE-BLOCK crm_setting ++ Env OCF_RESKEY_CRM_meta_timeout=15000 ++ Env OCF_RESKEY_CRM_meta_interval=10000 ++ ++CASE-BLOCK default_status ++ AgentRun stop ++ ++CASE-BLOCK prepare ++ Include crm_setting ++ Include default_status ++ ++CASE "check base env" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ ++CASE "check base env: invalid 'OCF_RESKEY_binary'" ++ Include prepare ++ Env OCF_RESKEY_binary=no_such ++ AgentRun start OCF_ERR_INSTALLED ++ ++CASE "check base env: invalid 'OCF_RESKEY_config_dir'" ++ Include prepare ++ Env OCF_RESKEY_config_dir=no_such ++ AgentRun start OCF_ERR_INSTALLED ++ ++CASE "check base env: 'OCF_RESKEY_binary'" ++ Include prepare ++ Env OCF_RESKEY_binary=/usr/sbin/postfix ++ AgentRun start ++ AgentRun monitor OCF_SUCCESS ++ ++CASE "check base env: 'OCF_RESKEY_config_dir' without trailing slash" ++ Include prepare ++ Env OCF_RESKEY_config_dir="/etc/postfix" ++ AgentRun start ++ AgentRun monitor OCF_SUCCESS ++ ++CASE "check base env: 'OCF_RESKEY_config_dir' with trailing slash" ++ Include prepare ++ Env OCF_RESKEY_config_dir="/etc/postfix/" ++ AgentRun start ++ AgentRun monitor OCF_SUCCESS ++ ++CASE "normal start" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ ++CASE "normal stop" ++ Include prepare ++ AgentRun start ++ AgentRun stop OCF_SUCCESS ++ ++CASE "double start" ++ Include prepare ++ AgentRun start ++ AgentRun start OCF_SUCCESS ++ ++CASE "double stop" ++ Include prepare ++ AgentRun stop OCF_SUCCESS ++ ++CASE "monitor a running resource" ++ Include prepare ++ AgentRun start ++ AgentRun monitor OCF_SUCCESS ++ ++CASE "(initial) probe a stopped resource" ++ Include prepare ++ Env OCF_RESKEY_CRM_meta_interval=0 ++ AgentRun monitor OCF_NOT_RUNNING ++ ++CASE "(re-)probe a running resource" ++ Include prepare ++ Env OCF_RESKEY_CRM_meta_interval=0 ++ AgentRun start ++ AgentRun monitor OCF_SUCCESS ++ ++CASE "unimplemented command" ++ Include prepare ++ AgentRun no_cmd OCF_ERR_UNIMPLEMENTED +diff --git a/tools/ocft/default/tomcat b/tools/ocft/default/tomcat +new file mode 100644 +index 0000000..56adf86 +--- /dev/null ++++ b/tools/ocft/default/tomcat +@@ -0,0 +1,73 @@ ++# tomcat ++# ++# NOTE: Clean up $catalina_home/logs before running this test ++# otherwise creating the pid/log files may fail ++# in the test case with a different user. ++ ++CONFIG ++ Agent tomcat ++ AgentRoot /usr/lib/ocf/resource.d/heartbeat ++ HangTimeout 120 ++ ++VARIABLE ++ # Adjust accrding to your configuration ++ catalina_home=/opt/tomcat7 ++ tomcat_user=tomcat7 ++ java_home=/usr/lib/jvm/java-1.6.0-openjdk.x86_64 ++ ++CASE-BLOCK required_args_tomcat ++ Env OCF_RESKEY_catalina_home=${catalina_home} ++ Env OCF_RESKEY_tomcat_user=${tomcat_user} ++ Env OCF_RESKEY_java_home=${java_home} ++ ++CASE-BLOCK args_clear ++ Unenv OCF_RESKEY_catalina_home ++ Unenv OCF_RESKEY_tomcat_user ++ Unenv OCF_RESKEY_java_home ++ ++CASE-BLOCK default_status ++ AgentRun stop ++ ++CASE-BLOCK prepare_tomcat ++ Include required_args_tomcat ++ Include default_status ++ ++# Test CASE ++# ++CASE "normal start tomcat require_args (user:user)" ++ Include prepare_tomcat ++ AgentRun start OCF_SUCCESS ++ AgentRun monitor OCF_SUCCESS ++ AgentRun stop OCF_SUCCESS ++ AgentRun monitor OCF_NOT_RUNNING ++ Include args_clear ++ ++CASE "normal start tomcat require_args (user:root)" ++ Include prepare_tomcat ++ Unenv OCF_RESKEY_tomcat_user ++ AgentRun start OCF_SUCCESS ++ AgentRun monitor OCF_SUCCESS ++ AgentRun stop OCF_SUCCESS ++ AgentRun monitor OCF_NOT_RUNNING ++ Include args_clear ++ ++CASE "error start tomcat no catalina_home" ++ Include prepare_tomcat ++ Unenv OCF_RESKEY_catalina_home ++ AgentRun start OCF_ERR_INSTALLED ++ Include args_clear ++ ++CASE "error start tomcat no java_home" ++ Include prepare_tomcat ++ Unenv OCF_RESKEY_java_home ++ AgentRun start OCF_ERR_INSTALLED ++ Include args_clear ++ ++CASE "error start tomcat no java command" ++ Include prepare_tomcat ++ Env OCF_RESKEY_java_home=/var ++ AgentRun start OCF_ERR_INSTALLED ++ AgentRun stop OCF_SUCCESS ++ AgentRun monitor OCF_NOT_RUNNING ++ Include args_clear ++ +diff --git a/tools/ocft/drbd.linbit b/tools/ocft/drbd.linbit +deleted file mode 100644 +index 4cc5519..0000000 +--- a/tools/ocft/drbd.linbit ++++ /dev/null +@@ -1,183 +0,0 @@ +-# linbit: drbd +- +-CONFIG +- Agent drbd +- AgentRoot /usr/lib/ocf/resource.d/linbit +- InstallPackage drbd +- HangTimeout 20 +- +-VARIABLE +- DRBDCONF=/tmp/ocft_drbd_tmp.conf +- +- # should be this machine's hostname/ip, please modify it by yourself. +- NAME_1=HOSTNAME1 +- IP_1=IP_ADDRESS1 +- +- # the block device just for test, please modify it by yourself. +- DISK_1=/dev/DEVICE1 +- +- PORT_1=5735 +- DEVICE_1=/dev/drbd0 +- +- #################################################################### +- +- # please modify it by yourself. +- NAME_2=HOSTNAME2 +- IP_2=IP_ADDRESS2 +- +- # the block device just for test, please modify it by yourself. +- DISK_2=/dev/DEVICE2 +- +- PORT_2=5735 +- DEVICE_2=/dev/drbd0 +- +- +- +-SETUP-AGENT +- cat >$DRBDCONF </dev/null 2>&1 +- if [ $? -eq 255 ]; then +- $DRBDADM create-md ocft0 +- fi +- +- # start drbd +- $DRBDADM up ocft0 +- +- # UpToDate +- if [ "$HOST" = "$NAME_1" ]; then +- $DRBDADM wait-connect ocft0 +- echo "drbd Syncing .." +- $DRBDADM primary --force ocft0 +- while true; do +- CSTATE=$($DRBDADM cstate ocft0) +- DSTATE=$($DRBDADM dstate ocft0) +- if [ "$CSTATE" = "Connected" -a "$DSTATE" = "UpToDate/UpToDate" ]; then +- break +- else +- sleep 3 +- fi +- done +- echo "done" +- fi +- +-CLEANUP-AGENT +- drbdadm -c $DRBDCONF down ocft0 +- rm -f $DRBDCONF +- +-CASE-BLOCK required_args +- Env OCF_RESKEY_drbdconf=$DRBDCONF +- Env OCF_RESKEY_drbd_resource=ocft0 +- Env OCF_RESKEY_CRM_meta_notify=true +- Env OCF_RESKEY_CRM_meta_clone_max=2 +- +-CASE-BLOCK default_status +- AgentRun stop +- +-CASE-BLOCK prepare +- Include required_args +- Include default_status +- +-CASE "check base env" +- Include required_args +- AgentRun validate-all OCF_SUCCESS +- +-CASE "normal start" +- Include prepare +- AgentRun start OCF_SUCCESS +- +-CASE "normal stop" +- Include prepare +- AgentRun start +- AgentRun stop OCF_SUCCESS +- +-CASE "wrong path of config file" +- Include prepare +- Env OCF_RESKEY_drbdconf=no_such_file +- AgentRun start OCF_ERR_INSTALLED +- +-CASE "wrong resource name" +- Include prepare +- Env OCF_RESKEY_drbd_resource=no_such_src +- # OCF_RESKEY_drbd_resource is a required parameter in agent meta-data, +- # if wrong, I think the agent should return OCF_ERR_CONFIGURED. +- AgentRun start OCF_ERR_CONFIGURED +- +-CASE "double start" +- Include prepare +- AgentRun start +- AgentRun start OCF_SUCCESS +- +-CASE "double stop" +- Include prepare +- AgentRun stop OCF_SUCCESS +- +-CASE "running monitor" +- Include prepare +- AgentRun start +- AgentRun monitor OCF_SUCCESS +- +-CASE "not running monitor" +- Include prepare +- AgentRun monitor OCF_NOT_RUNNING +- +-CASE "Primary/Secondary monitor" +- Include prepare +- AgentRun start +- AgentRun promote +- AgentRun monitor OCF_RUNNING_MASTER +- AgentRun demote +- AgentRun monitor OCF_SUCCESS +- +-CASE "unimplemented command" +- Include prepare +- AgentRun no_cmd OCF_ERR_UNIMPLEMENTED +- +-CASE "try to 'promote' in single-primary mode" +- Include prepare +- Include@$IP_2 prepare +- +- # start drbd +- AgentRun start +- AgentRun@$IP_2 start +- +- # promote local drbd first +- AgentRun promote OCF_SUCCESS +- +- # demote local drbd prepare for remote drbd promote +- AgentRun demote +- # remote drbd promote +- AgentRun@$IP_2 promote OCF_SUCCESS +- +- # promote fails, because remote drbd promote first. +- AgentRun promote OCF_ERR_GENERIC +diff --git a/tools/ocft/fedora/Filesystem b/tools/ocft/fedora/Filesystem +new file mode 100644 +index 0000000..4e1981f +--- /dev/null ++++ b/tools/ocft/fedora/Filesystem +@@ -0,0 +1,110 @@ ++# Filesystem ++# by dejan@suse.de on ++# Tue Feb 15 18:50:04 CET 2011 ++ ++CONFIG ++ Agent Filesystem ++ AgentRoot /usr/lib/ocf/resource.d/heartbeat ++ HangTimeout 20 ++ ++VARIABLE ++ OCFT_fs=/tmp/resource-agents/ocft-Filesystem-fs ++ OCFT_loop=/dev/loop7 ++ OCFT_dir=/tmp/resource-agents/ocft-Filesystem-mnt ++ ++SETUP-AGENT ++ losetup $OCFT_loop 2>/dev/null && exit 1 ++ rmdir $OCFT_dir 2>/dev/null || true ++ mkdir -p $OCFT_dir ++ dd if=/dev/zero of=$OCFT_fs bs=1 count=0 seek=16M 2>/dev/null ++ mke2fs -j -Fq -m 0 $OCFT_fs ++ losetup $OCFT_loop $OCFT_fs ++ ++CLEANUP-AGENT ++ rmdir $OCFT_dir ++ rm -f $OCFT_fs ++ losetup -d $OCFT_loop ++ ++CASE-BLOCK required_args ++ Env OCF_RESKEY_device=$OCFT_loop ++ Env OCF_RESKEY_fstype=ext3 ++ Env OCF_RESKEY_directory=$OCFT_dir ++ ++CASE-BLOCK default_status ++ AgentRun stop ++ ++CASE-BLOCK prepare ++ Include required_args ++ Include default_status ++ ++CASE "check base env" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ ++CASE "check base env: invalid 'OCF_RESKEY_device'" ++ Include prepare ++ Env OCF_RESKEY_device=/dev/no_such_device ++ AgentRun start OCF_ERR_INSTALLED ++ ++CASE "check base env: unset 'OCF_RESKEY_device'" ++ Include prepare ++ Unenv OCF_RESKEY_device ++ AgentRun start OCF_ERR_CONFIGURED ++ ++CASE "normal start" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ ++CASE "normal stop" ++ Include prepare ++ AgentRun start ++ AgentRun stop OCF_SUCCESS ++ ++CASE "double start" ++ Include prepare ++ AgentRun start ++ AgentRun start OCF_SUCCESS ++ ++CASE "double stop" ++ Include prepare ++ AgentRun stop OCF_SUCCESS ++ ++CASE "monitor when running" ++ Include prepare ++ AgentRun start ++ AgentRun monitor OCF_SUCCESS ++ ++CASE "monitor when not running" ++ Include prepare ++ AgentRun monitor OCF_NOT_RUNNING ++ ++CASE "monitor depth 10 when running" ++ Include prepare ++ AgentRun start ++ Env OCF_CHECK_LEVEL=10 ++ AgentRun monitor OCF_SUCCESS ++ ++CASE "monitor depth 20 with running" ++ Include prepare ++ AgentRun start ++ Env OCF_CHECK_LEVEL=20 ++ AgentRun monitor OCF_SUCCESS ++ ++CASE "start insert failure (remove device)" ++ Include prepare ++ Bash losetup -d $OCFT_loop ++ BashAtExit losetup $OCFT_loop $OCFT_fs ++ AgentRun start OCF_ERR_GENERIC ++ ++CASE "monitor depth 20 insert failure (r/o fs)" ++ Include prepare ++ AgentRun start ++ Bash mount -o remount,ro $OCFT_dir ++ BashAtExit mount -o remount,rw $OCFT_dir ++ Env OCF_CHECK_LEVEL=20 ++ AgentRun monitor OCF_ERR_GENERIC ++ ++CASE "unimplemented command" ++ Include prepare ++ AgentRun no_cmd OCF_ERR_UNIMPLEMENTED ++ +diff --git a/tools/ocft/fedora/IPaddr2v4 b/tools/ocft/fedora/IPaddr2v4 +new file mode 100644 +index 0000000..a0df278 +--- /dev/null ++++ b/tools/ocft/fedora/IPaddr2v4 +@@ -0,0 +1,323 @@ ++# IPaddr2v4 ++ ++# Note: This test case uses two NICs(eth0, eth1) and ++# a IPv4 address prefix (192.168.144.0/24). ++# Adjust them according to your environment at VARIABLE section if needed. ++ ++CONFIG ++ Agent IPaddr2 ++ AgentRoot /usr/lib/ocf/resource.d/heartbeat ++ HangTimeout 20 ++ ++VARIABLE ++ OCFT_target_ip=192.168.144.2 ++ OCFT_target_nic=eth0 ++ OCFT_target_prefix=24 ++ OCFT_target_netaddr=192.168.144.1/$OCFT_target_prefix ++ OCFT_target_brd=192.168.144.255 ++ OCFT_wrong_ip=192.168.120.1 ++ OCFT_force_nic=eth1 ++ OCFT_force_prefix=16 ++ OCFT_force_prefix2=28 ++ OCFT_force_brd=192.168.255.255 ++ ++SETUP-AGENT ++ ip addr add $OCFT_target_netaddr dev $OCFT_target_nic brd $OCFT_target_brd ++ ++CLEANUP-AGENT ++ ip addr del $OCFT_target_netaddr dev $OCFT_target_nic ++ ++CASE-BLOCK required_args ++ Env OCF_RESKEY_ip=$OCFT_target_ip ++ Env OCFT_check_ip=$OCFT_target_ip ++ Env OCFT_check_prefix=$OCFT_target_prefix ++ Env OCFT_check_nic=$OCFT_target_nic ++ ++CASE-BLOCK check_ip_assigned ++ Bash ip -4 -o addr show $OCFT_check_nic | grep -w $OCFT_check_ip/$OCFT_check_prefix >/dev/null # checking if the IPv4 address was assigned correctly ++ ++CASE-BLOCK check_ip_removed ++ Bash ! ip -4 -o addr show $OCFT_check_nic | grep -w $OCFT_check_ip/$OCFT_check_prefix >/dev/null # checking if the IPv4 address was removed correctly ++ ++CASE-BLOCK base_ip_assigned ++ Bash ip addr add $OCFT_target_netaddr dev $OCFT_target_nic brd $OCFT_target_brd ++ ++CASE-BLOCK base_ip_removed ++ Bash ip addr del $OCFT_target_netaddr dev $OCFT_target_nic ++ ++CASE-BLOCK default_status ++ AgentRun stop ++ ++CASE-BLOCK prepare ++ Include required_args ++ Include default_status ++ ++# CASE No.0 ++# ++CASE "normal start" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ Include check_ip_assigned ++ ++# CASE No.1 ++# ++CASE "normal stop" ++ Include prepare ++ AgentRun start ++ AgentRun stop OCF_SUCCESS ++ Include check_ip_removed ++ ++# CASE No.2 ++# ++CASE "double start" ++ Include prepare ++ AgentRun start ++ AgentRun start OCF_SUCCESS ++ ++# CASE No.3 ++# ++CASE "double stop" ++ Include prepare ++ AgentRun stop OCF_SUCCESS ++ ++# CASE No.4 ++# ++CASE "monitor with running" ++ Include prepare ++ AgentRun start ++ AgentRun monitor OCF_SUCCESS ++ ++# CASE No.5 ++# ++CASE "monitor with not running" ++ Include prepare ++ AgentRun monitor OCF_NOT_RUNNING ++ ++# CASE No.6 ++# Note: this result is different from IPaddr2 in 3.9.3. ++# IPaddr2 succeeds if the ip matched based on the netmask of the subnet ++# or fails if it did not match to any. ++# Recommended to always specify both nic, cidr_netmask, and broadcast when you needed. ++# IPaddr2 in 3.9.3 was using a wrong subnet mask (constant of 32) in this case. ++# ++CASE "params with nic, no cidr_netmask" ++ Include prepare ++ Env OCF_RESKEY_nic=$OCFT_target_nic ++ AgentRun start OCF_SUCCESS ++ Include check_ip_assigned ++ AgentRun monitor OCF_SUCCESS ++ AgentRun stop OCF_SUCCESS ++ Include check_ip_removed ++ ++# CASE No.7 ++# ++CASE "params with nic, cidr_netmask" ++ Include prepare ++ Env OCF_RESKEY_nic=$OCFT_target_nic ++ Env OCF_RESKEY_cidr_netmask=$OCFT_target_prefix ++ AgentRun start OCF_SUCCESS ++ Include check_ip_assigned ++ AgentRun monitor OCF_SUCCESS ++ AgentRun stop OCF_SUCCESS ++ Include check_ip_removed ++ ++# CASE No.8 ++# ++CASE "error params with wrong ip" ++ Include prepare ++ Env OCF_RESKEY_ip=$OCFT_wrong_ip ++ AgentRun start OCF_ERR_GENERIC ++ ++# CASE No.9 ++# Note: this result is different from IPaddr2 in 3.9.3. ++# IPaddr2 fails when it could not determine the correct subnet mask. ++# When it could not get base ip, it becomes the error. ++# Recommended to always specify both nic, cidr_netmask, and broadcast when you needed. ++# IPaddr2 in 3.9.3 was using a wrong subnet mask (constant of 32) in this case. ++# ++#CASE "params with force nic" ++# Include prepare ++# Env OCF_RESKEY_nic=$OCFT_force_nic ++# Env OCFT_check_nic=$OCFT_force_nic ++# AgentRun start OCF_ERR_GENERIC ++# Include check_ip_removed ++# Unenv OCF_RESKEY_nic ++ ++# CASE No.10 ++# Note: this result is different from IPaddr2 in 3.9.3. ++# IPaddr2 fails when it could not determine the broadcast. ++# Recommended to always specify both nic, cidr_netmask, and broadcast when you needed. ++# IPaddr2 in 3.9.3 succeeded but it's considered ambiguous. ++# ++CASE "params with force cidr_netmask (base netmask > assigned netmask)" ++ Include prepare ++ Env OCF_RESKEY_cidr_netmask=$OCFT_force_prefix ++ Env OCFT_check_prefix=$OCFT_force_prefix ++ AgentRun start OCF_ERR_GENERIC ++ Include check_ip_removed ++ ++# CASE No.11 ++# Note: this result is different from IPaddr2 in 3.9.3. ++# IPaddr2 succeeds but the broadcast is not set. ++# This is because findif.sh can not calculate a broadcast from a netmask. ++# Recommended to always specify both nic, cidr_netmask, and broadcast when you needed. ++# IPaddr2 in 3.9.3 succeeded with using a calculated broadcast. ++# ++#CASE "force to use the specified nic and cidr_netmask" ++# Include prepare ++# Env OCF_RESKEY_nic=$OCFT_force_nic ++# Env OCF_RESKEY_cidr_netmask=$OCFT_force_prefix ++# Env OCFT_check_nic=$OCFT_force_nic ++# Env OCFT_check_prefix=$OCFT_force_prefix ++# AgentRun start OCF_SUCCESS ++# AgentRun stop OCF_SUCCESS ++# Include check_ip_removed ++# Unenv OCF_RESKEY_cidr_netmask ++ ++ ++# CASE No.12 ++# Note: this result is different from IPaddr2 in 3.9.3. ++# IPaddr2 fails when it could not determine the correct subnet mask. ++# When it could not get base ip, it becomes the error. ++# Recommended to always specify both nic, cidr_netmask, and broadcast when you needed. ++# IPaddr2 in 3.9.3 was using a wrong subnet mask (constant of 32) in this case. ++# ++CASE "error params with wrong ip and nic (not exist base_ip)" ++ Include prepare ++ Include base_ip_removed ++ Env OCF_RESKEY_nic=$OCFT_target_nic ++ Env OCFT_check_nic=$OCFT_target_nic ++ AgentRun start OCF_ERR_GENERIC ++ Include check_ip_removed ++ Include base_ip_assigned ++ ++# CASE No.13 ++# ++CASE "params with cidr_netmask" ++ Include prepare ++ Env OCF_RESKEY_cidr_netmask=$OCFT_target_prefix ++ AgentRun start OCF_SUCCESS ++ Include check_ip_assigned ++ AgentRun monitor OCF_SUCCESS ++ AgentRun stop OCF_SUCCESS ++ Include check_ip_removed ++ ++# CASE No.14 ++# Note: this result is different from IPaddr2 in 3.9.3. ++# IPaddr2 does not override the broadcast by cidr_netmask. ++# Recommended to always specify both nic, cidr_netmask, and broadcast when you needed. ++# IPaddr2 in 3.9.3 overrode the broadcast calculated by cidr_netmask. ++# ++CASE "params with force cidr_netmask (base netmask < assigned netmask)" ++ Include prepare ++ Env OCF_RESKEY_cidr_netmask=$OCFT_force_prefix2 ++ Env OCFT_check_prefix=$OCFT_force_prefix2 ++ AgentRun start OCF_SUCCESS ++ Include check_ip_assigned ++ AgentRun monitor OCF_SUCCESS ++ AgentRun stop OCF_SUCCESS ++ Include check_ip_removed ++ ++# CASE No.15 ++# Note: this result is different from IPaddr2 in 3.9.3. ++# IPaddr2 fails when it could not determine the broadcast. ++# Recommended to always specify both nic, cidr_netmask, and broadcast when you needed. ++# IPaddr2 in 3.9.3 succeeded but it's considered ambiguous. ++# ++CASE "error params with wrong ip and cidr_netmask (not exist base_ip)" ++ Include prepare ++ Include base_ip_removed ++ Env OCF_RESKEY_cidr_netmask=$OCFT_target_prefix ++ AgentRun start OCF_ERR_GENERIC ++ Include base_ip_assigned ++ ++# CASE No.16 ++# Note: this result is different from IPaddr2 in 3.9.3. ++# IPaddr2 succeeds but the broadcast is not set. ++# This is because findif.sh can not calculate a broadcast from a netmask. ++# Recommended to always specify both nic, cidr_netmask, and broadcast when you needed. ++# IPaddr2 in 3.9.3 succeeded with using a calculated broadcast. ++# ++#CASE "force to use the specified nic and cidr_netmask" ++# Include prepare ++# Env OCF_RESKEY_nic=$OCFT_force_nic ++# Env OCF_RESKEY_cidr_netmask=$OCFT_force_prefix2 ++# Env OCFT_check_prefix=$OCFT_force_prefix2 ++# Env OCFT_check_nic=$OCFT_force_nic ++# AgentRun start OCF_SUCCESS ++# AgentRun stop OCF_SUCCESS ++# Include check_ip_removed ++ ++# CASE No.17 ++# Note: this result is different from IPaddr2 in 3.9.3. ++# IPaddr2 succeeds but the broadcast is not set. ++# This is because findif.sh can not calculate a broadcast from a netmask. ++# Recommended to always specify both nic, cidr_netmask, and broadcast when you needed. ++# IPaddr2 in 3.9.3 succeeded with using a calculated broadcast. ++# ++#CASE "force to use the specified nic and cidr_netmask (not exist base_ip)" ++# Include prepare ++# Include base_ip_removed ++# Env OCF_RESKEY_nic=$OCFT_force_nic ++# Env OCF_RESKEY_cidr_netmask=$OCFT_force_prefix2 ++# Env OCFT_check_prefix=$OCFT_force_prefix2 ++# Env OCFT_check_nic=$OCFT_force_nic ++# AgentRun start OCF_SUCCESS ++# AgentRun stop OCF_SUCCESS ++# Unenv OCF_RESKEY_nic ++# Unenv OCF_RESKEY_cidr_netmask ++# Include base_ip_assigned ++ ++# CASE No.18 ++# ++CASE "params with broadcast, no nic, no cidr_netmask" ++ Include prepare ++ Env OCF_RESKEY_broadcast=$OCFT_force_brd ++ AgentRun start OCF_SUCCESS ++ Include check_ip_assigned ++ AgentRun monitor OCF_SUCCESS ++ AgentRun stop OCF_SUCCESS ++ Include check_ip_removed ++ ++# CASE No.19 ++# ++CASE "params with broadcast, no nic, no cidr_netmask" ++ Include prepare ++ Include base_ip_removed ++ Env OCF_RESKEY_broadcast=$OCFT_force_brd ++ AgentRun start OCF_ERR_GENERIC ++ Include base_ip_assigned ++ ++# CASE No.20 ++# ++#CASE "force to use the specified nic and cidr_netmask" ++# Include prepare ++# Env OCF_RESKEY_nic=$OCFT_force_nic ++# Env OCF_RESKEY_cidr_netmask=$OCFT_force_prefix ++# Env OCF_RESKEY_broadcast=$OCFT_force_brd ++# Env OCFT_check_nic=$OCFT_force_nic ++# Env OCFT_check_prefix=$OCFT_force_prefix ++# AgentRun start OCF_SUCCESS ++# Include check_ip_assigned ++# AgentRun monitor OCF_SUCCESS ++# AgentRun stop OCF_SUCCESS ++# Include check_ip_removed ++# Unenv OCF_RESKEY_cidr_netmask ++ ++# CASE No.21 ++# ++#CASE "force to use the specified nic and cidr_netmask" ++# Include prepare ++# Include base_ip_removed ++# Env OCF_RESKEY_nic=$OCFT_force_nic ++# Env OCF_RESKEY_cidr_netmask=$OCFT_force_prefix2 ++# Env OCF_RESKEY_broadcast=$OCFT_target_brd ++# Env OCFT_check_nic=$OCFT_force_nic ++# Env OCFT_check_prefix=$OCFT_force_prefix2 ++# AgentRun start OCF_SUCCESS ++# Include check_ip_assigned ++# AgentRun monitor OCF_SUCCESS ++# AgentRun stop OCF_SUCCESS ++# Include check_ip_removed ++# Include base_ip_assigned ++ +diff --git a/tools/ocft/fedora/IPaddr2v6 b/tools/ocft/fedora/IPaddr2v6 +new file mode 100644 +index 0000000..fe35046 +--- /dev/null ++++ b/tools/ocft/fedora/IPaddr2v6 +@@ -0,0 +1,250 @@ ++# IPaddr2v6 ++ ++# Note: This test case uses two NICs(eth0, eth1) and ++# a IPv6 address prefix (2001:db8::/32, RFC3849). ++# Adjust them according to your environment at VARIABLE section if needed. ++ ++CONFIG ++ Agent IPaddr2 ++ AgentRoot /usr/lib/ocf/resource.d/heartbeat ++ HangTimeout 20 ++ ++VARIABLE ++ OCFT_target_ip=2001:db8:1234::2 ++ OCFT_target_nic=eth0 ++ OCFT_target_prefix=64 ++ OCFT_target_netaddr=2001:db8:1234::1/$OCFT_target_prefix ++ OCFT_target_linklocal=fe80::2 ++ OCFT_wrong_ip=2001:db8:5678::2 ++ OCFT_force_nic=eth1 ++ OCFT_force_prefix=80 ++ OCFT_force_prefix2=48 ++ ++SETUP-AGENT ++ ip addr add $OCFT_target_netaddr dev $OCFT_target_nic ++ ++CLEANUP-AGENT ++ ip addr del $OCFT_target_netaddr dev $OCFT_target_nic ++ ++CASE-BLOCK required_args ++ Env OCF_RESKEY_ip=$OCFT_target_ip ++ Env OCFT_check_ip=$OCFT_target_ip ++ Env OCFT_check_prefix=$OCFT_target_prefix ++ Env OCFT_check_nic=$OCFT_target_nic ++ ++CASE-BLOCK check_ip_assigned ++ Bash ip -6 -o addr show $OCFT_check_nic | grep -w $OCFT_check_ip/$OCFT_check_prefix >/dev/null # checking if the IPv6 address was assigned correctly ++ ++CASE-BLOCK check_ip_removed ++ Bash ! ip -6 -o addr show $OCFT_check_nic | grep -w $OCFT_check_ip/$OCFT_check_prefix >/dev/null # checking if the IPv6 address was removed correctly ++ ++CASE-BLOCK base_ip_assigned ++ Bash ip addr add $OCFT_target_netaddr dev $OCFT_target_nic ++ ++CASE-BLOCK base_ip_removed ++ Bash ip addr del $OCFT_target_netaddr dev $OCFT_target_nic ++ ++CASE-BLOCK default_status ++ AgentRun stop ++ ++CASE-BLOCK prepare ++ Include required_args ++ Include default_status ++ ++# CASE No.0 ++# ++CASE "normal start" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ Include check_ip_assigned ++ ++# CASE No.1 ++# ++CASE "normal stop" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ AgentRun stop OCF_SUCCESS ++ Include check_ip_removed ++ ++# CASE No.2 ++# ++CASE "double start" ++ Include prepare ++ AgentRun start ++ AgentRun start OCF_SUCCESS ++ ++# CASE No.3 ++# ++CASE "double stop" ++ Include prepare ++ AgentRun stop OCF_SUCCESS ++ ++# CASE No.4 ++# ++CASE "monitor with running" ++ Include prepare ++ AgentRun start ++ AgentRun monitor OCF_SUCCESS ++ ++# CASE No.5 ++# ++CASE "monitor with not running" ++ Include prepare ++ AgentRun monitor OCF_NOT_RUNNING ++ ++# CASE No.6 ++# ++CASE "error params with wrong ip" ++ Include prepare ++ Env OCF_RESKEY_ip=$OCFT_wrong_ip ++ AgentRun start OCF_ERR_GENERIC ++ ++# CASE No.7 ++# ++CASE "error params with no nic for a link-local IPv6 address" ++ Include prepare ++ Env OCF_RESKEY_ip=$OCFT_target_linklocal ++ Env OCFT_check_ip=$OCFT_target_linklocal ++ # nic is mandatory for a link-local address ++ AgentRun start OCF_ERR_CONFIGURED ++ ++# CASE No.8 ++# ++CASE "params with nic, no cidr_netmask" ++ Include prepare ++ Env OCF_RESKEY_nic=$OCFT_target_nic ++ AgentRun start OCF_SUCCESS ++ Include check_ip_assigned ++ AgentRun monitor OCF_SUCCESS ++ AgentRun stop OCF_SUCCESS ++ Include check_ip_removed ++ ++# CASE No.9 ++# ++CASE "normal usage for a link-local IPv6 address, params with nic" ++ Include prepare ++ Env OCF_RESKEY_ip=$OCFT_target_linklocal ++ Env OCFT_check_ip=$OCFT_target_linklocal ++ # nic is mandatory for a link-local address ++ Env OCF_RESKEY_nic=$OCFT_target_nic ++ Env OCFT_check_nic=$OCFT_target_nic ++ AgentRun start OCF_SUCCESS ++ Include check_ip_assigned ++ AgentRun stop OCF_SUCCESS ++ Include check_ip_removed ++ ++# CASE No.10 ++# ++CASE "error params with wrong ip and nic (not exist base_ip)" ++ Include prepare ++ Include base_ip_removed ++ Env OCF_RESKEY_nic=$OCFT_target_nic ++ Env OCFT_check_nic=$OCFT_target_nic ++ AgentRun start OCF_ERR_GENERIC ++ Include check_ip_removed ++ Include base_ip_assigned ++ ++# CASE No.11 ++# ++#CASE "params with force nic" ++# Include prepare ++# Env OCF_RESKEY_nic=$OCFT_force_nic ++# Env OCFT_check_nic=$OCFT_force_nic ++# AgentRun start OCF_ERR_GENERIC ++# Include check_ip_removed ++# Unenv OCF_RESKEY_nic ++ ++# CASE No.12 ++# ++CASE "params with force cidr_netmask" ++ Include prepare ++ Env OCF_RESKEY_cidr_netmask=$OCFT_target_prefix ++ Env OCFT_check_prefix=$OCFT_target_prefix ++ AgentRun start OCF_SUCCESS ++ Include check_ip_assigned ++ AgentRun stop OCF_SUCCESS ++ Include check_ip_removed ++ ++# CASE No.13 ++# ++CASE "params with force cidr_netmask (base netmask < assigned netmask)" ++ Include prepare ++ Env OCF_RESKEY_cidr_netmask=$OCFT_force_prefix ++ Env OCFT_check_prefix=$OCFT_force_prefix ++ AgentRun start OCF_ERR_GENERIC ++ Include check_ip_removed ++ ++# CASE No.14 ++# ++CASE "params with force cidr_netmask (base netmask > assigned netmask)" ++ Include prepare ++ Env OCF_RESKEY_cidr_netmask=$OCFT_force_prefix2 ++ Env OCFT_check_prefix=$OCFT_force_prefix2 ++ AgentRun start OCF_ERR_GENERIC ++ Include check_ip_removed ++ ++# CASE No.15 ++# ++CASE "params with cidr_netmask" ++ Include prepare ++ Include base_ip_removed ++ Env OCF_RESKEY_cidr_netmask=$OCFT_target_prefix ++ Env OCFT_check_prefix=$OCFT_target_prefix ++ AgentRun start OCF_ERR_GENERIC ++ Include base_ip_assigned ++ ++# CASE No.16 ++# ++CASE "params with nic, cidr_netmask" ++ Include prepare ++ Env OCF_RESKEY_nic=$OCFT_target_nic ++ Env OCF_RESKEY_cidr_netmask=$OCFT_target_prefix ++ Env OCFT_check_nic=$OCFT_target_nic ++ Env OCFT_check_prefix=$OCFT_target_prefix ++ AgentRun start OCF_SUCCESS ++ Include check_ip_assigned ++ AgentRun stop OCF_SUCCESS ++ Include check_ip_removed ++ ++# CASE No.17 ++# ++#CASE "force to use the specified nic and cidr_netmask (base netmask < assigned netmask)" ++# Include prepare ++# Env OCF_RESKEY_nic=$OCFT_force_nic ++# Env OCF_RESKEY_cidr_netmask=$OCFT_force_prefix ++# Env OCFT_check_nic=$OCFT_force_nic ++# Env OCFT_check_prefix=$OCFT_force_prefix ++# AgentRun start OCF_SUCCESS ++# Include check_ip_assigned ++# AgentRun stop OCF_SUCCESS ++# Include check_ip_removed ++ ++# CASE No.18 ++# This use case is now valid. It was not allowed until v3.9.2. ++# ++#CASE "force to use the specified nic and cidr_netmask (base netmask > assigned netmask)" ++# Include prepare ++# Env OCF_RESKEY_nic=$OCFT_force_nic ++# Env OCF_RESKEY_cidr_netmask=$OCFT_force_prefix2 ++# Env OCFT_check_nic=$OCFT_force_nic ++# Env OCFT_check_prefix=$OCFT_force_prefix2 ++# AgentRun start OCF_SUCCESS ++# Include check_ip_assigned ++# AgentRun stop OCF_SUCCESS ++# Include check_ip_removed ++ ++# CASE No.19 ++# ++#CASE "force to use the specified nic and cidr_netmask (base netmask > assigned netmask)" ++# Include prepare ++# Include base_ip_removed ++# Env OCF_RESKEY_nic=$OCFT_force_nic ++# Env OCF_RESKEY_cidr_netmask=$OCFT_force_prefix2 ++# Env OCFT_check_nic=$OCFT_force_nic ++# Env OCFT_check_prefix=$OCFT_force_prefix2 ++# AgentRun start OCF_SUCCESS ++# Include check_ip_assigned ++# AgentRun stop OCF_SUCCESS ++# Include check_ip_removed ++# Include base_ip_assigned ++ +diff --git a/tools/ocft/fedora/IPsrcaddr b/tools/ocft/fedora/IPsrcaddr +new file mode 100644 +index 0000000..934801d +--- /dev/null ++++ b/tools/ocft/fedora/IPsrcaddr +@@ -0,0 +1,61 @@ ++# IPsrcaddr ++ ++CONFIG ++ Agent IPsrcaddr ++ AgentRoot /usr/lib/ocf/resource.d/heartbeat ++ HangTimeout 20 ++ ++CASE-BLOCK required_args ++ Env OCF_RESKEY_ipaddress=$(ip addr | grep "inet " | tail -n 1 | sed "s/\// /g" | awk '{print $2}') ++ ++CASE-BLOCK default_status ++ AgentRun stop ++ ++CASE-BLOCK prepare ++ Include required_args ++ Include default_status ++ ++CASE "check base env" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ ++CASE "check base env: unset 'OCF_RESKEY_ipaddress'" ++ Include prepare ++ Unenv OCF_RESKEY_ipaddress ++ AgentRun start OCF_ERR_CONFIGURED ++ ++CASE "check base env: set invalid 'OCF_RESKEY_ipaddress'" ++ Include prepare ++ Env OCF_RESKEY_ipaddress=not_ip_address ++ AgentRun start OCF_ERR_CONFIGURED ++ ++CASE "normal start" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ ++CASE "normal stop" ++ Include prepare ++ AgentRun start ++ AgentRun stop OCF_SUCCESS ++ ++CASE "double start" ++ Include prepare ++ AgentRun start ++ AgentRun start OCF_SUCCESS ++ ++CASE "double stop" ++ Include prepare ++ AgentRun stop OCF_SUCCESS ++ ++CASE "monitor with running" ++ Include prepare ++ AgentRun start ++ AgentRun monitor OCF_SUCCESS ++ ++CASE "monitor with not running" ++ Include prepare ++ AgentRun monitor OCF_NOT_RUNNING ++ ++CASE "unimplemented command" ++ Include prepare ++ AgentRun no_cmd OCF_ERR_UNIMPLEMENTED +diff --git a/tools/ocft/fedora/SendArp b/tools/ocft/fedora/SendArp +new file mode 100644 +index 0000000..adae63e +--- /dev/null ++++ b/tools/ocft/fedora/SendArp +@@ -0,0 +1,73 @@ ++# SendArp ++ ++CONFIG ++ Agent SendArp ++ AgentRoot /usr/lib/ocf/resource.d/heartbeat ++ HangTimeout 15 ++ ++CASE-BLOCK required_args ++ Env OCF_RESKEY_ip=127.0.0.1 ++ Env OCF_RESKEY_nic=eth0 ++ Env OCF_RESKEY_background=false ++ ++CASE-BLOCK default_status ++ AgentRun stop ++ ++CASE-BLOCK prepare ++ Include required_args ++ Include default_status ++ ++CASE "check base env" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ ++CASE "check base env: unset 'OCF_RESKEY_ip'" ++ Include prepare ++ Unenv OCF_RESKEY_ip ++ AgentRun start OCF_ERR_CONFIGURED ++ ++CASE "check base env: set invalid 'OCF_RESKEY_ip'" ++ Include prepare ++ Env OCF_RESKEY_ip=not_ip_address ++ AgentRun start OCF_ERR_GENERIC ++ ++CASE "check base env: unset 'OCF_RESKEY_nic'" ++ Include prepare ++ Unenv OCF_RESKEY_nic ++ AgentRun start OCF_ERR_CONFIGURED ++ ++CASE "check base env: set invalid 'OCF_RESKEY_nic'" ++ Include prepare ++ Env OCF_RESKEY_nic=not_nic ++ AgentRun start OCF_ERR_GENERIC ++ ++CASE "normal start" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ ++CASE "normal stop" ++ Include prepare ++ AgentRun start ++ AgentRun stop OCF_SUCCESS ++ ++CASE "double start" ++ Include prepare ++ AgentRun start ++ AgentRun start OCF_SUCCESS ++ ++CASE "double stop" ++ Include prepare ++ AgentRun stop OCF_SUCCESS ++ ++CASE "monitor with running" ++ Include prepare ++ AgentRun start ++ AgentRun monitor OCF_SUCCESS ++ ++CASE "monitor with not running" ++ Include prepare ++ AgentRun monitor OCF_NOT_RUNNING ++ ++CASE "unimplemented command" ++ Include prepare ++ AgentRun no_cmd OCF_ERR_UNIMPLEMENTED +diff --git a/tools/ocft/fedora/Xinetd b/tools/ocft/fedora/Xinetd +new file mode 100644 +index 0000000..e26f495 +--- /dev/null ++++ b/tools/ocft/fedora/Xinetd +@@ -0,0 +1,62 @@ ++# Xinetd ++ ++CONFIG ++ Agent Xinetd ++ AgentRoot /usr/lib/ocf/resource.d/heartbeat ++ InstallPackage xinetd ++ ++SETUP-AGENT ++ service xinetd start ++ ++CLEANUP-AGENT ++ service xinetd stop ++ ++CASE-BLOCK required_args ++ Env OCF_RESKEY_service=echo-stream ++ ++CASE-BLOCK default_status ++ AgentRun stop ++ ++CASE-BLOCK prepare ++ Include required_args ++ Include default_status ++ ++CASE "check base env" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ ++CASE "check base env: unset 'OCF_RESKEY_protocol'" ++ Include prepare ++ Unenv OCF_RESKEY_service ++ AgentRun start OCF_ERR_CONFIGURED ++ ++CASE "normal start" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ ++CASE "normal stop" ++ Include prepare ++ AgentRun start ++ AgentRun stop OCF_SUCCESS ++ ++CASE "double start" ++ Include prepare ++ AgentRun start ++ AgentRun start OCF_SUCCESS ++ ++CASE "double stop" ++ Include prepare ++ AgentRun stop OCF_SUCCESS ++ ++CASE "monitor with running" ++ Include prepare ++ AgentRun start ++ AgentRun monitor OCF_SUCCESS ++ ++CASE "monitor with not running" ++ Include prepare ++ AgentRun monitor OCF_NOT_RUNNING ++ ++CASE "unimplemented command" ++ Include prepare ++ AgentRun no_cmd OCF_ERR_UNIMPLEMENTED +diff --git a/tools/ocft/fedora/apache b/tools/ocft/fedora/apache +new file mode 100644 +index 0000000..23cce28 +--- /dev/null ++++ b/tools/ocft/fedora/apache +@@ -0,0 +1,81 @@ ++# apache ++# make sure that your apache configuration loads mod_status ++ ++CONFIG ++ Agent apache ++ AgentRoot /usr/lib/ocf/resource.d/heartbeat ++ InstallPackage httpd ++ HangTimeout 20 ++ ++SETUP-AGENT ++ ++ cat << END >> /var/www/html/index.html ++ ++ My Test Site ++ ++END ++ ++ cp /etc/httpd/conf/httpd.conf /etc/httpd/conf/httpd.conf.bu ++ cat << END >> /etc/httpd/conf/httpd.conf ++ ++ SetHandler server-status ++ Order deny,allow ++ Deny from all ++ Allow from 127.0.0.1 ++ ++END ++ ++CLEANUP-AGENT ++ mv -f /etc/httpd/conf/httpd.conf.bu /etc/httpd/conf/httpd.conf ++ rm -f /var/www/html/index.html ++ ++CASE-BLOCK default_status ++ AgentRun stop ++ ++CASE-BLOCK prepare ++ Include default_status ++ ++CASE "check base env" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ ++CASE "check base env: set non-existing OCF_RESKEY_statusurl" ++ Include prepare ++ Env OCF_RESKEY_statusurl="yoyoyoyo" ++ AgentRun start OCF_ERR_GENERIC ++ ++CASE "check base env: set non-existing OCF_RESKEY_configfile" ++ Include prepare ++ Env OCF_RESKEY_configfile="/yoyoyoyo/nosuchfile" ++ AgentRun start OCF_ERR_INSTALLED ++ ++CASE "normal start" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ ++CASE "normal stop" ++ Include prepare ++ AgentRun start ++ AgentRun stop OCF_SUCCESS ++ ++CASE "double start" ++ Include prepare ++ AgentRun start ++ AgentRun start OCF_SUCCESS ++ ++CASE "double stop" ++ Include prepare ++ AgentRun stop OCF_SUCCESS ++ ++CASE "running monitor" ++ Include prepare ++ AgentRun start ++ AgentRun monitor OCF_SUCCESS ++ ++CASE "not running monitor" ++ Include prepare ++ AgentRun monitor OCF_NOT_RUNNING ++ ++CASE "unimplemented command" ++ Include prepare ++ AgentRun no_cmd OCF_ERR_UNIMPLEMENTED +diff --git a/tools/ocft/fedora/mysql b/tools/ocft/fedora/mysql +new file mode 100644 +index 0000000..c03be4f +--- /dev/null ++++ b/tools/ocft/fedora/mysql +@@ -0,0 +1,76 @@ ++# mysql ++ ++CONFIG ++ Agent mysql ++ AgentRoot /usr/lib/ocf/resource.d/heartbeat ++ InstallPackage mysql ++ InstallPackage mysql-server ++ HangTimeout 20 ++ ++ ++CASE-BLOCK crm_setting ++ Env OCF_RESKEY_CRM_meta_timeout=15000 ++ Env OCF_RESKEY_enable_creation=1 ++ ++CASE-BLOCK default_status ++ AgentRun stop ++ ++CASE-BLOCK prepare ++ Include crm_setting ++ Include default_status ++ ++CASE "check base env" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ ++CASE "check base env: invalid 'OCF_RESKEY_binary'" ++ Include prepare ++ Env OCF_RESKEY_binary=no_such ++ AgentRun start OCF_ERR_INSTALLED ++ ++CASE "normal start" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ ++CASE "normal stop" ++ Include prepare ++ AgentRun start ++ AgentRun stop OCF_SUCCESS ++ ++CASE "double start" ++ Include prepare ++ AgentRun start ++ AgentRun start OCF_SUCCESS ++ ++CASE "double stop" ++ Include prepare ++ AgentRun stop OCF_SUCCESS ++ ++CASE "running monitor" ++ Include prepare ++ AgentRun start ++ AgentRun monitor OCF_SUCCESS ++ ++CASE "not running monitor" ++ Include prepare ++ AgentRun monitor OCF_NOT_RUNNING ++ ++CASE "check lib file" ++ Include prepare ++ Bash chmod u-w /var/lib/mysql ++ BashAtExit chmod u+w /var/lib/mysql ++ AgentRun start OCF_ERR_PERM ++ ++CASE "unimplemented command" ++ Include prepare ++ AgentRun no_cmd OCF_ERR_UNIMPLEMENTED ++ ++CASE "non-existent user" ++ Include prepare ++ Env OCF_RESKEY_user=no_user ++ AgentRun start OCF_ERR_INSTALLED ++ ++CASE "invalid user" ++ Include prepare ++ Env OCF_RESKEY_user=nobody ++ AgentRun start OCF_ERR_PERM +diff --git a/tools/ocft/fedora/nfsserver b/tools/ocft/fedora/nfsserver +new file mode 100644 +index 0000000..5eadff4 +--- /dev/null ++++ b/tools/ocft/fedora/nfsserver +@@ -0,0 +1,74 @@ ++# nfsserver ++ ++CONFIG ++ Agent nfsserver ++ AgentRoot /usr/lib/ocf/resource.d/heartbeat ++ InstallPackage nfs-utils ++ HangTimeout 20 ++ ++CASE-BLOCK required_args ++ Env OCF_RESKEY_nfs_ip=127.0.0.1 ++ Env OCF_RESKEY_nfs_shared_infodir=/var/lib/nfs ++ Env OCF_RESKEY_nfs_init_script=/etc/init.d/nfs ++ ++CASE-BLOCK default_status ++ AgentRun stop ++ ++CASE-BLOCK prepare ++ Include required_args ++ Include default_status ++ ++CASE "check base env" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ ++CASE "check base env: invalid 'OCF_RESKEY_nfs_init_script'" ++ Include prepare ++ Env OCF_RESKEY_nfs_init_script=no_such_script ++ AgentRun start OCF_ERR_INSTALLED ++ ++CASE "check base env: unset 'OCF_RESKEY_nfs_ip'" ++ Include prepare ++ Unenv OCF_RESKEY_nfs_ip ++ AgentRun start OCF_ERR_CONFIGURED ++ ++CASE "check base env: unset 'OCF_RESKEY_nfs_shared_infodir'" ++ Include prepare ++ Unenv OCF_RESKEY_nfs_shared_infodir ++ AgentRun start OCF_ERR_CONFIGURED ++ ++CASE "check base env: invalid 'OCF_RESKEY_nfs_notify_cmd'" ++ Include prepare ++ Env OCF_RESKEY_nfs_notify_cmd=no_such_program ++ AgentRun start OCF_ERR_INSTALLED ++ ++CASE "normal start" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ ++CASE "normal stop" ++ Include prepare ++ AgentRun start ++ AgentRun stop OCF_SUCCESS ++ ++CASE "double start" ++ Include prepare ++ AgentRun start ++ AgentRun start OCF_SUCCESS ++ ++CASE "double stop" ++ Include prepare ++ AgentRun stop OCF_SUCCESS ++ ++CASE "monitor with running" ++ Include prepare ++ AgentRun start ++ AgentRun monitor OCF_SUCCESS ++ ++CASE "monitor with not running" ++ Include prepare ++ AgentRun monitor OCF_NOT_RUNNING ++ ++CASE "unimplemented command" ++ Include prepare ++ AgentRun no_cmd OCF_ERR_UNIMPLEMENTED +diff --git a/tools/ocft/fedora/pgsql b/tools/ocft/fedora/pgsql +new file mode 100644 +index 0000000..fd61ee9 +--- /dev/null ++++ b/tools/ocft/fedora/pgsql +@@ -0,0 +1,72 @@ ++# pgsql ++ ++CONFIG ++ Agent pgsql ++ AgentRoot /usr/lib/ocf/resource.d/heartbeat ++ InstallPackage postgresql-server ++ HangTimeout 20 ++ ++SETUP-AGENT ++ service postgresql initdb > /dev/null 2>&1 ++ /etc/init.d/postgresql start ++ /etc/init.d/postgresql stop ++ ++CASE-BLOCK crm_setting ++ Env OCF_RESKEY_CRM_meta_timeout=15000 ++ ++CASE-BLOCK default_status ++ AgentRun stop ++ ++CASE-BLOCK prepare ++ Include crm_setting ++ Include default_status ++ ++CASE "check base env" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ ++CASE "check base env: invalid 'OCF_RESKEY_pgctl'" ++ Include prepare ++ Env OCF_RESKEY_pgctl=no_such ++ AgentRun start OCF_ERR_INSTALLED ++ ++CASE "normal start" ++ Include prepare ++ AgentRun start OCF_SUCCESS ++ ++CASE "normal stop" ++ Include prepare ++ AgentRun start ++ AgentRun stop OCF_SUCCESS ++ ++CASE "double start" ++ Include prepare ++ AgentRun start ++ AgentRun start OCF_SUCCESS ++ ++CASE "double stop" ++ Include prepare ++ AgentRun stop OCF_SUCCESS ++ ++CASE "running monitor" ++ Include prepare ++ AgentRun start ++ AgentRun monitor OCF_SUCCESS ++ ++CASE "not running monitor" ++ Include prepare ++ AgentRun monitor OCF_NOT_RUNNING ++ ++CASE "unimplemented command" ++ Include prepare ++ AgentRun no_cmd OCF_ERR_UNIMPLEMENTED ++ ++CASE "non-existent user" ++ Include prepare ++ Env OCF_RESKEY_pgdba=no_user ++ AgentRun start OCF_ERR_INSTALLED ++ ++CASE "invalid user" ++ Include prepare ++ Env OCF_RESKEY_pgdba=nobody ++ AgentRun start OCF_ERR_PERM +diff --git a/tools/ocft/fedora/tomcat b/tools/ocft/fedora/tomcat +new file mode 100644 +index 0000000..2cd5ae1 +--- /dev/null ++++ b/tools/ocft/fedora/tomcat +@@ -0,0 +1,72 @@ ++# tomcat ++# ++# NOTE: Clean up $catalina_home/logs before running this test ++# otherwise creating the pid/log files may fail ++# in the test case with a different user. ++ ++CONFIG ++ Agent tomcat ++ AgentRoot /usr/lib/ocf/resource.d/heartbeat ++ InstallPackage tomcat ++ HangTimeout 120 ++ ++VARIABLE ++ # Adjust accrding to your configuration ++ catalina_home=/usr/share/tomcat ++ java_home=/usr/lib/jvm/jre-openjdk ++ ++CASE-BLOCK required_args_tomcat ++ Env OCF_RESKEY_catalina_home=${catalina_home} ++ Env OCF_RESKEY_java_home=${java_home} ++ ++CASE-BLOCK args_clear ++ Unenv OCF_RESKEY_catalina_home ++ Unenv OCF_RESKEY_tomcat_user ++ Unenv OCF_RESKEY_java_home ++ ++CASE-BLOCK default_status ++ AgentRun stop ++ ++CASE-BLOCK prepare_tomcat ++ Include required_args_tomcat ++ Include default_status ++ ++# Test CASE ++# ++#CASE "normal start tomcat require_args (user:user)" ++# Include prepare_tomcat ++# AgentRun start OCF_SUCCESS ++# AgentRun monitor OCF_SUCCESS ++# AgentRun stop OCF_SUCCESS ++# AgentRun monitor OCF_NOT_RUNNING ++# Include args_clear ++ ++#CASE "normal start tomcat require_args (user:root)" ++# Include prepare_tomcat ++# Unenv OCF_RESKEY_tomcat_user ++# AgentRun start OCF_SUCCESS ++# AgentRun monitor OCF_SUCCESS ++# AgentRun stop OCF_SUCCESS ++# AgentRun monitor OCF_NOT_RUNNING ++# Include args_clear ++ ++CASE "error start tomcat no catalina_home" ++ Include prepare_tomcat ++ Unenv OCF_RESKEY_catalina_home ++ AgentRun start OCF_ERR_INSTALLED ++ Include args_clear ++ ++CASE "error start tomcat no java_home" ++ Include prepare_tomcat ++ Unenv OCF_RESKEY_java_home ++ AgentRun start OCF_ERR_INSTALLED ++ Include args_clear ++ ++CASE "error start tomcat no java command" ++ Include prepare_tomcat ++ Env OCF_RESKEY_java_home=/var ++ AgentRun start OCF_ERR_INSTALLED ++ AgentRun stop OCF_SUCCESS ++ AgentRun monitor OCF_NOT_RUNNING ++ Include args_clear ++ +diff --git a/tools/ocft/iscsi b/tools/ocft/iscsi +deleted file mode 100644 +index c1325a1..0000000 +--- a/tools/ocft/iscsi ++++ /dev/null +@@ -1,82 +0,0 @@ +-# iscsi +- +-CONFIG +- Agent iscsi +- AgentRoot /usr/lib/ocf/resource.d/heartbeat +- InstallPackage open-iscsi +- InstallPackage iscsitarget +- HangTimeout 20 +- +-VARIABLE +- OCFT_disk=/var/run/resource-agents/ocft-iscsi +- OCFT_target="iqn.2011-03.ocft.localhost:disk0" +- OCFT_portal="127.0.0.1:3260" +- +-SETUP-AGENT +- dd if=/dev/zero of=$OCFT_disk bs=1024k count=1 2>/dev/null +- echo Target $OCFT_target >> /etc/ietd.conf +- echo " Lun 0 Path=$OCFT_disk,Type=fileio" >> /etc/ietd.conf +- /etc/init.d/iscsitarget start +- /etc/init.d/open-iscsi start +- /etc/init.d/iscsitarget restart +- +-CLEANUP-AGENT +- rm -f $OCFT_disk +- sed -i "/^Target $OCFT_target/,+1d" /etc/ietd.conf +- +-CASE-BLOCK required_args +- Env OCF_RESKEY_portal=$OCFT_portal +- Env OCF_RESKEY_target=$OCFT_target +- +-CASE-BLOCK default_status +- AgentRun stop +- +-CASE-BLOCK prepare +- Include required_args +- Include default_status +- +-CASE "check base env" +- Include prepare +- AgentRun start OCF_SUCCESS +- +-CASE "check base env: invalid 'OCF_RESKEY_portal'" +- Include prepare +- Unenv OCF_RESKEY_portal +- AgentRun start OCF_ERR_CONFIGURED +- +-CASE "check base env: unset 'OCF_RESKEY_target'" +- Include prepare +- Unenv OCF_RESKEY_target +- AgentRun start OCF_ERR_CONFIGURED +- +-CASE "normal start" +- Include prepare +- AgentRun start OCF_SUCCESS +- +-CASE "normal stop" +- Include prepare +- AgentRun start +- AgentRun stop OCF_SUCCESS +- +-CASE "double start" +- Include prepare +- AgentRun start +- AgentRun start OCF_SUCCESS +- +-CASE "double stop" +- Include prepare +- AgentRun stop OCF_SUCCESS +- +-CASE "monitor when running" +- Include prepare +- AgentRun start +- AgentRun monitor OCF_SUCCESS +- +-CASE "monitor when not running" +- Include prepare +- AgentRun monitor OCF_NOT_RUNNING +- +-CASE "unimplemented command" +- Include prepare +- AgentRun no_cmd OCF_ERR_UNIMPLEMENTED +- +diff --git a/tools/ocft/mysql b/tools/ocft/mysql +deleted file mode 100644 +index 27fcb58..0000000 +--- a/tools/ocft/mysql ++++ /dev/null +@@ -1,77 +0,0 @@ +-# mysql +- +-CONFIG +- Agent mysql +- AgentRoot /usr/lib/ocf/resource.d/heartbeat +- InstallPackage mysql +- HangTimeout 20 +- +-SETUP-AGENT +- /etc/init.d/mysql start +- /etc/init.d/mysql stop +- +-CASE-BLOCK crm_setting +- Env OCF_RESKEY_CRM_meta_timeout=15000 +- +-CASE-BLOCK default_status +- AgentRun stop +- +-CASE-BLOCK prepare +- Include crm_setting +- Include default_status +- +-CASE "check base env" +- Include prepare +- AgentRun start OCF_SUCCESS +- +-CASE "check base env: invalid 'OCF_RESKEY_binary'" +- Include prepare +- Env OCF_RESKEY_binary=no_such +- AgentRun start OCF_ERR_INSTALLED +- +-CASE "normal start" +- Include prepare +- AgentRun start OCF_SUCCESS +- +-CASE "normal stop" +- Include prepare +- AgentRun start +- AgentRun stop OCF_SUCCESS +- +-CASE "double start" +- Include prepare +- AgentRun start +- AgentRun start OCF_SUCCESS +- +-CASE "double stop" +- Include prepare +- AgentRun stop OCF_SUCCESS +- +-CASE "running monitor" +- Include prepare +- AgentRun start +- AgentRun monitor OCF_SUCCESS +- +-CASE "not running monitor" +- Include prepare +- AgentRun monitor OCF_NOT_RUNNING +- +-CASE "check lib file" +- Include prepare +- Bash chmod u-w /var/lib/mysql +- BashAtExit chmod u+w /var/lib/mysql +- AgentRun start OCF_ERR_PERM +- +-CASE "unimplemented command" +- Include prepare +- AgentRun no_cmd OCF_ERR_UNIMPLEMENTED +- +-CASE "non-existent user" +- Include prepare +- Env OCF_RESKEY_user=no_user +- AgentRun start OCF_ERR_INSTALLED +- +-CASE "invalid user" +- Include prepare +- Env OCF_RESKEY_user=nobody +- AgentRun start OCF_ERR_PERM +diff --git a/tools/ocft/mysql-proxy b/tools/ocft/mysql-proxy +deleted file mode 100644 +index e16d52b..0000000 +--- a/tools/ocft/mysql-proxy ++++ /dev/null +@@ -1,83 +0,0 @@ +-# mysql-proxy +-# by r.bhatia@ipax.at +-# +-# test cases (to implement): +-# +-# * /usr/sbin/ocf-tester -n mp -o binary="/usr/sbin/mysql-proxy" -o defaults_file="" -o parameters="--proxy-skip-profiling" \ +-# -o admin_address="127.0.0.1:4041" -o admin_username="root" -o admin_password="la" -o admin_lua_script="/usr/lib/mysql-proxy/lua/admin.lua" \ +-# -o proxy_backend_addresses="192.168.100.200:42006" -o proxy_address="/var/run/mysqld/mysqld.sock" /usr/lib/ocf/resource.d/heartbeat/mysql-proxy +-# +-# * OCF_CHECK_LEVEL 20 check +- +-CONFIG +- Agent mysql-proxy +- AgentRoot /usr/lib/ocf/resource.d/heartbeat/ +- InstallPackage mysql-proxy +- HangTimeout 20 +- +-SETUP-AGENT +- # nothing +- +-CASE-BLOCK crm_setting +- Env OCF_RESKEY_CRM_meta_timeout=15000 +- Env OCF_RESKEY_binary=/tmp/mysql-proxy +- Env OCF_RESKEY_admin_username=root +- Env OCF_RESKEY_admin_password=test123 +- Env OCF_RESKEY_admin_lua_script=/usr/lib/mysql-proxy/lua/admin.lua +- +-CASE-BLOCK default_status +- AgentRun stop +- +-CASE-BLOCK prepare +- Bash [ ! -x /tmp/mysql-proxy ] && ln -s `which mysql-proxy` /tmp/mysql-proxy || true +- Include crm_setting +- +-CASE-BLOCK teardown +- AgentRun stop +- BashAtExit rm -f /tmp/mysql-proxy +- +-CASE "check base env" +- Include prepare +- AgentRun start OCF_SUCCESS +- Include teardown +- +-CASE "check base env: invalid 'OCF_RESKEY_binary'" +- Include prepare +- Env OCF_RESKEY_binary=no_such +- AgentRun start OCF_ERR_INSTALLED +- BashAtExit rm -f /tmp/mysql-proxy +- +-CASE "normal start" +- Include prepare +- AgentRun start OCF_SUCCESS +- Include teardown +- +-CASE "normal stop" +- Include prepare +- AgentRun start +- AgentRun stop OCF_SUCCESS +- Include teardown +- +-CASE "double start" +- Include prepare +- AgentRun start +- AgentRun start OCF_SUCCESS +- Include teardown +- +-CASE "double stop" +- Include prepare +- AgentRun stop OCF_SUCCESS +- +-CASE "running monitor" +- Include prepare +- AgentRun start +- AgentRun monitor OCF_SUCCESS +- Include teardown +- +-CASE "not running monitor" +- Include prepare +- AgentRun monitor OCF_NOT_RUNNING +- +-CASE "unimplemented command" +- Include prepare +- AgentRun no_cmd OCF_ERR_UNIMPLEMENTED +diff --git a/tools/ocft/named b/tools/ocft/named +deleted file mode 100644 +index 90a4351..0000000 +--- a/tools/ocft/named ++++ /dev/null +@@ -1,69 +0,0 @@ +-#named +- +-# To work properly this test requires that standard bind and bin-utils +-# packages installed. +- +-CONFIG +- Agent named +- AgentRoot /usr/lib/ocf/resource.d/heartbeat +- InstallPackage bind +- InstallPackage bind-utils +- +-SETUP-AGENT +- /etc/init.d/named start +- /etc/init.d/named stop +- +-CASE-BLOCK crm_setting +- Env OCF_RESKEY_CRM_meta_timeout=15000 +- +-CASE-BLOCK default_status +- AgentRun stop +- +-CASE-BLOCK prepare +- Include crm_setting +- Include default_status +- +-CASE "check base env" +- Include prepare +- AgentRun start OCF_SUCCESS +- +-CASE "check base env: invalid 'OCF_RESKEY_named'" +- Include prepare +- Env OCF_RESKEY_named=no_such +- AgentRun start OCF_ERR_INSTALLED +- +-CASE "normal start" +- Include prepare +- AgentRun start OCF_SUCCESS +- +-CASE "normal stop" +- Include prepare +- AgentRun start +- AgentRun stop OCF_SUCCESS +- +-CASE "double start" +- Include prepare +- AgentRun start +- AgentRun start OCF_SUCCESS +- +-CASE "double stop" +- Include prepare +- AgentRun stop OCF_SUCCESS +- +-CASE "running monitor" +- Include prepare +- AgentRun start +- AgentRun monitor OCF_SUCCESS +- +-CASE "not running monitor" +- Include prepare +- AgentRun monitor OCF_NOT_RUNNING +- +-CASE "unimplemented command" +- Include prepare +- AgentRun no_cmd OCF_ERR_UNIMPLEMENTED +- +-CASE "non-existent user" +- Include prepare +- Env OCF_RESKEY_named_user=no_user +- AgentRun start OCF_ERR_INSTALLED +diff --git a/tools/ocft/nfsserver b/tools/ocft/nfsserver +deleted file mode 100644 +index cd73164..0000000 +--- a/tools/ocft/nfsserver ++++ /dev/null +@@ -1,75 +0,0 @@ +-# nfsserver +- +-CONFIG +- Agent nfsserver +- AgentRoot /usr/lib/ocf/resource.d/heartbeat +- InstallPackage nfs-kernel-server +- HangTimeout 20 +- +-CASE-BLOCK required_args +- Env OCF_RESKEY_nfs_init_script=/etc/init.d/nfsserver +- Env OCF_RESKEY_nfs_ip=127.0.0.1 +- Env OCF_RESKEY_nfs_shared_infodir=/var/lib/nfs +- Env OCF_RESKEY_nfs_notify_cmd=/usr/sbin/sm-notify +- +-CASE-BLOCK default_status +- AgentRun stop +- +-CASE-BLOCK prepare +- Include required_args +- Include default_status +- +-CASE "check base env" +- Include prepare +- AgentRun start OCF_SUCCESS +- +-CASE "check base env: invalid 'OCF_RESKEY_nfs_init_script'" +- Include prepare +- Env OCF_RESKEY_nfs_init_script=no_such_script +- AgentRun start OCF_ERR_INSTALLED +- +-CASE "check base env: unset 'OCF_RESKEY_nfs_ip'" +- Include prepare +- Unenv OCF_RESKEY_nfs_ip +- AgentRun start OCF_ERR_CONFIGURED +- +-CASE "check base env: unset 'OCF_RESKEY_nfs_shared_infodir'" +- Include prepare +- Unenv OCF_RESKEY_nfs_shared_infodir +- AgentRun start OCF_ERR_CONFIGURED +- +-CASE "check base env: invalid 'OCF_RESKEY_nfs_notify_cmd'" +- Include prepare +- Env OCF_RESKEY_nfs_notify_cmd=no_such_program +- AgentRun start OCF_ERR_INSTALLED +- +-CASE "normal start" +- Include prepare +- AgentRun start OCF_SUCCESS +- +-CASE "normal stop" +- Include prepare +- AgentRun start +- AgentRun stop OCF_SUCCESS +- +-CASE "double start" +- Include prepare +- AgentRun start +- AgentRun start OCF_SUCCESS +- +-CASE "double stop" +- Include prepare +- AgentRun stop OCF_SUCCESS +- +-CASE "monitor with running" +- Include prepare +- AgentRun start +- AgentRun monitor OCF_SUCCESS +- +-CASE "monitor with not running" +- Include prepare +- AgentRun monitor OCF_NOT_RUNNING +- +-CASE "unimplemented command" +- Include prepare +- AgentRun no_cmd OCF_ERR_UNIMPLEMENTED +diff --git a/tools/ocft/oracle b/tools/ocft/oracle +deleted file mode 100644 +index 6f145c7..0000000 +--- a/tools/ocft/oracle ++++ /dev/null +@@ -1,81 +0,0 @@ +-# oracle +-# (based on db2) +-# +-# Created on an SLE11SP2 running oracle 11g +-# database sid is orcl +-# adapt this in set_testenv below +-# TODO: need oracle expert to break it, then test it +-# +- +-CONFIG +- Agent oracle +- AgentRoot /usr/lib/ocf/resource.d/heartbeat +- HangTimeout 40 +- +-SETUP-AGENT +- # nothing +- +-CASE-BLOCK set_testenv +- Env OCFT_sid=orcl +- +-CASE-BLOCK crm_setting +- Env OCF_RESKEY_sid=$OCFT_sid +- Env OCF_RESKEY_CRM_meta_timeout=30000 +- +-CASE-BLOCK default_status +- AgentRun stop +- +-CASE-BLOCK prepare +- Include set_testenv +- Include crm_setting +- Include default_status +- +-CASE "check base env" +- Include prepare +- AgentRun start OCF_SUCCESS +- +-CASE "check base env: no 'OCF_RESKEY_sid'" +- Include prepare +- Env OCF_RESKEY_sid= +- AgentRun start OCF_ERR_CONFIGURED +- +-CASE "check base env: invalid 'OCF_RESKEY_home'" +- Include prepare +- Env OCF_RESKEY_home=/no_such +- AgentRun start OCF_ERR_INSTALLED +- +-CASE "unimplemented command" +- Include prepare +- AgentRun no_cmd OCF_ERR_UNIMPLEMENTED +- +-CASE "normal start" +- Include prepare +- AgentRun start OCF_SUCCESS +- +-CASE "normal stop" +- Include prepare +- AgentRun start +- AgentRun stop OCF_SUCCESS +- +-CASE "double start" +- Include prepare +- AgentRun start +- AgentRun start OCF_SUCCESS +- +-CASE "double stop" +- Include prepare +- AgentRun stop OCF_SUCCESS +- +-CASE "started: monitor" +- Include prepare +- AgentRun start +- AgentRun monitor OCF_SUCCESS +- +-CASE "not started: monitor" +- Include prepare +- AgentRun monitor OCF_NOT_RUNNING +- +-CASE "try different ipcrm method" +- Include prepare +- Env OCF_RESKEY_ipcrm=none +- AgentRun start OCF_SUCCESS +diff --git a/tools/ocft/pgsql b/tools/ocft/pgsql +deleted file mode 100644 +index 9944b09..0000000 +--- a/tools/ocft/pgsql ++++ /dev/null +@@ -1,71 +0,0 @@ +-# pgsql +- +-CONFIG +- Agent pgsql +- AgentRoot /usr/lib/ocf/resource.d/heartbeat +- InstallPackage postgresql-server +- HangTimeout 20 +- +-SETUP-AGENT +- /etc/init.d/postgresql start +- /etc/init.d/postgresql stop +- +-CASE-BLOCK crm_setting +- Env OCF_RESKEY_CRM_meta_timeout=15000 +- +-CASE-BLOCK default_status +- AgentRun stop +- +-CASE-BLOCK prepare +- Include crm_setting +- Include default_status +- +-CASE "check base env" +- Include prepare +- AgentRun start OCF_SUCCESS +- +-CASE "check base env: invalid 'OCF_RESKEY_pgctl'" +- Include prepare +- Env OCF_RESKEY_pgctl=no_such +- AgentRun start OCF_ERR_INSTALLED +- +-CASE "normal start" +- Include prepare +- AgentRun start OCF_SUCCESS +- +-CASE "normal stop" +- Include prepare +- AgentRun start +- AgentRun stop OCF_SUCCESS +- +-CASE "double start" +- Include prepare +- AgentRun start +- AgentRun start OCF_SUCCESS +- +-CASE "double stop" +- Include prepare +- AgentRun stop OCF_SUCCESS +- +-CASE "running monitor" +- Include prepare +- AgentRun start +- AgentRun monitor OCF_SUCCESS +- +-CASE "not running monitor" +- Include prepare +- AgentRun monitor OCF_NOT_RUNNING +- +-CASE "unimplemented command" +- Include prepare +- AgentRun no_cmd OCF_ERR_UNIMPLEMENTED +- +-CASE "non-existent user" +- Include prepare +- Env OCF_RESKEY_pgdba=no_user +- AgentRun start OCF_ERR_INSTALLED +- +-CASE "invalid user" +- Include prepare +- Env OCF_RESKEY_pgdba=nobody +- AgentRun start OCF_ERR_PERM +diff --git a/tools/ocft/portblock b/tools/ocft/portblock +deleted file mode 100644 +index 3475c63..0000000 +--- a/tools/ocft/portblock ++++ /dev/null +@@ -1,69 +0,0 @@ +-# portblock +- +-CONFIG +- Agent portblock +- AgentRoot /usr/lib/ocf/resource.d/heartbeat +- InstallPackage iptables +- HangTimeout 15 +- +-CASE-BLOCK required_args +- Env OCF_RESKEY_protocol=tcp +- Env OCF_RESKEY_portno=80 +- Env OCF_RESKEY_action=block +- +-CASE-BLOCK default_status +- AgentRun stop +- +-CASE-BLOCK prepare +- Include required_args +- Include default_status +- +-CASE "check base env" +- Include prepare +- AgentRun start OCF_SUCCESS +- +-CASE "check base env: unset 'OCF_RESKEY_protocol'" +- Include prepare +- Unenv OCF_RESKEY_protocol +- AgentRun start OCF_ERR_CONFIGURED +- +-CASE "check base env: unset 'OCF_RESKEY_portno'" +- Include prepare +- Unenv OCF_RESKEY_portno +- AgentRun start OCF_ERR_CONFIGURED +- +-CASE "check base env: unset 'OCF_RESKEY_action'" +- Include prepare +- Unenv OCF_RESKEY_action +- AgentRun start OCF_ERR_CONFIGURED +- +-CASE "normal start" +- Include prepare +- AgentRun start OCF_SUCCESS +- +-CASE "normal stop" +- Include prepare +- AgentRun start +- AgentRun stop OCF_SUCCESS +- +-CASE "double start" +- Include prepare +- AgentRun start +- AgentRun start OCF_SUCCESS +- +-CASE "double stop" +- Include prepare +- AgentRun stop OCF_SUCCESS +- +-CASE "monitor with running" +- Include prepare +- AgentRun start +- AgentRun monitor OCF_SUCCESS +- +-CASE "monitor with not running" +- Include prepare +- AgentRun monitor OCF_NOT_RUNNING +- +-CASE "unimplemented command" +- Include prepare +- AgentRun no_cmd OCF_ERR_UNIMPLEMENTED +diff --git a/tools/ocft/postfix b/tools/ocft/postfix +deleted file mode 100644 +index f17e968..0000000 +--- a/tools/ocft/postfix ++++ /dev/null +@@ -1,102 +0,0 @@ +-# postfix +-# by r.bhatia@ipax.at +-# +-# test cases (to implement): +-# +-# * /usr/sbin/ocf-tester -n post1 /usr/lib/ocf/resource.d/heartbeat/postfix; echo $? -> DONE +-# * /usr/sbin/ocf-tester -n post2 -o binary="/usr/sbin/postfix" \ +-# -o config_dir="" /usr/lib/ocf/resource.d/heartbeat/postfix; echo $? -> DONE +-# * /usr/sbin/ocf-tester -n post3 -o binary="/usr/sbin/postfix" \ +-# -o config_dir="/etc/postfix" /usr/lib/ocf/resource.d/heartbeat/postfix; echo $? -> DONE +-# * /usr/sbin/ocf-tester -n post4 -o binary="/usr/sbin/postfix" \ +-# -o config_dir="/root/postfix/" /usr/lib/ocf/resource.d/heartbeat/postfix; echo $? +- +-CONFIG +- Agent postfix +- AgentRoot /usr/lib/ocf/resource.d/heartbeat +- InstallPackage postfix +- HangTimeout 20 +- +-SETUP-AGENT +- # nothing +- +-CASE-BLOCK crm_setting +- Env OCF_RESKEY_CRM_meta_timeout=15000 +- Env OCF_RESKEY_CRM_meta_interval=10000 +- +-CASE-BLOCK default_status +- AgentRun stop +- +-CASE-BLOCK prepare +- Include crm_setting +- Include default_status +- +-CASE "check base env" +- Include prepare +- AgentRun start OCF_SUCCESS +- +-CASE "check base env: invalid 'OCF_RESKEY_binary'" +- Include prepare +- Env OCF_RESKEY_binary=no_such +- AgentRun start OCF_ERR_INSTALLED +- +-CASE "check base env: invalid 'OCF_RESKEY_config_dir'" +- Include prepare +- Env OCF_RESKEY_config_dir=no_such +- AgentRun start OCF_ERR_INSTALLED +- +-CASE "check base env: 'OCF_RESKEY_binary'" +- Include prepare +- Env OCF_RESKEY_binary=/usr/sbin/postfix +- AgentRun start +- AgentRun monitor OCF_SUCCESS +- +-CASE "check base env: 'OCF_RESKEY_config_dir' without trailing slash" +- Include prepare +- Env OCF_RESKEY_config_dir="/etc/postfix" +- AgentRun start +- AgentRun monitor OCF_SUCCESS +- +-CASE "check base env: 'OCF_RESKEY_config_dir' with trailing slash" +- Include prepare +- Env OCF_RESKEY_config_dir="/etc/postfix/" +- AgentRun start +- AgentRun monitor OCF_SUCCESS +- +-CASE "normal start" +- Include prepare +- AgentRun start OCF_SUCCESS +- +-CASE "normal stop" +- Include prepare +- AgentRun start +- AgentRun stop OCF_SUCCESS +- +-CASE "double start" +- Include prepare +- AgentRun start +- AgentRun start OCF_SUCCESS +- +-CASE "double stop" +- Include prepare +- AgentRun stop OCF_SUCCESS +- +-CASE "monitor a running resource" +- Include prepare +- AgentRun start +- AgentRun monitor OCF_SUCCESS +- +-CASE "(initial) probe a stopped resource" +- Include prepare +- Env OCF_RESKEY_CRM_meta_interval=0 +- AgentRun monitor OCF_NOT_RUNNING +- +-CASE "(re-)probe a running resource" +- Include prepare +- Env OCF_RESKEY_CRM_meta_interval=0 +- AgentRun start +- AgentRun monitor OCF_SUCCESS +- +-CASE "unimplemented command" +- Include prepare +- AgentRun no_cmd OCF_ERR_UNIMPLEMENTED +-- +1.7.1 + diff --git a/SOURCES/bz917681-slapd-heartbeat-updates.patch b/SOURCES/bz917681-slapd-heartbeat-updates.patch new file mode 100644 index 00000000..a0a2bb34 --- /dev/null +++ b/SOURCES/bz917681-slapd-heartbeat-updates.patch @@ -0,0 +1,23 @@ +diff --git a/heartbeat/slapd b/heartbeat/slapd +index 6661984..ffb40e8 100755 +--- a/heartbeat/slapd ++++ b/heartbeat/slapd +@@ -526,10 +526,14 @@ parameters=$OCF_RESKEY_parameters + pid_file=$OCF_RESKEY_pidfile + + if [ -z "$config" ]; then +- if [ -e "/etc/ldap/slapd.d" ]; then +- config="/etc/ldap/slapd.d" +- else +- config="/etc/ldap/slapd.conf" ++ config_dirname="/etc/ldap" ++ if [ -e "/etc/openldap" ]; then ++ config_dirname="/etc/openldap" ++ fi ++ ++ config="$config_dirname/slapd.conf" ++ if [ -e "$config_dirname/slapd.d" ]; then ++ config="$config_dirname/slapd.d" + fi + fi + diff --git a/SOURCES/bz917681-tomcat-heartbeat-updates.patch b/SOURCES/bz917681-tomcat-heartbeat-updates.patch new file mode 100644 index 00000000..72135682 --- /dev/null +++ b/SOURCES/bz917681-tomcat-heartbeat-updates.patch @@ -0,0 +1,470 @@ +diff --git a/heartbeat/tomcat b/heartbeat/tomcat +index 95cc49e..4fafdaa 100755 +--- a/heartbeat/tomcat ++++ b/heartbeat/tomcat +@@ -33,8 +33,8 @@ + # OCF_RESKEY_java_opts - Options to pass to Java JVM for start and stop. Default is none + # OCF_RESKEY_catalina_home - Home directory of Tomcat. Default is none + # OCF_RESKEY_catalina_base - Base directory of Tomcat. Default is OCF_RESKEY_catalina_home +-# OCF_RESKEY_catalina_out - Log file name of Tomcat. Default is OCF_RESKEY_catalina_home/logs/catalina.out +-# OCF_RESKEY_catalina_pid - A PID file name of Tomcat. Default is OCF_RESKEY_catalina_home/logs/catalina.pid ++# OCF_RESKEY_catalina_out - Log file name of Tomcat. Default is OCF_RESKEY_catalina_base/logs/catalina.out ++# OCF_RESKEY_catalina_pid - A PID file name of Tomcat. Default is OCF_RESKEY_catalina_base/logs/catalina.pid + # OCF_RESKEY_tomcat_start_opts - Start options of Tomcat. Default is none. + # OCF_RESKEY_catalina_opts - CATALINA_OPTS environment variable. Default is none. + # OCF_RESKEY_catalina_tmpdir - CATALINA_TMPDIR environment variable. Default is none. +@@ -86,11 +86,14 @@ isalive_tomcat() + # As the server stops, the PID file disappears. To avoid race conditions, + # we will have remembered the PID of a running instance on script entry. + local pid=$rememberedPID +- # If there is a PID file, use that ++ # If there is a PID file, attempt to use that + if [ -f $CATALINA_PID ]; then ++ local tmp + ocf_log debug "Reading pid from $CATALINA_PID" +- # race conditions on PID file being removed by stopping tomcat... +- pid=`head -n 1 $CATALINA_PID` ++ tmp=`head -n 1 $CATALINA_PID` ++ if [ $? -eq 0 ]; then ++ pid=$tmp ++ fi + fi + if [ -n "$pid" ] && [ "$pid" -gt 0 ]; then + # Retry message for restraint +@@ -103,6 +106,22 @@ isalive_tomcat() + } + + ############################################################################ ++# Check rotatelogs process and restart if it is stopped ++monitor_rotatelogs() ++{ ++ pgrep -f "$ROTATELOGS.*$CATALINA_BASE/logs/catalina_%F.log" > /dev/null 2>&1 ++ if [ $? -ne 0 ]; then ++ ocf_log warn "A rotatelogs command for $CATALINA_BASE/logs/catalina_%F.log is not running. Restarting it." ++ start_rotatelogs ++ if [ $? -eq 0 ]; then ++ ocf_log info "Restart rotatelogs process succeeded." ++ else ++ ocf_log warn "Restart rotatelogs process failed." ++ fi ++ fi ++} ++ ++############################################################################ + # Check tomcat process and service availability + monitor_tomcat() + { +@@ -110,32 +129,51 @@ monitor_tomcat() + return $OCF_NOT_RUNNING + isrunning_tomcat || + return $OCF_ERR_GENERIC ++ if ocf_is_true ${CATALINA_ROTATE_LOG}; then ++ # Monitor rotatelogs process and restart it if it is stopped. ++ # And never consider rotatelogs process failure to be a monitor failure ++ # as long as Tomcat process works fine. ++ monitor_rotatelogs ++ fi + return $OCF_SUCCESS + } + + ############################################################################ ++# Startup rotatelogs process ++start_rotatelogs() ++{ ++ # -s is required because tomcat5.5's login shell is /bin/false ++ su - -s /bin/sh $RESOURCE_TOMCAT_USER \ ++ -c "$ROTATELOGS -l \"$CATALINA_BASE/logs/catalina_%F.log\" $CATALINA_ROTATETIME" \ ++ < "$CATALINA_OUT" > /dev/null 2>&1 & ++} ++ ++############################################################################ + # Execute catalina.out log rotation + rotate_catalina_out() + { +- # Look for rotatelogs/rotatelogs2 +- if [ -x /usr/sbin/rotatelogs ]; then +- ROTATELOGS=/usr/sbin/rotatelogs +- elif [ -x /usr/sbin/rotatelogs2 ]; then +- ROTATELOGS=/usr/sbin/rotatelogs2 +- else +- ocf_log warn "rotatelogs command not found." +- return 1 ++ # Check catalina_%F.log is writable or not. ++ CURRENT_ROTATELOG_SUFFIX=`date +"%F"` ++ su - -s /bin/sh $RESOURCE_TOMCAT_USER \ ++ -c "touch \"$CATALINA_BASE/logs/catalina_$CURRENT_ROTATELOG_SUFFIX.log\"" > /dev/null 2>&1 ++ if [ $? -ne 0 ]; then ++ ocf_log err "$CATALINA_BASE/logs/catalina_$CURRENT_ROTATELOG_SUFFIX.log is not writable." ++ return $OCF_ERR_GENERIC + fi + + # Clean up and set permissions on required files +- rm -rf "$CATALINA_HOME"/temp/* "$CATALINA_OUT" ++ rm -rf "$CATALINA_BASE"/temp/* ++ if [ -p "$CATALINA_OUT" ]; then ++ rm -f "$CATALINA_OUT" ++ elif [ -e "$CATALINA_OUT" ]; then ++ DATE=`date +"%F-%H%M%S"` ++ ocf_log warn "$CATALINA_OUT already exists. It is saved as $CATALINA_OUT-$DATE" ++ mv "$CATALINA_OUT" "$CATALINA_OUT-$DATE" ++ fi + mkfifo -m700 "$CATALINA_OUT" + chown --dereference "$RESOURCE_TOMCAT_USER" "$CATALINA_OUT" || true + +- # -s is required because tomcat5.5's login shell is /bin/false +- su - -s /bin/sh $RESOURCE_TOMCAT_USER \ +- -c "$ROTATELOGS -l \"$CATALINA_HOME/logs/catalina_%F.log\" $CATALINA_ROTATETIME" \ +- < "$CATALINA_OUT" > /dev/null 2>&1 & ++ start_rotatelogs + } + + ############################################################################ +@@ -154,16 +192,25 @@ cat<<-END_TOMCAT_COMMAND + export JAVA_ENDORSED_DIRS="${JAVA_ENDORSED_DIRS}" + export LOGGING_CONFIG="${LOGGING_CONFIG}" + export LOGGING_MANAGER="${LOGGING_MANAGER}" +- $CATALINA_HOME/bin/catalina.sh $@ ++ export TOMCAT_CFG=${TOMCAT_CFG} ++ $TOMCAT_START_SCRIPT $@ + END_TOMCAT_COMMAND + } + attemptTomcatCommand() + { +- if [ "$RESOURCE_TOMCAT_USER" = RUNASIS ]; then +- "$CATALINA_HOME/bin/catalina.sh" $@ >> "$TOMCAT_CONSOLE" 2>&1 ++ if [ -n "$REDIRECT_DEFAULT_CONFIG" ]; then ++ export TOMCAT_CFG=$(mktemp ${HA_RSCTMP}/tomcat-tmp-XXXXX.cfg) ++ fi ++ ++ if [ "$RESOURCE_TOMCAT_USER" = root ]; then ++ "$TOMCAT_START_SCRIPT" $@ >> "$TOMCAT_CONSOLE" 2>&1 + else + tomcatCommand $@ | su - -s /bin/sh "$RESOURCE_TOMCAT_USER" >> "$TOMCAT_CONSOLE" 2>&1 + fi ++ ++ if [ -n "$REDIRECT_DEFAULT_CONFIG" ]; then ++ rm -f "$TOMCAT_CFG" ++ fi + } + + ############################################################################ +@@ -175,7 +222,7 @@ start_tomcat() + validate_all_tomcat || exit $? + + monitor_tomcat +- if [ $? = $OCF_SUCCESS ]; then ++ if [ $? -eq $OCF_SUCCESS ]; then + return $OCF_SUCCESS + fi + +@@ -183,12 +230,13 @@ start_tomcat() + rm -f $CATALINA_PID + + #ocf_log debug "catalina.out rotation FLG = ${CATALINA_ROTATE_LOG}" +- if [ ${CATALINA_ROTATE_LOG} = "YES" ]; then ++ if ocf_is_true ${CATALINA_ROTATE_LOG}; then + rotate_catalina_out +- if [ $? = 0 ]; then ++ if [ $? -eq 0 ]; then + ocf_log debug "Rotate catalina.out succeeded." + else +- ocf_log warn "Rotate catalina.out failed. Starting tomcat without catalina.out rotation." ++ ocf_log err "Rotate catalina.out failed. Avoid starting tomcat without catalina.out rotation." ++ return $OCF_ERR_GENERIC + fi + fi + +@@ -199,7 +247,7 @@ start_tomcat() + + while true; do + monitor_tomcat +- if [ $? = $OCF_SUCCESS ]; then ++ if [ $? -eq $OCF_SUCCESS ]; then + break + fi + ocf_log debug "start_tomcat[$TOMCAT_NAME]: retry monitor_tomcat" +@@ -213,7 +261,14 @@ start_tomcat() + # Stop Tomcat + stop_tomcat() + { +- RA_TIMEOUT=$((OCF_RESKEY_CRM_meta_timeout/1000)) ++ local stop_time ++ local RA_TIMEOUT=20 ++ local TOMCAT_STOP_OPTS="" ++ ++ if [ -n $OCF_RESKEY_CRM_meta_timeout ]; then ++ RA_TIMEOUT=$((OCF_RESKEY_CRM_meta_timeout/1000)) ++ fi ++ + STOP_TIMEOUT=$((RA_TIMEOUT-5)) + if [ -n "$MAX_STOP_TIME" ]; then + if [ $MAX_STOP_TIME -gt $RA_TIMEOUT ]; then +@@ -232,17 +287,23 @@ stop_tomcat() + + echo "`date "+%Y/%m/%d %T"`: stop ###########################" >> "$TOMCAT_CONSOLE" + +- attemptTomcatCommand stop $STOP_TIMEOUT -force ++ if [ "$TOMCAT_START_SCRIPT" = "$CATALINA_HOME/bin/catalina.sh" ]; then ++ TOMCAT_STOP_OPTS="$STOP_TIMEOUT --force" ++ fi ++ stop_time=$(date +%s) ++ attemptTomcatCommand stop $TOMCAT_STOP_OPTS + + lapse_sec=0 + while isalive_tomcat; do + sleep 1 +- lapse_sec=`expr $lapse_sec + 1` +- ocf_log debug "stop_tomcat[$TOMCAT_NAME]: stop failed, killing with SIGKILL ($lapse_sec)" +- kill -KILL $rememberedPID ++ lapse_sec=`expr $(date +%s) - $stop_time` ++ if [ $lapse_sec -ge $STOP_TIMEOUT ]; then ++ ocf_log debug "stop_tomcat[$TOMCAT_NAME]: stop failed, killing with SIGKILL ($lapse_sec)" ++ kill -s KILL $rememberedPID > /dev/null 2>&1 ++ fi + done + +- if [ ${CATALINA_ROTATE_LOG} = "YES" ]; then ++ if ocf_is_true ${CATALINA_ROTATE_LOG}; then + rm -f "$CATALINA_PID" "${CATALINA_OUT}" + else + rm -f "$CATALINA_PID" +@@ -305,7 +366,7 @@ and killing Tomcat. DEPRECATED. Does not retry. + The user who starts Tomcat. + + The user who starts Tomcat +- ++ + + + +@@ -345,7 +406,7 @@ Java JVM options used on start and stop. + + + +- ++ + + Home directory of Tomcat. + +@@ -365,7 +426,7 @@ Instance directory of Tomcat + + Log file name of Tomcat + +-Log file name of Tomcat, defaults to catalina_home/logs/catalina.out ++Log file name of Tomcat, defaults to catalina_base/logs/catalina.out + + + +@@ -377,6 +438,14 @@ A PID file name for Tomcat. + + + ++ ++ ++Absolute path to the custom tomcat start script to use. ++ ++Tomcat start script location ++ ++ ++ + + + Tomcat start options. +@@ -406,7 +475,7 @@ Temporary directory of Tomcat + Rotate catalina.out flag. + + Rotate catalina.out flag +- ++ + + + +@@ -458,46 +527,42 @@ END + + validate_all_tomcat() + { ++ local port ++ local rc=$OCF_SUCCESS + ocf_log info "validate_all_tomcat[$TOMCAT_NAME]" + +- misconfigured=0 +- notinstalled=0 +- wrongpermissions=0 +- + check_binary $WGET + ++ if [ -z "${TOMCAT_START_SCRIPT}" ]; then ++ ocf_log err "No default tomcat start script detected. Please specify start script location using the 'tomcat_start_script' option" ++ rc=$OCF_ERR_CONFIGURED ++ fi ++ + if [ -n "$MAX_STOP_TIME" ] && [ "$MAX_STOP_TIME" -lt 0 ]; then + ocf_log err "max_stop_time must be set to a value greater than 0." +- misconfigured=1 ++ rc=$OCF_ERR_CONFIGURED + fi + +- if [[ "$RESOURCE_STATUSURL" =~ :[0-9][0-9]* ]]; then ++ if echo "$RESOURCE_STATUSURL" | grep -q ":[0-9][0-9]*" ; then + port=${RESOURCE_STATUSURL##*:} + port=${port%%/*} + ocf_log debug "Tomcat port is $port" +- ocf_log debug "grep port=\"$port\" $CATALINA_HOME/conf/server.xml" +- if [ "$port" -gt 0 ]; then +- grep "port=\"$port\"" $CATALINA_HOME/conf/server.xml > /dev/null 2>&1 +- if [ $? -ne 0 ]; then +- ocf_log err "Your configured status URL specifies a port ($port), but the server does not have a connector listening to that port in $CATALINA_HOME/conf/server.xml" +- notinstalled=1 +- fi ++ ocf_log debug "grep port=\"$port\" $CATALINA_BASE/conf/server.xml" ++ grep "port=\"$port\"" $CATALINA_BASE/conf/server.xml > /dev/null 2>&1 ++ if [ $? -ne 0 ]; then ++ ocf_log err "Your configured status URL specifies a port ($port), but the server does not have a connector listening to that port in $CATALINA_BASE/conf/server.xml" ++ rc=$OCF_ERR_INSTALLED + fi + fi + +- if [ $misconfigured -gt 0 ]; then +- return $OCF_ERR_CONFIGURED +- fi +- +- if [ $notinstalled -gt 0 ]; then +- return $OCF_ERR_INSTALLED +- fi +- +- if [ $wrongpermissions -gt 0 ]; then +- return $OCF_ERR_PERM ++ if ocf_is_true ${CATALINA_ROTATE_LOG}; then ++ if [ ! -x "$ROTATELOGS" ]; then ++ ocf_log err "rotatelogs command does not exist." ++ rc=$OCF_ERR_INSTALLED ++ fi + fi + +- return $OCF_SUCCESS ++ return $rc + } + + # As we stop tomcat, it removes it's own pid file...we still want to know what it was +@@ -515,18 +580,28 @@ memorize_pid() + COMMAND=$1 + TOMCAT_NAME="${OCF_RESKEY_tomcat_name-tomcat}" + TOMCAT_CONSOLE="${OCF_RESKEY_script_log-/var/log/$TOMCAT_NAME.log}" +-RESOURCE_TOMCAT_USER="${OCF_RESKEY_tomcat_user-RUNASIS}" ++RESOURCE_TOMCAT_USER="${OCF_RESKEY_tomcat_user-root}" + RESOURCE_STATUSURL="${OCF_RESKEY_statusurl-http://127.0.0.1:8080}" + + JAVA_HOME="${OCF_RESKEY_java_home}" + JAVA_OPTS="${OCF_RESKEY_java_opts}" + CATALINA_HOME="${OCF_RESKEY_catalina_home}" + CATALINA_BASE="${OCF_RESKEY_catalina_base-${OCF_RESKEY_catalina_home}}" +-CATALINA_OUT="${OCF_RESKEY_catalina_out-$CATALINA_HOME/logs/catalina.out}" +-CATALINA_PID="${OCF_RESKEY_catalina_pid-$CATALINA_HOME/logs/catalina.pid}" ++CATALINA_OUT="${OCF_RESKEY_catalina_out-$CATALINA_BASE/logs/catalina.out}" ++ ++CATALINA_PID=$OCF_RESKEY_catalina_pid ++if [ -z "$CATALINA_PID" ]; then ++ mkdir -p "${HA_RSCTMP}/${TOMCAT_NAME}_tomcatstate/" ++ if [ "${RESOURCE_TOMCAT_USER}" != "root" ]; then ++ chown ${RESOURCE_TOMCAT_USER} "${HA_RSCTMP}/${TOMCAT_NAME}_tomcatstate/" ++ fi ++ CATALINA_PID="${HA_RSCTMP}/${TOMCAT_NAME}_tomcatstate/catalina.pid" ++fi ++ + MAX_STOP_TIME="${OCF_RESKEY_max_stop_time}" + + TOMCAT_START_OPTS="${OCF_RESKEY_tomcat_start_opts}" ++TOMCAT_START_SCRIPT="${OCF_RESKEY_tomcat_start_script}" + CATALINA_OPTS="-Dname=$TOMCAT_NAME ${OCF_RESKEY_catalina_opts}" + CATALINA_TMPDIR="${OCF_RESKEY_catalina_tmpdir}" + CATALINA_ROTATE_LOG="${OCF_RESKEY_catalina_rotate_log-NO}" +@@ -545,6 +620,15 @@ case "$COMMAND" in + help|usage) usage; exit $OCF_SUCCESS;; + esac + ++if [ -z "${TOMCAT_START_SCRIPT}" ]; then ++ if [ -e "$CATALINA_HOME/bin/catalina.sh" ]; then ++ TOMCAT_START_SCRIPT="$CATALINA_HOME/bin/catalina.sh" ++ elif [ -e "/usr/sbin/tomcat" ]; then ++ REDIRECT_DEFAULT_CONFIG=1 ++ TOMCAT_START_SCRIPT="/usr/sbin/tomcat" ++ fi ++fi ++ + if [ ! -d "$JAVA_HOME" -o ! -d "$CATALINA_HOME" -o ! -d "$CATALINA_BASE" ]; then + case $COMMAND in + stop) exit $OCF_SUCCESS;; +@@ -569,6 +653,16 @@ if [ ! -x "$JAVA" ]; then + exit $OCF_ERR_INSTALLED + fi + ++ROTATELOGS="" ++if ocf_is_true ${CATALINA_ROTATE_LOG}; then ++ # Look for rotatelogs/rotatelogs2 ++ if [ -x /usr/sbin/rotatelogs ]; then ++ ROTATELOGS=/usr/sbin/rotatelogs ++ elif [ -x /usr/sbin/rotatelogs2 ]; then ++ ROTATELOGS=/usr/sbin/rotatelogs2 ++ fi ++fi ++ + # + # ------------------ + # the main script +diff --git a/tools/ocft/fedora/tomcat b/tools/ocft/fedora/tomcat +index 7b1283e..4226329 100644 +--- a/tools/ocft/fedora/tomcat ++++ b/tools/ocft/fedora/tomcat +@@ -13,11 +13,13 @@ CONFIG + VARIABLE + # Adjust accrding to your configuration + catalina_home=/usr/share/tomcat +- java_home=/usr/lib/jvm/jre-openjdk ++ java_home=/usr/lib/jvm/jre ++ tomcat_user=tomcat + + CASE-BLOCK required_args_tomcat + Env OCF_RESKEY_catalina_home=${catalina_home} + Env OCF_RESKEY_java_home=${java_home} ++ Env OCF_RESKEY_tomcat_user=${tomcat_user} + + CASE-BLOCK args_clear + Unenv OCF_RESKEY_catalina_home +@@ -33,22 +35,22 @@ CASE-BLOCK prepare_tomcat + + # Test CASE + # +-#CASE "normal start tomcat require_args (user:user)" +-# Include prepare_tomcat +-# AgentRun start OCF_SUCCESS +-# AgentRun monitor OCF_SUCCESS +-# AgentRun stop OCF_SUCCESS +-# AgentRun monitor OCF_NOT_RUNNING +-# Include args_clear ++CASE "normal start tomcat require_args (user:user)" ++ Include prepare_tomcat ++ AgentRun start OCF_SUCCESS ++ AgentRun monitor OCF_SUCCESS ++ AgentRun stop OCF_SUCCESS ++ AgentRun monitor OCF_NOT_RUNNING ++ Include args_clear + +-#CASE "normal start tomcat require_args (user:root)" +-# Include prepare_tomcat +-# Unenv OCF_RESKEY_tomcat_user +-# AgentRun start OCF_SUCCESS +-# AgentRun monitor OCF_SUCCESS +-# AgentRun stop OCF_SUCCESS +-# AgentRun monitor OCF_NOT_RUNNING +-# Include args_clear ++CASE "normal start tomcat require_args (user:root)" ++ Include prepare_tomcat ++ Unenv OCF_RESKEY_tomcat_user ++ AgentRun start OCF_SUCCESS ++ AgentRun monitor OCF_SUCCESS ++ AgentRun stop OCF_SUCCESS ++ AgentRun monitor OCF_NOT_RUNNING ++ Include args_clear + + CASE "error start tomcat no catalina_home" + Include prepare_tomcat diff --git a/SOURCES/bz917681_nodename_fixes.patch b/SOURCES/bz917681_nodename_fixes.patch new file mode 100644 index 00000000..52d53f9a --- /dev/null +++ b/SOURCES/bz917681_nodename_fixes.patch @@ -0,0 +1,116 @@ +diff --git a/heartbeat/SAPInstance b/heartbeat/SAPInstance +index 510de7b..da394f5 100755 +--- a/heartbeat/SAPInstance ++++ b/heartbeat/SAPInstance +@@ -856,7 +856,7 @@ sapinstance_notify() { + # that is, when a slave resource was startet after the promote event of a already running master (e.g. node of slave was down) + # We also have to make sure to overrule the globaly set resource_stickiness or any fail-count factors => INFINITY + local n_uname="$OCF_RESKEY_CRM_meta_notify_demote_uname" +- if [ ${n_uname} != ${HOSTNAME} ]; then ++ if [ ${n_uname} != ${NODENAME} ]; then + ${HA_SBIN_DIR}/crm_master -v INFINITY -l reboot + fi + fi +@@ -879,6 +879,7 @@ SAPCONTROL="" + DIR_PROFILE="" + SAPSTARTPROFILE="" + CLONE=0 ++NODENAME=$(ocf_local_nodename) + + + if +diff --git a/heartbeat/mysql b/heartbeat/mysql +index c1c5573..f7eb9f2 100755 +--- a/heartbeat/mysql ++++ b/heartbeat/mysql +@@ -137,8 +137,8 @@ MYSQL_OPTIONS_TEST="$MYSQL_OPTIONS_LOCAL --user=$OCF_RESKEY_test_user --password + MYSQL_TOO_MANY_CONN_ERR=1040 + + CRM_MASTER="${HA_SBIN_DIR}/crm_master -l reboot " +-HOSTNAME=`uname -n` +-CRM_ATTR="${HA_SBIN_DIR}/crm_attribute -N $HOSTNAME " ++NODENAME=$(ocf_local_nodename) ++CRM_ATTR="${HA_SBIN_DIR}/crm_attribute -N $NODENAME " + INSTANCE_ATTR_NAME=`echo ${OCF_RESOURCE_INSTANCE}| awk -F : '{print $1}'` + CRM_ATTR_REPL_INFO="${HA_SBIN_DIR}/crm_attribute --type crm_config --name ${INSTANCE_ATTR_NAME}_REPL_INFO -s mysql_replication" + +@@ -998,7 +998,7 @@ mysql_start() { + # node that is just joining the cluster, and the CRM may have + # promoted a master before. + master_host=`echo $OCF_RESKEY_CRM_meta_notify_master_uname|tr -d " "` +- if [ "$master_host" -a "$master_host" != ${HOSTNAME} ]; then ++ if [ "$master_host" -a "$master_host" != ${NODENAME} ]; then + ocf_log info "Changing MySQL configuration to replicate from $master_host." + set_master + start_slave +@@ -1147,7 +1147,7 @@ mysql_notify() { + # time to check whether our replication slave is working + # correctly. + master_host=`echo $OCF_RESKEY_CRM_meta_notify_promote_uname|tr -d " "` +- if [ "$master_host" = ${HOSTNAME} ]; then ++ if [ "$master_host" = ${NODENAME} ]; then + ocf_log info "This will be the new master, ignoring post-promote notification." + else + ocf_log info "Resetting replication" +@@ -1172,7 +1172,7 @@ mysql_notify() { + ;; + 'pre-demote') + demote_host=`echo $OCF_RESKEY_CRM_meta_notify_demote_uname|tr -d " "` +- if [ $demote_host = ${HOSTNAME} ]; then ++ if [ $demote_host = ${NODENAME} ]; then + ocf_log info "post-demote notification for $demote_host" + set_read_only on + if [ $? -ne 0 ]; then +@@ -1199,7 +1199,7 @@ mysql_notify() { + ;; + 'post-demote') + demote_host=`echo $OCF_RESKEY_CRM_meta_notify_demote_uname|tr -d " "` +- if [ $demote_host = ${HOSTNAME} ]; then ++ if [ $demote_host = ${NODENAME} ]; then + ocf_log info "Ignoring post-demote notification for my own demotion." + return $OCF_SUCCESS + fi +diff --git a/heartbeat/ocf-shellfuncs.in b/heartbeat/ocf-shellfuncs.in +index 35b0a5a..1406c80 100644 +--- a/heartbeat/ocf-shellfuncs.in ++++ b/heartbeat/ocf-shellfuncs.in +@@ -513,6 +513,25 @@ ocf_version_cmp() { + fi + } + ++ocf_local_nodename() { ++ # use crm_node -n for pacemaker > 1.1.8 ++ which pacemakerd > /dev/null 2>&1 ++ if [ $? -eq 0 ]; then ++ local version=$(pacemakerd -$ | grep "Pacemaker .*" | awk '{ print $2 }') ++ ocf_version_cmp "$version" "1.1.8" ++ if [ $? -eq 2 ]; then ++ which crm_node > /dev/null 2>&1 ++ if [ $? -eq 0 ]; then ++ crm_node -n ++ return ++ fi ++ fi ++ fi ++ ++ # otherwise use uname -n ++ uname -n ++} ++ + # usage: dirname DIR + dirname() + { +diff --git a/heartbeat/pgsql b/heartbeat/pgsql +index 14fdfa6..b6b54b0 100755 +--- a/heartbeat/pgsql ++++ b/heartbeat/pgsql +@@ -1734,7 +1734,7 @@ BACKUPLABEL=${OCF_RESKEY_pgdata}/backup_label + RESOURCE_NAME=`echo $OCF_RESOURCE_INSTANCE | cut -d ":" -f 1` + PGSQL_WAL_RECEIVER_STATUS_ATTR="${RESOURCE_NAME}-receiver-status" + RECOVERY_CONF=${OCF_RESKEY_pgdata}/recovery.conf +-NODENAME=`uname -n | tr '[A-Z]' '[a-z]'` ++NODENAME=$(ocf_local_nodename | tr '[A-Z]' '[a-z]') + + if is_replication; then + REP_MODE_CONF=${OCF_RESKEY_tmpdir}/rep_mode.conf + diff --git a/SOURCES/bz917806-oracle-tns-admin.patch b/SOURCES/bz917806-oracle-tns-admin.patch new file mode 100644 index 00000000..f16ca017 --- /dev/null +++ b/SOURCES/bz917806-oracle-tns-admin.patch @@ -0,0 +1,96 @@ +From bc521235c8b630dd1f379e005c51b106a4cce701 Mon Sep 17 00:00:00 2001 +From: David Vossel +Date: Tue, 10 Sep 2013 18:17:21 -0500 +Subject: [PATCH] Low: oralsnr: Add tns_admin option for setting custom + TNS_ADMIN path + +--- + heartbeat/ora-common.sh | 9 +++++++-- + heartbeat/oracle | 2 +- + heartbeat/oralsnr | 14 +++++++++++++- + 3 files changed, 21 insertions(+), 4 deletions(-) + +diff --git a/heartbeat/ora-common.sh b/heartbeat/ora-common.sh +index f52dbc5..5bbb163 100644 +--- a/heartbeat/ora-common.sh ++++ b/heartbeat/ora-common.sh +@@ -19,6 +19,7 @@ ora_common_getconfig() { + ORACLE_SID=$1 + ORACLE_HOME=$2 + ORACLE_OWNER=$3 ++ TNS_ADMIN=$4 + + # get ORACLE_HOME from /etc/oratab if not set + [ x = "x$ORACLE_HOME" ] && +@@ -28,9 +29,13 @@ ora_common_getconfig() { + [ x = "x$ORACLE_OWNER" ] && + ORACLE_OWNER=`ls -ld $ORACLE_HOME/. 2>/dev/null | awk 'NR==1{print $3}'` + ++ # There are use-cases were users want to be able to set a custom TMS_ADMIN path. ++ # When TNS_ADMIN is not provided, use the default path. ++ [ x = "x$TNS_ADMIN" ] && ++ TNS_ADMIN=$ORACLE_HOME/network/admin ++ + LD_LIBRARY_PATH=$ORACLE_HOME/lib + LIBPATH=$ORACLE_HOME/lib +- TNS_ADMIN=$ORACLE_HOME/network/admin + PATH=$ORACLE_HOME/bin:$ORACLE_HOME/dbs:$PATH + export ORACLE_SID ORACLE_HOME ORACLE_OWNER TNS_ADMIN + export LD_LIBRARY_PATH LIBPATH +@@ -70,7 +75,7 @@ ORACLE_HOME=$ORACLE_HOME + ORACLE_OWNER=$ORACLE_OWNER + LD_LIBRARY_PATH=$ORACLE_HOME/lib + LIBPATH=$ORACLE_HOME/lib +-TNS_ADMIN=$ORACLE_HOME/network/admin ++TNS_ADMIN=$TNS_ADMIN + export ORACLE_SID ORACLE_HOME ORACLE_OWNER TNS_ADMIN + export LD_LIBRARY_PATH LIBPATH + EOF +diff --git a/heartbeat/oracle b/heartbeat/oracle +index 2d17e1a..d6b2c50 100755 +--- a/heartbeat/oracle ++++ b/heartbeat/oracle +@@ -473,7 +473,7 @@ ora_cleanup() { + } + + oracle_getconfig() { +- ora_common_getconfig "$OCF_RESKEY_sid" "$OCF_RESKEY_home" "$OCF_RESKEY_user" ++ ora_common_getconfig "$OCF_RESKEY_sid" "$OCF_RESKEY_home" "$OCF_RESKEY_user" "$OCF_RESKEY_tns_admin" + + clear_backupmode=${OCF_RESKEY_clear_backupmode:-"false"} + shutdown_method=${OCF_RESKEY_shutdown_method:-"checkpoint/abort"} +diff --git a/heartbeat/oralsnr b/heartbeat/oralsnr +index 3a6d6f2..98fb120 100755 +--- a/heartbeat/oralsnr ++++ b/heartbeat/oralsnr +@@ -104,6 +104,18 @@ Defaults to LISTENER. + + + ++ ++ ++ Full path to the directory that contains the Oracle ++ listener tnsnames.ora configuration file. The shell ++ variable TNS_ADMIN is set to the value provided. ++ ++ ++ Full path to the directory containing tnsnames.ora ++ ++ ++ ++ + + + +@@ -245,7 +257,7 @@ oralsnr_status() { + } + + oralsnr_getconfig() { +- ora_common_getconfig "$OCF_RESKEY_sid" "$OCF_RESKEY_home" "$OCF_RESKEY_user" ++ ora_common_getconfig "$OCF_RESKEY_sid" "$OCF_RESKEY_home" "$OCF_RESKEY_user" "$OCF_RESKEY_tns_admin" + listener=${OCF_RESKEY_listener:-"LISTENER"} + } + +-- +1.8.1 + diff --git a/SOURCES/bz984054.patch b/SOURCES/bz984054.patch new file mode 100644 index 00000000..54c7a61e --- /dev/null +++ b/SOURCES/bz984054.patch @@ -0,0 +1,76 @@ +From de258066eafa7a2c3a42ef88e2c7657ae95d1e99 Mon Sep 17 00:00:00 2001 +From: David Vossel +Date: Tue, 16 Jul 2013 18:29:42 -0500 +Subject: [PATCH] Low: LVM: Detect duplicate resources with the same volgrpname + name when using exclusive activation with tags. + +For exclusive activation with tags, we already detect +if the resource is a clone and prevent the LVM resource +from activating. This check goes a step further and +detects if there is another primitive attempting to access +the same volume group in pacemaker's configuraiton. This +check is ignored if pacemaker is not in use, allowing this +agent to continue to be portable to other cluster managers +in the future. + +This patch also re-words the 'exclusive' option's documentation +in order to clarify how volume_list filtering works. + +Resolves: rhbz#984054 +--- + heartbeat/LVM | 32 +++++++++++++++++++++++++++++--- + 1 file changed, 29 insertions(+), 3 deletions(-) + +diff --git a/heartbeat/LVM b/heartbeat/LVM +index 0ff6ba7..27315df 100755 +--- a/heartbeat/LVM ++++ b/heartbeat/LVM +@@ -80,9 +80,17 @@ The name of volume group. + If set, the volume group will be activated exclusively. This option works one of + two ways. If the volume group has the cluster attribute set, then the volume group + will be activated exclusively using clvmd across the cluster. If the cluster attribute +-is not set, the volume group will be activated exclusively using a tag and the volume_list +-filter. When the tag option is in use, the volume_list in lvm.con must be initialized. This +-can be as simple as setting 'volume_list = []' depending on your setup. ++is not set, the volume group will be activated exclusively through the use of the ++volume_list filter in lvm.conf. In the filter scenario, the LVM agent verifies ++that pacemaker's configuration will result in the volume group only being active on a ++single node in the cluster and that the local node's volume_list filter will prevent ++the volume group from activating outside of the resource agent. On activation this ++agent claims the volume group through the use of a unique tag, and then overrides the ++volume_list field in a way that allows the volume group to be activated only by the ++agent. To use exclusive activation without clvmd, the volume_list in lvm.conf must be ++initialized. If volume groups exist locally that are not controlled by the cluster, such ++as the root volume group, make sure those volume groups are listed in the volume_list ++so they will be allowed to activate on bootup. + + Exclusive activation + +@@ -191,6 +199,24 @@ verify_tags_environment() + return $OCF_ERR_GENERIC + fi + ++ ++ ## ++ # Verify that if this agent is being used in a Pacemaker cluster, ++ # no other LVM agents in the cib contain the same volgrpname ++ ## ++ if have_binary "cibadmin" ; then ++ # This detects if there is any other LVM primitive (besides this instance) that ++ # is already assigned the same volume group. If so, do not activate this instance. ++ cibadmin --local -Q --xpath '//primitive[@type="LVM"][@id!="'${OCF_RESOURCE_INSTANCE}'"]//instance_attributes//nvpair[@name="volgrpname"][@value="'${OCF_RESKEY_volgrpname}'"]' \ ++ > /dev/null 2>&1 ++ ++ if [ $? -eq 0 ]; then ++ ocf_log err "LVM: Improper setup detected" ++ ocf_log err "Duplicate LVM resource controlling vg '$OCF_RESKEY_volgrpname' detected in cib configuration. Can not activate exclusively" ++ return $OCF_ERR_GENERIC ++ fi ++ ++ fi + return $OCF_SUCCESS + } + +-- +1.8.1 + diff --git a/SOURCES/fix-LVM-clvmd-retry.patch b/SOURCES/fix-LVM-clvmd-retry.patch new file mode 100644 index 00000000..126181a2 --- /dev/null +++ b/SOURCES/fix-LVM-clvmd-retry.patch @@ -0,0 +1,25 @@ +From b1baea609901fff82e8318e9b7527f73253e0ec3 Mon Sep 17 00:00:00 2001 +From: David Vossel +Date: Thu, 12 Sep 2013 19:56:27 -0500 +Subject: [PATCH] Low: LVM: fix invalid return statement + +--- + heartbeat/LVM | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/heartbeat/LVM b/heartbeat/LVM +index 0ff6ba7..ec1ee7d 100755 +--- a/heartbeat/LVM ++++ b/heartbeat/LVM +@@ -405,7 +405,7 @@ retry_exclusive_start() + shift 2 + done + +- return ocf_run vgchange $vgchange_options $OCF_RESKEY_volgrpname ++ ocf_run vgchange $vgchange_options $OCF_RESKEY_volgrpname + } + + # +-- +1.8.1 + diff --git a/SOURCES/nfs-fixes-update.patch b/SOURCES/nfs-fixes-update.patch new file mode 100644 index 00000000..aeafff1f --- /dev/null +++ b/SOURCES/nfs-fixes-update.patch @@ -0,0 +1,143 @@ +From 6900fcb7b014bd0177c44f20447caca4658b45c6 Mon Sep 17 00:00:00 2001 +From: David Vossel +Date: Wed, 29 Apr 2015 11:12:23 -0500 +Subject: [PATCH 2/6] nfsserver updates + +--- + heartbeat/nfsserver | 51 ++++++++++++++++++++++++++++++++++----------------- + 1 file changed, 34 insertions(+), 17 deletions(-) + +diff --git a/heartbeat/nfsserver b/heartbeat/nfsserver +index de1a802..33cb607 100755 +--- a/heartbeat/nfsserver ++++ b/heartbeat/nfsserver +@@ -208,9 +208,9 @@ The mount point for the sunrpc file system. + + + +- +- +- ++ ++ ++ + + + +@@ -391,7 +391,12 @@ set_arg() + # only write to the tmp /etc/sysconfig/nfs if sysconfig exists. + # otherwise this distro does not support setting these options. + if [ -d "/etc/sysconfig" ]; then +- echo "${key}=\"${value}\"" >> $file ++ # replace if the value exists, append otherwise ++ if grep "^\s*${key}=" $file ; then ++ sed -i "s/\s*${key}=.*$/${key}=\"${value}\"/" $file ++ else ++ echo "${key}=\"${value}\"" >> $file ++ fi + elif [ "$requires_sysconfig" = "true" ]; then + ocf_log warn "/etc/sysconfig/nfs not found, unable to set port and nfsd args." + fi +@@ -404,6 +409,11 @@ set_env_args() + local tmpconfig=$(mktemp ${HA_RSCTMP}/nfsserver-tmp-XXXXX) + local statd_args + ++ if [ -f "$NFS_SYSCONFIG" ]; then ++ ## Take the $NFS_SYSCONFIG file as our skeleton ++ cp $NFS_SYSCONFIG $tmpconfig ++ fi ++ + # nfsd args + set_arg "RPCNFSDARGS" "$OCF_RESKEY_nfsd_args" "$tmpconfig" "true" + +@@ -434,14 +444,20 @@ set_env_args() + + # override local nfs config. preserve previous local config though. + if [ -s $tmpconfig ]; then +- cat $NFS_SYSCONFIG | grep -e "$NFS_SYSCONFIG_AUTOGEN_TAG" ++ cat $NFS_SYSCONFIG | grep -q -e "$NFS_SYSCONFIG_AUTOGEN_TAG" > /dev/null 2>&1 + if [ $? -ne 0 ]; then + # backup local nfs config if it doesn't have our HA autogen tag in it. + mv -f $NFS_SYSCONFIG $NFS_SYSCONFIG_LOCAL_BACKUP + fi +- echo "# $NFS_SYSCONFIG_AUTOGEN_TAG" > $NFS_SYSCONFIG +- echo "# local config backup stored here, '$NFS_SYSCONFIG_LOCAL_BACKUP'" >> $NFS_SYSCONFIG +- cat $tmpconfig >> $NFS_SYSCONFIG ++ ++ cat $tmpconfig | grep -q -e "$NFS_SYSCONFIG_AUTOGEN_TAG" > /dev/null 2>&1 ++ if [ $? -ne 0 ]; then ++ echo "# $NFS_SYSCONFIG_AUTOGEN_TAG" > $NFS_SYSCONFIG ++ echo "# local config backup stored here, '$NFS_SYSCONFIG_LOCAL_BACKUP'" >> $NFS_SYSCONFIG ++ cat $tmpconfig >> $NFS_SYSCONFIG ++ else ++ cat $tmpconfig > $NFS_SYSCONFIG ++ fi + fi + rm -f $tmpconfig + } +@@ -460,13 +476,14 @@ prepare_directory () + [ -d "$fp/$STATD_DIR/sm" ] || mkdir -p "$fp/$STATD_DIR/sm" + [ -d "$fp/$STATD_DIR/sm.ha" ] || mkdir -p "$fp/$STATD_DIR/sm.ha" + [ -d "$fp/$STATD_DIR/sm.bak" ] || mkdir -p "$fp/$STATD_DIR/sm.bak" +- [ -n "`id -u rpcuser`" -a "`id -g rpcuser`" ] && chown -R rpcuser.rpcuser "$fp/$STATD_DIR" ++ [ -n "`id -u rpcuser 2>/dev/null`" -a "`id -g rpcuser 2>/dev/null`" ] && ++ chown -R rpcuser.rpcuser "$fp/$STATD_DIR" + + [ -f "$fp/etab" ] || touch "$fp/etab" + [ -f "$fp/xtab" ] || touch "$fp/xtab" + [ -f "$fp/rmtab" ] || touch "$fp/rmtab" + +- dd if=/dev/urandom of=$fp/$STATD_DIR/state bs=1 count=4 &> /dev/null ++ dd if=/dev/urandom of=$fp/$STATD_DIR/state bs=1 count=4 >/dev/null 2>&1 + [ -n "`id -u rpcuser`" -a "`id -g rpcuser`" ] && chown rpcuser.rpcuser "$fp/$STATD_DIR/state" + [ $SELINUX_ENABLED -eq 0 ] && chcon -R "$SELINUX_LABEL" "$fp" + } +@@ -546,15 +563,15 @@ locking_start() + + terminate() + { +- declare pids +- declare i=0 ++ local pids ++ local i=0 + + while : ; do + pids=$(binary_status $1) + [ -z "$pids" ] && return 0 + kill $pids + sleep 1 +- ((i++)) ++ i=$((i + 1)) + [ $i -gt 3 ] && return 1 + done + } +@@ -562,22 +579,22 @@ terminate() + + killkill() + { +- declare pids +- declare i=0 ++ local pids ++ local i=0 + + while : ; do + pids=$(binary_status $1) + [ -z "$pids" ] && return 0 + kill -9 $pids + sleep 1 +- ((i++)) ++ i=$((i + 1)) + [ $i -gt 3 ] && return 1 + done + } + + stop_process() + { +- declare process=$1 ++ local process=$1 + + ocf_log info "Stopping $process" + if terminate $process; then +-- +1.8.4.2 + diff --git a/SOURCES/rabbitmq-cluster.patch b/SOURCES/rabbitmq-cluster.patch new file mode 100644 index 00000000..b9c6b5cb --- /dev/null +++ b/SOURCES/rabbitmq-cluster.patch @@ -0,0 +1,415 @@ +From a06ce7c166f4a7801b1fb7d50c77dead8a0c7a1d Mon Sep 17 00:00:00 2001 +From: David Vossel +Date: Wed, 21 Jan 2015 18:00:18 -0500 +Subject: [PATCH] High: introducing rabbitmq clustering agent + +--- + doc/man/Makefile.am | 1 + + heartbeat/Makefile.am | 1 + + heartbeat/rabbitmq-cluster | 370 +++++++++++++++++++++++++++++++++++++++++++++ + 3 files changed, 372 insertions(+) + create mode 100755 heartbeat/rabbitmq-cluster + +diff --git a/doc/man/Makefile.am b/doc/man/Makefile.am +index eafb2d1..62e619a 100644 +--- a/doc/man/Makefile.am ++++ b/doc/man/Makefile.am +@@ -127,6 +127,7 @@ man_MANS = ocf_heartbeat_AoEtarget.7 \ + ocf_heartbeat_postfix.7 \ + ocf_heartbeat_pound.7 \ + ocf_heartbeat_proftpd.7 \ ++ ocf_heartbeat_rabbitmq-cluster.7 \ + ocf_heartbeat_rsyncd.7 \ + ocf_heartbeat_rsyslog.7 \ + ocf_heartbeat_scsi2reservation.7 \ +diff --git a/heartbeat/Makefile.am b/heartbeat/Makefile.am +index 330b7f7..66dcff2 100644 +--- a/heartbeat/Makefile.am ++++ b/heartbeat/Makefile.am +@@ -106,6 +106,7 @@ ocf_SCRIPTS = ClusterMon \ + pgsql \ + proftpd \ + Pure-FTPd \ ++ rabbitmq-cluster \ + Raid1 \ + Route \ + rsyncd \ +diff --git a/heartbeat/rabbitmq-cluster b/heartbeat/rabbitmq-cluster +new file mode 100755 +index 0000000..b9dcfc3 +--- /dev/null ++++ b/heartbeat/rabbitmq-cluster +@@ -0,0 +1,370 @@ ++#!/bin/sh ++# ++# Copyright (c) 2014 David Vossel ++# All Rights Reserved. ++# ++# This program is free software; you can redistribute it and/or modify ++# it under the terms of version 2 of the GNU General Public License as ++# published by the Free Software Foundation. ++# ++# This program is distributed in the hope that it would be useful, but ++# WITHOUT ANY WARRANTY; without even the implied warranty of ++# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. ++# ++# Further, this software is distributed without any warranty that it is ++# free of the rightful claim of any third person regarding infringement ++# or the like. Any license provided herein, whether implied or ++# otherwise, applies only to this software file. Patent licenses, if ++# any, provided herein do not apply to combinations of this program with ++# other software, or any other product whatsoever. ++# ++# You should have received a copy of the GNU General Public License ++# along with this program; if not, write the Free Software Foundation, ++# Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA. ++# ++ ++####################################################################### ++# Initialization: ++ ++: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat} ++. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs ++ ++####################################################################### ++ ++RMQ_SERVER=/usr/sbin/rabbitmq-server ++RMQ_CTL=/usr/sbin/rabbitmqctl ++RMQ_DATA_DIR="/var/lib/rabbitmq/mnesia" ++RMQ_PID_DIR="/var/run/rabbitmq" ++RMQ_PID_FILE="/var/run/rabbitmq/rmq.pid" ++RMQ_LOG_DIR="/var/log/rabbitmq" ++NODENAME=$(ocf_local_nodename) ++ ++RMQ_CRM_ATTR_COOKIE="rmq-node-attr-${OCF_RESOURCE_INSTANCE}" ++ ++meta_data() { ++ cat < ++ ++ ++1.0 ++ ++ ++Starts cloned rabbitmq cluster instance ++ ++rabbitmq clustered ++ ++ ++ ++ ++Policy string to pass to 'rabbitmqctl set_policy' right after bootstrapping the first rabbitmq instance. ++ ++rabbitmqctl set_policy args ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++ ++END ++} ++ ++####################################################################### ++ ++rmq_usage() { ++ cat < /dev/null 2>&1 ++} ++ ++rmq_local_node() ++{ ++ ++ local node_name=$(rabbitmqctl status 2>&1 | sed -n -e "s/^.*[S|s]tatus of node \(.*\)\s.*$/\1/p" | tr -d "'") ++ ++ if [ -z "$node_name" ]; then ++ node_name=$(cat /etc/rabbitmq/rabbitmq-env.conf 2>/dev/null | grep "\s*RABBITMQ_NODENAME=" | awk -F= '{print $2}') ++ fi ++ ++ echo "$node_name" ++} ++ ++rmq_join_list() ++{ ++ cibadmin -Q 2>/dev/null | grep "$RMQ_CRM_ATTR_COOKIE" | sed -n -e "s/^.*value=.\(.*\)\".*$/\1/p" ++} ++ ++rmq_write_nodename() ++{ ++ local node_name=$(rmq_local_node) ++ ++ if [ -z "$node_name" ]; then ++ ocf_log err "Failed to determine rabbitmq node name, exiting" ++ exit $OCF_ERR_GENERIC ++ fi ++ ++ # store the pcmknode to rmq node mapping as an attribute ++ ${HA_SBIN_DIR}/crm_attribute -N $NODENAME -l reboot --name "$RMQ_CRM_ATTR_COOKIE" -v "$node_name" ++} ++ ++rmq_delete_nodename() ++{ ++ # remove node-name ++ ${HA_SBIN_DIR}/crm_attribute -N $NODENAME -l reboot --name "$RMQ_CRM_ATTR_COOKIE" -D ++} ++ ++prepare_dir () { ++ if [ ! -d ${1} ] ; then ++ mkdir -p ${1} ++ chown -R rabbitmq:rabbitmq ${1} ++ chmod 755 ${1} ++ fi ++} ++ ++remove_pid () { ++ rm -f ${RMQ_PID_FILE} > /dev/null 2>&1 ++} ++ ++rmq_monitor() { ++ local rc ++ ++ $RMQ_CTL cluster_status > /dev/null 2>&1 ++ rc=$? ++ case "$rc" in ++ 0) ++ ocf_log debug "RabbitMQ server is running normally" ++ rmq_write_nodename ++ ++ return $OCF_SUCCESS ++ ;; ++ 2) ++ ocf_log info "RabbitMQ server is not running" ++ rmq_delete_nodename ++ return $OCF_NOT_RUNNING ++ ;; ++ *) ++ ocf_log err "Unexpected return code from '$RMQ_CTL cluster status' exit code: $rc" ++ rmq_delete_nodename ++ return $OCF_ERR_GENERIC ++ ;; ++ esac ++} ++ ++rmq_init_and_wait() ++{ ++ local rc ++ ++ prepare_dir $RMQ_PID_DIR ++ prepare_dir $RMQ_LOG_DIR ++ remove_pid ++ ++ # the server startup script uses this environment variable ++ export RABBITMQ_PID_FILE="$RMQ_PID_FILE" ++ ++ setsid sh -c "$RMQ_SERVER > ${RMQ_LOG_DIR}/startup_log 2> ${RMQ_LOG_DIR}/startup_err" & ++ ++ ocf_log info "Waiting for server to start" ++ $RMQ_CTL wait $RMQ_PID_FILE ++ rc=$? ++ if [ $rc -ne $OCF_SUCCESS ]; then ++ remove_pid ++ ocf_log info "rabbitmq-server start failed: $rc" ++ return $OCF_ERR_GENERIC ++ fi ++ ++ rmq_monitor ++ return $? ++} ++ ++rmq_set_policy() ++{ ++ $RMQ_CTL set_policy $@ > /dev/null 2>&1 ++} ++ ++rmq_start_first() ++{ ++ local rc ++ ++ ocf_log info "Bootstrapping rabbitmq cluster" ++ rmq_wipe_data ++ rmq_init_and_wait ++ rc=$? ++ ++ if [ $rc -eq 0 ]; then ++ rc=$OCF_SUCCESS ++ ocf_log info "cluster bootstrapped" ++ ++ if [ -n "$OCF_RESKEY_set_policy" ]; then ++ # do not quote set_policy, we are passing in arguments ++ rmq_set_policy $OCF_RESKEY_set_policy > /dev/null 2>&1 ++ if [ $? -ne 0 ]; then ++ ocf_log err "Failed to set policy: $OCF_RESKEY_set_policy" ++ rc=$OCF_ERR_GENERIC ++ else ++ ocf_log info "Policy set: $OCF_RESKEY_set_policy" ++ fi ++ fi ++ ++ else ++ ocf_log info "failed to bootstrap cluster. Check SELINUX policy" ++ rc=$OCF_ERR_GENERIC ++ fi ++ ++ return $rc ++} ++ ++rmq_join_existing() ++{ ++ local join_list="$1" ++ local rc=$OCF_ERR_GENERIC ++ ++ ocf_log info "Joining existing cluster with [ $(echo $join_list | tr '\n' ' ') ] nodes." ++ rmq_init_and_wait ++ if [ $? -ne 0 ]; then ++ return $OCF_ERR_GENERIC ++ fi ++ ++ # unconditionally join the cluster ++ $RMQ_CTL stop_app > /dev/null 2>&1 ++ for node in $(echo "$join_list"); do ++ ocf_log info "Attempting to join cluster with target node $node" ++ $RMQ_CTL join_cluster $node ++ if [ $? -eq 0 ]; then ++ ocf_log info "Joined cluster by connecting to node $node, starting app" ++ $RMQ_CTL start_app ++ rc=$? ++ if [ $rc -ne 0 ]; then ++ ocf_log err "'$RMQ_CTL start_app' failed" ++ fi ++ break; ++ fi ++ done ++ ++ if [ "$rc" -ne 0 ]; then ++ ocf_log info "Join process incomplete, shutting down." ++ return $OCF_ERR_GENERIC ++ fi ++ ++ ocf_log info "Successfully joined existing rabbitmq cluster" ++ return $OCF_SUCCESS ++} ++ ++rmq_start() { ++ local join_list="" ++ local rc ++ ++ rmq_monitor ++ if [ $? -eq $OCF_SUCCESS ]; then ++ return $OCF_SUCCESS ++ fi ++ ++ join_list=$(rmq_join_list) ++ ++ # No join list means no active instances are up. This instance ++ # is the first, so it needs to bootstrap the rest ++ if [ -z "$join_list" ]; then ++ rmq_start_first ++ rc=$? ++ return $rc ++ fi ++ ++ # first try to join without wiping mnesia data ++ rmq_join_existing "$join_list" ++ if [ $? -ne 0 ]; then ++ ocf_log info "node failed to join, wiping data directory and trying again" ++ # if the graceful join fails, use the hammer and reset all the data. ++ rmq_stop ++ rmq_wipe_data ++ rmq_join_existing "$join_list" ++ if [ $? -ne 0 ]; then ++ ocf_log info "node failed to join even after reseting local data. Check SELINUX policy" ++ return $OCF_ERR_GENERIC ++ fi ++ fi ++ ++ return $OCF_SUCCESS ++} ++ ++rmq_stop() { ++ rmq_monitor ++ if [ $? -eq $OCF_NOT_RUNNING ]; then ++ return $OCF_SUCCESS ++ fi ++ ++ $RMQ_CTL stop ++ rc=$? ++ ++ if [ $rc -ne 0 ]; then ++ ocf_log err "rabbitmq-server stop command failed: $RMQ_CTL stop, $rc" ++ return $rc ++ fi ++ ++ #TODO add kill logic ++ stop_wait=1 ++ while [ $stop_wait = 1 ]; do ++ rmq_monitor ++ rc=$? ++ if [ "$rc" -eq $OCF_NOT_RUNNING ]; then ++ stop_wait=0 ++ break ++ elif [ "$rc" -ne $OCF_SUCCESS ]; then ++ ocf_log info "rabbitmq-server stop failed: $rc" ++ exit $OCF_ERR_GENERIC ++ fi ++ sleep 1 ++ done ++ ++ remove_pid ++ return $OCF_SUCCESS ++} ++ ++rmq_validate() { ++ check_binary $RMQ_SERVER ++ check_binary $RMQ_CTL ++ ++ # This resource only makes sense as a clone right now. at some point ++ # we may want to verify the following. ++ #TODO verify cloned ++ #TODO verify ordered=true ++ ++ # Given that this resource does the cluster join explicitly, ++ # having a cluster_nodes list in the static config file will ++ # likely conflict with this agent. ++ #TODO verify no cluster list in rabbitmq conf ++ #cat /etc/rabbitmq/rabbitmq.config | grep "cluster_nodes" ++ ++ return $OCF_SUCCESS ++} ++ ++case $__OCF_ACTION in ++meta-data) meta_data ++ exit $OCF_SUCCESS ++ ;; ++start) rmq_start;; ++stop) rmq_stop;; ++monitor) rmq_monitor;; ++validate-all) rmq_validate;; ++usage|help) rmq_usage ++ exit $OCF_SUCCESS ++ ;; ++*) rmq_usage ++ exit $OCF_ERR_UNIMPLEMENTED ++ ;; ++esac ++rc=$? ++ocf_log debug "${OCF_RESOURCE_INSTANCE} $__OCF_ACTION : $rc" ++exit $rc ++ +-- +1.8.4.2 + diff --git a/SPECS/resource-agents.spec b/SPECS/resource-agents.spec new file mode 100644 index 00000000..a16660ae --- /dev/null +++ b/SPECS/resource-agents.spec @@ -0,0 +1,1966 @@ +# +# All modifications and additions to the file contributed by third parties +# remain the property of their copyright owners, unless otherwise agreed +# upon. The license for this file, and modifications and additions to the +# file, is the same license as for the pristine package itself (unless the +# license for the pristine package is not an Open Source License, in which +# case the license is the MIT License). An "Open Source License" is a +# license that conforms to the Open Source Definition (Version 1.9) +# published by the Open Source Initiative. +# + + + + + + +# +# Since this spec file supports multiple distributions, ensure we +# use the correct group for each. +# + +## Whether this platform defaults to using systemd as an init system +## (needs to be evaluated prior to BuildRequires being enumerated and +## installed as it's intended to conditionally select some of these, and +## for that there are only few indicators with varying reliability: +## - presence of systemd-defined macros (when building in a full-fledged +## environment, which is not the case with ordinary mock-based builds) +## - systemd-aware rpm as manifested with the presence of particular +## macro (rpm itself will trivially always be present when building) +## - existence of /usr/lib/os-release file, which is something heavily +## propagated by systemd project +## - when not good enough, there's always a possibility to check +## particular distro-specific macros (incl. version comparison) +%define systemd_native (%{?_unitdir:1}%{?!_unitdir:0}%{nil \ + } || %{?__transaction_systemd_inhibit:1}%{?!__transaction_systemd_inhibit:0}%{nil \ + } || %(test -f /usr/lib/os-release; test $? -ne 0; echo $?)) + +%global upstream_prefix ClusterLabs-resource-agents +%global upstream_version 5434e96 + +%global sap_script_prefix sap_redhat_cluster_connector +%global sap_hash 6353d27 + +# determine the ras-set to process based on configure invokation +%bcond_with rgmanager +%bcond_without linuxha + +Name: resource-agents +Summary: Open Source HA Reusable Cluster Resource Scripts +Version: 3.9.5 +Release: 124%{?dist} +License: GPLv2+, LGPLv2+ and ASL 2.0 +URL: https://github.com/ClusterLabs/resource-agents +%if 0%{?fedora} || 0%{?centos_version} || 0%{?rhel} +Group: System Environment/Base +%else +Group: Productivity/Clustering/HA +%endif +Source0: %{upstream_prefix}-%{upstream_version}.tar.gz +Source1: %{sap_script_prefix}-%{sap_hash}.tar.gz +Patch1: bz984054.patch +Patch2: bz884164-multi-lib-fixes.patch +Patch3: bz10005924-default-apache-config.patch +Patch4: bz799065-apache-simple-monitor.patch +Patch5: fix-LVM-clvmd-retry.patch +Patch6: bz917806-oracle-tns-admin.patch +Patch7: bz917681-VirtualDomain-heartbeat-updates.patch +Patch8: bz917681_nodename_fixes.patch +Patch9: bz1014641-VirtualDomain-syntax-error.patch +Patch10: bz917681-VirtualDomain-heartbeat-updates_v2.patch +Patch11: bz1016140-start-predefined-domains.patch +Patch12: bz917681-ipv6-send_ua-fix.patch +Patch13: bz917681-ocft_fedora_supported_test_cases.patch +Patch14: bz1033016-nfsserver-missing-etab.patch +Patch15: bz917681-slapd-heartbeat-updates.patch +Patch16: bz917681-tomcat-heartbeat-updates.patch +Patch17: bz1029061-virtualdomain-parse-error.patch +Patch18: bz1064512-clvmd-agent.patch +Patch19: bz1060367-vm-monitor-wo-libvirtd.patch +Patch20: bz1060367-vm-monitor-wo-libvirtd_2.patch +Patch21: bz1116166-galera-agent.patch +Patch22: bz1091101-nfs-updates.patch +Patch23: bz1091101-nfs-error-msg-fix.patch +Patch24: bz1091101-nfs-rquotad-port-option-fix.patch +Patch25: bz1083041-virtual-domain-monitor-lxc-fix.patch +Patch26: bz1083231-fs-wait-module-load.patch +Patch27: bz1097593-LVM-warn-lvmetad.patch +Patch28: bz1105655-virtualdomain-restore-start-stop-default-timeout.patch +Patch29: bz1128933-IPaddr2-exit-reason-support.patch +Patch30: bz1128933-VirtualDomain-exit-reason-support.patch +Patch31: bz1128933-binary-check-exit-reason-support.patch +Patch32: bz1128933-exportfs-exit-reason-support.patch +Patch33: bz1128933-introducing-exit-reason-support.patch +Patch34: bz1128933-nfsnotify-exit-reason-support.patch +Patch35: bz1128933-nfssserver-exit-reason-support.patch +Patch36: bz773395-clvm-autoset-locking-type.patch +Patch37: bz1058102-man-page-updates.patch +Patch38: bz1118029-iscsi-agents.patch +Patch39: bz1122285-ethmonitor-infiniband.patch +Patch40: bz1128933-exit-reason-string-updates.patch +Patch41: bz1095944-safe-umount-option.patch +Patch42: bz1118029_iscsi_syntax_fix.patch +Patch43: bz1138871_mysql_stop_fix.patch +Patch44: bz1116166-Low-galera-do-not-advertise-notify-in-the-usage.patch +Patch45: bz1116166-Low-galera-be-very-generous-in-the-promotion-timeout.patch +Patch46: bz1116166-galera-do-not-ignore-check_password.patch +Patch47: bz1128933-Fix-shellfuncs-fix-syntax-error-caused-by-exit_reaso.patch +Patch48: bz1128933-Fix-ocf_exit_reason-implicit-format-string-s-for-sin.patch +Patch49: bz1128933-Fix-ha_log-drop-global-__ha_log_ignore_stderr_once-h.patch +Patch50: bz1138871-avoid-check-binary-in-validate.patch +Patch51: bz1138871-mysql-error-validation-fails-monitor.patch +Patch52: bz1135026-introducing-docker-agent.patch +Patch53: bz1135026-docker-stop-fix.patch +Patch54: bz1135026-docker-name-arg.patch +Patch55: bz1135026-docker-monitor_cmd-arg.patch +Patch56: bz1135026-docker-handle-invalid-monitor-cmd.patch +Patch57: bz1118029-iscsi-remove-write-back.patch +Patch58: rabbitmq-cluster.patch +Patch59: bz1189187-redis-agent.patch +Patch60: bz1170376-galera-no-readonly.patch +Patch61: bz1198681-clvm-activate-vgs-option.patch +Patch62: bz1200756-ipsrcaddr-misconfig.patch +Patch63: bz773399-netmast-error.patch +Patch64: bz1059988-db2-support.patch +Patch65: bz1077888-ctdb-updates.patch +Patch66: bz1171162-clvmd-opt-fix.patch +Patch67: bz1183136-nginx-support.patch +Patch68: bz1213971-ethmon-opt.patch +Patch69: nfs-fixes-update.patch +Patch70: bz1160365-iface-vlan.patch.patch +Patch71: bz1214781-lvm-partial-activation-fix.patch.patch +Patch72: bz1223615-apache-includes-fix.patch.patch +Patch73: NovaCompute.patch +Patch74: bz1214360-NovaCompute-update1.patch.patch +Patch75: bz1227293-dhcpd-chroot-fix.patch.patch +Patch76: bz1231032-redis-update.patch.patch +Patch77: bz1232376-oracle-agent-update.diff +Patch78: bz1168251-SAPHana-agents.patch +Patch79: bz1168251-SAPHana-agents-update.patch +Patch80: bz1168251-SAPHana-agents-update2.patch +Patch81: bz1168251-SAPHana-agents-update3.patch +Patch82: bz1168251-SAPHana-agents_update4.patch +Patch83: bz1251484-redis-client-passwd-support.patch +Patch84: bz1282723-novacompute-novaevacuate-fix-evacute-typo.patch +Patch85: bz1287303-novaevacuate-invoke-off-action.patch +Patch86: bz1126073-1-nfsserver-fix-systemd-status-detection.patch +Patch87: bz1299404-galera-custom-host-port.patch +Patch88: bz1247303-rabbitmq-cluster-forget-stopped-cluster-nodes.patch +Patch89: bz1249430-1-tomcat-fix-selinux-enforced.patch +Patch90: bz1250728-send_arp-fix-buffer-overflow-on-infiniband.patch +Patch91: bz1263348-mysql-tmpfile-leak.patch +Patch92: bz1242181-virtualdomain-migrate_options.patch +Patch93: bz1242558-virtualdomain-may-remove-config-file.patch +Patch94: bz1301189-virtualdomain-fix-locale.patch +Patch95: bz1276699-ipaddr2-use-ipv6-dad-for-collision-detection.patch +Patch96: bz1212632-nagios.patch +Patch97: bz1303803-Backup-and-restore-rabbitmq-users-during-resource-re.patch +Patch98: bz1265527-sap_redhat_cluster_connector-hostnames-with-dash.patch +Patch99: bz1287314-novaevacuate-simplify-nova-check.patch +Patch100: bz1303037-1-portblock.patch +Patch101: bz1284526-galera-crash-recovery.patch +Patch102: bz1284526-galera-heuristic-recovered.patch +Patch103: bz1284526-galera-no-grastate.patch +Patch104: bz1289107-saphana-mcos-support.patch +Patch105: bz1296406-virtualdomain-migration_speed-migration_downtime.patch +Patch106: bz1307160-virtualdomain-fix-unnecessary-error-when-probing-nonexistent-domain.patch +Patch107: bz1317578-oralsnr-fails-if-username-is-longer-than-8-chars.patch +Patch108: bz1318985-oracle-fix-unable-to-start-because-of-ORA-01081.patch +Patch109: bz1325453-nfsserver-var-lib-nfs-fix.patch +Patch110: bz1320783-nova-compute-wait-fix-invalid-hostname-issue.patch +Patch111: bz1328018-garbd-Introduces-garbd-resource-agent.patch +Patch112: bz1337109-tickle_tcp-fix.patch +Patch113: bz1337615-nfsserver-rpcpipefs_dir.patch +Patch114: bz1337124-mysql-use-replication_port-parameter.patch +Patch115: bz1328386-1-oracle-monprofile-container-databases.patch +Patch116: bz1342478-rabbitmq-cluster-return-code-69-not-running.patch +Patch117: bz1343905-1-rabbitmq-cluster-dump-restore-users-3.6.x.patch +Patch118: bz1343905-2-rabbitmq-cluster-dump-restore-users-3.6.x.patch +Patch119: bz1343905-3-rabbitmq-cluster-dump-restore-users-3.6.x.patch +Patch120: bz1126073-2-nfsserver-fix-systemd-status-detection.patch +Patch121: bz1358895-oracle-fix-monprofile.patch +Patch122: bz1343905-rabbitmq-automatic-cluster-recovery.patch +Patch123: bz1328386-2-oracle-monprofile-container-databases.patch +Patch124: bz1328386-3-oracle-monprofile-container-databases.patch +Patch125: bz1303037-2-portblock.patch +Patch126: bz1249430-2-tomcat-fix-selinux-enforced.patch +Patch127: bz1387491-nfsserver-keep-options.patch +Patch128: bz1390974-redis-fix-selinux-permissions.patch +Patch129: bz1305549-redis-notify-clients-of-master-being-demoted.patch +Patch130: bz1305549-nova-compute-wait-nova-compute-unfence.patch +Patch131: bz1360768-galera-prevent-promote-after-demote.patch +Patch132: bz1376588-iSCSITarget-properly-create-portals-for-lio-t.patch +Patch133: bz1384955-nfsserver-dont-stop-rpcbind.patch +Patch134: bz1387363-Filesystem-submount-check.patch +Patch135: bz1388854-delay-change-startdelay.patch +Patch136: bz1391470-galera-last-commit-fix-for-mariadb-10.1.18.patch +Patch137: bz1391580-portblock-return-success-on-stop-with-invalid-ip.patch +Patch138: bz1402370-portblock-wait.patch +Patch139: bz1406152-exportfs-ipv6-fix.patch +Patch140: bz1395142-1-update-saphana-saphanatopology.patch +Patch141: bz1395142-2-update-saphana-saphanatopology.patch +Patch142: bz1260713-1-sapdatabase-process-count-suser.patch +Patch143: bz1260713-2-sapdatabase-process-count-suser.patch +Patch144: bz1397393-rabbitmq-cluster-reset-mnesia-before-join.patch +Patch145: bz1392432-LVM-partial_activation-fix.patch +Patch146: bz1159328-LVM-check_writethrough.patch +Patch147: bz1359252-clvm-remove-reload-action.patch +Patch148: bz1389300-iSCSILogicalUnit-IPv6-support.patch +Patch149: bz1400172-IPsrcaddr-fix-duplicate-routes.patch +Patch150: bz1420565-pgsql-dont-use-crm_failcount.patch +Patch151: bz1427611-ocf_log-use-same-log-format-as-pacemaker.patch +Patch152: bz1430304-NodeUtilization.patch +Patch153: bz1430385-iSCSILogicalUnit-iSCSITarget-concurrent-safe.patch +Patch154: bz1434351-IPaddr2-send-arp-monitor-action.patch +Patch155: bz1435171-named-add-support-for-rndc-options.patch +Patch156: bz1077888-CTDB-fix-logging.patch +Patch157: bz1393189-1-IPaddr2-detect-duplicate-IP.patch +Patch158: bz1393189-2-IPaddr2-detect-duplicate-IP.patch +Patch159: bz1408656-ethmonitor-monitor-interface-without-ip.patch +Patch160: bz1411225-oraasm.patch +Patch161: bz1435982-rabbitmq-cluster-pacemaker-remote.patch +Patch162: bz1380405-send_arp-usage.patch +Patch163: bz1427574-DB2-fix-HADR-DB2-V98-or-later.patch +Patch164: bz1342376-rabbitmq-cluster-backup-and-restore-users-policies.patch +Patch165: bz1445861-IPaddr2-IPv6-add-preferred_lft-parameter.patch +Patch166: bz1316130-systemd-drop-in-clvmd-LVM.patch +Patch167: bz1449681-1-saphana-saphanatopology-update-0.152.21.patch +Patch168: bz1451097-1-galera-fix-bootstrap-when-cluster-has-no-data.patch +Patch169: bz1451097-2-galera-fix-bootstrap-when-cluster-has-no-data.patch +Patch170: bz1451097-3-galera-fix-bootstrap-when-cluster-has-no-data.patch +Patch171: bz1452049-docker-create-directories.patch +#Patch172: bz1454699-LVM-status-check-for-missing-VG.patch +#Patch173: bz1451933-LVM-update-metadata-on-start-relocate.patch +Patch174: bz1451933-LVM-warn-when-cache-mode-not-writethrough.patch +Patch175: bz1449681-2-saphana-saphanatopology-update-0.152.21.patch +Patch176: bz1342376-2-rabbitmq-cluster-backup-and-restore-users-policies.patch +Patch177: bz1342376-3-rabbitmq-cluster-backup-and-restore-users-policies.patch +Patch178: bz1436189-sybase.patch +Patch179: bz1465822-OCF-improve-locking.patch +Patch180: bz1466187-SAPInstance-IS_ERS-parameter-for-ASCS-ERS-Netweaver.patch +Patch181: bz1455305-VirtualDomain-fix-sed-migrate_options.patch +Patch182: bz1462802-systemd-tmpfiles.patch +Patch183: bz1445628-findif-improve-IPv6-NIC-detection.patch +Patch184: bz1489734-1-support-per-host-per-bundle-attribs.patch +Patch185: bz1489734-2-support-per-host-per-bundle-attribs.patch +Patch186: bz1496393-NovaEvacuate-Instance-HA-OSP12.patch +Patch187: bz1500352-amazon-aws-agents.patch +Patch188: bz1465827-mysql-fix-master-score-maintenance.patch +Patch189: bz1508366-docker-dont-ignore-stopped-containers.patch +Patch190: bz1508362-docker-improve-exit-reasons.patch +Patch191: bz1484473-ethmonitor-vlan-fix.patch +Patch192: bz1504112-nfsserver-allow-stop-to-timeout.patch +Patch193: bz1457382-portblock-suppress-dd-output.patch +Patch194: bz1364242-ethmonitor-add-intel-omnipath-support.patch +Patch195: bz1499677-galera-recover-from-empty-gvwstate.dat.patch +Patch196: bz1516180-db2-fix-hadr-promote-when-master-failed.patch +Patch197: bz1516435-azure-lb.patch +Patch198: bz1512580-CTDB-fix-probe.patch +Patch199: bz1520574-ocf_attribute_target-fallback-fix.patch +Patch200: bz1523953-CTDB-detect-new-config-path.patch +Patch201: bz1533168-NovaEvacuate-add-support-for-keystone-v3-authentication.patch +Patch202: bz1536548-sap_redhat_cluster_connector-fix-unknown-gvi-function.patch +Patch203: bz1543366-redis-add-support-for-tunneling-replication-traffic.patch +Patch204: bz1546083-galera-fix-temp-logfile-rights.patch + +Obsoletes: heartbeat-resources <= %{version} +Provides: heartbeat-resources = %{version} + +## Setup/build bits +BuildRoot: %(mktemp -ud %{_tmppath}/%{name}-%{version}-%{release}-XXXXXX) + +# Build dependencies +BuildRequires: automake autoconf pkgconfig +BuildRequires: perl python-devel +BuildRequires: libxslt glib2-devel +BuildRequires: which + +%if %{systemd_native} +BuildRequires: pkgconfig(systemd) +%endif + +%if 0%{?fedora} || 0%{?centos_version} || 0%{?rhel} +#BuildRequires: cluster-glue-libs-devel +BuildRequires: docbook-style-xsl docbook-dtds +%if 0%{?rhel} == 0 +BuildRequires: libnet-devel +%endif +%endif + +## Runtime deps +# system tools shared by several agents +Requires: /bin/bash /bin/grep /bin/sed /bin/gawk +Requires: /bin/ps /usr/bin/pkill /bin/hostname /bin/netstat +Requires: /usr/sbin/fuser /bin/mount + +# Filesystem / fs.sh / netfs.sh +Requires: /sbin/fsck +Requires: /usr/sbin/fsck.ext2 /usr/sbin/fsck.ext3 /usr/sbin/fsck.ext4 +Requires: /usr/sbin/fsck.xfs +Requires: /sbin/mount.nfs /sbin/mount.nfs4 /usr/sbin/mount.cifs + +# IPaddr2 +Requires: /sbin/ip + +# LVM / lvm.sh +Requires: /usr/sbin/lvm + +# nfsserver / netfs.sh +Requires: /usr/sbin/rpc.nfsd /sbin/rpc.statd /usr/sbin/rpc.mountd + +# rgmanager +%if %{with rgmanager} +# ip.sh +Requires: /usr/sbin/ethtool +Requires: /sbin/rdisc /usr/sbin/arping /bin/ping /bin/ping6 + +# nfsexport.sh +Requires: /sbin/findfs +Requires: /sbin/quotaon /sbin/quotacheck +%endif + +## Runtime dependencies required to guarantee heartbeat agents +## are functional +%if %{with linuxha} +# ethmonitor requires the bc calculator +Requires: bc +# tools needed for Filesystem resource +Requires: psmisc +# Tools needed for clvm resource. +Requires: procps-ng +%endif + +%description +A set of scripts to interface with several services to operate in a +High Availability environment for both Pacemaker and rgmanager +service managers. + +%ifarch x86_64 ppc64le +%package sap +License: GPLv2+ +Summary: SAP cluster resource agents and connector script +%if 0%{?fedora} || 0%{?centos_version} || 0%{?rhel} +Group: System Environment/Base +%else +Group: Productivity/Clustering/HA +%endif +Requires: %{name} = %{version}-%{release} +Requires: perl + +%description sap +The SAP resource agents and connector script interface with +Pacemaker to allow SAP instances to be managed in a cluster +environment. +%endif + +%ifarch x86_64 ppc64le +%package sap-hana +License: GPLv2+ +Summary: SAP HANA cluster resource agents +%if 0%{?fedora} || 0%{?centos_version} || 0%{?rhel} +Group: System Environment/Base +%else +Group: Productivity/Clustering/HA +%endif +Requires: %{name} = %{version}-%{release} +Requires: perl + +%description sap-hana +The SAP HANA resource agents interface with Pacemaker to allow +SAP instances to be managed in a cluster environment. +%endif + +%prep +%if 0%{?suse_version} == 0 && 0%{?fedora} == 0 && 0%{?centos_version} == 0 && 0%{?rhel} == 0 +%{error:Unable to determine the distribution/version. This is generally caused by missing /etc/rpm/macros.dist. Please install the correct build packages or define the required macros manually.} +exit 1 +%endif +%setup -q -n %{upstream_prefix}-%{upstream_version} +%setup -a 1 -n %{upstream_prefix}-%{upstream_version} +%patch1 -p1 +%patch2 -p1 +%patch3 -p1 +%patch4 -p1 +%patch5 -p1 +%patch6 -p1 +%patch7 -p1 +%patch8 -p1 +%patch9 -p1 +%patch10 -p1 +%patch11 -p1 +%patch12 -p1 -b .bz917681.1 +%patch13 -p1 -b .bz917681.1 +%patch14 -p1 +%patch15 -p1 +%patch16 -p1 +%patch17 -p1 +%patch18 -p1 +%patch19 -p1 +%patch20 -p1 +%patch21 -p1 +%patch22 -p1 +%patch23 -p1 +%patch24 -p1 +%patch25 -p1 +%patch26 -p1 +%patch27 -p1 +%patch28 -p1 +%patch29 -p1 +%patch30 -p1 +%patch31 -p1 +%patch32 -p1 +%patch33 -p1 +%patch34 -p1 +%patch35 -p1 +%patch36 -p1 +%patch37 -p1 +%patch38 -p1 +%patch39 -p1 +%patch40 -p1 +%patch41 -p1 +%patch42 -p1 +%patch43 -p1 +%patch44 -p1 +%patch45 -p1 +%patch46 -p1 +%patch47 -p1 +%patch48 -p1 +%patch49 -p1 +%patch50 -p1 +%patch51 -p1 +%patch52 -p1 +%patch53 -p1 +%patch54 -p1 +%patch55 -p1 +%patch56 -p1 +%patch57 -p1 +%patch58 -p1 +%patch59 -p1 +%patch60 -p1 +%patch61 -p1 +%patch62 -p1 +%patch63 -p1 +%patch64 -p1 +%patch65 -p1 +%patch66 -p1 +%patch67 -p1 +%patch68 -p1 +%patch69 -p1 +%patch70 -p1 +%patch71 -p1 +%patch72 -p1 +%patch73 -p1 +%patch74 -p1 +%patch75 -p1 +%patch76 -p1 +%patch77 -p1 +%patch78 -p1 +%patch79 -p1 +%patch80 -p1 +%patch81 -p1 +%patch82 -p1 +%patch83 -p1 +%patch84 -p1 +%patch85 -p1 +%patch86 -p1 +%patch87 -p1 +%patch88 -p1 +%patch89 -p1 +%patch90 -p1 +%patch91 -p1 +%patch92 -p1 +%patch93 -p1 +%patch94 -p1 +%patch95 -p1 +%patch96 -p1 +%patch97 -p1 +%patch98 -p1 +%patch99 -p1 +%patch100 -p1 +%patch101 -p1 +%patch102 -p1 +%patch103 -p1 +%patch104 -p1 +%patch105 -p1 +%patch106 -p1 +%patch107 -p1 +%patch108 -p1 +%patch109 -p1 +%patch110 -p1 +%patch111 -p1 -F2 +%patch112 -p1 +%patch113 -p1 +%patch114 -p1 +%patch115 -p1 +%patch116 -p1 +%patch117 -p1 +%patch118 -p1 +%patch119 -p1 -F2 +%patch120 -p1 +%patch121 -p1 +%patch122 -p1 +%patch123 -p1 +%patch124 -p1 -F2 +%patch125 -p1 +%patch126 -p1 +%patch127 -p1 +%patch128 -p1 +%patch129 -p1 +%patch130 -p1 +%patch131 -p1 -F1 +%patch132 -p1 +%patch133 -p1 +%patch134 -p1 +%patch135 -p1 +%patch136 -p1 +%patch137 -p1 +%patch138 -p1 +%patch139 -p1 +%patch140 -p1 +%patch141 -p1 +%patch142 -p1 +%patch143 -p1 +%patch144 -p1 +%patch145 -p1 +%patch146 -p1 +%patch147 -p1 +%patch148 -p1 +%patch149 -p1 +%patch150 -p1 +%patch151 -p1 +%patch152 -p1 +%patch153 -p1 +%patch154 -p1 +%patch155 -p1 +%patch156 -p1 +%patch157 -p1 +%patch158 -p1 +%patch159 -p1 +%patch160 -p1 +%patch161 -p1 +%patch162 -p1 -F2 +%patch163 -p1 +%patch164 -p1 +%patch165 -p1 +%patch166 -p1 +%patch167 -p1 +%patch168 -p1 +%patch169 -p1 +%patch170 -p1 +%patch171 -p1 +#%patch172 -p1 +#%patch173 -p1 +%patch174 -p1 +%patch175 -p1 +%patch176 -p1 +%patch177 -p1 +%patch178 -p1 +%patch179 -p1 +%patch180 -p1 +%patch181 -p1 +%patch182 -p1 +%patch183 -p1 +%patch184 -p1 +%patch185 -p1 -F2 +%patch186 -p1 +%patch187 -p1 +%patch188 -p1 +%patch189 -p1 +%patch190 -p1 +%patch191 -p1 +%patch192 -p1 +%patch193 -p1 +%patch194 -p1 +%patch195 -p1 +%patch196 -p1 +%patch197 -p1 +%patch198 -p1 -F2 +%patch199 -p1 +%patch200 -p1 -F2 +%patch201 -p1 +%patch202 -p1 +%patch203 -p1 +%patch204 -p1 + +%build +if [ ! -f configure ]; then + ./autogen.sh +fi + +chmod 755 heartbeat/awseip +chmod 755 heartbeat/awsvip +chmod 755 heartbeat/aws-vpc-move-ip +chmod 755 heartbeat/azure-lb +chmod 755 heartbeat/galera +chmod 755 heartbeat/garbd +chmod 755 heartbeat/mysql-common.sh +chmod 755 heartbeat/nagios +chmod 755 heartbeat/nfsnotify +chmod 755 heartbeat/docker +chmod 755 heartbeat/rabbitmq-cluster +chmod 755 heartbeat/redis +chmod 755 heartbeat/iface-vlan +chmod 755 heartbeat/nova-compute-wait +chmod 755 heartbeat/oraasm +chmod 755 heartbeat/NovaEvacuate +chmod 755 heartbeat/NodeUtilization +chmod 755 heartbeat/SAPHana +chmod 755 heartbeat/SAPHanaTopology +chmod 755 heartbeat/sybaseASE + +%if 0%{?fedora} >= 11 || 0%{?centos_version} > 5 || 0%{?rhel} > 5 +CFLAGS="$(echo '%{optflags}')" +%global conf_opt_fatal "--enable-fatal-warnings=no" +%else +CFLAGS="${CFLAGS} ${RPM_OPT_FLAGS}" +%global conf_opt_fatal "--enable-fatal-warnings=yes" +%endif + +%if %{with rgmanager} +%global rasset rgmanager +%endif +%if %{with linuxha} +%global rasset linux-ha +%endif +%if %{with rgmanager} && %{with linuxha} +%global rasset all +%endif + +export CFLAGS + +chmod 755 heartbeat/clvm + +%configure \ + %{conf_opt_fatal} \ +%if %{defined _unitdir} + --with-systemdsystemunitdir=%{_unitdir} \ +%endif +%if %{defined _tmpfilesdir} + --with-systemdtmpfilesdir=%{_tmpfilesdir} \ +%endif + --with-pkg-name=%{name} \ + --with-ras-set=%{rasset} \ + --with-ocft-cases=fedora + +%if %{defined jobs} +JFLAGS="$(echo '-j%{jobs}')" +%else +JFLAGS="$(echo '%{_smp_mflags}')" +%endif + +make $JFLAGS + +%install +rm -rf %{buildroot} +make install DESTDIR=%{buildroot} + +test -d %{buildroot}/usr/sbin || mkdir %{buildroot}/usr/sbin +mv %{sap_script_prefix}-%{sap_hash}/sap_redhat_cluster_connector %{buildroot}/usr/sbin/sap_redhat_cluster_connector + +## tree fixup +# remove docs (there is only one and they should come from doc sections in files) +rm -rf %{buildroot}/usr/share/doc/resource-agents + +## +# Create symbolic link between IPAddr and IPAddr2 +## +rm -f %{buildroot}/usr/lib/ocf/resource.d/heartbeat/IPaddr +ln -s /usr/lib/ocf/resource.d/heartbeat/IPaddr2 %{buildroot}/usr/lib/ocf/resource.d/heartbeat/IPaddr + +%clean +rm -rf %{buildroot} + +%files +%defattr(-,root,root) +%doc AUTHORS COPYING COPYING.GPLv3 ChangeLog +%if %{with linuxha} +%doc doc/README.webapps +%doc %{_datadir}/%{name}/ra-api-1.dtd +%endif + +%if %{with rgmanager} +%{_datadir}/cluster +%{_sbindir}/rhev-check.sh +%endif + +%if %{with linuxha} +%dir /usr/lib/ocf +%dir /usr/lib/ocf/resource.d +%dir /usr/lib/ocf/lib + +/usr/lib/ocf/lib/heartbeat + +/usr/lib/ocf/resource.d/heartbeat +/usr/lib/ocf/resource.d/openstack +%if %{with rgmanager} +/usr/lib/ocf/resource.d/redhat +%endif + +%if %{defined _unitdir} +%{_unitdir}/resource-agents-deps.target +%endif +%if %{defined _tmpfilesdir} +%{_tmpfilesdir}/%{name}.conf +%endif + +%dir %{_datadir}/%{name} +%dir %{_datadir}/%{name}/ocft +%{_datadir}/%{name}/ocft/configs +%{_datadir}/%{name}/ocft/caselib +%{_datadir}/%{name}/ocft/README +%{_datadir}/%{name}/ocft/README.zh_CN + +%{_sbindir}/ocft + +%{_includedir}/heartbeat + +%dir %attr (1755, root, root) %{_var}/run/resource-agents + +%{_mandir}/man7/*.7* + +### +# Supported, but in another sub package +### +%exclude %{_sbindir}/sap_redhat_cluster_connector +%exclude %{_sbindir}/show_SAPHanaSR_attributes +%exclude /usr/lib/ocf/resource.d/heartbeat/SAP* +%exclude /usr/lib/ocf/lib/heartbeat/sap* +%exclude %{_mandir}/man7/*SAP* + +### +# Unsupported +### +%exclude /usr/lib/ocf/resource.d/heartbeat/AoEtarget +%exclude /usr/lib/ocf/resource.d/heartbeat/AudibleAlarm +%exclude /usr/lib/ocf/resource.d/heartbeat/ClusterMon +%exclude /usr/lib/ocf/resource.d/heartbeat/EvmsSCC +%exclude /usr/lib/ocf/resource.d/heartbeat/Evmsd +%exclude /usr/lib/ocf/resource.d/heartbeat/ICP +%exclude /usr/lib/ocf/resource.d/heartbeat/LinuxSCSI +%exclude /usr/lib/ocf/resource.d/heartbeat/ManageRAID +%exclude /usr/lib/ocf/resource.d/heartbeat/ManageVE +%exclude /usr/lib/ocf/resource.d/heartbeat/Pure-FTPd +%exclude /usr/lib/ocf/resource.d/heartbeat/Raid1 +%exclude /usr/lib/ocf/resource.d/heartbeat/ServeRAID +%exclude /usr/lib/ocf/resource.d/heartbeat/SphinxSearchDaemon +%exclude /usr/lib/ocf/resource.d/heartbeat/Stateful +%exclude /usr/lib/ocf/resource.d/heartbeat/SysInfo +%exclude /usr/lib/ocf/resource.d/heartbeat/VIPArip +%exclude /usr/lib/ocf/resource.d/heartbeat/WAS +%exclude /usr/lib/ocf/resource.d/heartbeat/WAS6 +%exclude /usr/lib/ocf/resource.d/heartbeat/WinPopup +%exclude /usr/lib/ocf/resource.d/heartbeat/Xen +%exclude /usr/lib/ocf/resource.d/heartbeat/anything +%exclude /usr/lib/ocf/resource.d/heartbeat/asterisk +%exclude /usr/lib/ocf/resource.d/heartbeat/eDir88 +%exclude /usr/lib/ocf/resource.d/heartbeat/fio +%exclude /usr/lib/ocf/resource.d/heartbeat/ids +%exclude /usr/lib/ocf/resource.d/heartbeat/iscsi +%exclude /usr/lib/ocf/resource.d/heartbeat/jboss +%exclude /usr/lib/ocf/resource.d/heartbeat/ldirectord +%exclude /usr/lib/ocf/resource.d/heartbeat/lxc +%exclude /usr/lib/ocf/resource.d/heartbeat/pingd +%exclude /usr/lib/ocf/resource.d/heartbeat/pound +%exclude /usr/lib/ocf/resource.d/heartbeat/proftpd +%exclude /usr/lib/ocf/resource.d/heartbeat/scsi2reservation +%exclude /usr/lib/ocf/resource.d/heartbeat/sfex +%exclude /usr/lib/ocf/resource.d/heartbeat/syslog-ng +%exclude /usr/lib/ocf/resource.d/heartbeat/varnish +%exclude /usr/lib/ocf/resource.d/heartbeat/vmware +%exclude /usr/lib/ocf/resource.d/heartbeat/zabbixserver +%exclude /usr/lib/ocf/resource.d/heartbeat/mysql-proxy +%exclude /usr/lib/ocf/resource.d/heartbeat/rsyslog +%exclude %{_mandir}/man7/ocf_heartbeat_AoEtarget.7.gz +%exclude %{_mandir}/man7/ocf_heartbeat_AudibleAlarm.7.gz +%exclude %{_mandir}/man7/ocf_heartbeat_ClusterMon.7.gz +%exclude %{_mandir}/man7/ocf_heartbeat_EvmsSCC.7.gz +%exclude %{_mandir}/man7/ocf_heartbeat_Evmsd.7.gz +%exclude %{_mandir}/man7/ocf_heartbeat_ICP.7.gz +%exclude %{_mandir}/man7/ocf_heartbeat_IPaddr.7.gz +%exclude %{_mandir}/man7/ocf_heartbeat_LinuxSCSI.7.gz +%exclude %{_mandir}/man7/ocf_heartbeat_ManageRAID.7.gz +%exclude %{_mandir}/man7/ocf_heartbeat_ManageVE.7.gz +%exclude %{_mandir}/man7/ocf_heartbeat_Pure-FTPd.7.gz +%exclude %{_mandir}/man7/ocf_heartbeat_Raid1.7.gz +%exclude %{_mandir}/man7/ocf_heartbeat_ServeRAID.7.gz +%exclude %{_mandir}/man7/ocf_heartbeat_SphinxSearchDaemon.7.gz +%exclude %{_mandir}/man7/ocf_heartbeat_Stateful.7.gz +%exclude %{_mandir}/man7/ocf_heartbeat_SysInfo.7.gz +%exclude %{_mandir}/man7/ocf_heartbeat_VIPArip.7.gz +%exclude %{_mandir}/man7/ocf_heartbeat_WAS.7.gz +%exclude %{_mandir}/man7/ocf_heartbeat_WAS6.7.gz +%exclude %{_mandir}/man7/ocf_heartbeat_WinPopup.7.gz +%exclude %{_mandir}/man7/ocf_heartbeat_Xen.7.gz +%exclude %{_mandir}/man7/ocf_heartbeat_anything.7.gz +%exclude %{_mandir}/man7/ocf_heartbeat_asterisk.7.gz +%exclude %{_mandir}/man7/ocf_heartbeat_eDir88.7.gz +%exclude %{_mandir}/man7/ocf_heartbeat_fio.7.gz +%exclude %{_mandir}/man7/ocf_heartbeat_ids.7.gz +%exclude %{_mandir}/man7/ocf_heartbeat_iscsi.7.gz +%exclude %{_mandir}/man7/ocf_heartbeat_jboss.7.gz +%exclude %{_mandir}/man7/ocf_heartbeat_lxc.7.gz +%exclude %{_mandir}/man7/ocf_heartbeat_pingd.7.gz +%exclude %{_mandir}/man7/ocf_heartbeat_pound.7.gz +%exclude %{_mandir}/man7/ocf_heartbeat_proftpd.7.gz +%exclude %{_mandir}/man7/ocf_heartbeat_scsi2reservation.7.gz +%exclude %{_mandir}/man7/ocf_heartbeat_sfex.7.gz +%exclude %{_mandir}/man7/ocf_heartbeat_syslog-ng.7.gz +%exclude %{_mandir}/man7/ocf_heartbeat_varnish.7.gz +%exclude %{_mandir}/man7/ocf_heartbeat_vmware.7.gz +%exclude %{_mandir}/man7/ocf_heartbeat_zabbixserver.7.gz +%exclude %{_mandir}/man7/ocf_heartbeat_mysql-proxy.7.gz +%exclude %{_mandir}/man7/ocf_heartbeat_rsyslog.7.gz + +### +# Other excluded files. +### +# This tool has to be updated for the new pacemaker lrmd. +%exclude %{_sbindir}/ocf-tester +%exclude %{_mandir}/man8/ocf-tester.8* +# ldirectord is not supported +%exclude /etc/ha.d/resource.d/ldirectord +%exclude /etc/init.d/ldirectord +%exclude /etc/logrotate.d/ldirectord +%exclude /usr/sbin/ldirectord +%exclude %{_mandir}/man8/ldirectord.8.gz + +# For compatability with pre-existing agents +%dir %{_sysconfdir}/ha.d +%{_sysconfdir}/ha.d/shellfuncs + +%{_libexecdir}/heartbeat +%endif + +%if %{with rgmanager} +%post -n resource-agents +ccs_update_schema > /dev/null 2>&1 ||: +%endif + +%ifarch x86_64 ppc64le +%files sap +%defattr(-,root,root) +%{_sbindir}/sap_redhat_cluster_connector +/usr/lib/ocf/resource.d/heartbeat/SAP* +/usr/lib/ocf/lib/heartbeat/sap* +%{_mandir}/man7/*SAP* +%exclude %{_mandir}/man7/*SAPHana* +%exclude /usr/lib/ocf/resource.d/heartbeat/SAPHana* +%endif + +%ifarch x86_64 ppc64le +%files sap-hana +%defattr(-,root,root) +/usr/lib/ocf/resource.d/heartbeat/SAPHana* +%{_mandir}/man7/*SAPHana* +%endif + +%changelog +* Thu Feb 22 2018 Oyvind Albrigtsen - 3.9.5-124 +- awseip/awsvip: increase default "api_delay" to 3s to avoid failures + + Resolves: rhbz#1500352 + +* Wed Feb 21 2018 Oyvind Albrigtsen - 3.9.5-123 +- awseip: fix for multi-NICs + + Resolves: rhbz#1547218 + +* Mon Feb 19 2018 Oyvind Albrigtsen - 3.9.5-122 +- galera: fix temp logfile rights to support MySQL 10.1.21+ + + Resolves: rhbz#1546083 + +* Mon Feb 12 2018 Oyvind Albrigtsen - 3.9.5-121 +- redis: support tunneling replication traffic + + Resolves: rhbz#1543366 + +* Tue Jan 23 2018 Oyvind Albrigtsen - 3.9.5-120 +- sap_redhat_cluster_connector: fix unknown gvi function + + Resolves: rhbz#1536548 + +* Thu Jan 11 2018 Oyvind Albrigtsen - 3.9.5-119 +- NovaEvacuate: add support for keystone v3 authentication + + Resolves: rhbz#1533168 + +* Mon Dec 11 2017 Oyvind Albrigtsen - 3.9.5-118 +- CTDB: detect new config path + + Resolves: rhbz#1523953 + +* Thu Dec 7 2017 Oyvind Albrigtsen - 3.9.5-117 +- ocf_attribute_target: add fallback for Pacemaker versions without + bundle support + + Resolves: rhbz#1520574 + +* Fri Dec 1 2017 Oyvind Albrigtsen - 3.9.5-116 +- azure-lb: new resource agent +- CTDB: fix initial probe + + Resolves: rhbz#1516435 + Resolves: rhbz#1512580 + +* Wed Nov 22 2017 Oyvind Albrigtsen - 3.9.5-115 +- db2: fix HADR promote when master failed + + Resolves: rhbz#1516180 + +* Thu Nov 9 2017 Oyvind Albrigtsen - 3.9.5-114 +- ethmonitor: add intel omnipath support + + Resolves: rhbz#1364242 + +* Thu Nov 9 2017 Oyvind Albrigtsen - 3.9.5-113 +- galera: recover from empty gvwstate.dat + + Resolves: rhbz#1499677 + +* Thu Nov 2 2017 Oyvind Albrigtsen - 3.9.5-112 +- ethmonitor: VLAN fix +- nfsserver: allow stop to timeout +- portblock: suppress dd output +- LVM: dont use "vgscan --cache" + + Resolves: rhbz#1484473 + Resolves: rhbz#1504112 + Resolves: rhbz#1457382 + Resolves: rhbz#1486888 + +* Wed Nov 1 2017 Oyvind Albrigtsen - 3.9.5-111 +- docker: dont ignore stopped containers +- docker: improve exit reasons + + Resolves: rhbz#bz1508366 + Resolves: rhbz#bz1508362 + +* Thu Oct 26 2017 Oyvind Albrigtsen - 3.9.5-110 +- mysql: fix master score after maintenance mode + + Resolves: rhbz#1465827 + +* Fri Oct 20 2017 Oyvind Albrigtsen - 3.9.5-109 +- awseip/awsvip/aws-vpc-move-ip: new resource agents for Amazon AWS + + Resolves: rhbz#1500352 + +* Thu Sep 28 2017 Oyvind Albrigtsen - 3.9.5-107 +- NovaEvacuate: changes to support Instance HA on OSP12 + + Resolves: rhbz#1496393 + +* Wed Sep 20 2017 Oyvind Albrigtsen - 3.9.5-106 +- sybaseASE: new resource agent +- OCF: improve locking +- SAPInstance: add "IS_ERS" parameter for ASCS ERS Netweaver +- VirtualDomain: fix "migrate_options" parsing +- systemd: use tmpfiles.d to create temp directory on boot +- findif: improve IPv6 NIC detection +- support per-host and per-bundle attributes + + Resolves: rhbz#1436189 + Resolves: rhbz#1465822 + Resolves: rhbz#1466187 + Resolves: rhbz#1455305 + Resolves: rhbz#1462802 + Resolves: rhbz#1445628 + Resolves: rhbz#1489734 + + +* Fri Jun 23 2017 Oyvind Albrigtsen - 3.9.5-105 +- rabbitmq-cluster: fix to keep expiration policy + + Resolves: rhbz#1342376 + +* Fri Jun 2 2017 Oyvind Albrigtsen - 3.9.5-104 +- SAPHana/SAPHanaTopology: update to version 0.152.21 + + Resolves: rhbz#1449681 + +* Wed May 31 2017 Oyvind Albrigtsen - 3.9.5-102 +- LVM: update metadata on start/relocate +- LVM: warn when cache mode is not writethrough + + Resolves: rhbz#1451933 + +* Tue May 30 2017 Oyvind Albrigtsen - 3.9.5-101 +- LVM: status check for missing VG + + Resolves: rhbz#1454699 + +* Mon May 22 2017 Oyvind Albrigtsen - 3.9.5-100 +- docker: add "mount_points" parameter to be able to create directories + + Resolves: rhbz#1452049 + +* Tue May 16 2017 Oyvind Albrigtsen - 3.9.5-99 +- galera: fix bootstrap when cluster has no data + + Resolves: rhbz#1451097 + +* Wed May 3 2017 Oyvind Albrigtsen - 3.9.5-97 +- systemd: add drop-in for clvmd and LVM to avoid fencing on shutdown + + Resolves: rhbz#1316130 + +* Wed Apr 26 2017 Oyvind Albrigtsen - 3.9.5-96 +- IPaddr2: add "preferred_lft" parameter for IPv6 + + Resolves: rhbz#1445861 + +* Fri Apr 7 2017 Oyvind Albrigtsen - 3.9.5-95 +- DB2: fix HADR for DB2 V98 or later + + Resolves: rhbz#1427574 + +* Tue Apr 4 2017 Oyvind Albrigtsen - 3.9.5-94 +- send_arp: update usage info + + Resolves: rhbz#1380405 + +* Tue Apr 4 2017 Oyvind Albrigtsen - 3.9.5-93 +- rabbitmq-cluster: allow to run on Pacemaker remote nodes +- oraasm: new resource agent for Oracle ASM + + Resolves: rhbz#1435982 + Resolves: rhbz#1411225 + +* Tue Mar 28 2017 Oyvind Albrigtsen - 3.9.5-90 +- ethmonitor: fix to monitor interface without IP + + Resolves: rhbz#bz1408656 + +* Tue Mar 28 2017 Oyvind Albrigtsen - 3.9.5-89 +- NodeUtilization: new resource agent +- iSCSILogicalUnit, iSCSITarget: make concurrent-safe +- IPaddr2: send gratuitious ARP packets during monitor action +- named: add support for rndc options +- CTDB: fix logging +- IPaddr2: add option to detect duplicate IP + + Resolves: rhbz#1430304 + Resolves: rhbz#1430385 + Resolves: rhbz#1434351 + Resolves: rhbz#1435171 + Resolves: rhbz#1077888 + Resolves: rhbz#1393189 + +* Thu Mar 9 2017 Oyvind Albrigtsen - 3.9.5-88 +- clvm: remove reload action +- iSCSILogicalUnit: add IPv6-support +- IPsrcaddr: fix issue with duplicate routes +- pgsql: don't use crm_failcount +- ocf_log: use same log format as Pacemaker + + Resolves: rhbz#1359252 + Resolves: rhbz#1389300 + Resolves: rhbz#1400172 + Resolves: rhbz#1420565 + Resolves: rhbz#1427611 + +* Thu Feb 2 2017 Oyvind Albrigtsen - 3.9.5-87 +- LVM: fix for "partial vg activates when partial_activation=false" +- redis: notify clients of master being demoted +- SAP/SAP HANA: ppc64le build + + Resolves: rhbz#1392432 + Resolves: rhbz#1305549 + Resolves: rhbz#1371088 + +* Fri Jan 27 2017 Oyvind Albrigtsen - 3.9.5-86 +- SAPDatabase: fix process count for SUSER +- rabbitmq-cluster: reset Mnesia before join + + Resolves: rhbz#1260713 + Resolves: rhbz#1397393 + +* Fri Jan 13 2017 Oyvind Albrigtsen - 3.9.5-85 +- exportfs: fix for IPv6 addresses +- SAPHana/SAPHanaTopology: update to version 0.152.17 +- Add netstat dependency + + Resolves: rhbz#1406152 + Resolves: rhbz#1395142 + Resolves: rhbz#1402370 + +* Tue Dec 20 2016 Oyvind Albrigtsen - 3.9.5-84 +- galera: prevent promote after demote +- iSCSITarget: properly create portals for lio-t +- nfsserver: dont stop rpcbind +- Filesystem: submount check +- Delay: change startdelay +- galera: last commit fix for MariaDB 10.1.18+ +- portblock: return success on stop with invalid IP +- portblock: use iptables wait + + Resolves: rhbz#1360768 + Resolves: rhbz#1376588 + Resolves: rhbz#1384955 + Resolves: rhbz#1387363 + Resolves: rhbz#1388854 + Resolves: rhbz#1391470 + Resolves: rhbz#1391580 + Resolves: rhbz#1395596 + +* Tue Nov 29 2016 Oyvind Albrigtsen - 3.9.5-83 +- nfsserver: keep options in /etc/sysconfig/nfs +- redis: fix SELinux permissions +- redis: notify clients of master being demoted + + Resolves: rhbz#1387491 + Resolves: rhbz#1390974 + Resolves: rhbz#1305549 + +* Tue Sep 20 2016 Oyvind Albrigtsen - 3.9.5-82 +- portblock: create tickle_dir if it doesn't exist +- tomcat: use systemd if available + + Resolves: rhbz#1303037 + Resolves: rhbz#1249430 + +* Mon Aug 29 2016 Oyvind Albrigtsen - 3.9.5-81 +- oracle: fix issue with C## in monprofile and inform user that + monuser must start with C## as well for container databases + + Resolves: rhbz#1328386 + +* Wed Jul 27 2016 Andrew Beekhof - 3.9.5-80 +- rabbit: Allow automatic cluster recovery before forcing it + + Resolves: rhbz#1343905 + +* Fri Jul 22 2016 Oyvind Albrigtsen - 3.9.5-79 +- oracle: use monprofile parameter + + Resolves: rhbz#1358895 + +* Thu Jul 21 2016 Oyvind Albrigtsen - 3.9.5-78 +- nfsserver: fix monitor issues causing NFS to start on + "debug-monitor" and "resource cleanup" +- nfsserver: remove "up to 10 tries" on start to avoid issues with + some services taking longer to start +- nfsserver: stop rpc-gssd to allow unmounting of "rpcpipefs_dir" + + Resolves: rhbz#1356866 + Resolves: rhbz#1126073 + Resolves: rhbz#1346733 + +* Tue Jul 5 2016 Oyvind Albrigtsen - 3.9.5-77 +- rabbitmq-cluster: add return codes for not running + + Resolves: rhbz#1342478 + +* Fri Jun 24 2016 Oyvind Albrigtsen - 3.9.5-76 +- rabbitmq-cluster: support dump/restore users for RabbitMQ v. 3.6.x + + Resolves: rhbz#1343905 + +* Mon Jun 6 2016 Oyvind Albrigtsen - 3.9.5-73 +- portblock: fix tickle_tcp bug +- nfsserver: use rpcpipefs_dir variable +- mysql: use replication_port variable +- oracle: inform user that monprofile must start with C## for + container databases + + Resolves: rhbz#1337109 + Resolves: rhbz#1337615 + Resolves: rhbz#1337124 + Resolves: rhbz#1328386 + +* Fri Jun 3 2016 Damien Ciabrini - 3.9.5-72 +- garbd: Introduces garbd resource-agent + + Resolves: rhbz#1328018 + +* Fri May 13 2016 Oyvind Albrigtsen - 3.9.5-71 +- nova-compute-wait: fix "Invalid Nova host name" issue + + Resolves: rhbz#1320783 + +* Tue May 3 2016 Oyvind Albrigtsen - 3.9.5-70 +- nfsserver: fix nfs-idmapd fails to start due to + var-lib-nfs-rpc_pipefs.mount being active + + Resolves: rhbz#1325453 + +* Tue Apr 26 2016 Oyvind Albrigtsen - 3.9.5-69 +- SAP HANA: add Multiple Components One System (MCOS) support +- VirtualDomain: add migration_speed and migration_downtime options +- VirtualDomain: fix unnecessary error when probing nonexistent domain +- oralsnr: fix status check fail when username is more than 8 characters long +- oracle: fix unable to start because of ORA-01081 + + Resolves: rhbz#1289107 + Resolves: rhbz#1296406 + Resolves: rhbz#1307160 + Resolves: rhbz#1317578 + Resolves: rhbz#1318985 + +* Thu Mar 17 2016 Damien Ciabrini - 3.9.5-68 +- galera: recover blocked nodes with --tc-heuristics-recover + + Resolves: rhbz#1284526 + +* Tue Mar 1 2016 Oyvind Albrigtsen - 3.9.5-67 +- sap_redhat_cluster_connector: add support for hostnames with "-" +- NovaEvacuate: simplify nova check +- portblock: new resource agent + + Resolves: rhbz#1265527 + Resolves: rhbz#1287314 + Resolves: rhbz#1303037 + +* Tue Mar 1 2016 Peter Lemenkov - 3.9.5-65 +- RabbitMQ: keep users during resource reload (small regression fix) + + Resolves: rhbz#1303803 + +* Tue Mar 1 2016 Peter Lemenkov - 3.9.5-64 +- RabbitMQ: keep users during resource reload + + Resolves: rhbz#1303803 + +* Tue Mar 1 2016 Oyvind Albrigtsen - 3.9.5-63 +- IPaddr2: use IPv6 DAD for collision detection +- nagios: new resource agent + + Resolves: rhbz#1276699 + Resolves: rhbz#1212632 + +* Mon Feb 29 2016 Oyvind Albrigtsen - 3.9.5-62 +- tomcat: fix for SELinux enforced mode +- send_arp: fix buffer overflow on infiniband devices +- mysql: fix tmpfile leak +- VirtualDomain: add migrate_options parameter +- VirtualDomain: fix issue where config file might get removed +- VirtualDomain: fix locale in stop and status functions() + + Resolves: rhbz#1249430 + Resolves: rhbz#1250728 + Resolves: rhbz#1263348 + Resolves: rhbz#1242181 + Resolves: rhbz#1242558 + Resolves: rhbz#1301189 + +* Mon Feb 22 2016 Oyvind Albrigtsen - 3.9.5-60 +- rabbitmq-cluster: fix to forget stopped cluster nodes +- nfsserver: fix systemd status detection + + Resolves: rhbz#1247303 + Resolves: rhbz#1126073 + +* Wed Feb 3 2016 Oyvind Albrigtsen - 3.9.5-57 +- Replace NovaCompute with nova-compute-wait which lets systemd + manage the nova-compute process + + Resolves: rhbz#1304011 + +* Wed Feb 3 2016 Oyvind Albrigtsen - 3.9.5-56 +- galera: add custom host/port support + + Resolves: rhbz#1299404 + +* Tue Feb 2 2016 Oyvind Albrigtsen - 3.9.5-55 +- NovaCompute/NovaEvacuate: Fix 'evacute' typo +- NovaEvacuate invoke off action + + Resolves: rhbz#1282723 + Resolves: rhbz#1287303 + +* Mon Sep 7 2015 Fabio M. Di Nitto - 3.9.5-54 +- Fix redis client password regexp + Resolves: rhbz#1251484 + +* Thu Sep 3 2015 Fabio M. Di Nitto - 3.9.5-53 +- Add support redis client password authentication + Resolves: rhbz#1251484 + +* Thu Jul 23 2015 David Vossel - 3.9.5-52 +- Only build SAP hana packages for x86_64 + + Resolves: rhbz#1244827 + +* Thu Jul 23 2015 David Vossel - 3.9.5-51 +- Properly include SAP hana packages in correct subpackage. + + Resolves: rhbz#1244827 + +* Thu Jul 23 2015 David Vossel - 3.9.5-50 +- Sync SAP Hana agents with upstream + + Resolves: rhbz#1244827 + +* Wed Jul 22 2015 David Vossel - 3.9.5-49 +- Place SAP Hana agents in sap-hana subpackage + + Resolves: rhbz#1244827 + +* Fri Jul 10 2015 David Vossel - 3.9.5-48 +- add support for oracle resource agents + + Resolves: rhbz#1232376 + +* Thu Jun 25 2015 David Vossel - 3.9.5-47 +- NovaCompute and NovaEvacuate updates +- dhcpd chroot fix +- redis 0byte error fix + + Resolves: rhbz#1214360 + Resolves: rhbz#1227293 + Resolves: rhbz#1231032 + +* Thu Jun 25 2015 David Vossel - 3.9.5-46 +- iface-vlan agent +- Allow partial activation when physical volumes are missing. +- Properly handle 'includes' during apache config parsing +- Support for NovaCompute resource-agent + + Resolves: rhbz#1160365 + Resolves: rhbz#1214781 + Resolves: rhbz#1223615 + Resolves: rhbz#1214360 + +* Wed Apr 29 2015 David Vossel - 3.9.5-45 +- Fix clvmd usage of daemon_options +- Use better default nfsserver start timeouts +- Make nfsserver preserve options in /etc/sysconfig/nfs +- Add link_status_only option to ethmonitor agent +- Add support for nginx agent +- Add support for db2 agent +- CTDB agent updates + + Resolves: rhbz#1171162 + Resolves: rhbz#1173193 + Resolves: rhbz#1182787 + Resolves: rhbz#1213971 + Resolves: rhbz#1183136 + Resolves: rhbz#1059988 + Resolves: rhbz#1077888 + +* Tue Apr 28 2015 David Vossel - 3.9.5-44 +- For IPsrcaddr, properly handle misconfiguration in a way that + doesn't result in fencing. +- Return exit reason for invalid netmask in IPaddr2 + + Resolves: rhbz#1200756 + Resolves: rhbz#773399 + +* Mon Apr 27 2015 David Vossel - 3.9.5-43 +- Add activate_vgs option to clvmd to control activating volume + groups + + Resolves: rhbz#1198681 + +* Thu Apr 23 2015 David Vossel - 3.9.5-42 +- Improve galera resource-agent to not require use of read-only + mode to retrieve last known write sequence number. + + Resolves: rhbz#1170376 + +* Thu Feb 5 2015 David Vossel - 3.9.5-41 +- Support for redis resource-agent + + Resolves: rhbz#1189187 + +* Mon Jan 26 2015 David Vossel - 3.9.5-20.2 +- Support for rabbitmq-cluster resource-agent + + Resolves: rhbz#1185754 + +* Fri Dec 19 2014 David Vossel - 3.9.5-40 +- Remove usage of write_back from iSCSILogicalUnit + + Resolves: rhbz#1118029 + +* Thu Dec 11 2014 David Vossel - 3.9.5-39 +- Updates spec file to include iscsi resources + + Resolves: rhbz#1118029 + +* Mon Oct 27 2014 David Vossel - 3.9.5-38 +- Handle invalid monitor_cmd option for docker resource-agent + + Resolves: rhbz#1135026 + +* Sun Oct 26 2014 David Vossel - 3.9.5-37 +- Rename docker agent's 'container' arg to 'name' to avoid confusion + with pacemaker's metadata 'container' argument. +- Introduce monitor_cmd into docker agent. + + Resolves: rhbz#1135026 + +* Thu Oct 23 2014 David Vossel - 3.9.5-36 +- Fixes cleaning up stale docker containers during stop if + container instance failed. + + Resolves: rhbz#1135026 + +* Thu Oct 23 2014 David Vossel - 3.9.5-35 +- Introduces docker resource-agent for managing docker containers. + The docker agent is being released as tech preview. + + Resolves: rhbz#1135026 + +* Wed Oct 22 2014 David Vossel - 3.9.5-34 +- Fixes mysql agents behavior when monitoring resource instance + when environment validation fails. + + Resolves: rhbz#1138871 + +* Tue Sep 23 2014 David Vossel - 3.9.5-33 +- Merges latest upstream patches for galera agent +- Merges latest upstream patchs for exit reason string + + Resolves: rhbz#1116166 + Resolves: rhbz#1128933 + +* Wed Sep 17 2014 David Vossel - 3.9.5-32 +- Fixes iSCSILogicalUnit syntax error +- Fixes mysql stop operation when db storage is unavailable + + Resolves: rhbz#1118029 + Resolves: rhbz#1138871 + +* Mon Aug 25 2014 David Vossel - 3.9.5-31 +- Man page updates give pcs config examples +- add iscsi agent support +- add infiniband support to ethmonitor +- add resource-agent support of exit reason string +- add safe umount option to Filesystem resource agent + + Resolves: rhbz#1058102 + Resolves: rhbz#1118029 + Resolves: rhbz#1122285 + Resolves: rhbz#1128933 + Resolves: rhbz#1095944 + +* Fri Aug 15 2014 David Vossel - 3.9.5-30 +- Support monitor of lxc without requiring libvirt. +- Wait for filesystem modules to load during start. +- Warn users managing clustered LVM when lvmetad is in use. +- Restore VirtualDomain default start stop timeout values. +- Support exit reason string +- Auto set lvm locking type to clustered when clvmd is in use. + +Resolves: rhbz# 1083041 +Resolves: rhbz# 1083231 +Resolves: rhbz# 1097593 +Resolves: rhbz# 1105655 +Resolves: rhbz# 1128933 +Resolves: rhbz# 773395 + + +* Fri Jul 18 2014 David Vossel - 3.9.5-29 +- Support the check_user and check_passwd galera resource-agent + options. +- Minor NFS agent updates. + + Resolves: rhbz#1116166 + Resolves: rhbz#1091101 + +* Thu Jul 10 2014 David Vossel - 3.9.5-28 +- Updates to nfs server related agent. +- Introduces nfsnotify for sending NFSv3 NSM state change + notifications allowing NFSv3 clients to reclaim locks. + + Resolves: rhbz#1091101 + +* Wed Jul 09 2014 David Vossel - 3.9.5-27 +- Introducing the galera resource-agent. + + Resolves: rhbz#1116166 + +* Tue Mar 18 2014 David Vossel - 3.9.5-26 +- Handle monitor qemu based VirtualDomain resources without + requiring libvirtd even if configuration file does not + contain an 'emulator' value pointing to the emulator binary. + + Resolves: rhbz#1060367 + +* Fri Feb 14 2014 David Vossel - 3.9.5-25 +- Rename clvmd agent to clvm to avoid problems associated + with having a resource-agent named the same exact name + as the binary the agent manages. + + Resolves: rhbz#1064512 + +* Fri Feb 14 2014 David Vossel - 3.9.5-24 +- Addition of the clvmd resource-agent +- Support monitoring qemu based VirtualDomain resources without + requiring libvirtd to be running. + + Resolves: rhbz#1064512 + Resolves: rhbz#1060367 + +* Fri Jan 24 2014 Daniel Mach - 3.9.5-23 +- Mass rebuild 2014-01-24 + +* Mon Jan 20 2014 David Vossel - 3.9.5-22 +- Fixes VirtualDomain config parse error. + + Resolves: rhbz#1029061 + +* Fri Dec 27 2013 Daniel Mach - 3.9.5-21 +- Mass rebuild 2013-12-27 + +* Tue Nov 26 2013 David Vossel - 3.9.5-20 +- tomcat agent updates for pacemaker support +- slapd agent updates for pacemaker support +- Fixes missing etab file required for nfsserver + + Resolves: rhbz#1033016 + Resolves: rhbz#917681 + +* Wed Nov 20 2013 David Vossel - 3.9.5-19 +- Add back the Delay agent. + + Resolves: rhbz#917681 + +* Thu Nov 07 2013 David Vossel - 3.9.5-18 +- Remove support for (nginx, mysql-proxy, rsyslog). nginx and + mysql-proxy are not a supported projects. Rsyslog is not an + agent we will be supporting in an HA environment. + + Resolves: rhbz#917681 + +* Wed Nov 06 2013 David Vossel - 3.9.5-17 +- Split send_ua utility out of IPv6addr.c source so it can be + re-used in IPaddr2 without requiring cluster-glue. +- Fixes issue with pgsql and SAPInstance not setting transient + attributes correctly when local corosync node name is not + equal to 'uname -n' +- High: ocft: Fedora supported test cases + + Resolves: rhbz#917681 + +* Mon Oct 07 2013 David Vossel - 3.9.5-16 +- Fixes issue with mysql agent not being able to set transient + attributes on local node correctly. +- Fixes bash syntax error in VirtualDomain during 'stop' +- Fixes VirtualDomain default hypervisor usage. +- Fixes VirtualDomain 'start' of pre-defined domain + + Resolves: rhbz#917681 + Resolves: rhbz#1014641 + Resolves: rhbz#1016140 + +* Thu Sep 26 2013 David Vossel - 3.9.5-15 +- Update VirtualDomain heartbeat agent for heartbeat merger. +- Includes upstream fixes for pacemaker_remote lxc test case. + + Resolves: rhbz#917681 + +* Thu Sep 12 2013 David Vossel - 3.9.5-14 +- Add ability for apache agent to perform simple monitoring + of server request/response without requiring server-status + to be enabled. +- Fixes invalid return statement in LVM agent. +- Oracle TNS_ADMIN option + + Resolves: rhbz#917806 + Resolves: rhbz#917681 + Resolves: rhbz#799065 + +* Mon Sep 9 2013 David Vossel - 3.9.5-13 +- Use correct default config for apache + Resolves: rhbz#1005924 + +* Tue Jul 30 2013 David Vossel - 3.9.5-12 +- Symbolic links do not have file permissions. + +* Tue Jul 30 2013 David Vossel - 3.9.5-11 +- Fixes file permissions problem detected in rpmdiff test + +* Tue Jul 30 2013 David Vossel - 3.9.5-10 +- Removes ldirectord package +- Puts sap agents and connector script in subpackage +- exclude unsupported packages +- symlink ipaddr to ipaddr2 so only a single agent is supported + +* Mon Jul 29 2013 David Vossel - 3.9.5-9 +- Fixes more multi-lib problems. + +* Mon Jul 29 2013 David Vossel - 3.9.5-8 +- Add runtime dependencies section for Heartbeat agents. +- Fix multi-lib inconsistencies found during rpm diff testing. +- Add dist field back to rpm release name. + +* Tue Jul 16 2013 David Vossel - 3.9.5-7 +- Detect duplicate resources with the same volgrpname + name when using exclusive activation with tags + + Resolves: # rhbz984054 + +* Tue Jun 18 2013 David Vossel - 3.9.5-6 +- Restores rsctmp directory to upstream default. + +* Tue Jun 18 2013 David Vossel - 3.9.5-5 +- Merges redhat provider into heartbeat provider. Remove + rgmanager's redhat provider. + + Resolves: rhbz#917681 + Resolves: rhbz#928890 + Resolves: rhbz#952716 + Resolves: rhbz#960555 + +* Tue Mar 12 2013 David Vossel - 3.9.5-4 +- Fixes build system error with conditional logic involving + IPv6addr. + +* Mon Mar 11 2013 David Vossel - 3.9.5-3 +- Fixes build dependency for pod2man when building against + rhel-7. + +* Mon Mar 11 2013 David Vossel - 3.9.5-2 +- Resolves rhbz#915050 + +* Mon Mar 11 2013 David Vossel - 3.9.5-1 +- New upstream release. + +* Fri Nov 09 2012 Chris Feist - 3.9.2-5 +- Fixed upstream tarball location + +* Fri Nov 09 2012 Chris Feist - 3.9.2-4 +- Removed version after dist tag +- Resolves: rhbz#875250 + +* Mon Oct 29 2012 Chris Feist - 3.9.2-3.8 +- Remove cluster-glue-libs-devel +- Disable IPv6addr & sfex to fix deps on libplumgpl & libplum (due to + disappearance of cluster-glue in F18) + +* Sat Jul 21 2012 Fedora Release Engineering - 3.9.2-3.5 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_18_Mass_Rebuild + +* Thu Jul 5 2012 Chris Feist - 3.9.2-3.4 +- Fix location of lvm (change from /sbin to /usr/sbin) + +* Wed Apr 4 2012 Jon Ciesla - 3.9.2-3.3 +- Rebuilt to fix rawhide dependency issues (caused by move of fsck from + /sbin to /usr/sbin). + +* Fri Mar 30 2012 Jon Ciesla - 3.9.2-3.1 +- libnet rebuild. + +* Sat Jan 14 2012 Fedora Release Engineering - 3.9.2-2.1 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_17_Mass_Rebuild + +* Fri Jul 8 2011 Fabio M. Di Nitto - 3.9.2-2 +- add post call to resource-agents to integrate with cluster 3.1.4 + +* Thu Jun 30 2011 Fabio M. Di Nitto - 3.9.2-1 +- new upstream release +- fix 2 regressions from 3.9.1 + +* Mon Jun 20 2011 Fabio M. Di Nitto - 3.9.1-1 +- new upstream release +- import spec file from upstream + +* Tue Mar 1 2011 Fabio M. Di Nitto - 3.1.1-1 +- new upstream release 3.1.1 and 1.0.4 + +* Wed Feb 09 2011 Fedora Release Engineering - 3.1.0-2 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_15_Mass_Rebuild + +* Thu Dec 2 2010 Fabio M. Di Nitto - 3.1.0-1 +- new upstream release +- spec file update: + Update upstream URL + Update source URL + use standard configure macro + use standard make invokation + +* Thu Oct 7 2010 Fabio M. Di Nitto - 3.0.17-1 +- new upstream release + Resolves: rhbz#632595, rhbz#633856, rhbz#632385, rhbz#628013 + Resolves: rhbz#621313, rhbz#595383, rhbz#580492, rhbz#605733 + Resolves: rhbz#636243, rhbz#591003, rhbz#637913, rhbz#634718 + Resolves: rhbz#617247, rhbz#617247, rhbz#617234, rhbz#631943 + Resolves: rhbz#639018 + +* Thu Oct 7 2010 Andrew Beekhof - 3.0.16-2 +- new upstream release of the Pacemaker agents: 71b1377f907c + +* Thu Sep 2 2010 Fabio M. Di Nitto - 3.0.16-1 +- new upstream release + Resolves: rhbz#619096, rhbz#614046, rhbz#620679, rhbz#619680 + Resolves: rhbz#621562, rhbz#621694, rhbz#608887, rhbz#622844 + Resolves: rhbz#623810, rhbz#617306, rhbz#623816, rhbz#624691 + Resolves: rhbz#622576 + +* Thu Jul 29 2010 Fabio M. Di Nitto - 3.0.14-1 +- new upstream release + Resolves: rhbz#553383, rhbz#557563, rhbz#578625, rhbz#591003 + Resolves: rhbz#593721, rhbz#593726, rhbz#595455, rhbz#595547 + Resolves: rhbz#596918, rhbz#601315, rhbz#604298, rhbz#606368 + Resolves: rhbz#606470, rhbz#606480, rhbz#606754, rhbz#606989 + Resolves: rhbz#607321, rhbz#608154, rhbz#608887, rhbz#609181 + Resolves: rhbz#609866, rhbz#609978, rhbz#612097, rhbz#612110 + Resolves: rhbz#612165, rhbz#612941, rhbz#614127, rhbz#614356 + Resolves: rhbz#614421, rhbz#614457, rhbz#614961, rhbz#615202 + Resolves: rhbz#615203, rhbz#615255, rhbz#617163, rhbz#617566 + Resolves: rhbz#618534, rhbz#618703, rhbz#618806, rhbz#618814 + +* Mon Jun 7 2010 Fabio M. Di Nitto - 3.0.13-1 +- new upstream release + Resolves: rhbz#592103, rhbz#593108, rhbz#578617, rhbz#594626 + Resolves: rhbz#594511, rhbz#596046, rhbz#594111, rhbz#597002 + Resolves: rhbz#599643 + +* Tue May 18 2010 Andrew Beekhof - 3.0.12-2 +- libnet is not available on RHEL +- Do not package ldirectord on RHEL + Resolves: rhbz#577264 + +* Mon May 10 2010 Fabio M. Di Nitto - 3.0.12-1 +- new upstream release + Resolves: rhbz#585217, rhbz#586100, rhbz#581533, rhbz#582753 + Resolves: rhbz#582754, rhbz#585083, rhbz#587079, rhbz#588890 + Resolves: rhbz#588925, rhbz#583789, rhbz#589131, rhbz#588010 + Resolves: rhbz#576871, rhbz#576871, rhbz#590000, rhbz#589823 + +* Mon May 10 2010 Andrew Beekhof - 3.0.12-1 +- New pacemaker agents upstream release: a7c0f35916bf + + High: pgsql: properly implement pghost parameter + + High: RA: mysql: fix syntax error + + High: SAPInstance RA: do not rely on op target rc when monitoring clones (lf#2371) + + High: set the HA_RSCTMP directory to /var/run/resource-agents (lf#2378) + + Medium: IPaddr/IPaddr2: add a description of the assumption in meta-data + + Medium: IPaddr: return the correct code if interface delete failed + + Medium: nfsserver: rpc.statd as the notify cmd does not work with -v (thanks to Carl Lewis) + + Medium: oracle: reduce output from sqlplus to the last line for queries (bnc#567815) + + Medium: pgsql: implement "config" parameter + + Medium: RA: iSCSITarget: follow changed IET access policy + +* Wed Apr 21 2010 Fabio M. Di Nitto - 3.0.11-1 +- new upstream release + Resolves: rhbz#583945, rhbz#581047, rhbz#576330, rhbz#583017 + Resolves: rhbz#583019, rhbz#583948, rhbz#584003, rhbz#582017 + Resolves: rhbz#555901, rhbz#582754, rhbz#582573, rhbz#581533 +- Switch to file based Requires. + Also address several other problems related to missing runtime + components in different agents. + With the current Requires: set, we guarantee all basic functionalities + out of the box for lvm/fs/clusterfs/netfs/networking. + Resolves: rhbz#570008 + +* Sat Apr 17 2010 Andrew Beekhof - 3.0.10-2 +- New pacemaker agents upstream release + + High: RA: vmware: fix set_environment() invocation (LF 2342) + + High: RA: vmware: update to version 0.2 + + Medium: Filesystem: prefer /proc/mounts to /etc/mtab for non-bind mounts (lf#2388) + + Medium: IPaddr2: don't bring the interface down on stop (thanks to Lars Ellenberg) + + Medium: IPsrcaddr: modify the interface route (lf#2367) + + Medium: ldirectord: Allow multiple email addresses (LF 2168) + + Medium: ldirectord: fix setting defaults for configfile and ldirectord (lf#2328) + + Medium: meta-data: improve timeouts in most resource agents + + Medium: nfsserver: use default values (lf#2321) + + Medium: ocf-shellfuncs: don't log but print to stderr if connected to a terminal + + Medium: ocf-shellfuncs: don't output to stderr if using syslog + + Medium: oracle/oralsnr: improve exit codes if the environment isn't valid + + Medium: RA: iSCSILogicalUnit: fix monitor for STGT + + Medium: RA: make sure that OCF_RESKEY_CRM_meta_interval is always defined (LF 2284) + + Medium: RA: ManageRAID: require bash + + Medium: RA: ManageRAID: require bash + + Medium: RA: VirtualDomain: bail out early if config file can't be read during probe (Novell 593988) + + Medium: RA: VirtualDomain: fix incorrect use of __OCF_ACTION + + Medium: RA: VirtualDomain: improve error messages + + Medium: RA: VirtualDomain: spin on define until we definitely have a domain name + + Medium: Route: add route table parameter (lf#2335) + + Medium: sfex: don't use pid file (lf#2363,bnc#585416) + + Medium: sfex: exit with success on stop if sfex has never been started (bnc#585416) + +* Fri Apr 9 2010 Fabio M. Di Nitto - 3.0.10-1 +- New rgmanager resource agents upstream release + Resolves: rhbz#519491, rhbz#570525, rhbz#571806, rhbz#574027 + Resolves: rhbz#574215, rhbz#574886, rhbz#576322, rhbz#576335 + Resolves: rhbz#575103, rhbz#577856, rhbz#577874, rhbz#578249 + Resolves: rhbz#578625, rhbz#578626, rhbz#578628, rhbz#578626 + Resolves: rhbz#579621, rhbz#579623, rhbz#579625, rhbz#579626 + Resolves: rhbz#579059 + +* Wed Mar 24 2010 Andrew Beekhof - 3.0.9-2 +- Resolves: rhbz#572993 - Patched build process to correctly generate ldirectord man page +- Resolves: rhbz#574732 - Add libnet-devel as a dependancy to ensure IPaddrv6 is built + +* Mon Mar 1 2010 Fabio M. Di Nitto - 3.0.9-1 +- New rgmanager resource agents upstream release + Resolves: rhbz#455300, rhbz#568446, rhbz#561862, rhbz#536902 + Resolves: rhbz#512171, rhbz#519491 + +* Mon Feb 22 2010 Fabio M. Di Nitto - 3.0.8-1 +- New rgmanager resource agents upstream release + Resolves: rhbz#548133, rhbz#565907, rhbz#545602, rhbz#555901 + Resolves: rhbz#564471, rhbz#515717, rhbz#557128, rhbz#536157 + Resolves: rhbz#455300, rhbz#561416, rhbz#562237, rhbz#537201 + Resolves: rhbz#536962, rhbz#553383, rhbz#556961, rhbz#555363 + Resolves: rhbz#557128, rhbz#455300, rhbz#557167, rhbz#459630 + Resolves: rhbz#532808, rhbz#556603, rhbz#554968, rhbz#555047 + Resolves: rhbz#554968, rhbz#555047 +- spec file update: + * update spec file copyright date + * use bz2 tarball + +* Fri Jan 15 2010 Fabio M. Di Nitto - 3.0.7-2 +- Add python as BuildRequires + +* Mon Jan 11 2010 Fabio M. Di Nitto - 3.0.7-1 +- New rgmanager resource agents upstream release + Resolves: rhbz#526286, rhbz#533461 + +* Mon Jan 11 2010 Andrew Beekhof - 3.0.6-2 +- Update Pacameker agents to upstream version: c76b4a6eb576 + + High: RA: VirtualDomain: fix forceful stop (LF 2283) + + High: apache: monitor operation of depth 10 for web applications (LF 2234) + + Medium: IPaddr2: CLUSTERIP/iptables rule not always inserted on failed monitor (LF 2281) + + Medium: RA: Route: improve validate (LF 2232) + + Medium: mark obsolete RAs as deprecated (LF 2244) + + Medium: mysql: escalate stop to KILL if regular shutdown doesn't work + +* Mon Dec 7 2009 Fabio M. Di Nitto - 3.0.6-1 +- New rgmanager resource agents upstream release +- spec file update: + * use global instead of define + * use new Source0 url + * use %name macro more aggressively + +* Mon Dec 7 2009 Andrew Beekhof - 3.0.5-2 +- Update Pacameker agents to upstream version: bc00c0b065d9 + + High: RA: introduce OCF_FUNCTIONS_DIR, allow it to be overridden (LF2239) + + High: doc: add man pages for all RAs (LF2237) + + High: syslog-ng: new RA + + High: vmware: make meta-data work and several cleanups (LF 2212) + + Medium: .ocf-shellfuncs: add ocf_is_probe function + + Medium: Dev: make RAs executable (LF2239) + + Medium: IPv6addr: ifdef out the ip offset hack for libnet v1.1.4 (LF 2034) + + Medium: add mercurial repository version information to .ocf-shellfuncs + + Medium: build: add perl-MailTools runtime dependency to ldirectord package (LF 1469) + + Medium: iSCSITarget, iSCSILogicalUnit: support LIO + + Medium: nfsserver: use check_binary properly in validate (LF 2211) + + Medium: nfsserver: validate should not check if nfs_shared_infodir exists (thanks to eelco@procolix.com) (LF 2219) + + Medium: oracle/oralsnr: export variables properly + + Medium: pgsql: remove the previous backup_label if it exists + + Medium: postfix: fix double stop (thanks to Dinh N. Quoc) + + RA: LVM: Make monitor operation quiet in logs (bnc#546353) + + RA: Xen: Remove instance_attribute "allow_migrate" (bnc#539968) + + ldirectord: OCF agent: overhaul + +* Fri Nov 20 2009 Fabio M. Di Nitto - 3.0.5-1 +- New rgmanager resource agents upstream release +- Allow pacemaker to use rgmanager resource agents + +* Wed Oct 28 2009 Andrew Beekhof - 3.0.4-2 +- Update Pacameker agents to upstream version: e2338892f59f + + High: send_arp - turn on unsolicited mode for compatibilty with the libnet version's exit codes + + High: Trap sigterm for compatibility with the libnet version of send_arp + + Medium: Bug - lf#2147: IPaddr2: behave if the interface is down + + Medium: IPv6addr: recognize network masks properly + + Medium: RA: VirtualDomain: avoid needlessly invoking "virsh define" + +* Wed Oct 21 2009 Fabio M. Di Nitto - 3.0.4-1 +- New rgmanager resource agents upstream release + +* Mon Oct 12 2009 Andrew Beekhof - 3.0.3-3 +- Update Pacameker agents to upstream version: 099c0e5d80db + + Add the ha_parameter function back into .ocf-shellfuncs. + + Bug bnc#534803 - Provide a default for MAILCMD + + Fix use of undefined macro @HA_NOARCHDATAHBDIR@ + + High (LF 2138): IPsrcaddr: replace 0/0 with proper ip prefix (thanks to Michael Ricordeau and Michael Schwartzkopff) + + Import shellfuncs from heartbeat as badly written RAs use it + + Medium (LF 2173): nfsserver: exit properly in nfsserver_validate + + Medium: RA: Filesystem: implement monitor operation + + Medium: RA: VirtualDomain: loop on status if libvirtd is unreachable + + Medium: RA: VirtualDomain: loop on status if libvirtd is unreachable (addendum) + + Medium: RA: iSCSILogicalUnit: use a 16-byte default SCSI ID + + Medium: RA: iSCSITarget: be more persistent deleting targets on stop + + Medium: RA: portblock: add per-IP filtering capability + + Medium: mysql-proxy: log_level and keepalive parameters + + Medium: oracle: drop spurious output from sqlplus + + RA: Filesystem: allow configuring smbfs mounts as clones + +* Wed Sep 23 2009 Fabio M. Di Nitto - 3.0.3-1 +- New rgmanager resource agents upstream release + +* Thu Aug 20 2009 Fabio M. Di Nitto - 3.0.1-1 +- New rgmanager resource agents upstream release + +* Tue Aug 18 2009 Andrew Beekhof - 3.0.0-16 +- Create an ldirectord package +- Update Pacameker agents to upstream version: 2198dc90bec4 + + Build: Import ldirectord. + + Ensure HA_VARRUNDIR has a value to substitute + + High: Add findif tool (mandatory for IPaddr/IPaddr2) + + High: IPv6addr: new nic and cidr_netmask parameters + + High: postfix: new resource agent + + Include license information + + Low (LF 2159): Squid: make the regexp match more precisely output of netstat + + Low: configure: Fix package name. + + Low: ldirectord: add dependency on $remote_fs. + + Low: ldirectord: add mandatory required header to init script. + + Medium (LF 2165): IPaddr2: remove all colons from the mac address before passing it to send_arp + + Medium: VirtualDomain: destroy domain shortly before timeout expiry + + Medium: shellfuncs: Make the mktemp wrappers work. + + Remove references to Echo function + + Remove references to heartbeat shellfuncs. + + Remove useless path lookups + + findif: actually include the right header. Simplify configure. + + ldirectord: Remove superfluous configure artifact. + + ocf-tester: Fix package reference and path to DTD. + +* Tue Aug 11 2009 Ville Skyttä - 3.0.0-15 +- Use bzipped upstream hg tarball. + +* Wed Jul 29 2009 Fabio M. Di Nitto - 3.0.0-14 +- Merge Pacemaker cluster resource agents: + * Add Source1. + * Drop noarch. We have real binaries now. + * Update BuildRequires. + * Update all relevant prep/build/install/files/description sections. + +* Sun Jul 26 2009 Fedora Release Engineering - 3.0.0-13 +- Rebuilt for https://fedoraproject.org/wiki/Fedora_12_Mass_Rebuild + +* Wed Jul 8 2009 Fabio M. Di Nitto - 3.0.0-12 +- spec file updates: + * Update copyright header + * final release.. undefine alphatag + +* Thu Jul 2 2009 Fabio M. Di Nitto - 3.0.0-11.rc4 +- New upstream release. + +* Sat Jun 20 2009 Fabio M. Di Nitto - 3.0.0-10.rc3 +- New upstream release. + +* Wed Jun 10 2009 Fabio M. Di Nitto - 3.0.0-9.rc2 +- New upstream release + git94df30ca63e49afb1e8aeede65df8a3e5bcd0970 + +* Tue Mar 24 2009 Fabio M. Di Nitto - 3.0.0-8.rc1 +- New upstream release. +- Update BuildRoot usage to preferred versions/names + +* Mon Mar 9 2009 Fabio M. Di Nitto - 3.0.0-7.beta1 +- New upstream release. + +* Fri Mar 6 2009 Fabio M. Di Nitto - 3.0.0-6.alpha7 +- New upstream release. + +* Tue Mar 3 2009 Fabio M. Di Nitto - 3.0.0-5.alpha6 +- New upstream release. + +* Tue Feb 24 2009 Fabio M. Di Nitto - 3.0.0-4.alpha5 +- Drop Conflicts with rgmanager. + +* Mon Feb 23 2009 Fabio M. Di Nitto - 3.0.0-3.alpha5 +- New upstream release. + +* Thu Feb 19 2009 Fabio M. Di Nitto - 3.0.0-2.alpha4 +- Add comments on how to build this package. + +* Thu Feb 5 2009 Fabio M. Di Nitto - 3.0.0-1.alpha4 +- New upstream release. +- Fix datadir/cluster directory ownership. + +* Tue Jan 27 2009 Fabio M. Di Nitto - 3.0.0-1.alpha3 + - Initial packaging