-
Notifications
You must be signed in to change notification settings - Fork 11
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add cibadmin gatherer based on dot access maps
- Loading branch information
Showing
6 changed files
with
274 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
package gatherers | ||
|
||
import ( | ||
log "github.com/sirupsen/logrus" | ||
"github.com/trento-project/agent/pkg/factsengine/entities" | ||
"github.com/trento-project/agent/pkg/utils" | ||
) | ||
|
||
const ( | ||
CibAdminGathererName = "cibadmin" | ||
) | ||
|
||
// nolint:gochecknoglobals | ||
var ( | ||
CibAdminCommandError = entities.FactGatheringError{ | ||
Type: "cibadmin-command-error", | ||
Message: "error running crm_mon command", | ||
} | ||
|
||
CibAdminDecodingError = entities.FactGatheringError{ | ||
Type: "cibadmin-decoding-error", | ||
Message: "error decoding cibadmin output", | ||
} | ||
) | ||
|
||
type CibAdminGatherer struct { | ||
executor utils.CommandExecutor | ||
} | ||
|
||
func NewDefaultCibAdminGatherer() *CibAdminGatherer { | ||
return NewCibAdminGatherer(utils.Executor{}) | ||
} | ||
|
||
func NewCibAdminGatherer(executor utils.CommandExecutor) *CibAdminGatherer { | ||
return &CibAdminGatherer{ | ||
executor: executor, | ||
} | ||
} | ||
|
||
func (g *CibAdminGatherer) Gather(factsRequests []entities.FactRequest) ([]entities.Fact, error) { | ||
log.Infof("Starting %s facts gathering process", CibAdminGathererName) | ||
|
||
cibadmin, err := g.executor.Exec("cibadmin", "--query", "--local") | ||
if err != nil { | ||
return nil, CibAdminCommandError.Wrap(err.Error()) | ||
} | ||
|
||
elementsToList := []string{"primitive", "clone", "master", "group", | ||
"nvpair", "op", "rsc_location", "rsc_order", "rsc_colocation"} | ||
|
||
factValueMap, err := parseXMLToFactValueMap(cibadmin, elementsToList) | ||
if err != nil { | ||
return nil, CibAdminDecodingError.Wrap(err.Error()) | ||
} | ||
|
||
facts := []entities.Fact{} | ||
|
||
for _, factReq := range factsRequests { | ||
var fact entities.Fact | ||
|
||
if value, err := factValueMap.GetValue(factReq.Argument); err == nil { | ||
fact = entities.NewFactGatheredWithRequest(factReq, value) | ||
|
||
} else { | ||
log.Error(err) | ||
fact = entities.NewFactGatheredWithError(factReq, err) | ||
} | ||
facts = append(facts, fact) | ||
} | ||
|
||
log.Infof("Requested %s facts gathered", CibAdminGathererName) | ||
return facts, err | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
package gatherers_test | ||
|
||
import ( | ||
"errors" | ||
"io" | ||
"os" | ||
"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" | ||
) | ||
|
||
type CibAdminTestSuite struct { | ||
suite.Suite | ||
mockExecutor *utilsMocks.CommandExecutor | ||
cibAdminOutput []byte | ||
} | ||
|
||
func TestCibAdminTestSuite(t *testing.T) { | ||
suite.Run(t, new(CibAdminTestSuite)) | ||
} | ||
|
||
func (suite *CibAdminTestSuite) SetupSuite() { | ||
lFile, _ := os.Open(helpers.GetFixturePath("gatherers/cibadmin.xml")) | ||
content, _ := io.ReadAll(lFile) | ||
|
||
suite.cibAdminOutput = content | ||
} | ||
|
||
func (suite *CibAdminTestSuite) SetupTest() { | ||
suite.mockExecutor = new(utilsMocks.CommandExecutor) | ||
} | ||
|
||
func (suite *CibAdminTestSuite) TestCibAdminGatherCmdNotFound() { | ||
suite.mockExecutor.On("Exec", "cibadmin", "--query", "--local").Return( | ||
suite.cibAdminOutput, errors.New("cibadmin not found")) | ||
|
||
p := gatherers.NewCibAdminGatherer(suite.mockExecutor) | ||
|
||
factRequests := []entities.FactRequest{ | ||
{ | ||
Name: "cib", | ||
Gatherer: "cibadmin", | ||
Argument: "cib", | ||
CheckID: "check1", | ||
}, | ||
} | ||
|
||
_, err := p.Gather(factRequests) | ||
|
||
suite.EqualError(err, "fact gathering error: cibadmin-command-error - "+ | ||
"error running crm_mon command: cibadmin not found") | ||
} | ||
|
||
func (suite *CibAdminTestSuite) TestCibAdminInvalidXML() { | ||
suite.mockExecutor.On("Exec", "cibadmin", "--query", "--local").Return( | ||
[]byte("invalid"), nil) | ||
|
||
p := gatherers.NewCibAdminGatherer(suite.mockExecutor) | ||
|
||
factRequests := []entities.FactRequest{ | ||
{ | ||
Name: "cib", | ||
Gatherer: "cibadmin", | ||
Argument: "cib", | ||
CheckID: "check1", | ||
}, | ||
} | ||
|
||
_, err := p.Gather(factRequests) | ||
|
||
suite.EqualError(err, "fact gathering error: cibadmin-decoding-error - "+ | ||
"error decoding cibadmin output: EOF") | ||
} | ||
|
||
func (suite *CibAdminTestSuite) TestCibAdminGather() { | ||
suite.mockExecutor.On("Exec", "cibadmin", "--query", "--local").Return( | ||
suite.cibAdminOutput, nil) | ||
|
||
p := gatherers.NewCibAdminGatherer(suite.mockExecutor) | ||
|
||
factRequests := []entities.FactRequest{ | ||
{ | ||
Name: "sid", | ||
Gatherer: "cibadmin", | ||
Argument: "cib.configuration.resources.master.0.primitive.0.instance_attributes.nvpair.0.value", | ||
CheckID: "check1", | ||
}, | ||
{ | ||
Name: "nvpair", | ||
Gatherer: "cibadmin", | ||
Argument: "cib.configuration.crm_config.cluster_property_set.nvpair.0", | ||
CheckID: "check2", | ||
}, | ||
{ | ||
Name: "not_found", | ||
Gatherer: "cibadmin", | ||
Argument: "cib.not_found.crm_config", | ||
CheckID: "check3", | ||
}, | ||
} | ||
|
||
factResults, err := p.Gather(factRequests) | ||
|
||
expectedResults := []entities.Fact{ | ||
{ | ||
Name: "sid", | ||
Value: &entities.FactValueString{Value: "PRD"}, | ||
CheckID: "check1", | ||
}, | ||
{ | ||
Name: "nvpair", | ||
Value: &entities.FactValueMap{ | ||
Value: map[string]entities.FactValue{ | ||
"id": &entities.FactValueString{Value: "cib-bootstrap-options-have-watchdog"}, | ||
"name": &entities.FactValueString{Value: "have-watchdog"}, | ||
"value": &entities.FactValueBool{Value: true}, | ||
}, | ||
}, | ||
CheckID: "check2", | ||
}, | ||
{ | ||
Name: "not_found", | ||
Value: nil, | ||
CheckID: "check3", | ||
Error: &entities.FactGatheringError{ | ||
Type: "value-not-found", | ||
Message: "error getting value: requested field value not found: " + | ||
"cib.not_found.crm_config"}, | ||
}, | ||
} | ||
|
||
suite.NoError(err) | ||
suite.ElementsMatch(expectedResults, factResults) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
package gatherers | ||
|
||
import ( | ||
"fmt" | ||
|
||
"github.com/clbanning/mxj/v2" | ||
"github.com/trento-project/agent/pkg/factsengine/entities" | ||
) | ||
|
||
func init() { | ||
mxj.PrependAttrWithHyphen(false) | ||
} | ||
|
||
func parseXMLToFactValueMap(xmlContent []byte, elementsToList []string) (*entities.FactValueMap, error) { | ||
mv, err := mxj.NewMapXml(xmlContent) | ||
if err != nil { | ||
return nil, err | ||
} | ||
|
||
for _, element := range elementsToList { | ||
err = convertList(&mv, element) | ||
if err != nil { | ||
return nil, fmt.Errorf("error converting %s to list", element) | ||
} | ||
} | ||
|
||
mapValue := map[string]interface{}(mv) | ||
factValue := entities.ParseInterfaceFactValue(mapValue) | ||
factValueMap, ok := factValue.(*entities.FactValueMap) | ||
if !ok { | ||
return nil, fmt.Errorf("error converting to FactValueMap") | ||
} | ||
|
||
return factValueMap, nil | ||
} | ||
|
||
// convertList converts given keys to list if only one value was present | ||
// this is needed as many fields are lists even though they might have | ||
// one element | ||
func convertList(mv *mxj.Map, key string) error { | ||
paths := mv.PathsForKey(key) | ||
for _, path := range paths { | ||
value, err := mv.ValuesForPath(path) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
values := map[string]interface{}{ | ||
key: value, | ||
} | ||
|
||
_, err = mv.UpdateValuesForPath(values, path) | ||
if err != nil { | ||
return err | ||
} | ||
} | ||
|
||
return nil | ||
} |