Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
nelsonkopliku committed Dec 16, 2022
1 parent ebf3205 commit eee7a98
Show file tree
Hide file tree
Showing 5 changed files with 223 additions and 93 deletions.
1 change: 1 addition & 0 deletions internal/factsengine/gatherers/gatherer.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,6 @@ func StandardGatherers() map[string]FactGatherer {
SystemDGathererName: NewDefaultSystemDGatherer(),
PackageVersionGathererName: NewDefaultPackageVersionGatherer(),
SBDConfigGathererName: NewDefaultSBDGatherer(),
SBDDumpGathererName: NewDefaultSBDDumpGatherer(),
}
}
126 changes: 107 additions & 19 deletions internal/factsengine/gatherers/sbddump.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,44 +13,132 @@ const (
SBDDumpGathererName = "sbd_dump"
)

// nolint:gochecknoglobals
var (
SBDDevicesLoadingError = entities.FactGatheringError{
Type: "sbd-devices-loading-error",
Message: "error loading the configured sbd devices",
}

SBDDumpCommandError = entities.FactGatheringError{
Type: "sbd-dump-command-error",
Message: "error while executing sbd dump",
}
)

type SBDDumpGatherer struct {
executor utils.CommandExecutor
executor utils.CommandExecutor
sbdGatherer *SBDGatherer
}

func NewDefaultSBDDumpGatherer() *SBDDumpGatherer {
return NewSBDDumpGatherer(utils.Executor{})
return NewSBDDumpGatherer(utils.Executor{}, NewDefaultSBDGatherer())
}

func NewSBDDumpGatherer(executor utils.CommandExecutor) *SBDDumpGatherer {
func NewSBDDumpGatherer(executor utils.CommandExecutor, sbdGatherer *SBDGatherer) *SBDDumpGatherer {
return &SBDDumpGatherer{
executor: executor,
executor: executor,
sbdGatherer: sbdGatherer,
}
}

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

for _, factReq := range factsRequests {
//FIXME: This is a workaround until we allow multiple arguments per fact request
args := strings.Split(factReq.Argument, ":")
SBDDump, err := gatherer.executor.Exec(
"sbd", "dump", "-d", args[0], "dump")
if err != nil {
log.Errorf("Error getting sbd dump for device: %s", args[0])
return facts, err
}
configuredDevices, err := loadDevices(gatherer.sbdGatherer)

if err != nil {
return facts, SBDDevicesLoadingError.Wrap(err.Error())
}

SBDDumpMap := utils.FindMatches(`(?m)^(\S+(?: \S+)*)\s*:\s(\S*)$`, SBDDump)
key := strings.ReplaceAll(args[1], " ", "_")
if value, ok := SBDDumpMap[key]; ok {
fact := entities.NewFactGatheredWithRequest(factReq, entities.ParseStringToFactValue(fmt.Sprint(value)))
facts = append(facts, fact)
for _, factRequest := range factsRequests {
var fact entities.Fact

if devicesDumps, err := getSBDDevicesDumps(gatherer.executor, configuredDevices); err == nil {
fact = entities.NewFactGatheredWithRequest(factRequest, &entities.FactValueMap{Value: devicesDumps})
} else {
log.Warnf("%s gatherer: requested fact %s not found", SBDDumpGathererName, factReq.Argument)
gatheringError := SBDDumpCommandError.Wrap(err.Error())

fact = entities.NewFactGatheredWithError(factRequest, gatheringError)
}
facts = append(facts, fact)
}

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

func loadDevices(gatherer *SBDGatherer) ([]string, error) {
sbdDevicesRequest := []entities.FactRequest{
{
Name: "configured_devices",
Gatherer: "sbd_config",
Argument: "SBD_DEVICE",
},
}

sbdDevicesFacts, err := gatherer.Gather(sbdDevicesRequest)

if err != nil {
return []string{}, err
}

sbdDevicesFact := sbdDevicesFacts[0]

if sbdDevicesFact.Error != nil {
return []string{}, sbdDevicesFact.Error
}

deviceAsStringValue, ok := sbdDevicesFact.Value.(*entities.FactValueString)

if !ok {
return []string{}, fmt.Errorf("Unable to determine the device name: %s", sbdDevicesFact.Value)
}

return strings.Split(deviceAsStringValue.Value, ";"), nil
}

func getSBDDevicesDumps(
executor utils.CommandExecutor,
configuredDevices []string) (map[string]entities.FactValue, error) {
var devicesDumps = make(map[string]entities.FactValue)

for _, device := range configuredDevices {
SBDDumpMap, err := getSBDDumpFactValueMap(executor, device)
if err != nil {
log.Errorf("Error getting sbd dump for device: %s", device)

return nil, err
}

devicesDumps[device] = SBDDumpMap
}

return devicesDumps, nil
}

func getSBDDumpFactValueMap(executor utils.CommandExecutor, device string) (*entities.FactValueMap, error) {
SBDDump, err := executor.Exec("sbd", "dump", "-d", device, "dump")
if err != nil {
return nil, err
}

SBDDumpMap := utils.FindMatches(`(?m)^(\S+(?: \S+)*)\s*:\s(\S*)$`, SBDDump)

var deviceDump = make(map[string]entities.FactValue)

for key, value := range SBDDumpMap {
valueAsString, ok := value.(string)

if !ok {
err := fmt.Errorf(`Unable to parse sbd dump entry "%s" as string: %s`, key, value)
log.Error(err)
return nil, err
}

deviceDump[key] = entities.ParseStringToFactValue(valueAsString)
}

return &entities.FactValueMap{Value: deviceDump}, nil
}
175 changes: 103 additions & 72 deletions internal/factsengine/gatherers/sbddump_test.go
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
package gatherers
package gatherers_test

import (
"errors"
"io/ioutil"
"os"
"os/exec"
"testing"

"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"
Expand All @@ -20,122 +21,152 @@ func TestSBDDumpTestSuite(t *testing.T) {
suite.Run(t, new(SBDDumpTestSuite))
}

func (suite *SBDDumpTestSuite) TestSBDDumpGathererMissingFact() {
func (suite *SBDDumpTestSuite) TestSBDDumpUnableToLoadDevices() {
mockExecutor := new(utilsMocks.CommandExecutor)

mockOutputFile, _ := os.Open(helpers.GetFixturePath("gatherers/sbddump.output"))
mockOutput, _ := ioutil.ReadAll(mockOutputFile)
mockExecutor.On("Exec", "sbd", "dump", "-d", "/dev/sdj", "dump").Return(mockOutput, nil)

c := &SBDDumpGatherer{
executor: mockExecutor,
}
sbdDumpGatherer := gatherers.NewSBDDumpGatherer(
mockExecutor,
gatherers.NewSBDGatherer(helpers.GetFixturePath("discovery/cluster/sbd/sbd_config_invalid")),
)

factRequests := []entities.FactRequest{
{
Name: "nonexistant_timeout",
Name: "sbd_devices_dump",
Gatherer: "sbd_dump",
Argument: "/dev/sdj:Timeout (nonexistant)",
},
}

factResults, err := c.Gather(factRequests)

expectedResults := []entities.Fact{}
gatheredFacts, err := sbdDumpGatherer.Gather(factRequests)

suite.NoError(err)
suite.ElementsMatch(expectedResults, factResults)
expectedError := &entities.FactGatheringError{
Message: "error loading the configured sbd devices: fact gathering error: " +
"sbd-config-file-error - error reading sbd configuration file: " +
"could not parse sbd config file: error on line 1: missing =",
Type: "sbd-devices-loading-error",
}
suite.EqualError(err, expectedError.Error())
suite.Empty(gatheredFacts)
}

func (suite *SBDDumpTestSuite) TestSBDDumpGatherer() {
func (suite *SBDDumpTestSuite) TestSBDDumpUnableToDumpDevice() {
mockExecutor := new(utilsMocks.CommandExecutor)

mockOutputFile, _ := os.Open("../../../test/fixtures/gatherers/sbddump.output")
mockOutputFile, _ := os.Open(helpers.GetFixturePath("gatherers/dev.vdc.sbddump.output"))
mockOutput, _ := ioutil.ReadAll(mockOutputFile)
mockExecutor.On("Exec", "sbd", "dump", "-d", "/dev/sdj", "dump").Return(mockOutput, nil)
mockExecutor.On("Exec", "sbd", "dump", "-d", "/dev/vdb", "dump").Return(nil, errors.New("a failure"))
mockExecutor.On("Exec", "sbd", "dump", "-d", "/dev/vdc", "dump").Return(mockOutput, nil)

c := &SBDDumpGatherer{
executor: mockExecutor,
}
sbdDumpGatherer := gatherers.NewSBDDumpGatherer(
mockExecutor,
gatherers.NewSBDGatherer(helpers.GetFixturePath("discovery/cluster/sbd/sbd_config")),
)

factRequests := []entities.FactRequest{
{
Name: "header_version",
Name: "sbd_devices_dump",
Gatherer: "sbd_dump",
Argument: "/dev/sdj:Header version",
},
{
Name: "sector_size",
Name: "another_sbd_devices_dump",
Gatherer: "sbd_dump",
Argument: "/dev/sdj:Sector size",
},
{
Name: "watchdog_timeout",
Gatherer: "sbd_dump",
Argument: "/dev/sdj:Timeout (watchdog)",
},
{
Name: "allocate_timeout",
Gatherer: "sbd_dump",
Argument: "/dev/sdj:Timeout (allocate)",
},
{
Name: "loop_timeout",
Gatherer: "sbd_dump",
Argument: "/dev/sdj:Timeout (loop)",
Argument: "an-ignored-argument",
},
}

factResults, err := c.Gather(factRequests)
gatheredFacts, err := sbdDumpGatherer.Gather(factRequests)

expectedResults := []entities.Fact{
expectedFacts := []entities.Fact{
{
Name: "header_version",
Value: &entities.FactValueFloat{Value: 2.1},
Name: "sbd_devices_dump",
Value: nil,
Error: &entities.FactGatheringError{
Message: "error while executing sbd dump: a failure",
Type: "sbd-dump-command-error",
},
},
{
Name: "sector_size",
Value: &entities.FactValueInt{Value: 512},
},
{
Name: "watchdog_timeout",
Value: &entities.FactValueInt{Value: 5},
},
{
Name: "allocate_timeout",
Value: &entities.FactValueInt{Value: 2},
},
{
Name: "loop_timeout",
Value: &entities.FactValueInt{Value: 1},
Name: "another_sbd_devices_dump",
Value: nil,
Error: &entities.FactGatheringError{
Message: "error while executing sbd dump: a failure",
Type: "sbd-dump-command-error",
},
},
}

suite.NoError(err)
suite.ElementsMatch(expectedResults, factResults)
suite.ElementsMatch(expectedFacts, gatheredFacts)
}

func (suite *SBDDumpTestSuite) TestSBDDumpCommandNotFound() {
func (suite *SBDDumpTestSuite) TestSBDDumpGatherer() {
mockExecutor := new(utilsMocks.CommandExecutor)

mockExecutor.On("Exec", "sbd", "dump", "-d", "/dev/sdj", "dump").Return(nil, exec.ErrNotFound)
deviceVDBMockOutputFile, _ := os.Open(helpers.GetFixturePath("gatherers/dev.vdb.sbddump.output"))
deviceVDBMockOutput, _ := ioutil.ReadAll(deviceVDBMockOutputFile)

c := &SBDDumpGatherer{
executor: mockExecutor,
}
deviceVDCMockOutputFile, _ := os.Open(helpers.GetFixturePath("gatherers/dev.vdc.sbddump.output"))
deviceVDCMockOutput, _ := ioutil.ReadAll(deviceVDCMockOutputFile)

mockExecutor.On("Exec", "sbd", "dump", "-d", "/dev/vdb", "dump").Return(deviceVDBMockOutput, nil)
mockExecutor.On("Exec", "sbd", "dump", "-d", "/dev/vdc", "dump").Return(deviceVDCMockOutput, nil)

sbdDumpGatherer := gatherers.NewSBDDumpGatherer(
mockExecutor,
gatherers.NewSBDGatherer(helpers.GetFixturePath("discovery/cluster/sbd/sbd_config")),
)

factRequests := []entities.FactRequest{
{
Name: "watchdog_timeout",
Name: "sbd_devices_dump",
Gatherer: "sbd_dump",
Argument: "/dev/sdj:Timeout (watchdog)",
},
{
Name: "another_sbd_devices_dump",
Gatherer: "sbd_dump",
Argument: "an-ignored-argument",
},
}

factResults, err := c.Gather(factRequests)
factResults, err := sbdDumpGatherer.Gather(factRequests)

deviceVDBDump := &entities.FactValueMap{Value: map[string]entities.FactValue{
"Header_version": &entities.FactValueFloat{Value: 2.1},
"Number_of_slots": &entities.FactValueInt{Value: 255},
"Sector_size": &entities.FactValueInt{Value: 512},
"Timeout_(allocate)": &entities.FactValueInt{Value: 2},
"Timeout_(loop)": &entities.FactValueInt{Value: 1},
"Timeout_(msgwait)": &entities.FactValueInt{Value: 10},
"Timeout_(watchdog)": &entities.FactValueInt{Value: 5},
"UUID": &entities.FactValueString{Value: "e09c8993-0cba-438d-a4c3-78e91f58ee52"},
}}

deviceVDCDump := &entities.FactValueMap{Value: map[string]entities.FactValue{
"Header_version": &entities.FactValueFloat{Value: 2.1},
"Number_of_slots": &entities.FactValueInt{Value: 255},
"Sector_size": &entities.FactValueInt{Value: 512},
"Timeout_(allocate)": &entities.FactValueInt{Value: 2},
"Timeout_(loop)": &entities.FactValueInt{Value: 1},
"Timeout_(msgwait)": &entities.FactValueInt{Value: 10},
"Timeout_(watchdog)": &entities.FactValueInt{Value: 5},
"UUID": &entities.FactValueString{Value: "e5b7c05a-1d3c-43d0-827a-9d4dd05ca54a"},
}}

expectedResults := []entities.Fact{}
expectedResults := []entities.Fact{
{
Name: "sbd_devices_dump",
Value: &entities.FactValueMap{Value: map[string]entities.FactValue{
"/dev/vdb": deviceVDBDump,
"/dev/vdc": deviceVDCDump,
}},
},
{
Name: "another_sbd_devices_dump",
Value: &entities.FactValueMap{Value: map[string]entities.FactValue{
"/dev/vdb": deviceVDBDump,
"/dev/vdc": deviceVDCDump,
}},
},
}

suite.Error(err)
suite.NoError(err)
suite.ElementsMatch(expectedResults, factResults)
}
Loading

0 comments on commit eee7a98

Please sign in to comment.