diff --git a/engine/graph/engine.go b/engine/graph/engine.go index 788caf99..f15650be 100644 --- a/engine/graph/engine.go +++ b/engine/graph/engine.go @@ -25,6 +25,7 @@ import ( "github.com/purpleidea/mgmt/converger" "github.com/purpleidea/mgmt/engine" + engineUtil "github.com/purpleidea/mgmt/engine/util" "github.com/purpleidea/mgmt/pgraph" "github.com/purpleidea/mgmt/util/errwrap" "github.com/purpleidea/mgmt/util/semaphore" @@ -180,8 +181,7 @@ func (obj *Engine) Commit() error { return errwrap.Wrapf(err, "the Res did not Validate") } - // FIXME: is res.Name() sufficiently unique to use as a UID here? - pathUID := fmt.Sprintf("%s-%s", res.Kind(), res.Name()) + pathUID := engineUtil.ResPathUID(res) statePrefix := fmt.Sprintf("%s/", path.Join(obj.statePrefix(), pathUID)) // don't create this unless it *will* be used diff --git a/engine/util/util.go b/engine/util/util.go index a798c55d..6e045b4c 100644 --- a/engine/util/util.go +++ b/engine/util/util.go @@ -23,6 +23,7 @@ import ( "encoding/base64" "encoding/gob" "fmt" + "os" "os/user" "reflect" "strconv" @@ -62,6 +63,23 @@ const ( DBusSignalJobRemoved = "JobRemoved" ) +// ResPathUID returns a unique resource UID based on its name and kind. It's +// safe to use as a token in a path, and as a result has no slashes in it. +func ResPathUID(res engine.Res) string { + // res.Name() is NOT sufficiently unique to use as a UID here, because: + // a name of: /tmp/mgmt/foo is /tmp-mgmt-foo and + // a name of: /tmp/mgmt-foo -> /tmp-mgmt-foo if we replace slashes. + // As a result, we base64 encode (but without slashes). + name := strings.Replace(res.Name(), "/", "-", -1) // TODO: use ReplaceAll in 1.12 + if os.PathSeparator != '/' { // lol windows? + name = strings.Replace(name, string(os.PathSeparator), "-", -1) // TODO: use ReplaceAll in 1.12 + } + b := []byte(res.Name()) + encoded := base64.URLEncoding.EncodeToString(b) + // Add the safe name on so that it's easier to identify by name... + return fmt.Sprintf("%s-%s+%s", res.Kind(), encoded, name) +} + // ResToB64 encodes a resource to a base64 encoded string (after serialization). func ResToB64(res engine.Res) (string, error) { b := bytes.Buffer{}