Skip to content

Commit

Permalink
Disp work gatherer (#281)
Browse files Browse the repository at this point in the history
* Implemente disp+work gatherer

* Add gatherer to standard gatherers list
  • Loading branch information
arbulu89 authored Oct 23, 2023
1 parent c1e5123 commit 995be5e
Show file tree
Hide file tree
Showing 6 changed files with 381 additions and 0 deletions.
142 changes: 142 additions & 0 deletions internal/factsengine/gatherers/dispwork.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
package gatherers

import (
"encoding/json"
"fmt"
"path/filepath"
"regexp"
"strings"

log "github.com/sirupsen/logrus"
"github.com/spf13/afero"
"github.com/trento-project/agent/internal/core/sapsystem"
"github.com/trento-project/agent/pkg/factsengine/entities"
"github.com/trento-project/agent/pkg/utils"
)

const (
DispWorkGathererName = "disp+work"
)

// nolint:gochecknoglobals
var (
DispWorkFileSystemError = entities.FactGatheringError{
Type: "dispwork-file-system-error",
Message: "error reading the file system",
}

DispWorkCommandError = entities.FactGatheringError{
Type: "dispwork-command-error",
Message: "error running disp+work command",
}

DispWorkDecodingError = entities.FactGatheringError{
Type: "dispwork-decoding-error",
Message: "error decoding disp+work output",
}

// the names groups values are the values used to compose the resulting fact value map
entriesPatternCompiled = regexp.MustCompile("(?m)" +
"^kernel release\\s+(?P<kernel_release>.*)$|" +
"^compilation mode\\s+(?P<compilation_mode>.*)$|" +
"^patch number\\s+(?P<patch_number>.*)$")

groupedNames = entriesPatternCompiled.SubexpNames()[1:]
)

type DispWorkGatherer struct {
fs afero.Fs
executor utils.CommandExecutor
}

type dispWorkData struct {
CompilationMode string `json:"compilation_mode"`
KernelRelease string `json:"kernel_release"`
PatchNumber string `json:"patch_number"`
}

func NewDefaultDispWorkGatherer() *DispWorkGatherer {
return NewDispWorkGatherer(afero.NewOsFs(), utils.Executor{})
}

func NewDispWorkGatherer(fs afero.Fs, executor utils.CommandExecutor) *DispWorkGatherer {
return &DispWorkGatherer{
fs: fs,
executor: executor,
}
}

func (g *DispWorkGatherer) Gather(factsRequests []entities.FactRequest) ([]entities.Fact, error) {
facts := []entities.Fact{}
log.Infof("Starting %s facts gathering process", DispWorkGathererName)

systemPaths, err := sapsystem.FindSystems(g.fs)
if err != nil {
return nil, DispWorkFileSystemError.Wrap(err.Error())
}

dispWorkMap := make(map[string]dispWorkData)

for _, systemPath := range systemPaths {
sid := filepath.Base(systemPath)
sapUser := fmt.Sprintf("%sadm", strings.ToLower(sid))

dispWorkOutput, err := g.executor.Exec("su", "-", sapUser, "-c", "\"disp+work\"")
if err != nil {
gatheringError := DispWorkCommandError.Wrap(err.Error())
log.Error(gatheringError)
dispWorkMap[sid] = dispWorkData{} // fill with empty data
continue
}

result := fillRegexpGroups(string(dispWorkOutput))

dispWorkMap[sid] = dispWorkData{
CompilationMode: result["compilation_mode"],
KernelRelease: result["kernel_release"],
PatchNumber: result["patch_number"],
}
}

factValue, err := dispWorkDataToFactValue(dispWorkMap)
if err != nil {
gatheringError := DispWorkDecodingError.Wrap(err.Error())
log.Error(gatheringError)
return nil, gatheringError
}

for _, factReq := range factsRequests {
facts = append(facts, entities.NewFactGatheredWithRequest(factReq, factValue))
}

log.Infof("Requested %s facts gathered", DispWorkGathererName)
return facts, nil
}

func fillRegexpGroups(output string) map[string]string {
result := make(map[string]string)
for _, match := range entriesPatternCompiled.FindAllStringSubmatch(output, -1) {
for i, name := range groupedNames {
if value, found := result[name]; found && value != "" {
continue
}
result[name] = match[i+1]
}
}
return result
}

func dispWorkDataToFactValue(data map[string]dispWorkData) (entities.FactValue, error) {
marshalled, err := json.Marshal(&data)
if err != nil {
return nil, err
}

var unmarshalled map[string]interface{}
err = json.Unmarshal(marshalled, &unmarshalled)
if err != nil {
return nil, err
}

return entities.NewFactValue(unmarshalled)
}
133 changes: 133 additions & 0 deletions internal/factsengine/gatherers/dispwork_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
package gatherers_test

import (
"errors"
"io"
"os"
"testing"

"github.com/spf13/afero"
"github.com/stretchr/testify/suite"
"github.com/trento-project/agent/internal/factsengine/gatherers"
"github.com/trento-project/agent/pkg/factsengine/entities"
utilsMocks "github.com/trento-project/agent/pkg/utils/mocks"
"github.com/trento-project/agent/test/helpers"
)

type DispWorkGathererTestSuite struct {
suite.Suite
fs afero.Fs
mockExecutor *utilsMocks.CommandExecutor
}

func TestDispWorkGathererSuite(t *testing.T) {
suite.Run(t, new(DispWorkGathererTestSuite))
}

func (suite *DispWorkGathererTestSuite) SetupTest() {
fs := afero.NewMemMapFs()
err := fs.MkdirAll("/usr/sap/PRD", 0644)
suite.NoError(err)
err = fs.MkdirAll("/usr/sap/QAS", 0644)
suite.NoError(err)
err = fs.MkdirAll("/usr/sap/QA2", 0644)
suite.NoError(err)
err = fs.MkdirAll("/usr/sap/DEV", 0644)
suite.NoError(err)

suite.fs = fs
suite.mockExecutor = new(utilsMocks.CommandExecutor)
}

func (suite *DispWorkGathererTestSuite) TestDispWorkGatheringSuccess() {
validOutputFile, _ := os.Open(helpers.GetFixturePath("gatherers/dispwork-valid.output"))
validOutput, _ := io.ReadAll(validOutputFile)
partialOutputFile, _ := os.Open(helpers.GetFixturePath("gatherers/dispwork-partial.output"))
partialOutput, _ := io.ReadAll(partialOutputFile)
unsortedOutputFile, _ := os.Open(helpers.GetFixturePath("gatherers/dispwork-unsorted.output"))
unsortedOutput, _ := io.ReadAll(unsortedOutputFile)
suite.mockExecutor.
On("Exec", "su", "-", "prdadm", "-c", "\"disp+work\"").
Return(validOutput, nil).
On("Exec", "su", "-", "qasadm", "-c", "\"disp+work\"").
Return(partialOutput, nil).
On("Exec", "su", "-", "qa2adm", "-c", "\"disp+work\"").
Return(unsortedOutput, nil).
On("Exec", "su", "-", "devadm", "-c", "\"disp+work\"").
Return(nil, errors.New("some error"))

g := gatherers.NewDispWorkGatherer(suite.fs, suite.mockExecutor)

fr := []entities.FactRequest{
{
Name: "dispwork",
CheckID: "check1",
Gatherer: "disp+work",
},
}

expectedResults := []entities.Fact{{
Name: "dispwork",
CheckID: "check1",
Value: &entities.FactValueMap{
Value: map[string]entities.FactValue{
"PRD": &entities.FactValueMap{
Value: map[string]entities.FactValue{
"compilation_mode": &entities.FactValueString{Value: "UNICODE"},
"kernel_release": &entities.FactValueString{Value: "753"},
"patch_number": &entities.FactValueString{Value: "900"},
},
},
"QAS": &entities.FactValueMap{
Value: map[string]entities.FactValue{
"compilation_mode": &entities.FactValueString{Value: ""},
"kernel_release": &entities.FactValueString{Value: "753"},
"patch_number": &entities.FactValueString{Value: ""},
},
},
"QA2": &entities.FactValueMap{
Value: map[string]entities.FactValue{
"compilation_mode": &entities.FactValueString{Value: "UNICODE"},
"kernel_release": &entities.FactValueString{Value: "753"},
"patch_number": &entities.FactValueString{Value: "900"},
},
},
"DEV": &entities.FactValueMap{
Value: map[string]entities.FactValue{
"compilation_mode": &entities.FactValueString{Value: ""},
"kernel_release": &entities.FactValueString{Value: ""},
"patch_number": &entities.FactValueString{Value: ""},
},
},
},
},
}}

result, err := g.Gather(fr)
suite.NoError(err)
suite.EqualValues(expectedResults, result)
}

func (suite *DispWorkGathererTestSuite) TestDispWorkGatheringEmptyFileSystem() {
g := gatherers.NewDispWorkGatherer(afero.NewMemMapFs(), suite.mockExecutor)

fr := []entities.FactRequest{
{
Name: "dispwork",
CheckID: "check1",
Gatherer: "disp+work",
},
}

expectedResults := []entities.Fact{{
Name: "dispwork",
CheckID: "check1",
Value: &entities.FactValueMap{
Value: map[string]entities.FactValue{},
},
}}

result, err := g.Gather(fr)
suite.NoError(err)
suite.EqualValues(expectedResults, result)
}
3 changes: 3 additions & 0 deletions internal/factsengine/gatherers/gatherer.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,9 @@ func StandardGatherers() FactGatherersTree {
DirScanGathererName: map[string]FactGatherer{
"v1": NewDefaultDirScanGatherer(),
},
DispWorkGathererName: map[string]FactGatherer{
"v1": NewDefaultDispWorkGatherer(),
},
FstabGathererName: map[string]FactGatherer{
"v1": NewDefaultFstabGatherer(),
},
Expand Down
12 changes: 12 additions & 0 deletions test/fixtures/gatherers/dispwork-partial.output
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@

--------------------
disp+work information
--------------------

kernel release 753

kernel make variant 753_REL

compiled on Linux GNU SLES-11 x86_64 cc4.8.5 use-pr211015 for linuxx86_64

compiled for 64 BIT
46 changes: 46 additions & 0 deletions test/fixtures/gatherers/dispwork-unsorted.output
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@

--------------------
disp+work information
--------------------

patch number 900

kernel make variant 753_REL

compilation mode UNICODE

compiled on Linux GNU SLES-11 x86_64 cc4.8.5 use-pr211015 for linuxx86_64

compiled for 64 BIT

kernel release 753

compile time Oct 16 2021 00:21:02

Wed Oct 18 13:22:52 2023
Loading DB library '/usr/sap/NWP/SYS/exe/run/dbhdbslib.so' ...
Library '/usr/sap/NWP/SYS/exe/run/dbhdbslib.so' loaded
Version of '/usr/sap/NWP/SYS/exe/run/dbhdbslib.so' is "753.02", patchlevel (0.900)

update level 0


source id 0.900

RKS compatibility level 1

DW_GUI compatibility level 900


---------------------
supported environment
---------------------

database (SAP, table SVERS) 740
750
751
752
769

operating system
Linux
45 changes: 45 additions & 0 deletions test/fixtures/gatherers/dispwork-valid.output
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@

--------------------
disp+work information
--------------------

kernel release 753

kernel make variant 753_REL

compiled on Linux GNU SLES-11 x86_64 cc4.8.5 use-pr211015 for linuxx86_64

compiled for 64 BIT

compilation mode UNICODE

compile time Oct 16 2021 00:21:02

Wed Oct 18 13:22:52 2023
Loading DB library '/usr/sap/NWP/SYS/exe/run/dbhdbslib.so' ...
Library '/usr/sap/NWP/SYS/exe/run/dbhdbslib.so' loaded
Version of '/usr/sap/NWP/SYS/exe/run/dbhdbslib.so' is "753.02", patchlevel (0.900)

update level 0

patch number 900

source id 0.900

RKS compatibility level 1

DW_GUI compatibility level 900


---------------------
supported environment
---------------------

database (SAP, table SVERS) 740
750
751
752
769

operating system
Linux

0 comments on commit 995be5e

Please sign in to comment.