Script 'mail_helper' called by obssrc Hello community, here is the log from the commit of package sapstartsrv-resource-agents for openSUSE:Factory checked in at 2022-09-21 14:43:21 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/sapstartsrv-resource-agents (Old) and /work/SRC/openSUSE:Factory/.sapstartsrv-resource-agents.new.2083 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "sapstartsrv-resource-agents" Wed Sep 21 14:43:21 2022 rev:5 rq:1005157 version:0.9.1+git.1663751963.e0ef8a2 Changes: -------- --- /work/SRC/openSUSE:Factory/sapstartsrv-resource-agents/sapstartsrv-resource-agents.changes 2021-04-29 22:53:02.669989564 +0200 +++ /work/SRC/openSUSE:Factory/.sapstartsrv-resource-agents.new.2083/sapstartsrv-resource-agents.changes 2022-09-21 14:44:21.566063443 +0200 @@ -1,0 +2,21 @@ +Wed Sep 14 09:37:25 UTC 2022 - abr...@suse.com + +- Version bump to 0.9.1 +- man page updates based on customer feedback on conferences +- remove 'BuildRequire python3-mock' as this is no longer needed + for the tests + +------------------------------------------------------------------- +Fri Feb 25 11:18:02 UTC 2022 - abr...@suse.com + +- Add systemd support for the resource agent to interact with the + new SAP unit files for sapstartsrv. + As the new version of the SAP Startup Framework will use systemd + unit files to control the sapstartsrv process instead of the + previous used SysV init script, we need to adapt the handling of + sapstartsrv inside the resource agents to support both ways. + (bsc#1189529) +- prevent false posivite with pgrep in function '_get_status' + (bsc#1193568) + +------------------------------------------------------------------- Old: ---- sapstartsrv-resource-agents-0.9.0+git.1619681975.ad20a04.tar.gz New: ---- sapstartsrv-resource-agents-0.9.1+git.1663751963.e0ef8a2.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ sapstartsrv-resource-agents.spec ++++++ --- /var/tmp/diff_new_pack.JyhFY1/_old 2022-09-21 14:44:22.010064603 +0200 +++ /var/tmp/diff_new_pack.JyhFY1/_new 2022-09-21 14:44:22.018064624 +0200 @@ -1,7 +1,7 @@ # # spec file for package sapstartsrv-resource-agents # -# Copyright (c) 2020-2021 SUSE LLC. +# Copyright (c) 2020-2022 SUSE LLC. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -24,7 +24,7 @@ License: GPL-2.0 Group: Productivity/Clustering/HA Summary: Resource agent for SAP instance specific sapstartsrv service -Version: 0.9.0+git.1619681975.ad20a04 +Version: 0.9.1+git.1663751963.e0ef8a2 Release: 0 URL: https://github.com/SUSE/SAPStartSrv-resourceAgent Source0: %{name}-%{version}.tar.gz @@ -34,7 +34,6 @@ Requires: pacemaker > 1.1.1 Requires: python3 %if %{with test} -BuildRequires: python3-mock BuildRequires: python3-pytest %endif ++++++ _service ++++++ --- /var/tmp/diff_new_pack.JyhFY1/_old 2022-09-21 14:44:22.054064718 +0200 +++ /var/tmp/diff_new_pack.JyhFY1/_new 2022-09-21 14:44:22.058064728 +0200 @@ -4,8 +4,8 @@ <param name="scm">git</param> <param name="exclude">.git</param> <param name="filename">sapstartsrv-resource-agents</param> - <param name="versionformat">0.9.0+git.%ct.%h</param> - <param name="revision">ad20a04897921e678909b6da9d87ffdae9b32293</param> + <param name="versionformat">0.9.1+git.%ct.%h</param> + <param name="revision">e0ef8a2c4cf21d373f0085e4cd11fecb76ed87aa</param> </service> <service name="recompress" mode="disabled"> ++++++ sapstartsrv-resource-agents-0.9.0+git.1619681975.ad20a04.tar.gz -> sapstartsrv-resource-agents-0.9.1+git.1663751963.e0ef8a2.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sapstartsrv-resource-agents-0.9.0+git.1619681975.ad20a04/_service new/sapstartsrv-resource-agents-0.9.1+git.1663751963.e0ef8a2/_service --- old/sapstartsrv-resource-agents-0.9.0+git.1619681975.ad20a04/_service 2021-04-29 09:39:35.000000000 +0200 +++ new/sapstartsrv-resource-agents-0.9.1+git.1663751963.e0ef8a2/_service 2022-09-21 11:19:23.000000000 +0200 @@ -4,7 +4,7 @@ <param name="scm">git</param> <param name="exclude">.git</param> <param name="filename">sapstartsrv-resource-agents</param> - <param name="versionformat">0.9.0+git.%ct.%h</param> + <param name="versionformat">0.9.1+git.%ct.%h</param> <param name="revision">%%VERSION%%</param> </service> diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sapstartsrv-resource-agents-0.9.0+git.1619681975.ad20a04/man/SAPStartSrv_basic_cluster.7 new/sapstartsrv-resource-agents-0.9.1+git.1663751963.e0ef8a2/man/SAPStartSrv_basic_cluster.7 --- old/sapstartsrv-resource-agents-0.9.0+git.1619681975.ad20a04/man/SAPStartSrv_basic_cluster.7 2021-04-29 09:39:35.000000000 +0200 +++ new/sapstartsrv-resource-agents-0.9.1+git.1663751963.e0ef8a2/man/SAPStartSrv_basic_cluster.7 2022-09-21 11:19:23.000000000 +0200 @@ -1,6 +1,6 @@ -.\" Version: 0.1.0 +.\" Version: 0.9.1 .\" -.TH SAPStartSrv_basic_cluster 7 "05 Jan 2021" "" "SAPStartSrv" +.TH SAPStartSrv_basic_cluster 7 "02 Feb 2022" "" "SAPStartSrv" .\" .SH NAME SAPStartSrv_basic_cluster \- basic settings to make SAPStartSrv work @@ -18,6 +18,12 @@ \fBsystemd services\fR The services sapinit, sapping and sappong are needed for this cluster. + +For SystemV style saphostagent and sapstartsrv, the sapinit script needs to be +enabled. +For systemd style saphostagent and sapstartsrv, the service saphostagent needs +to be enabled and running, instance services SAP${SID}_${INO} need to be disabled. +See also REQUIREMENTS in man page ocf_suse_SAPStartSrv(7). .PP \fBtcp_retries2 = 9\fR @@ -33,6 +39,27 @@ for default SAP application server and central services configuration. .\" TODO NFS mount options for smooth takeover of sap instances, e.g. soft? .PP +\fBUsers and groups\fR + +Technical users and groups, such as <sid>adm are defined locally in the Linux +system. Further user <sid>adm needs to be in group haclient. +See man page passwd(5) and usermod(8. + +\fBHostnames\fR + +Name resolution of the cluster nodes and the virtual IP address must be done +locally on all cluster nodes. See man page hosts(5). + +\fBTime synchronization\fR + +Strict time synchronization between the cluster nodes is mandatory, e.g. per NTP. +See man page chrony.conf(5). + +\fBNFS mounted filesystems\fR + +The shared filesystems /sapmnt/$SID/ and /usr/sap/$SID/ can be statically mounted +on all cluster nodes. See man page fstab(5) and example below. +.PP \fB* CRM Basics\fR \fBstonith-enabled = true\fR @@ -57,14 +84,14 @@ .br .\" TODO A value of '1' ... -\fBmigration-threshold = 3\fR +\fBmigration-threshold = 1\fR The crm rsc_default parameter migration-threshold defines how many errors on a resource can be detected before this resource will be moved to another node. -See also \fBfailure-timeout\fR . +For ENSA1 the migration-threshold needs to be 1 always. For ENSA2 the value could +be higher. See also \fBfailure-timeout\fR . .\" TODO needed for resource monitor option on-fail=restart .br -.\" TODO A value of '3' ... ENSA2 \fBrecord-pending = true\fR @@ -74,7 +101,6 @@ \'starting\' and \'stopping\' in crm_mon. Also the sap_suse_cluster_connector interface uses this information. .br -.\" TODO The value 'true' is needed for the sap_suse_cluster_connector interface. \fBfailure-timeout = 86400\fR @@ -114,8 +140,8 @@ Shown are specific parameters which are needed. Some general parameters are left out. .br -This example has been taken from a three-node cluster SLE-HA 15 GA with -diskless SBD: +This example has been taken from an ENSA2 three-node cluster SLE-HA 15 GA +with diskless SBD: .PP .RS 4 property cib-bootstrap-options: \\ @@ -153,8 +179,8 @@ record-pending=true .RE -This example has been taken from a two-node cluster SLE-HA 15 GA with -disk-based SBD. An optional priority fecing is configured and the SBD +This example has been taken from an ENSA2 two-node cluster SLE-HA 15 GA +with disk-based SBD. An optional priority fecing is configured and the SBD pcmk_delay_max has been reduced: .PP .RS 4 @@ -242,12 +268,61 @@ .RE .br .PP +\fB* systemd services for the SAP instance\fR +.PP +In case systemd style init is used for the SAP instance: +saphostagent needs to be enabled and running, instance services need +to be disabled. Example SID is HA1, instance number is 10. +.PP +.RS 4 +.br +# systemctl list-unit-files | grep -i sap +.br +# systemctl status SAPHA1_10.service +.br +# systemd-cgls -u SAP.slice +.br +# systemd-cgls -u SAPHA1_10.service +.RE +.br +.PP +\fB* SAP instance profile\fR +.PP +Check the instance profile for HA specific settings. +Example SID is EN2, instance number is 10. +.PP +.RS 4 +.br +# su - en2adm +.br +~> sapcontrol -nr 10 -function GetStartProfile |\\ +.br +grep -e art_Program_ -e Autostart -e halib +.br +~> exit +.RE +.br +.PP +\fB* sidadm group membership\fR +.PP +Check if the sidadm user is member of the HA specific haclient group. +Example SID is EN2. +.PP +.RS 4 +.br +# groups en2adm +.RE +.br +.PP .\" .SH FILES .TP /etc/passwd the local user database .TP +/etc/groups +the local group database +.TP /etc/hosts the local hostname resolution database .TP @@ -270,7 +345,8 @@ \fBocf_suse_SAPStartSrv\fP(7) , \fBsap_suse_cluster_connector\fP(8) , \fBocf_pacemaker_ping\fP(7) , \fBocf_heartbeat_ethmonitor\fP(7) , \fBattrd_updater\fP(8) , \fBsbd\fP(8) , \fBstonith_sbd\fP(8) , \fBcrm\fP(8) , -\fBcorosync.conf\fP(5) , \fBvotequorum\fP(5) , +\fBcorosync.conf\fP(5) , \fBvotequorum\fP(5) , \fBhosts\fP(5) , \fBfstab\fP(5) , +\fBpasswd\fP(5) , \fBgroups\fP(8) , \fBusermod\fP(8) , \fBchrony.conf\fP(5) , .br https://www.kernel.org/doc/Documentation/networking/ip-sysctl.txt .\" TODO https://pracucci.com/linux-tcp-rto-min-max-and-tcp-retries2.html @@ -283,7 +359,7 @@ .\" .SH COPYRIGHT .br -(c) 2020-2021 SUSE LLC +(c) 2020-2022 SUSE LLC .br SAPStartSrv comes with ABSOLUTELY NO WARRANTY. .br diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sapstartsrv-resource-agents-0.9.0+git.1619681975.ad20a04/man/SAPStartSrv_maintenance_procedures.7 new/sapstartsrv-resource-agents-0.9.1+git.1663751963.e0ef8a2/man/SAPStartSrv_maintenance_procedures.7 --- old/sapstartsrv-resource-agents-0.9.0+git.1619681975.ad20a04/man/SAPStartSrv_maintenance_procedures.7 1970-01-01 01:00:00.000000000 +0100 +++ new/sapstartsrv-resource-agents-0.9.1+git.1663751963.e0ef8a2/man/SAPStartSrv_maintenance_procedures.7 2022-09-21 11:19:23.000000000 +0200 @@ -0,0 +1,232 @@ +.\ Version: 0.9.1 +.\" +.TH SAPStartSrv_maintenance_examples 7 "23 Jun 2022" "" "SAPStartSrv" +.\" +.SH NAME +SAPStartSrv_maintenance_examples \- maintenance examples for SAPStartSrv +.PP +.\" +.SH DESCRIPTION +.\" +Maintenance examples for SAPStartSrv and SUSE HA for SAP Enqueue Standalone +clusters. +Please see ocf_suse_SAPStartSrv(7), SAPStartSrv_basic_cluster(7) and sap_suse_cluster_connector(8) for more examples and read the REQUIREMENTS section there. +.PP +.\" +.SH EXAMPLES +.PP +\fB*\fR Check status of Linux cluster and ENSA replication pair. + +This steps should be performed before doing anything with the cluster, and +after something has been done. +.PP +.RS 2 +# cs_clusterstate -i +.br +# crm_mon -1r +.br +# crm configure show | grep cli- +.br +# su - en1adm -c "sapcontrol -nr 00 -function GetSystemInstanceList" +.br +# su - en1adm -c "sapcontrol -nr 00 -function GetProcessList" +.br +# su - en1adm -c "sapcontrol -nr 00 -function HACheckMaintenanceMode" +.br +# su - en1adm -c "sapcontrol -nr 00 -function HAGetFailoverConfig" +.br +# cs_clusterstate -i +.RE +.PP +\fB*\fR Set resource group of ASCS into maintenance. + +This is needed to allow manual actions on the ASCS group??s resources. +In this example, SID is EN1, instance number of ASCS is 00. +It is neccessary to wait for each step to complete and to check the result. +See also exmaple below. +.PP +.RS 2 +# crm resource maintenance grp_EN1_ASCS00 on +.br +# crm configure show grp_EN1_ASCS00 +.RE +.PP +\fB*\fR Get resource group of ASCS back from maintenance. + +This is needed to put back under cluster control the ASCS group??s resources. +In this example, SID is EN1, instance number of ASCS is 00. +It is neccessary to wait for each step to complete and to check the result. +See also exmaple above. +.PP +.RS 2 +# crm resource refresh grp_EN1_ASCS00 +.br +# crm resource maintenance grp_EN1_ASCS00 off +.br +# crm configure show grp_EN1_ASCS00 +.RE +.PP +\fB*\fR Set whole Linux cluster into maintenance. + +.RS 2 +# crm configure property maintenance-mode=true +.br +# crm_attribute --query -t crm_config -n maintenance-mode +.RE +.PP +\fB*\fR Remove left-over maintenance attribute from overall Linux cluster. + +This could be done to avoid confusion caused by different maintenance procedures. +See above overview on maintenance procedures whith running Linux cluster. +Before doing so, check for cluster attribute maintenance-mode="false". +.PP +.RS 2 +# crm_attribute --delete -t crm_config -n maintenance-mode +.br +# crm_attribute --query -t crm_config -n maintenance-mode +.RE +.PP +\fB*\fR Remove left-over standby attribute from Linux cluster nodes. + +This could be done to avoid confusion caused by different maintenance procedures. +See above overview on maintenance procedures whith running Linux cluster. +Before doing so for all nodes, check for node attribute standby="off" on all nodes. +.PP +.RS 2 +# crm_attribute --delete -t node -N node1 -n standby +.br +# crm_attribute --query -t node -N node1 -n standby +.RE +.PP +\fB*\fR Remove left-over maintenance attribute from resource. + +This should usually not be needed. +See above overview on maintenance procedures whith running Linux cluster. +.PP +.RS 2 +# crm_resource --resource grp_EN1_ASCS00 --delete-parameter maintenance --meta +.\" .br +.\" # TODO check +.RE +.PP +\fB*\fR Disable Linux cluster on all cluster nodes. + +On any cluster node the cluster will not start automatically on boot anymore. +Nevertheless a currently running cluster will keep running. +.PP +.RS 2 +# crm cluster run "crm cluster disable" +.br +# crm cluster run "systemctl status pacemaker" | grep pacemaker.service +.RE +.PP +\fB*\fR Start Linux cluster on all cluster nodes. +.PP +.RS 2 +# crm cluster run "crm cluster start" +.br +# crm cluster run "systemctl status pacemaker" | grep pacemaker.service +.RE +.PP +\fB*\fR Perform an ASCS takeover by using SAP tools. + +In this example, SID is EN1, instance number of ASCS is 00, instance number +of ERS is 10. +Only two nodes are in the Linux cluster. +As consequence of ASCS takeover, the cluster will move the ERS. +It is neccessary to wait for each step to complete and to check the result. +.PP +.RS 2 +# su - en1adm -c "sapcontrol -nr 00 -function HAFailoverToNode ''" +.br +# crm resource clear rsc_sap_EN1_ASCS00 +.br +# crm resource cleanup rsc_sap_EN1_ERS10 +.RE +.PP +.\" \fB*\fR Overview on SAP Rolling Kernel Switch procedure. +.\" .PP +.\" TODO SAP notes 2254173, 2077934, 1872602, 953653 +.\" TODO SUM +.\" TODO SAP note 2464065 +.\" .RE +.\" .PP +\fB*\fR Overview on simple procedure for stopping and temporarily disabling the Linux cluster. +ASCS and ERS instances get fully stopped. + +This procedure can be used to update SAP instances, OS or hardware. +ASCS and ERS roles and resource status remains unchanged. +It is neccessary to wait for each step to complete and to check the result. +It also is neccessary to test and document the whole procedure before applying +in production. The ASCS instance will not be available from step 1.2 to step 3.3. +This is not compliant to official SAP upgrade procedures, like Rolling Kernel Switch. +.PP +.RS 2 +1.1 stopping ERS instance +.br +1.2 stopping ASCS instance +.br +1.3 disabling pacemaker on all cluster node +.br +1.4 stopping cluster on all cluster node +.PP +2. doing the maintenance activity +.PP +3.1 enabling pacemaker on all cluster nodes +.br +3.2 starting cluster on all cluster nodes +.br +3.3 starting ASCS instance +.br +3.4 starting ERS instance +.RE +.PP +\fB*\fR Overview on maintenance procedure for Linux cluster or OS. ASCS and ERS instances +remain running. + +.RS 2 +1. Check status of Linux cluster and ASCS/ERS, see above. +.br +2. Set the Linux cluster into maintenance mode. +.br +3. Stop Linux Cluster on all nodes. +.br +4. Perform maintenance on Linux cluster or OS. +.br +5. Start Linux cluster on all nodes. +.br +6. Let Linux cluster detect status of ASCS/ERS resources. +.br +7. Set cluster ready for operations. +.br +8. Check status of Linux cluster and ASCS/ERS, see above. +.RE +.PP +.\" +.SH BUGS +Please report feedback and suggestions to feedb...@suse.com. +.PP +.\" +.SH SEE ALSO +\fBocf_suse_SAPStartSrv\fP(7) , \fBSAPStartSrv_basic_cluster\fP(7) , +\fBsap_suse_cluster_connector\fP(8) , +\fBcrm\fP(8) , \fBcrm_simulate\fP(8) , \fBcrm_report\fP(8) , \fBcibadmin\fP(8) , +\fBsbd\fP(8) , \fBcorosync-cfgtool\fP(8) , +\fBsystemctl\fP(8) , +\fBcs_clusterstate\fP(8) , \fBcs_wait_for_idle\fP(8) , \fBcs_show_ensa_status\fP(8) , +\fBha_related_sap_notes\fP(7) +.PP +.\" +.SH AUTHORS +F.Herschel, L.Pinne +.PP +.\" +.SH COPYRIGHT +.br +(c) 2020-2022 SUSE LLC +.br +SAPStartSrv comes with ABSOLUTELY NO WARRANTY. +.br +For details see the GNU General Public License at +http://www.gnu.org/licenses/gpl.html +.\" diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sapstartsrv-resource-agents-0.9.0+git.1619681975.ad20a04/man/ocf_suse_SAPStartSrv.7 new/sapstartsrv-resource-agents-0.9.1+git.1663751963.e0ef8a2/man/ocf_suse_SAPStartSrv.7 --- old/sapstartsrv-resource-agents-0.9.0+git.1619681975.ad20a04/man/ocf_suse_SAPStartSrv.7 2021-04-29 09:39:35.000000000 +0200 +++ new/sapstartsrv-resource-agents-0.9.1+git.1663751963.e0ef8a2/man/ocf_suse_SAPStartSrv.7 2022-09-21 11:19:23.000000000 +0200 @@ -1,6 +1,6 @@ -.\" Version: 0.1.0 +.\" Version: 0.9.1 .\" -.TH ocf_suse_SAPStartSrv 7 "01 Feb 2021" "" "OCF resource agents" +.TH ocf_suse_SAPStartSrv 7 "23 Jun 2022" "" "OCF resource agents" .\" .SH NAME SAPStartSrv \- Manages sapstartsv for a single SAP instance as an HA resource. @@ -13,7 +13,7 @@ .\" .SH DESCRIPTION -\fBSAPStartSrv\fP is an resource agent for managing the sapstartsrv process for +\fBSAPStartSrv\fP is a resource agent for managing the sapstartsrv process for a single SAP instance as an HA resource. .PP One SAP instance is defined by having exactly one instance profile. @@ -93,8 +93,8 @@ \fBmonitor\fR .RS 4 The SAPStartSrv resource must by intention not define a monitor operation. -This is, because the failing sapstartsrv must never force an SAPInstance -restart which would happen, as the two resources reside in one resource group. +This is, because the failing sapstartsrv must never force a SAPInstance restart. +That would happen because the two resources reside in one resource group. .\" TODO op monitor on-fail="ignore" .RE .PP @@ -121,11 +121,11 @@ .SH EXAMPLES * Example configuration for SAP ASCS instance resource group in an ENSA2 setup. .br -SAP system name is EVA, SAP service is ASCS, SAP instance number is 00, SAP virtual hostname is sapeva. An loadbalancer is used together with dedicated IP netmask configuration for specific public cloud environments. The SAPInstance has been given a fencing priority, a crm property priority-fencing-delay is needed to make this work. See SAPStartSrv_basic_cluster(7). +SAP system name is EVA, SAP service is ASCS, SAP instance number is 00, SAP virtual hostname is sapeva. An loadbalancer is used together with dedicated IP netmask configuration for specific public cloud environments. The SAPInstance has been given a fencing priority, a crm property priority-fencing-delay is needed to make this work. See SAPStartSrv_basic_cluster(7). The shown SAPInstance monitor timeout is a trade-off between fast recovery of the ASCS vs. resilience against sporadic temporary NFS issues. You may slightly increase it to fit your infrastructure. Too short ASCS monitor timeouts likely will conflict with the instance??s internal recovery. The also needed ERS instance group and location constraint is shown in another example. .PP .RS 4 -primitive rsc_SAPStartSrv_EVA_ASCS00 SAPStartSrv \\ +primitive rsc_SAPStartSrv_EVA_ASCS00 ocf:suse:SAPStartSrv \\ .br params InstanceName=EVA_ASCS00_sapeva .PP @@ -172,8 +172,9 @@ .br SAP system name is EN2, SAP service is ERS, SAP instance number is 10, SAP virtual hostname is sapeva. An IP address is configured as usual for on-premise use. If possible, the ERS instance should run on a different node than the ASCS. -The also needed ASCSS instance group is shown in another example. +The also needed ASCS instance group is shown in another example. .PP +.RS 4 primitive rsc_SAPStartSrv_EN2_ERS10 ocf:suse:SAPStartSrv \\ .br params InstanceName=EN2_ERS10_sapen2er @@ -214,6 +215,50 @@ .br .RE .PP +* Example SAP ASCS instance profile adapted for ENSA2 HA setup. +.br +SAP SID is EN2, instance number is 00, virtual hostname is sapen2er, service is _ENQ . +Optionally you could limit the number of restarts of services, this is not done here. +The instance profile /sapmnt/EN2/profile/EN2_ASCS00_sapen2er is adpated like this: +.PP +.RS 4 +# ... some more above +.br +_ENQ = enq.sap$(SAPSYSTEMNAME)_$(INSTANCE_NAME) +.br +Execute_04 = local rm -f $(_ENQ) +.br +Execute_05 = local ln -s -f $(DIR_EXECUTABLE)/enq_server$(FT_EXE) $(_ENQ) +.br +Start_Program_01 = local $(_ENQ) pf=$(_PF) +.br +# some more below ... +.br +.RE +.PP +* Example SAP ERS instance profile adapted for ENSA2 HA setup. +.br +SAP SID is EN2, instance number is 10, virtual hostname is sapen2er, service is _ENQR . +See also man page sap_suse_cluster_connector(8). +The instance profile /sapmnt/EN2/profile/EN2_ERS10_sapen2er is adpated like this: +.PP +.RS 4 +# ... some more above +.br +_ENQR = enqr.sap$(SAPSYSTEMNAME)_$(INSTANCE_NAME) +.br +Execute_02 = local rm -f $(_ENQR) +.br +Execute_03 = local ln -s -f $(DIR_EXECUTABLE)/enq_replicator$(FT_EXE) $(_ENQR) +.br +Start_Program_00 = local $(_ENQR) pf=$(_PF) NR=$(SCSID) +.br +service/halib_cluster_connector = /usr/bin/sap_suse_cluster_connector +.br +service/halib = $(DIR_CT_RUN)/saphascriptco.so +.br +.RE +.PP * Search for log entries of SAPStartSrv, show errors only: .PP .RS 4 @@ -229,7 +274,7 @@ # cibadmin -Ql | grep rsc_SAPStartSrv_EN2_ERS10.*fail-count .RE .PP -* Manually trigger an SAPStartSRv probe action for instance ADA_ASCS00_engine. +* Manually trigger a SAPStartSrv probe action for instance ADA_ASCS00_engine. Output goes to the usual logfiles. .PP .RS 4 @@ -244,8 +289,9 @@ .PP .\" TODO example for checking enqueue table? .\" TODO example for checking process list? +.PP .\" -.SH FILES +.SH FILES .TP /usr/lib/ocf/resource.d/suse/SAPStartSrv the resource agent @@ -256,7 +302,7 @@ /usr/sap/$SID/$InstanceName/exe/ default path for the sapstartsrv executable .TP -/usr/sap/$SID/SYS/profile/ +/sapmnt/$SID/profile/ (resp. /usr/sap/$SID/SYS/profile/) default path for DIR_PROFILE .TP /usr/sap/sapservices @@ -282,7 +328,7 @@ .PP * SAP instance profile Autostart feature is disabled for ASCS and ERS. .PP -* SAP instance profile entry Restart_Program_xx is replaced by Start_Program_xx for ERS. +* For ENSA1 and ENSA2 HA setups, the ASCS instance profile entry for the enqueue service _ENQ, Restart_Program_xx is replaced by Start_Program_xx. Same for the ERS instance profile entry for the enqueue replicator service _ENQR. Other services stay untouched. .PP * The sapinit boot script does not read entries from sapservices file at boot. Thus services sapping and sappong to handle sapservices file at system boot. .PP @@ -292,23 +338,46 @@ .PP * It is not allowed to block resources from being controlled manually. Thus BLOCK_RESOURCES in /etc/sap_suse_cluster_connector is not allowed anymore. .PP +* You need SAP hostagent installed and started on your systems. +For SystemV style, the sapinit script needs to be enabled. +For systemd style, the service saphostagent needs to be enabled and running. +Instance services SAP${SID}_${INO} need to be disabled. +The systemd enabled saphostagent and sapstartsrv is supported from +sapstartsrv-resource-agents 0.9.1 onwards. +An appropriate SAPInstance resource agent is needed, newer than November 2021. +Please refer to the OS documentation for the systemd version. +Please refer to SAP documentation for the SAP HANA version. +Combining systemd style hostagent with SystemV style instance is allowed. +However, all nodes in one Linux cluster have to use the same style. +.PP ./" .SH BUGS .\" In case of any problem, please use your favourite SAP support process to .\" open a request for the component BC-OP-LNX-SUSE. +The trace_ra resourcre tracing feature is not implemented so far. +.br Please report feedback and suggestions to feedb...@suse.com. .PP .\" .SH SEE ALSO \fBocf_heartbeat_SAPInstance\fP(7) , \fBocf_heartbeat_IPaddr2\fP(7) , -\fBSAPStartSrv_basic_cluster\fP(7) , +\fBSAPStartSrv_basic_cluster\fP(7) , \fBsystemctl\fP(1) , .\" TODO aws-vpc-route53 gcp-vpc-move-route .\" TODO SAPStartSrv-showAttr(8) ? \fBsapservices-move\fP(8) , \fBsap_suse_cluster_connector\fP(8) , -\fBcrm\fP(8) , \fBnfs\fP(5) , \fBmount\fP(8) , \fBha_related_suse_tids\fP(7) , +\fBcrm\fP(8) , \fBnfs\fP(5) , \fBmount\fP(8) , +\fBha_related_suse_tids\fP(7) , \fBha_related_sap_notes\fP(7) , .br https://documentation.suse.com/sbp/all/?context=sles-sap , .br +https://www.suse.com/support/kb/doc/?id=000019244 , +.br +https://www.suse.com/support/kb/doc/?id=000019293 , +.br +https://www.suse.com/support/kb/doc/?id=000019924 , +.br +https://www.suse.com/support/kb/doc/?id=000019944 , +.br https://www.suse.com/support/kb/doc/?id=7023714 , .br http://clusterlabs.org/doc/en-US/Pacemaker/1.1/html/Pacemaker_Explained/s-ocf-return-codes.html , @@ -316,22 +385,32 @@ https://help.sap.com/doc/e9a0eddf6eb14a82bcbe3be3c9a58c7e/1610%20001/en-US/frameset.htm?frameset.htm , .br https://help.sap.com/viewer/fe1db4ed6c5510148f66fbccd85f175f/7.02.22/en-US/47e023f3bf423c83e10000000a42189c.html +.br +https://wiki.scn.sap.com/wiki/display/SI/Troubleshooting+for+Enqueue+Failover+in+ASCS+with+ERS .\" .br .\" https://blogs.sap.com/2018/04/03/high-availability-with-standalone-enqueue-server-2/ , .\" .br .\" https://blogs.sap.com/2020/08/27/evolution-of-ensa2-and-erp2.../ , .br -https://launchpad.support.sap.com/#/notes/2711036 , +https://launchpad.support.sap.com/#/notes/1763512 , .br -https://launchpad.support.sap.com/#/notes/2630416 , +https://launchpad.support.sap.com/#/notes/1872602 , .br -https://launchpad.support.sap.com/#/notes/2501860 , +https://launchpad.support.sap.com/#/notes/2077934 , +.br +https://launchpad.support.sap.com/#/notes/2254173 , .br https://launchpad.support.sap.com/#/notes/2464065 , .br -https://launchpad.support.sap.com/#/notes/2254173 , +https://launchpad.support.sap.com/#/notes/2501860 , .br -https://launchpad.support.sap.com/#/notes/2077934 , +https://launchpad.support.sap.com/#/notes/2625407 , +.br +https://launchpad.support.sap.com/#/notes/2630416 , +.br +https://launchpad.support.sap.com/#/notes/2711036 , +.br +https://launchpad.support.sap.com/#/notes/2717369 , .br https://launchpad.support.sap.com/#/notes/953653 .PP @@ -341,7 +420,7 @@ .PP .\" .SH COPYRIGHT -(c) 2020-2021 SUSE LLC +(c) 2020-2022 SUSE LLC .br The resource agent SAPStartSrv comes with ABSOLUTELY NO WARRANTY. .br diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sapstartsrv-resource-agents-0.9.0+git.1619681975.ad20a04/man/sapping.7 new/sapstartsrv-resource-agents-0.9.1+git.1663751963.e0ef8a2/man/sapping.7 --- old/sapstartsrv-resource-agents-0.9.0+git.1619681975.ad20a04/man/sapping.7 2021-04-29 09:39:35.000000000 +0200 +++ new/sapstartsrv-resource-agents-0.9.1+git.1663751963.e0ef8a2/man/sapping.7 2022-09-21 11:19:23.000000000 +0200 @@ -1,6 +1,6 @@ -.\" Version: 0.1.0 +.\" Version: 0.9.1 .\" -.TH sapping/sappong 7 "01 Feb 2021" "" "SAPStartSrv" +.TH sapping/sappong 7 "02 Feb 2022" "" "SAPStartSrv" .\" .SH NAME sapping \- service for hiding sapservices file from sapinit service at system boot. @@ -11,7 +11,7 @@ .SH DESCRIPTION \fBsapping\fP is a systemd service for hiding sapservices file from sapinit service at system boot. .br -\fBsappong\fP is a systemd service for un-hiding sapservices file after sapinit service has been started at system boot. +\fBsappong\fP is a systemd service for unhiding sapservices file after sapinit service has been started at system boot. .br The services are intended to be called at boot time. Administrative use during regular operations is not intended. .PP @@ -58,7 +58,7 @@ .\" .SH COPYRIGHT .br -(c) 2020 SUSE LLC +(c) 2020-2022 SUSE LLC .br sapping/sappong comes with ABSOLUTELY NO WARRANTY. .br diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sapstartsrv-resource-agents-0.9.0+git.1619681975.ad20a04/man/sapservices-move.8 new/sapstartsrv-resource-agents-0.9.1+git.1663751963.e0ef8a2/man/sapservices-move.8 --- old/sapstartsrv-resource-agents-0.9.0+git.1619681975.ad20a04/man/sapservices-move.8 2021-04-29 09:39:35.000000000 +0200 +++ new/sapstartsrv-resource-agents-0.9.1+git.1663751963.e0ef8a2/man/sapservices-move.8 2022-09-21 11:19:23.000000000 +0200 @@ -1,6 +1,6 @@ -.\" Version: 0.1.0 +.\" Version: 0.9.1 .\" -.TH sapservices-move 8 "27 Jan 2021" "" "SAPStartSrv" +.TH sapservices-move 8 "02 Feb 2022" "" "SAPStartSrv" .\" .SH NAME sapservices-move \- hiding sapservices file from sapinit service at system boot. @@ -16,7 +16,7 @@ .br \- sapping is hiding the sapservices file from sapinit service at system boot. .br - \- sappong is restoring the sapservices file after sapinit service has been started. + \- sappong is unhiding the sapservices file after sapinit service has been started. Hiding the sapservices file from sapinit is necessary in certain HA cluster setups. Affected are HA clusters for SAP enqueue replication where cluster nodes have concurrent access to all instance working directories, e.g. by simplified NFS mount structure. In such environments sapstartsrv needs to be started specific for each SAP instance (e.g. ASCS/ERS), to avoid side effects with other instances. @@ -96,9 +96,9 @@ .\" .SH COPYRIGHT .br -(c) 2020-2021 SUSE LLC +(c) 2020-2022 SUSE LLC .br -sapping/sappong comes with ABSOLUTELY NO WARRANTY. +sapservices-move comes with ABSOLUTELY NO WARRANTY. .br For details see the GNU General Public License at http://www.gnu.org/licenses/gpl.html diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sapstartsrv-resource-agents-0.9.0+git.1619681975.ad20a04/ra/SAPStartSrv.in new/sapstartsrv-resource-agents-0.9.1+git.1663751963.e0ef8a2/ra/SAPStartSrv.in --- old/sapstartsrv-resource-agents-0.9.0+git.1619681975.ad20a04/ra/SAPStartSrv.in 2021-04-29 09:39:35.000000000 +0200 +++ new/sapstartsrv-resource-agents-0.9.1+git.1663751963.e0ef8a2/ra/SAPStartSrv.in 2022-09-21 11:19:23.000000000 +0200 @@ -9,14 +9,14 @@ # Based on code from: Fabian Herschel # Support: # License: GNU General Public License (GPL) -# Copyright: (c) 2020 SUSE LLC +# Copyright: (c) 2020-2022 SUSE LLC # # An example usage: # See usage() function below for more details... # # OCF instance parameters: -# - OCF_RESKEY_InstanceName -# - not currently OCF_RESKEY_START_PROFILE (optional, well known directories will be +# - OCF_RESKEY_InstanceName +# - not currently OCF_RESKEY_START_PROFILE (optional, well known directories will be # searched by default) # # - supports sapstartsrv for SAP instances NW7.40 or newer, SAP S/4HANA ABAP Platform 1909 @@ -47,6 +47,9 @@ MONITOR_SERVICES_DEFAULT = \ 'disp+work|msg_server|enserver|enrepserver|jcontrol|jstart|enq_server|enq_replicator' +SYSTEMCTL = '/usr/bin/systemctl' + + class ProcessResult(object): """ Class to store subprocess.Popen output information and offer some @@ -62,7 +65,7 @@ def __init__(self, cmd, returncode, output, err): self.cmd = cmd self.returncode = returncode - self.output = output.decode() # Make it compatiable with python2 and 3 + self.output = output.decode() # Make it compatiable with python2 and 3 self.err = err.decode() @@ -90,6 +93,7 @@ self.sidadm = None self.instance_name = None self.instance_number = None + self.systemd_unit_name = None self.virtual_host = None self.dir_executable = None self.saptstartsrv_path = None @@ -104,6 +108,8 @@ result = run_command( 'pgrep -f -l "sapstartsrv.*pf=.*{}_{}_{}"'.format( self.sid, self.instance_name, self.virtual_host)) + if result.returncode == 0 and not re.match(r'.*\bsapstartsrv\b.*', result.output): + result.returncode = 1 logger.info('Current status: %d. Output: %s' % (result.returncode, result.output)) return result @@ -134,10 +140,10 @@ if ocf.have_binary(self.saptstartsrv_path) and ocf.have_binary(self.sapcontrol_path): return ocf.OCF_SUCCESS - else: - logger.error( - 'Cannot find sapstartsrv and sapcontrol executable in %s' % - (self.dir_executable)) + + logger.error( + 'Cannot find sapstartsrv and sapcontrol executable in %s' % + (self.dir_executable)) # Find executables in standard locations. E.g: /usr/sap/HA1/ASCS00/exe/run self.dir_executable = '/usr/sap/{}/{}/exe/run'.format(self.sid, self.instance_name) @@ -175,20 +181,21 @@ Initialize variables ''' - if len(self.full_name.split('_')) != 3: - logger.error('InstanceName parsing error. It must follow SID_NAME00_VIRTHOST syntax') - return ocf.OCF_ERR_ARGS + if len(self.full_name.split('_')) < 3: + logger.error('InstanceName parsing error. It must follow SID_NAME00_VIRTHOST syntax') + return ocf.OCF_ERR_ARGS try: - self.sid = self.full_name.split('_')[0] - self.instance_name = self.full_name.split('_')[1] - self.virtual_host = '_'.join(self.full_name.split('_')[2:]) - instance_data = re.match('[a-zA-Z]+([0-9]{2})', self.instance_name).groups() - self.instance_number = instance_data[0] - self.sidadm = '{}adm'.format(self.sid.lower()) + self.sid = self.full_name.split('_')[0] + self.instance_name = self.full_name.split('_')[1] + self.virtual_host = '_'.join(self.full_name.split('_')[2:]) + instance_data = re.match('[a-zA-Z]+([0-9]{2})', self.instance_name).groups() + self.instance_number = instance_data[0] + self.sidadm = '{}adm'.format(self.sid.lower()) + self.systemd_unit_name = 'SAP{}_{}.service'.format(self.sid.upper(), self.instance_number) except (IndexError, AttributeError): - logger.error('InstanceName parsing error. It must follow SID_NAME00_VIRTHOST syntax') - return ocf.OCF_ERR_ARGS + logger.error('InstanceName parsing error. It must follow SID_NAME00_VIRTHOST syntax') + return ocf.OCF_ERR_ARGS result = self._find_executables() if result != ocf.OCF_SUCCESS: @@ -204,11 +211,67 @@ return ocf.OCF_SUCCESS - def start(self): + def _is_unit_active(self): + ''' + Run systemctl is-active unit_name + ''' + result = run_command( + '{} is-active {}'.format(SYSTEMCTL, self.systemd_unit_name)) + return result.returncode == 0 + + def _get_systemd_unit(self): + ''' + Run systemctl list-unit-files unit_name + ''' + pattern = r'.*\s%s.*' % self.systemd_unit_name + result = run_command( + '{} list-unit-files {}'.format(SYSTEMCTL, self.systemd_unit_name)) + if result.returncode == 0 and not re.match(pattern, result.output): + result.returncode = 1 + return result.returncode == 0 + + def _chk_systemd_support(self): + ''' + Check availability of SAP systemd support + ''' + if ocf.have_binary(SYSTEMCTL): + unit_file = '/etc/systemd/system/{}'.format(self.systemd_unit_name) + if os.path.exists(unit_file): + return True + if self._get_systemd_unit(): + return True + + return False + + def _start_systemd_style(self): + ''' + Run systemctl start unit + ''' + if self._is_unit_active(): + logger.info( + 'systemd service %s is active' % (self.systemd_unit_name)) + return ocf.OCF_SUCCESS + + logger.warn( + 'systemd service %s is not active, it will be started using systemd' % + (self.systemd_unit_name)) + result = run_command( + '{} start {}'.format(SYSTEMCTL, self.systemd_unit_name)) + if result.returncode == 0: + return ocf.OCF_SUCCESS + + logger.error( + 'error during start of systemd unit %s!' % + (self.systemd_unit_name)) + if ocf.is_probe(): + return ocf.OCF_NOT_RUNNING + + return ocf.OCF_ERR_GENERIC + + def _start_sys5_style(self): ''' Run sapstartsrv command ''' - self._inititialize() run_command('rm -f /tmp/.sapstream5{}13'.format(self.instance_number)) run_command('rm -f /tmp/.sapstream5{}14'.format(self.instance_number)) start_result = run_command('{} pf={} -D -u {}'.format( @@ -217,18 +280,29 @@ result = self._get_status() if result.returncode == 0: logger.info( - 'sapstartsrv for SAP Instance %s-%s started: %s' % + 'sapstartsrv for SAP Instance %s_%s started: %s' % (self.sid, self.instance_name, start_result.output)) return ocf.OCF_SUCCESS logger.error( - 'sapstartsrv for SAP Instance %s-%s start failed: %s' % + 'sapstartsrv for SAP Instance %s_%s start failed: %s' % (self.sid, self.instance_name, start_result.err)) + return ocf.OCF_NOT_RUNNING + def start(self): + ''' + Start sapstartsrv + ''' + self._inititialize() + if self._chk_systemd_support(): + return self._start_systemd_style() + + return self._start_sys5_style() + def stop(self): ''' - Run sapcontrol command to with StopService + Run sapcontrol command with StopService ''' self._inititialize() result = self._get_status() @@ -237,18 +311,18 @@ '{} -nr {} -function StopService'.format( self.sapcontrol_path, self.instance_number)) logger.info( - 'Stopping sapstartsrv of SAP Instance %s-%s: %s' % - (self.sid, self.instance_number, stop_result.output)) + 'Stopping sapstartsrv of SAP Instance %s_%s: %s' % + (self.sid, self.instance_name, stop_result.output)) if stop_result.returncode == 0: return ocf.OCF_SUCCESS logger.error( - 'SAP Instance %s-%s stop failed: %s' % - (self.sid, self.instance_number, stop_result.err)) + 'SAP Instance %s_%s stop failed: %s' % + (self.sid, self.instance_name, stop_result.err)) return ocf.OCF_ERR_GENERIC logger.info( - 'SAP Instance %s-%s already stopped' % (self.sid, self.instance_number)) + 'SAP Instance %s_%s already stopped' % (self.sid, self.instance_name)) return ocf.OCF_SUCCESS def status(self): @@ -270,8 +344,8 @@ if ocf.is_probe(): if self._get_status().returncode == 0: return ocf.OCF_SUCCESS - else: - return ocf.OCF_NOT_RUNNING + + return ocf.OCF_NOT_RUNNING ''' For regular monitors always return success, because recover of sapstartsrv is already handeled by SAPInstance This might be changed in a next-generation edition @@ -317,8 +391,8 @@ sapstartsrv_agent.add_parameter( name='InstanceName', shortdesc='Instance name: SID_INSTANCE_VIR-HOSTNAME', - longdesc='The full qualified SAP instance name. e.g. HA1_ASCS00_sapha1as. ' \ - 'Usually this is the name of the SAP instance profile.', + longdesc='The full qualified SAP instance name. e.g. HA1_ASCS00_sapha1as. ' + 'Usually this is the name of the SAP instance profile.', content_type='string', required=True, unique=True, @@ -328,8 +402,8 @@ sapstartsrv_agent.add_parameter( name='START_PROFILE', shortdesc='Start profile name', - longdesc='The name of the SAP Instance profile. Specify this parameter, if you have ' \ - 'changed the name of the SAP Instance profile after the default SAP installation.', + longdesc='The name of the SAP Instance profile. Specify this parameter, if you have ' + 'changed the name of the SAP Instance profile after the default SAP installation.', content_type='string', unique=True, default='' diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sapstartsrv-resource-agents-0.9.0+git.1619681975.ad20a04/sapstartsrv-resource-agents.changes new/sapstartsrv-resource-agents-0.9.1+git.1663751963.e0ef8a2/sapstartsrv-resource-agents.changes --- old/sapstartsrv-resource-agents-0.9.0+git.1619681975.ad20a04/sapstartsrv-resource-agents.changes 2021-04-29 09:39:35.000000000 +0200 +++ new/sapstartsrv-resource-agents-0.9.1+git.1663751963.e0ef8a2/sapstartsrv-resource-agents.changes 2022-09-21 11:19:23.000000000 +0200 @@ -1,4 +1,25 @@ ------------------------------------------------------------------- +Wed Sep 14 09:37:25 UTC 2022 - abr...@suse.com + +- Version bump to 0.9.1 +- man page updates based on customer feedback on conferences +- remove 'BuildRequire python3-mock' as this is no longer needed + for the tests + +------------------------------------------------------------------- +Fri Feb 25 11:18:02 UTC 2022 - abr...@suse.com + +- Add systemd support for the resource agent to interact with the + new SAP unit files for sapstartsrv. + As the new version of the SAP Startup Framework will use systemd + unit files to control the sapstartsrv process instead of the + previous used SysV init script, we need to adapt the handling of + sapstartsrv inside the resource agents to support both ways. + (bsc#1189529) +- prevent false posivite with pgrep in function '_get_status' + (bsc#1193568) + +------------------------------------------------------------------- Thu Apr 22 13:05:47 UTC 2021 - abr...@suse.com - remove deprecated option "syslog" from the sapping.service and diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sapstartsrv-resource-agents-0.9.0+git.1619681975.ad20a04/sapstartsrv-resource-agents.spec new/sapstartsrv-resource-agents-0.9.1+git.1663751963.e0ef8a2/sapstartsrv-resource-agents.spec --- old/sapstartsrv-resource-agents-0.9.0+git.1619681975.ad20a04/sapstartsrv-resource-agents.spec 2021-04-29 09:39:35.000000000 +0200 +++ new/sapstartsrv-resource-agents-0.9.1+git.1663751963.e0ef8a2/sapstartsrv-resource-agents.spec 2022-09-21 11:19:23.000000000 +0200 @@ -1,7 +1,7 @@ # # spec file for package sapstartsrv-resource-agents # -# Copyright (c) 2020-2021 SUSE LLC. +# Copyright (c) 2020-2022 SUSE LLC. # # All modifications and additions to the file contributed by third parties # remain the property of their copyright owners, unless otherwise agreed @@ -34,7 +34,6 @@ Requires: pacemaker > 1.1.1 Requires: python3 %if %{with test} -BuildRequires: python3-mock BuildRequires: python3-pytest %endif diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/sapstartsrv-resource-agents-0.9.0+git.1619681975.ad20a04/tests/SAPStartSrv_test.py new/sapstartsrv-resource-agents-0.9.1+git.1663751963.e0ef8a2/tests/SAPStartSrv_test.py --- old/sapstartsrv-resource-agents-0.9.0+git.1619681975.ad20a04/tests/SAPStartSrv_test.py 2021-04-29 09:39:35.000000000 +0200 +++ new/sapstartsrv-resource-agents-0.9.1+git.1663751963.e0ef8a2/tests/SAPStartSrv_test.py 2022-09-21 11:19:23.000000000 +0200 @@ -49,6 +49,7 @@ self._instance_name = 'ASCS' self._instance_number = '00' self._virtualhost = 'virthost' + self._systemd_unit_name = 'SAPPRD_00.service' self._agent = SAPStartSrv.SapStartSrv( '{}_{}{}_{}'.format( self._sid, self._instance_name, self._instance_number, self._virtualhost)) @@ -88,12 +89,156 @@ mock_process.communicate.assert_called_once_with() mock_process_result.assert_called_once_with('cmd', 0, 'output', 'error') + @mock.patch('SAPStartSrv.run_command') + def test_is_unit_active(self, mock_run_command): + mock_result = mock.Mock(output='output', returncode=0) + mock_run_command.return_value = mock_result + self._agent.systemd_unit_name = 'SAPPRD_00.service' + + result = self._agent._is_unit_active() + assert result is True + mock_run_command.assert_called_once_with( + '/usr/bin/systemctl is-active SAPPRD_00.service') + + @mock.patch('SAPStartSrv.run_command') + def test_is_unit_not_active(self, mock_run_command): + mock_result = mock.Mock(output='output', returncode=1) + mock_run_command.return_value = mock_result + self._agent.systemd_unit_name = 'SAPPRD_00.service' + + result = self._agent._is_unit_active() + assert result is False + mock_run_command.assert_called_once_with( + '/usr/bin/systemctl is-active SAPPRD_00.service') + + @mock.patch('SAPStartSrv.run_command') + def test_get_systemd_unit_success(self, mock_run_command): + mock_result = mock.Mock(output='UNIT FILE STATE \nSAPPRD_00.service\n\n1 unit files listed.\n', returncode=0) + mock_run_command.return_value = mock_result + self._agent.systemd_unit_name = 'SAPPRD_00.service' + + result = self._agent._get_systemd_unit() + assert result is True + mock_run_command.assert_called_once_with( + '/usr/bin/systemctl list-unit-files SAPPRD_00.service') + + @mock.patch('SAPStartSrv.run_command') + def test_get_systemd_unit_error(self, mock_run_command): + mock_result = mock.Mock(output='output', returncode=1) + mock_run_command.return_value = mock_result + self._agent.systemd_unit_name = 'SAPPRD_00.service' + + result = self._agent._get_systemd_unit() + assert result is False + mock_run_command.assert_called_once_with( + '/usr/bin/systemctl list-unit-files SAPPRD_00.service') + + @mock.patch('ocf.have_binary') + @mock.patch('os.path.exists') + def test_chk_systemd_support_binary_success( + self, mock_exists, mock_have_binary): + + self._agent.systemd_unit_name = 'SAPPRD_00.service' + + mock_have_binary.return_value = True + mock_exists.return_value = False + + get_systemd_unit_mock = mock.Mock(return_value=False) + self._agent._get_systemd_unit = get_systemd_unit_mock + + result = self._agent._chk_systemd_support() + assert result is False + + mock_have_binary.assert_called_once_with( + '/usr/bin/systemctl' + ) + + @mock.patch('ocf.have_binary') + def test_chk_systemd_support_binary_error( + self, mock_have_binary): + + self._agent.systemd_unit_name = 'SAPPRD_00.service' + + mock_have_binary.return_value = False + + result = self._agent._chk_systemd_support() + assert result is False + + mock_have_binary.assert_called_once_with( + '/usr/bin/systemctl' + ) + + @mock.patch('ocf.have_binary') + @mock.patch('os.path.exists') + def test_chk_systemd_support_binary_success_exists_success( + self, mock_exists, mock_have_binary): + + self._agent.systemd_unit_name = 'SAPPRD_00.service' + + mock_have_binary.return_value = True + mock_exists.return_value = True + + result = self._agent._chk_systemd_support() + assert result is True + + mock_have_binary.assert_called_once_with( + '/usr/bin/systemctl' + ) + mock_exists.assert_called_once_with( + '/etc/systemd/system/SAPPRD_00.service' + ) + + @mock.patch('ocf.have_binary') + @mock.patch('os.path.exists') + def test_chk_systemd_support_binary_success_exists_error( + self, mock_exists, mock_have_binary): + + self._agent.systemd_unit_name = 'SAPPRD_00.service' + + mock_have_binary.return_value = True + mock_exists.return_value = False + + get_systemd_unit_mock = mock.Mock(return_value=False) + self._agent._get_systemd_unit = get_systemd_unit_mock + + result = self._agent._chk_systemd_support() + assert result is False + + mock_have_binary.assert_called_once_with( + '/usr/bin/systemctl' + ) + mock_exists.assert_called_once_with( + '/etc/systemd/system/SAPPRD_00.service' + ) + + @mock.patch('ocf.have_binary') + @mock.patch('os.path.exists') + def test_chk_systemd_support_binary_success_exists_error_get_unit( + self, mock_exists, mock_have_binary): + + self._agent.systemd_unit_name = 'SAPPRD_00.service' + + mock_have_binary.return_value = True + mock_exists.return_value = False + + get_systemd_unit_mock = mock.Mock(return_value=True) + self._agent._get_systemd_unit = get_systemd_unit_mock + + result = self._agent._chk_systemd_support() + assert result is True + + mock_have_binary.assert_called_once_with( + '/usr/bin/systemctl' + ) + mock_exists.assert_called_once_with( + '/etc/systemd/system/SAPPRD_00.service' + ) @mock.patch('ocf.logger.info') @mock.patch('SAPStartSrv.run_command') def test_get_status(self, mock_run_command, mock_logger): - mock_result = mock.Mock(output='output', returncode=0) + mock_result = mock.Mock(output=' sapstartsrv ', returncode=0) mock_run_command.return_value = mock_result self._agent.sid = 'PRD' self._agent.instance_name = 'ASCS00' @@ -103,8 +248,21 @@ assert result == mock_result mock_run_command.assert_called_once_with( 'pgrep -f -l "sapstartsrv.*pf=.*PRD_ASCS00_virthost"') - mock_logger.assert_called_once_with('Current status: 0. Output: output') + mock_logger.assert_called_once_with('Current status: 0. Output: sapstartsrv ') + mock_run_command.reset_mock() + mock_logger.reset_mock() + mock_result = mock.Mock(output='output', returncode=0) + mock_run_command.return_value = mock_result + self._agent.sid = 'PRD' + self._agent.instance_name = 'ASCS00' + self._agent.virtual_host = 'virthost' + + result = self._agent._get_status() + assert result == mock_result + mock_run_command.assert_called_once_with( + 'pgrep -f -l "sapstartsrv.*pf=.*PRD_ASCS00_virthost"') + mock_logger.assert_called_once_with('Current status: 1. Output: output') @mock.patch('ocf.OCF_SUCCESS', 0) @mock.patch('ocf.have_binary') @@ -390,8 +548,7 @@ @mock.patch('ocf.logger.info') @mock.patch('ocf.OCF_SUCCESS', 0) @mock.patch('SAPStartSrv.run_command') - def test_start_success(self, mock_run_command, mock_logger): - self._agent._inititialize = mock.Mock() + def test_start_sys5_style_success(self, mock_run_command, mock_logger): self._agent.instance_name = 'ASCS00' self._agent.instance_number = '00' self._agent.saptstartsrv_path = '/mock/sapstartsrv' @@ -406,11 +563,9 @@ get_status_mock = mock.Mock(return_value=get_status_result_mock) self._agent._get_status = get_status_mock - ocf_returncode = self._agent.start() + ocf_returncode = self._agent._start_sys5_style() assert ocf_returncode == 0 - self._agent._inititialize.assert_called_once_with() - mock_run_command.assert_has_calls([ mock.call('rm -f /tmp/.sapstream50013'), mock.call('rm -f /tmp/.sapstream50014'), @@ -418,13 +573,12 @@ ]) mock_logger.assert_called_once_with( - 'sapstartsrv for SAP Instance PRD-ASCS00 started: output') + 'sapstartsrv for SAP Instance PRD_ASCS00 started: output') @mock.patch('ocf.logger.error') @mock.patch('ocf.OCF_NOT_RUNNING', 1) @mock.patch('SAPStartSrv.run_command') - def test_start_error(self, mock_run_command, mock_logger): - self._agent._inititialize = mock.Mock() + def test_start_sys5_style_error(self, mock_run_command, mock_logger): self._agent.instance_name = 'ASCS00' self._agent.instance_number = '00' self._agent.saptstartsrv_path = '/mock/sapstartsrv' @@ -432,18 +586,16 @@ self._agent.sid = 'PRD' self._agent.sidadm = 'prdadm' - start_mock = mock.Mock(output='output', err='error') - mock_run_command.side_effect = [None, None, start_mock] + start_sys5_style_mock = mock.Mock(output='output', err='error') + mock_run_command.side_effect = [None, None, start_sys5_style_mock] get_status_result_mock = mock.Mock(returncode=1) get_status_mock = mock.Mock(return_value=get_status_result_mock) self._agent._get_status = get_status_mock - ocf_returncode = self._agent.start() + ocf_returncode = self._agent._start_sys5_style() assert ocf_returncode == 1 - self._agent._inititialize.assert_called_once_with() - mock_run_command.assert_has_calls([ mock.call('rm -f /tmp/.sapstream50013'), mock.call('rm -f /tmp/.sapstream50014'), @@ -451,13 +603,164 @@ ]) mock_logger.assert_called_once_with( - 'sapstartsrv for SAP Instance PRD-ASCS00 start failed: error') + 'sapstartsrv for SAP Instance PRD_ASCS00 start failed: error') + + @mock.patch('ocf.logger.info') + @mock.patch('ocf.OCF_SUCCESS', 0) + def test_start_systemd_style_success_running(self, mock_logger): + self._agent.systemd_unit_name = 'SAPPRD_00.service' + is_unit_active_mock = mock.Mock(return_value=True) + self._agent._is_unit_active = is_unit_active_mock + + result = self._agent._start_systemd_style() + assert result == 0 + + mock_logger.assert_called_once_with( + 'systemd service SAPPRD_00.service is active') + + @mock.patch('ocf.logger.warn') + @mock.patch('ocf.OCF_SUCCESS', 0) + @mock.patch('SAPStartSrv.run_command') + def test_start_systemd_style_success_not_running(self, mock_run_command, mock_logger): + self._agent.systemd_unit_name = 'SAPPRD_00.service' + is_unit_active_mock = mock.Mock(return_value=False) + self._agent._is_unit_active = is_unit_active_mock + + start_mock = mock.Mock(output='output', err='error', returncode=0) + mock_run_command.return_value = start_mock + + result = self._agent._start_systemd_style() + assert result == 0 + + mock_run_command.assert_called_once_with( + '/usr/bin/systemctl start SAPPRD_00.service') + + mock_logger.assert_called_once_with( + 'systemd service SAPPRD_00.service is not active, it will be started using systemd') + + @mock.patch('ocf.logger.error') + @mock.patch('ocf.OCF_SUCCESS', 0) + @mock.patch('ocf.OCF_NOT_RUNNING', 7) + @mock.patch('ocf.is_probe') + @mock.patch('SAPStartSrv.run_command') + def test_start_systemd_style_error_probe(self, mock_run_command, mock_is_probe, mock_logger): + self._agent.systemd_unit_name = 'SAPPRD_00.service' + is_unit_active_mock = mock.Mock(return_value=False) + self._agent._is_unit_active = is_unit_active_mock + + start_mock = mock.Mock(output='output', err='error', returncode=1) + mock_run_command.return_value = start_mock + mock_is_probe.return_value = True + + result = self._agent._start_systemd_style() + assert result == 7 + + mock_run_command.assert_called_once_with( + '/usr/bin/systemctl start SAPPRD_00.service') + + mock_logger.assert_called_once_with( + 'error during start of systemd unit SAPPRD_00.service!') + + @mock.patch('ocf.logger.error') + @mock.patch('ocf.OCF_SUCCESS', 0) + @mock.patch('ocf.OCF_ERR_GENERIC', 1) + @mock.patch('ocf.is_probe') + @mock.patch('SAPStartSrv.run_command') + def test_start_systemd_style_error_not_probe( + self, mock_run_command, mock_is_probe, mock_logger): + self._agent.systemd_unit_name = 'SAPPRD_00.service' + is_unit_active_mock = mock.Mock(return_value=False) + self._agent._is_unit_active = is_unit_active_mock + + start_mock = mock.Mock(output='output', err='error', returncode=1) + mock_run_command.return_value = start_mock + mock_is_probe.return_value = False + + result = self._agent._start_systemd_style() + assert result == 1 + + mock_run_command.assert_called_once_with( + '/usr/bin/systemctl start SAPPRD_00.service') + + mock_logger.assert_called_once_with( + 'error during start of systemd unit SAPPRD_00.service!') + + @mock.patch('ocf.OCF_SUCCESS', 0) + def test_start_systemd_style_success(self): + self._agent._inititialize = mock.Mock() + + chk_systemd_support_mock = mock.Mock(return_value=True) + self._agent._chk_systemd_support = chk_systemd_support_mock + start_systemd_style_mock = mock.Mock(return_value=0) + self._agent._start_systemd_style = start_systemd_style_mock + + result = self._agent.start() + assert result == 0 + + self._agent._inititialize.assert_called_once_with() + + @mock.patch('ocf.OCF_SUCCESS', 0) + def test_start_success_sys5_style(self): + self._agent._inititialize = mock.Mock() + + chk_systemd_support_mock = mock.Mock(return_value=False) + self._agent._chk_systemd_support = chk_systemd_support_mock + start_sys5_style_mock = mock.Mock(return_value=0) + self._agent._start_sys5_style = start_sys5_style_mock + + result = self._agent.start() + assert result == 0 + + self._agent._inititialize.assert_called_once_with() + + @mock.patch('ocf.OCF_SUCCESS', 0) + def test_start_error_sys5_style(self): + self._agent._inititialize = mock.Mock() + + chk_systemd_support_mock = mock.Mock(return_value=False) + self._agent._chk_systemd_support = chk_systemd_support_mock + start_sys5_style_mock = mock.Mock(return_value=1) + self._agent._start_sys5_style = start_sys5_style_mock + + result = self._agent.start() + assert result == 1 + + self._agent._inititialize.assert_called_once_with() + + @mock.patch('ocf.OCF_SUCCESS', 0) + def test_start_success_systemd_style(self): + self._agent._inititialize = mock.Mock() + + chk_systemd_support_mock = mock.Mock(return_value=True) + self._agent._chk_systemd_support = chk_systemd_support_mock + start_systemd_style_mock = mock.Mock(return_value=0) + self._agent._start_systemd_style = start_systemd_style_mock + + result = self._agent.start() + assert result == 0 + + self._agent._inititialize.assert_called_once_with() + + @mock.patch('ocf.OCF_SUCCESS', 0) + def test_start_error_systemd_style(self): + self._agent._inititialize = mock.Mock() + + chk_systemd_support_mock = mock.Mock(return_value=True) + self._agent._chk_systemd_support = chk_systemd_support_mock + start_systemd_style_mock = mock.Mock(return_value=1) + self._agent._start_systemd_style = start_systemd_style_mock + + result = self._agent.start() + assert result == 1 + + self._agent._inititialize.assert_called_once_with() @mock.patch('ocf.logger.info') @mock.patch('ocf.OCF_SUCCESS', 0) @mock.patch('SAPStartSrv.run_command') def test_stop_success(self, mock_run_command, mock_logger): self._agent._inititialize = mock.Mock() + self._agent.instance_name = 'ASCS00' self._agent.instance_number = '00' self._agent.sapcontrol_path = '/mock/sapcontrol' self._agent.sid = 'PRD' @@ -476,14 +779,14 @@ mock_run_command.assert_called_once_with('/mock/sapcontrol -nr 00 -function StopService') mock_logger.assert_called_once_with( - 'Stopping sapstartsrv of SAP Instance PRD-00: output') + 'Stopping sapstartsrv of SAP Instance PRD_ASCS00: output') @mock.patch('ocf.logger.info') @mock.patch('ocf.OCF_SUCCESS', 0) @mock.patch('SAPStartSrv.run_command') def test_stop_already_stopped(self, mock_run_command, mock_logger): self._agent._inititialize = mock.Mock() - self._agent.instance_number = '00' + self._agent.instance_name = 'ASCS00' self._agent.sid = 'PRD' self._agent._get_status = mock.Mock(return_value=mock.Mock(returncode=1)) @@ -497,13 +800,14 @@ assert mock_run_command.call_count == 0 mock_logger.assert_called_once_with( - 'SAP Instance PRD-00 already stopped') + 'SAP Instance PRD_ASCS00 already stopped') @mock.patch('ocf.logger.error') @mock.patch('ocf.OCF_ERR_GENERIC', 1) @mock.patch('SAPStartSrv.run_command') def test_stop_error(self, mock_run_command, mock_logger): self._agent._inititialize = mock.Mock() + self._agent.instance_name = 'ASCS00' self._agent.instance_number = '00' self._agent.sapcontrol_path = '/mock/sapcontrol' self._agent.sid = 'PRD' @@ -522,7 +826,7 @@ mock_run_command.assert_called_once_with('/mock/sapcontrol -nr 00 -function StopService') mock_logger.assert_called_once_with( - 'SAP Instance PRD-00 stop failed: error') + 'SAP Instance PRD_ASCS00 stop failed: error') @mock.patch('ocf.OCF_SUCCESS', 0) def test_status_success(self):