diff --git a/internal/factsengine/gatherers/sapservices.go b/internal/factsengine/gatherers/sapservices.go index c5d73409..709fce48 100644 --- a/internal/factsengine/gatherers/sapservices.go +++ b/internal/factsengine/gatherers/sapservices.go @@ -31,14 +31,15 @@ var ( Type: "sap-services-reading-error", Message: "error reading the sapservices file", } - SapstartSIDExtractionPattern = regexp.MustCompile(`(?s)pf=[^[:space:]]+/(.*?)_.*_.*`) - SystemdSIDExtractionPattern = regexp.MustCompile(`(?s)start SAP(.*?)_.*`) + SapstartSIDExtractionPattern = regexp.MustCompile(`(?s)pf=[^[:space:]]+/(.*?)_(.*(\d{2}))_.*`) + SystemdSIDExtractionPattern = regexp.MustCompile(`(?s)start SAP(.*?)_(\d{2})`) ) type SapServicesEntry struct { - SID string `json:"sid"` - Kind SapServicesStartupKind `json:"kind"` - Content string `json:"content"` + SID string `json:"sid"` + Kind SapServicesStartupKind `json:"kind"` + Content string `json:"content"` + Instance string `json:"instance_nr"` } func systemdStartup(sapServicesContent string) bool { @@ -49,20 +50,20 @@ func sapstartStartup(sapServicesContent string) bool { return strings.Contains(sapServicesContent, "sapstartsrv") } -func extractSIDFromSystemdService(sapServicesContent string) string { +func extractInfoFromSystemdService(sapServicesContent string) (string, string) { matches := SystemdSIDExtractionPattern.FindStringSubmatch(sapServicesContent) - if len(matches) != 2 { - return "" + if len(matches) != 3 { + return "", "" } - return matches[1] + return matches[1], matches[2] } -func extractSIDFromSapstartService(sapServicesContent string) string { +func extractInfoFromSapstartService(sapServicesContent string) (string, string) { matches := SapstartSIDExtractionPattern.FindStringSubmatch(sapServicesContent) - if len(matches) != 2 { - return "" + if len(matches) != 4 { + return "", "" } - return matches[1] + return matches[1], matches[3] } type SapServices struct { @@ -129,29 +130,37 @@ func (s *SapServices) getSapServicesFileEntries() ([]SapServicesEntry, error) { continue } + // If the line does not start with a comment but has a comment in the middle, cut the comment + cleanedLine, _, _ := strings.Cut(scannedLine, "#") + scannedLine = cleanedLine + var kind SapServicesStartupKind var sid string + var instance string if systemdStartup(scannedLine) { kind = SapServicesSystemdStartup - extractedSID := extractSIDFromSystemdService(scannedLine) - if extractedSID == "" { + extractedSID, extractedInstance := extractInfoFromSystemdService(scannedLine) + if extractedSID == "" || extractedInstance == "" { return nil, SapServicesParsingError.Wrap( - fmt.Sprintf("could not extract sid from systemd SAP services entry: %s", scannedLine), + fmt.Sprintf("could not extract values from systemd SAP services entry: %s", scannedLine), ) } + sid = extractedSID + instance = extractedInstance } if sapstartStartup(scannedLine) { kind = SapServicesSapstartStartup - extractedSID := extractSIDFromSapstartService(scannedLine) - if extractedSID == "" { + extractedSID, extractedInstance := extractInfoFromSapstartService(scannedLine) + if extractedSID == "" || extractedInstance == "" { return nil, SapServicesParsingError.Wrap( - fmt.Sprintf("could not extract sid from sapstartsrv SAP services entry: %s", scannedLine), + fmt.Sprintf("could not extract values from sapstartsrv SAP services entry: %s", scannedLine), ) } sid = extractedSID + instance = extractedInstance } if kind == "" { @@ -160,9 +169,10 @@ func (s *SapServices) getSapServicesFileEntries() ([]SapServicesEntry, error) { } entry := SapServicesEntry{ - SID: sid, - Kind: kind, - Content: scannedLine, + SID: sid, + Kind: kind, + Content: scannedLine, + Instance: instance, } entries = append(entries, entry) diff --git a/internal/factsengine/gatherers/sapservices_test.go b/internal/factsengine/gatherers/sapservices_test.go index 96ec9071..1dcc4139 100644 --- a/internal/factsengine/gatherers/sapservices_test.go +++ b/internal/factsengine/gatherers/sapservices_test.go @@ -34,6 +34,29 @@ func (s *SapServicesGathererSuite) TestSapServicesGathererFileNotFound() { s.EqualError(err, "fact gathering error: sap-services-reading-error - error reading the sapservices file: open /usr/sap/sapservices: file does not exist") } +func (s *SapServicesGathererSuite) TestSapServicesGathererInstanceNotIdentifiedSystemd() { + tFs := afero.NewMemMapFs() + _ = afero.WriteFile(tFs, "/usr/sap/sapservices", []byte(` +#!/bin/sh +limit.descriptors=1048576 +systemctl --no-ask-password start SAPS41_0 +systemctl --no-ask-password start SAPS41_1 +`), 0777) + + fr := []entities.FactRequest{ + { + Name: "sapservices", + CheckID: "check1", + Gatherer: "sapservices", + }, + } + + g := gatherers.NewSapServicesGatherer("/usr/sap/sapservices", tFs) + result, err := g.Gather(fr) + s.Nil(result) + s.EqualError(err, "fact gathering error: sap-services-parsing-error - error parsing the sapservices file: could not extract values from systemd SAP services entry: systemctl --no-ask-password start SAPS41_0 ") + +} func (s *SapServicesGathererSuite) TestSapServicesGathererSIDNotIdentifiedSystemd() { tFs := afero.NewMemMapFs() _ = afero.WriteFile(tFs, "/usr/sap/sapservices", []byte(` @@ -54,7 +77,7 @@ systemctl --no-ask-password start SADS41_41 g := gatherers.NewSapServicesGatherer("/usr/sap/sapservices", tFs) result, err := g.Gather(fr) s.Nil(result) - s.EqualError(err, "fact gathering error: sap-services-parsing-error - error parsing the sapservices file: could not extract sid from systemd SAP services entry: systemctl --no-ask-password start SADS41_41") + s.EqualError(err, "fact gathering error: sap-services-parsing-error - error parsing the sapservices file: could not extract values from systemd SAP services entry: systemctl --no-ask-password start SADS41_41") } @@ -79,7 +102,31 @@ LD_LIBRARY_PATH=/usr/sap/S41/D40/exe:$LD_LIBRARY_PATH; export LD_LIBRARY_PATH; / g := gatherers.NewSapServicesGatherer("/usr/sap/sapservices", tFs) result, err := g.Gather(fr) s.Nil(result) - s.EqualError(err, "fact gathering error: sap-services-parsing-error - error parsing the sapservices file: could not extract sid from sapstartsrv SAP services entry: LD_LIBRARY_PATH=/usr/sap/HS1/HDB11/exe:$LD_LIBRARY_PATH;export LD_LIBRARY_PATH;/usr/sap/HS1/HDB11/exe/sapstartsrv pf=/usr/sap/HS1/SYS/profile/HS1HDB11_s41db -D -u hs1adm") + s.EqualError(err, "fact gathering error: sap-services-parsing-error - error parsing the sapservices file: could not extract values from sapstartsrv SAP services entry: LD_LIBRARY_PATH=/usr/sap/HS1/HDB11/exe:$LD_LIBRARY_PATH;export LD_LIBRARY_PATH;/usr/sap/HS1/HDB11/exe/sapstartsrv pf=/usr/sap/HS1/SYS/profile/HS1HDB11_s41db -D -u hs1adm") +} + +func (s *SapServicesGathererSuite) TestSapServicesGathererInstanceNotIdentifiedSapstart() { + tFs := afero.NewMemMapFs() + _ = afero.WriteFile(tFs, "/usr/sap/sapservices", []byte(` +#!/bin/sh +limit.descriptors=1048576 +LD_LIBRARY_PATH=/usr/sap/HS1/HDB11/exe:$LD_LIBRARY_PATH;export LD_LIBRARY_PATH;/usr/sap/HS1/HDB11/exe/sapstartsrv pf=/usr/sap/HS1/SYS/profile/HS1_HDB1_s41db -D -u hs1adm +LD_LIBRARY_PATH=/usr/sap/S41/ASCS41/exe:$LD_LIBRARY_PATH; export LD_LIBRARY_PATH; /usr/sap/S41/ASCS41/exe/sapstartsrv pf=/usr/sap/S41/SYS/profile/S41_ASCS41_s41app -D -u s41adm +LD_LIBRARY_PATH=/usr/sap/S41/D40/exe:$LD_LIBRARY_PATH; export LD_LIBRARY_PATH; /usr/sap/S41/D40/exe/sapstartsrv pf=/usr/sap/S41/SYS/profile/S41_D40_s41app -D -u s41adm +`), 0777) + + fr := []entities.FactRequest{ + { + Name: "sapservices", + CheckID: "check1", + Gatherer: "sapservices", + }, + } + + g := gatherers.NewSapServicesGatherer("/usr/sap/sapservices", tFs) + result, err := g.Gather(fr) + s.Nil(result) + s.EqualError(err, "fact gathering error: sap-services-parsing-error - error parsing the sapservices file: could not extract values from sapstartsrv SAP services entry: LD_LIBRARY_PATH=/usr/sap/HS1/HDB11/exe:$LD_LIBRARY_PATH;export LD_LIBRARY_PATH;/usr/sap/HS1/HDB11/exe/sapstartsrv pf=/usr/sap/HS1/SYS/profile/HS1_HDB1_s41db -D -u hs1adm") } func (s *SapServicesGathererSuite) TestSapServicesGathererSuccessSapstart() { //nolint:dupl @@ -107,16 +154,18 @@ LD_LIBRARY_PATH=/usr/sap/S41/ASCS41/exe:$LD_LIBRARY_PATH; export LD_LIBRARY_PATH Value: []entities.FactValue{ &entities.FactValueMap{ Value: map[string]entities.FactValue{ - "sid": &entities.FactValueString{Value: "HS1"}, - "kind": &entities.FactValueString{Value: "sapstartsrv"}, - "content": &entities.FactValueString{Value: "LD_LIBRARY_PATH=/usr/sap/HS1/HDB11/exe:$LD_LIBRARY_PATH;export LD_LIBRARY_PATH;/usr/sap/HS1/HDB11/exe/sapstartsrv pf=/usr/sap/HS1/SYS/profile/HS1_HDB11_s41db -D -u hs1adm"}, + "sid": &entities.FactValueString{Value: "HS1"}, + "kind": &entities.FactValueString{Value: "sapstartsrv"}, + "instance_nr": &entities.FactValueString{Value: "11"}, + "content": &entities.FactValueString{Value: "LD_LIBRARY_PATH=/usr/sap/HS1/HDB11/exe:$LD_LIBRARY_PATH;export LD_LIBRARY_PATH;/usr/sap/HS1/HDB11/exe/sapstartsrv pf=/usr/sap/HS1/SYS/profile/HS1_HDB11_s41db -D -u hs1adm"}, }, }, &entities.FactValueMap{ Value: map[string]entities.FactValue{ - "sid": &entities.FactValueString{Value: "S41"}, - "kind": &entities.FactValueString{Value: "sapstartsrv"}, - "content": &entities.FactValueString{Value: "LD_LIBRARY_PATH=/usr/sap/S41/ASCS41/exe:$LD_LIBRARY_PATH; export LD_LIBRARY_PATH; /usr/sap/S41/ASCS41/exe/sapstartsrv pf=/usr/sap/S41/SYS/profile/S41_ASCS41_s41app -D -u s41adm"}, + "sid": &entities.FactValueString{Value: "S41"}, + "kind": &entities.FactValueString{Value: "sapstartsrv"}, + "instance_nr": &entities.FactValueString{Value: "41"}, + "content": &entities.FactValueString{Value: "LD_LIBRARY_PATH=/usr/sap/S41/ASCS41/exe:$LD_LIBRARY_PATH; export LD_LIBRARY_PATH; /usr/sap/S41/ASCS41/exe/sapstartsrv pf=/usr/sap/S41/SYS/profile/S41_ASCS41_s41app -D -u s41adm"}, }, }, }, @@ -154,16 +203,68 @@ systemctl --no-ask-password start SAPS42_41 Value: []entities.FactValue{ &entities.FactValueMap{ Value: map[string]entities.FactValue{ - "sid": &entities.FactValueString{Value: "S41"}, - "kind": &entities.FactValueString{Value: "systemctl"}, - "content": &entities.FactValueString{Value: "systemctl --no-ask-password start SAPS41_40"}, + "sid": &entities.FactValueString{Value: "S41"}, + "kind": &entities.FactValueString{Value: "systemctl"}, + "instance_nr": &entities.FactValueString{Value: "40"}, + "content": &entities.FactValueString{Value: "systemctl --no-ask-password start SAPS41_40"}, + }, + }, + &entities.FactValueMap{ + Value: map[string]entities.FactValue{ + "sid": &entities.FactValueString{Value: "S42"}, + "kind": &entities.FactValueString{Value: "systemctl"}, + "instance_nr": &entities.FactValueString{Value: "41"}, + "content": &entities.FactValueString{Value: "systemctl --no-ask-password start SAPS42_41"}, + }, + }, + }, + }, + }, + } + g := gatherers.NewSapServicesGatherer("/usr/sap/sapservices", tFs) + result, err := g.Gather(fr) + s.NoError(err) + s.EqualValues(expectedFacts, result) +} + +func (s *SapServicesGathererSuite) TestSapServicesGathererSuccessWithAMiddleComment() { //nolint:dupl + tFs := afero.NewMemMapFs() + _ = afero.WriteFile(tFs, "/usr/sap/sapservices", []byte(` +#!/bin/sh +limit.descriptors=1048576 +systemctl --no-ask-password start SAPHA1_10 # sapstartsrv pf=/usr/sap/HA1/SYS/profile/HA1_ERS10_sapha1er +systemctl --no-ask-password start SAPS42_41 +`), 0777) + + fr := []entities.FactRequest{ + { + Name: "sapservices", + CheckID: "check1", + Gatherer: "sapservices", + }, + } + + expectedFacts := []entities.Fact{ + { + Name: "sapservices", + CheckID: "check1", + Value: &entities.FactValueList{ + Value: []entities.FactValue{ + &entities.FactValueMap{ + Value: map[string]entities.FactValue{ + "sid": &entities.FactValueString{Value: "HA1"}, + "kind": &entities.FactValueString{Value: "systemctl"}, + "instance_nr": &entities.FactValueString{Value: "10"}, + + "content": &entities.FactValueString{Value: "systemctl --no-ask-password start SAPHA1_10 "}, }, }, &entities.FactValueMap{ Value: map[string]entities.FactValue{ - "sid": &entities.FactValueString{Value: "S42"}, - "kind": &entities.FactValueString{Value: "systemctl"}, - "content": &entities.FactValueString{Value: "systemctl --no-ask-password start SAPS42_41"}, + "sid": &entities.FactValueString{Value: "S42"}, + "kind": &entities.FactValueString{Value: "systemctl"}, + "instance_nr": &entities.FactValueString{Value: "41"}, + "content": &entities.FactValueString{Value: "systemctl --no-ask-password start SAPS42_41"}, }, }, },