engine: resources: exec: AutoEdge to User/Group/File

Fixes https://github.com/purpleidea/mgmt/issues/221

Signed-off-by: Joe Groocock <me@frebib.net>
This commit is contained in:
Joe Groocock
2021-05-04 13:09:32 +01:00
committed by James Shubin
parent 2d7deef4e2
commit fe2b8c9fee
3 changed files with 145 additions and 6 deletions

View File

@@ -570,26 +570,38 @@ type ExecUID struct {
// ExecResAutoEdges holds the state of the auto edge generator. // ExecResAutoEdges holds the state of the auto edge generator.
type ExecResAutoEdges struct { type ExecResAutoEdges struct {
edges []engine.ResUID edges []engine.ResUID
pointer int
} }
// Next returns the next automatic edge. // Next returns the next automatic edge.
func (obj *ExecResAutoEdges) Next() []engine.ResUID { func (obj *ExecResAutoEdges) Next() []engine.ResUID {
return obj.edges if len(obj.edges) == 0 {
return nil
}
value := obj.edges[obj.pointer]
obj.pointer++
return []engine.ResUID{value}
} }
// Test gets results of the earlier Next() call, & returns if we should // Test gets results of the earlier Next() call, & returns if we should
// continue! // continue!
func (obj *ExecResAutoEdges) Test(input []bool) bool { func (obj *ExecResAutoEdges) Test(input []bool) bool {
return false // never keep going if len(obj.edges) <= obj.pointer {
// TODO: we could return false if we find as many edges as the number of different path's in cmdFiles() return false
}
if len(input) != 1 { // in case we get given bad data
panic(fmt.Sprintf("Expecting a single value!"))
}
return true // keep going
} }
// AutoEdges returns the AutoEdge interface. In this case the systemd units. // AutoEdges returns the AutoEdge interface. In this case the systemd units.
func (obj *ExecRes) AutoEdges() (engine.AutoEdge, error) { func (obj *ExecRes) AutoEdges() (engine.AutoEdge, error) {
var data []engine.ResUID var data []engine.ResUID
var reversed = true
for _, x := range obj.cmdFiles() { for _, x := range obj.cmdFiles() {
var reversed = true
data = append(data, &PkgFileUID{ data = append(data, &PkgFileUID{
BaseUID: engine.BaseUID{ BaseUID: engine.BaseUID{
Name: obj.Name(), Name: obj.Name(),
@@ -598,9 +610,39 @@ func (obj *ExecRes) AutoEdges() (engine.AutoEdge, error) {
}, },
path: x, // what matters path: x, // what matters
}) })
data = append(data, &FileUID{
BaseUID: engine.BaseUID{
Name: obj.Name(),
Kind: obj.Kind(),
Reversed: &reversed,
},
path: x,
})
} }
if obj.User != "" {
data = append(data, &UserUID{
BaseUID: engine.BaseUID{
Name: obj.Name(),
Kind: obj.Kind(),
Reversed: &reversed,
},
name: obj.User,
})
}
if obj.Group != "" {
data = append(data, &GroupUID{
BaseUID: engine.BaseUID{
Name: obj.Name(),
Kind: obj.Kind(),
Reversed: &reversed,
},
name: obj.Group,
})
}
return &ExecResAutoEdges{ return &ExecResAutoEdges{
edges: data, edges: data,
pointer: 0,
}, nil }, nil
} }

View File

@@ -28,6 +28,8 @@ import (
"time" "time"
"github.com/purpleidea/mgmt/engine" "github.com/purpleidea/mgmt/engine"
"github.com/purpleidea/mgmt/engine/graph/autoedge"
"github.com/purpleidea/mgmt/pgraph"
) )
func fakeExecInit(t *testing.T) (*engine.Init, *ExecSends) { func fakeExecInit(t *testing.T) (*engine.Init, *ExecSends) {
@@ -257,3 +259,77 @@ func TestExecTimeoutBehaviour(t *testing.T) {
// no error // no error
} }
func TestExecAutoEdge1(t *testing.T) {
g, err := pgraph.NewGraph("TestGraph")
if err != nil {
t.Errorf("error creating graph: %v", err)
return
}
resUser, err := engine.NewNamedResource("user", "someuser")
if err != nil {
t.Errorf("error creating user resource: %v", err)
return
}
resGroup, err := engine.NewNamedResource("group", "somegroup")
if err != nil {
t.Errorf("error creating group resource: %v", err)
return
}
resFile, err := engine.NewNamedResource("file", "/somefile")
if err != nil {
t.Errorf("error creating group resource: %v", err)
return
}
resExec, err := engine.NewNamedResource("exec", "somefile")
if err != nil {
t.Errorf("error creating exec resource: %v", err)
return
}
exc := resExec.(*ExecRes)
exc.Cmd = resFile.Name()
exc.User = resUser.Name()
exc.Group = resGroup.Name()
g.AddVertex(resUser, resGroup, resFile, resExec)
if i := g.NumEdges(); i != 0 {
t.Errorf("should have 0 edges instead of: %d", i)
return
}
debug := testing.Verbose() // set via the -test.v flag to `go test`
logf := func(format string, v ...interface{}) {
t.Logf("test: "+format, v...)
}
if err := autoedge.AutoEdge(g, debug, logf); err != nil {
t.Errorf("error running autoedges: %v", err)
return
}
expected, err := pgraph.NewGraph("Expected")
if err != nil {
t.Errorf("error creating graph: %v", err)
return
}
expectEdge := func(from, to pgraph.Vertex) {
edge := &engine.Edge{Name: fmt.Sprintf("%s -> %s (expected)", from, to)}
expected.AddEdge(from, to, edge)
}
expectEdge(resFile, resExec)
expectEdge(resUser, resExec)
expectEdge(resGroup, resExec)
vertexCmp := func(v1, v2 pgraph.Vertex) (bool, error) { return v1 == v2, nil } // pointer compare is sufficient
edgeCmp := func(e1, e2 pgraph.Edge) (bool, error) { return true, nil } // we don't care about edges here
if err := expected.GraphCmp(g, vertexCmp, edgeCmp); err != nil {
t.Errorf("graph doesn't match expected: %s", err)
return
}
}

View File

@@ -333,6 +333,26 @@ func (obj *UserRes) Cmp(r engine.Res) error {
type UserUID struct { type UserUID struct {
engine.BaseUID engine.BaseUID
name string name string
uid *uint32
}
// IFF aka if and only if they are equivalent, return true. If not, false.
func (obj *UserUID) IFF(uid engine.ResUID) bool {
res, ok := uid.(*UserUID)
if !ok {
return false
}
if obj.uid != nil && res.uid != nil {
if *obj.uid != *res.uid {
return false
}
}
if obj.name != "" && res.name != "" {
if obj.name != res.name {
return false
}
}
return true
} }
// UserResAutoEdges holds the state of the auto edge generator. // UserResAutoEdges holds the state of the auto edge generator.
@@ -411,6 +431,7 @@ func (obj *UserRes) UIDs() []engine.ResUID {
x := &UserUID{ x := &UserUID{
BaseUID: engine.BaseUID{Name: obj.Name(), Kind: obj.Kind()}, BaseUID: engine.BaseUID{Name: obj.Name(), Kind: obj.Kind()},
name: obj.Name(), name: obj.Name(),
uid: obj.UID,
} }
return []engine.ResUID{x} return []engine.ResUID{x}
} }