Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Pretty print fact values #176

Merged
merged 2 commits into from
Jan 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ jobs:
./trento-agent facts list --plugins-folder /tmp/plugins 2>&1 | grep -q "dummy"
- name: run facts gather command
run: |
./trento-agent facts gather --gatherer dummy --argument 1 --plugins-folder /tmp/plugins 2>&1 | grep -q '\"Name\\\": \\\"1\\\"'
./trento-agent facts gather --gatherer dummy --argument 1 --plugins-folder /tmp/plugins 2>&1 | grep -q 'Name: 1'

build-static-binary:
runs-on: ubuntu-20.04
Expand Down
19 changes: 1 addition & 18 deletions cmd/facts.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
package cmd

import (
"bytes"
"encoding/json"

"github.com/pkg/errors"
log "github.com/sirupsen/logrus"
"github.com/spf13/cobra"
Expand Down Expand Up @@ -116,7 +113,7 @@ func gather(*cobra.Command, []string) {
cleanupAndFatal(err)
}

result, err := prettifyInterfaceToJSON(value[0])
result, err := value[0].Prettify()
if err != nil {
cleanupAndFatal(err)
}
Expand Down Expand Up @@ -161,17 +158,3 @@ func list(*cobra.Command, []string) {
log.Printf(g)
}
}

func prettifyInterfaceToJSON(data interface{}) (string, error) {
jsonResult, err := json.Marshal(data)
if err != nil {
return "", errors.Wrap(err, "Error building the response")
}

var prettyJSON bytes.Buffer
if err := json.Indent(&prettyJSON, jsonResult, "", " "); err != nil {
return "", errors.Wrap(err, "Error indenting the json data")
}

return prettyJSON.String(), nil
}
29 changes: 29 additions & 0 deletions pkg/factsengine/entities/fact_value.go
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
package entities

import (
"bytes"
"encoding/json"
"fmt"
"math"
"strconv"
"strings"

"github.com/pkg/errors"
)

// nolint:gochecknoglobals
Expand Down Expand Up @@ -192,3 +196,28 @@ func getValue(fact FactValue, values []string) (FactValue, error) {
return value, nil
}
}

func Prettify(fact FactValue) (string, error) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this maybe be a private function?
And it could've been perfectly a struct function as well:
func (f *FactValue) Prettify() (string, error)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was the same way I tried to pursue at the beginning, but it requires a method to be implemented for each implementation of FactValue. Instead, this way the function just works ™️ with every concrete type

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@arbulu89 you cannot add methods to an interface

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The function is better, you could achieve a semi functional result with a dedicated struct with the method implemented and then embedding with some hassle in every struct you want to prettify

But honestly I don't think it's very ideomatic, seems like some sort of oop abstract superclass with some default methods

if fact == nil {
return "()", nil
}

interfaceValue := fact.AsInterface()

jsonResult, err := json.Marshal(interfaceValue)
if err != nil {
return "", errors.Wrap(err, "Error building the response")
}

var prettyfiedJSON bytes.Buffer
if err := json.Indent(&prettyfiedJSON, jsonResult, "", " "); err != nil {
return "", errors.Wrap(err, "Error indenting the json data")
}

prettifiedJSONString := prettyfiedJSON.String()

rhaiValue := strings.ReplaceAll(prettifiedJSONString, "{", "#{")
rhaiValue = strings.ReplaceAll(rhaiValue, "null", "()")

return rhaiValue, nil
}
16 changes: 15 additions & 1 deletion pkg/factsengine/entities/facts_gathered.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package entities

import "fmt"
import (
"fmt"

"github.com/pkg/errors"
)

const (
FactsGathererdEventSource = "https://github.com/trento-project/agent"
Expand Down Expand Up @@ -36,6 +40,16 @@ func (e *FactGatheringError) Wrap(msg string) *FactGatheringError {
}
}

func (e *Fact) Prettify() (string, error) {
prettifiedValue, err := Prettify(e.Value)
if err != nil {
return "", errors.Wrap(err, "Error prettifying fact value data")
}

result := fmt.Sprintf("Name: %s\nCheck ID: %s\n\nValue:\n\n%s", e.Name, e.CheckID, prettifiedValue)
return result, nil
}

func NewFactGatheredWithRequest(factReq FactRequest, value FactValue) Fact {
return Fact{
Name: factReq.Name,
Expand Down
45 changes: 45 additions & 0 deletions pkg/factsengine/entities/facts_gathered_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package entities_test

import (
"testing"

"github.com/stretchr/testify/suite"
"github.com/trento-project/agent/pkg/factsengine/entities"
)

type FactsGatheredTestSuite struct {
suite.Suite
}

func TestFactsGatheredTestSuite(t *testing.T) {
suite.Run(t, new(FactsGatheredTestSuite))
}

func (suite *FactsGatheredTestSuite) TestFactPrettify() {
factValueMap := &entities.FactValueMap{
Value: map[string]entities.FactValue{
"basic": &entities.FactValueString{Value: "basic"},
"list": &entities.FactValueList{
Value: []entities.FactValue{
&entities.FactValueString{Value: "string"},
&entities.FactValueInt{Value: 2},
&entities.FactValueList{Value: []entities.FactValue{
&entities.FactValueFloat{Value: 1.5},
}},
}},
"map": &entities.FactValueMap{Value: map[string]entities.FactValue{
"int": &entities.FactValueInt{Value: 5},
}},
}}

fact := entities.Fact{
Name: "fact",
CheckID: "12345",
Value: factValueMap,
Error: nil,
}

prettyPrintedOutput, _ := fact.Prettify()

suite.Equal(prettyPrintedOutput, "Name: fact\nCheck ID: 12345\n\nValue:\n\n#{\n \"basic\": \"basic\",\n \"list\": [\n \"string\",\n 2,\n [\n 1.5\n ]\n ],\n \"map\": #{\n \"int\": 5\n }\n}")
}