From e60dda50276ef009c58e83bd1a4ecfe0a1a52bd1 Mon Sep 17 00:00:00 2001 From: James Shubin Date: Wed, 9 Mar 2016 03:10:03 -0500 Subject: [PATCH] Add some of the pkg and svc autoedge logic This adds another chunk of it, and makes some other small fixes. --- examples/autoedges3.yaml | 29 ++++++ misc_test.go | 134 ++++++++++++++++++++++++++++ packagekit.go | 25 ++---- pkg.go | 186 ++++++++++++++++++++++++++++----------- resources.go | 6 +- svc.go | 72 +++++++++++++-- 6 files changed, 380 insertions(+), 72 deletions(-) create mode 100644 examples/autoedges3.yaml diff --git a/examples/autoedges3.yaml b/examples/autoedges3.yaml new file mode 100644 index 00000000..b344b57e --- /dev/null +++ b/examples/autoedges3.yaml @@ -0,0 +1,29 @@ +--- +graph: mygraph +resources: + pkg: + - name: drbd-utils + meta: + autoedge: true + state: installed + file: + - name: file1 + meta: + autoedge: true + path: "/etc/drbd.conf" + content: | + # this is an mgmt test + state: exists + - name: file2 + meta: + autoedge: true + path: "/etc/drbd.d/" + content: | + i am a directory + state: exists + svc: + - name: drbd + meta: + autoedge: true + state: stopped +edges: [] diff --git a/misc_test.go b/misc_test.go index 1cc6cb04..990e643b 100644 --- a/misc_test.go +++ b/misc_test.go @@ -656,4 +656,138 @@ func TestMiscT11(t *testing.T) { if !reflect.DeepEqual(ex9, out9) { t.Errorf("RemoveCommonFilePrefixes expected: %v; got: %v.", ex9, out9) } + + in10 := []string{ + "/etc/drbd.conf", + "/etc/drbd.d/", // watch me, i'm a dir + "/etc/drbd.d/global_common.conf", // and watch me i'm a file! + "/lib/drbd/drbd", + "/lib/drbd/drbdadm-83", + "/lib/drbd/drbdadm-84", + "/lib/drbd/drbdsetup-83", + "/lib/drbd/drbdsetup-84", + "/usr/lib/drbd/crm-fence-peer.sh", + "/usr/lib/drbd/crm-unfence-peer.sh", + "/usr/lib/drbd/notify-emergency-reboot.sh", + "/usr/lib/drbd/notify-emergency-shutdown.sh", + "/usr/lib/drbd/notify-io-error.sh", + "/usr/lib/drbd/notify-out-of-sync.sh", + "/usr/lib/drbd/notify-pri-lost-after-sb.sh", + "/usr/lib/drbd/notify-pri-lost.sh", + "/usr/lib/drbd/notify-pri-on-incon-degr.sh", + "/usr/lib/drbd/notify-split-brain.sh", + "/usr/lib/drbd/notify.sh", + "/usr/lib/drbd/outdate-peer.sh", + "/usr/lib/drbd/rhcs_fence", + "/usr/lib/drbd/snapshot-resync-target-lvm.sh", + "/usr/lib/drbd/stonith_admin-fence-peer.sh", + "/usr/lib/drbd/unsnapshot-resync-target-lvm.sh", + "/usr/lib/systemd/system/drbd.service", + "/usr/lib/tmpfiles.d/drbd.conf", + "/usr/sbin/drbd-overview", + "/usr/sbin/drbdadm", + "/usr/sbin/drbdmeta", + "/usr/sbin/drbdsetup", + "/usr/share/doc/drbd-utils/", // watch me, i'm a dir too + "/usr/share/doc/drbd-utils/COPYING", + "/usr/share/doc/drbd-utils/ChangeLog", + "/usr/share/doc/drbd-utils/README", + "/usr/share/doc/drbd-utils/drbd.conf.example", + "/usr/share/man/man5/drbd.conf-8.3.5.gz", + "/usr/share/man/man5/drbd.conf-8.4.5.gz", + "/usr/share/man/man5/drbd.conf-9.0.5.gz", + "/usr/share/man/man5/drbd.conf.5.gz", + "/usr/share/man/man8/drbd-8.3.8.gz", + "/usr/share/man/man8/drbd-8.4.8.gz", + "/usr/share/man/man8/drbd-9.0.8.gz", + "/usr/share/man/man8/drbd-overview-9.0.8.gz", + "/usr/share/man/man8/drbd-overview.8.gz", + "/usr/share/man/man8/drbd.8.gz", + "/usr/share/man/man8/drbdadm-8.3.8.gz", + "/usr/share/man/man8/drbdadm-8.4.8.gz", + "/usr/share/man/man8/drbdadm-9.0.8.gz", + "/usr/share/man/man8/drbdadm.8.gz", + "/usr/share/man/man8/drbddisk-8.3.8.gz", + "/usr/share/man/man8/drbddisk-8.4.8.gz", + "/usr/share/man/man8/drbdmeta-8.3.8.gz", + "/usr/share/man/man8/drbdmeta-8.4.8.gz", + "/usr/share/man/man8/drbdmeta-9.0.8.gz", + "/usr/share/man/man8/drbdmeta.8.gz", + "/usr/share/man/man8/drbdsetup-8.3.8.gz", + "/usr/share/man/man8/drbdsetup-8.4.8.gz", + "/usr/share/man/man8/drbdsetup-9.0.8.gz", + "/usr/share/man/man8/drbdsetup.8.gz", + "/var/lib/drbd", + } + ex10 := []string{ + "/etc/drbd.conf", + "/etc/drbd.d/global_common.conf", + "/lib/drbd/drbd", + "/lib/drbd/drbdadm-83", + "/lib/drbd/drbdadm-84", + "/lib/drbd/drbdsetup-83", + "/lib/drbd/drbdsetup-84", + "/usr/lib/drbd/crm-fence-peer.sh", + "/usr/lib/drbd/crm-unfence-peer.sh", + "/usr/lib/drbd/notify-emergency-reboot.sh", + "/usr/lib/drbd/notify-emergency-shutdown.sh", + "/usr/lib/drbd/notify-io-error.sh", + "/usr/lib/drbd/notify-out-of-sync.sh", + "/usr/lib/drbd/notify-pri-lost-after-sb.sh", + "/usr/lib/drbd/notify-pri-lost.sh", + "/usr/lib/drbd/notify-pri-on-incon-degr.sh", + "/usr/lib/drbd/notify-split-brain.sh", + "/usr/lib/drbd/notify.sh", + "/usr/lib/drbd/outdate-peer.sh", + "/usr/lib/drbd/rhcs_fence", + "/usr/lib/drbd/snapshot-resync-target-lvm.sh", + "/usr/lib/drbd/stonith_admin-fence-peer.sh", + "/usr/lib/drbd/unsnapshot-resync-target-lvm.sh", + "/usr/lib/systemd/system/drbd.service", + "/usr/lib/tmpfiles.d/drbd.conf", + "/usr/sbin/drbd-overview", + "/usr/sbin/drbdadm", + "/usr/sbin/drbdmeta", + "/usr/sbin/drbdsetup", + "/usr/share/doc/drbd-utils/COPYING", + "/usr/share/doc/drbd-utils/ChangeLog", + "/usr/share/doc/drbd-utils/README", + "/usr/share/doc/drbd-utils/drbd.conf.example", + "/usr/share/man/man5/drbd.conf-8.3.5.gz", + "/usr/share/man/man5/drbd.conf-8.4.5.gz", + "/usr/share/man/man5/drbd.conf-9.0.5.gz", + "/usr/share/man/man5/drbd.conf.5.gz", + "/usr/share/man/man8/drbd-8.3.8.gz", + "/usr/share/man/man8/drbd-8.4.8.gz", + "/usr/share/man/man8/drbd-9.0.8.gz", + "/usr/share/man/man8/drbd-overview-9.0.8.gz", + "/usr/share/man/man8/drbd-overview.8.gz", + "/usr/share/man/man8/drbd.8.gz", + "/usr/share/man/man8/drbdadm-8.3.8.gz", + "/usr/share/man/man8/drbdadm-8.4.8.gz", + "/usr/share/man/man8/drbdadm-9.0.8.gz", + "/usr/share/man/man8/drbdadm.8.gz", + "/usr/share/man/man8/drbddisk-8.3.8.gz", + "/usr/share/man/man8/drbddisk-8.4.8.gz", + "/usr/share/man/man8/drbdmeta-8.3.8.gz", + "/usr/share/man/man8/drbdmeta-8.4.8.gz", + "/usr/share/man/man8/drbdmeta-9.0.8.gz", + "/usr/share/man/man8/drbdmeta.8.gz", + "/usr/share/man/man8/drbdsetup-8.3.8.gz", + "/usr/share/man/man8/drbdsetup-8.4.8.gz", + "/usr/share/man/man8/drbdsetup-9.0.8.gz", + "/usr/share/man/man8/drbdsetup.8.gz", + "/var/lib/drbd", + } + sort.Strings(ex10) + out10 := RemoveCommonFilePrefixes(in10) + sort.Strings(out10) + if !reflect.DeepEqual(ex10, out10) { + t.Errorf("RemoveCommonFilePrefixes expected: %v; got: %v.", ex10, out10) + for i := 0; i < len(ex10); i++ { + if ex10[i] != out10[i] { + t.Errorf("# %d: %v <> %v", i, ex10[i], out10[i]) + } + } + } } diff --git a/packagekit.go b/packagekit.go index fd86c051..7f767b15 100644 --- a/packagekit.go +++ b/packagekit.go @@ -196,16 +196,10 @@ func (bus *Conn) matchSignal(ch chan *dbus.Signal, path dbus.ObjectPath, iface s if call.Err != nil { return call.Err } - if PK_DEBUG { - log.Println("PackageKit: matchSignal(): Added!") - } // The caller has to make sure that ch is sufficiently buffered; if a // message arrives when a write to c is not possible, it is discarded! // This can be disastrous if we're waiting for a "Finished" signal! bus.GetBus().Signal(ch) - if PK_DEBUG { - log.Println("PackageKit: matchSignal(): Success!") - } return nil } @@ -411,11 +405,9 @@ loop: // a package was installed... // only start the timer once we're here... timeout = PkSignalPackageTimeout - continue loop } else if signal.Name == FmtTransactionMethod("Finished") { finished = true timeout = PkSignalDestroyTimeout // wait a bit - continue loop } else if signal.Name == FmtTransactionMethod("Destroy") { return nil // success } else { @@ -508,8 +500,6 @@ loop: if signal.Name == FmtTransactionMethod("ErrorCode") { return errors.New(fmt.Sprintf("PackageKit: Error: %v", signal.Body)) } else if signal.Name == FmtTransactionMethod("Package") { - // a package was installed... - continue loop } else if signal.Name == FmtTransactionMethod("Finished") { // TODO: should we wait for the Destroy signal? break loop @@ -574,8 +564,6 @@ loop: continue loop // failed conversion } files[key] = fileList // build up map - - continue loop } else if signal.Name == FmtTransactionMethod("Finished") { // TODO: should we wait for the Destroy signal? break loop @@ -593,6 +581,9 @@ loop: // get list of packages that are installed and which can be updated, mod filter func (bus *Conn) GetUpdates(filter uint64) ([]string, error) { + if PK_DEBUG { + log.Println("PackageKit: GetUpdates()") + } packageIds := []string{} ch := make(chan *dbus.Signal, PkBufferSize) // we need to buffer :( interfacePath, err := bus.CreateTransaction() @@ -635,7 +626,6 @@ loop: } } packageIds = append(packageIds, packageId) - } else if signal.Name == FmtTransactionMethod("Finished") { // TODO: should we wait for the Destroy signal? break loop @@ -708,8 +698,9 @@ func (bus *Conn) PackagesToPackageIds(packageMap map[string]string, filter uint6 return nil, errors.New(fmt.Sprintf("Empty package state for %v", pkg)) } found[index] = true + stateIsVersion := (state != "installed" && state != "uninstalled" && state != "newest") // must be a ver. string - if state != "installed" && state != "uninstalled" && state != "newest" { // must be a ver. string + if stateIsVersion { if state == ver && ver != "" { // we match what we want... usePackageId[index] = packageId } @@ -718,11 +709,13 @@ func (bus *Conn) PackagesToPackageIds(packageMap map[string]string, filter uint6 if FlagInData("installed", data) { installed[index] = true version[index] = ver - if state == "uninstalled" { + // state of "uninstalled" matched during CheckApply, and + // states of "installed" and "newest" for fileList + if !stateIsVersion { usePackageId[index] = packageId // save for later } } else { // not installed... - if state == "installed" || state == "newest" { + if !stateIsVersion { // if there is more than one result, eg: there // is the old and newest version of a package, // then this section can run more than once... diff --git a/pkg.go b/pkg.go index 563e76a3..62db5c8f 100644 --- a/pkg.go +++ b/pkg.go @@ -22,15 +22,18 @@ import ( "errors" "fmt" "log" + "path" + "strings" ) type PkgRes struct { BaseRes `yaml:",inline"` - State string `yaml:"state"` // state: installed, uninstalled, newest, - AllowUntrusted bool `yaml:"allowuntrusted"` // allow untrusted packages to be installed? - AllowNonFree bool `yaml:"allownonfree"` // allow nonfree packages to be found? - AllowUnsupported bool `yaml:"allowunsupported"` // allow unsupported packages to be found? - fileList []string // FIXME: update if pkg changes + State string `yaml:"state"` // state: installed, uninstalled, newest, + AllowUntrusted bool `yaml:"allowuntrusted"` // allow untrusted packages to be installed? + AllowNonFree bool `yaml:"allownonfree"` // allow nonfree packages to be found? + AllowUnsupported bool `yaml:"allowunsupported"` // allow unsupported packages to be found? + //bus *Conn // pk bus connection + fileList []string // FIXME: update if pkg changes } // helper function for creating new pkg resources that calls Init() @@ -53,10 +56,35 @@ func NewPkgRes(name, state string, allowuntrusted, allownonfree, allowunsupporte func (obj *PkgRes) Init() { obj.BaseRes.kind = "Pkg" obj.BaseRes.Init() // call base init, b/c we're overriding + + bus := NewBus() + if bus == nil { + log.Fatal("Can't connect to PackageKit bus.") + } + defer bus.Close() + + data, err := obj.PkgMappingHelper(bus) + if err != nil { + // FIXME: return error? + log.Fatalf("The PkgMappingHelper failed with: %v.", err) + return + } + + packageIds := []string{data.PackageId} // just one for now + filesMap, err := bus.GetFilesByPackageId(packageIds) + if err != nil { + // FIXME: return error? + log.Fatalf("Can't run GetFilesByPackageId: %v", err) + return + } + if files, ok := filesMap[data.PackageId]; ok { + obj.fileList = DirifyFileList(files, false) + } } -func (obj *PkgRes) Kind() string { - return "Pkg" +// XXX: run this when resource exits +func (obj *PkgRes) Close() { + //obj.bus.Close() } func (obj *PkgRes) Validate() bool { @@ -143,22 +171,7 @@ func (obj *PkgRes) Watch() { } } -func (obj *PkgRes) CheckApply(apply bool) (stateok bool, err error) { - log.Printf("%v[%v]: CheckApply(%t)", obj.Kind(), obj.GetName(), apply) - - if obj.State == "" { // TODO: Validate() should replace this check! - log.Fatalf("%v[%v]: Package state is undefined!", obj.Kind(), obj.GetName()) - } - - if obj.isStateOK { // cache the state - return true, nil - } - - bus := NewBus() - if bus == nil { - return false, errors.New("Can't connect to PackageKit bus.") - } - defer bus.Close() +func (obj *PkgRes) PkgMappingHelper(bus *Conn) (*PkPackageIdActionData, error) { var packageMap = map[string]string{ obj.Name: obj.State, // key is pkg name, value is pkg state @@ -180,16 +193,41 @@ func (obj *PkgRes) CheckApply(apply bool) (stateok bool, err error) { } result, e := bus.PackagesToPackageIds(packageMap, filter) if e != nil { - return false, errors.New(fmt.Sprintf("PackagesToPackageIds error: %v", e)) + return nil, errors.New(fmt.Sprintf("Can't run PackagesToPackageIds: %v", e)) } data, ok := result[obj.Name] // lookup single package // package doesn't exist, this is an error! if !ok || !data.Found { - return false, errors.New(fmt.Sprintf("Can't find package named '%s'.", obj.Name)) + return nil, errors.New(fmt.Sprintf("Can't find package named '%s'.", obj.Name)) } - //obj.State == "installed" || "uninstalled" || "newest" || "4.2-1.fc23" + return data, nil +} + +func (obj *PkgRes) CheckApply(apply bool) (stateok bool, err error) { + log.Printf("%v[%v]: CheckApply(%t)", obj.Kind(), obj.GetName(), apply) + + if obj.State == "" { // TODO: Validate() should replace this check! + log.Fatalf("%v[%v]: Package state is undefined!", obj.Kind(), obj.GetName()) + } + + if obj.isStateOK { // cache the state + return true, nil + } + + bus := NewBus() + if bus == nil { + return false, errors.New("Can't connect to PackageKit bus.") + } + defer bus.Close() + + data, err := obj.PkgMappingHelper(bus) + if err != nil { + return false, errors.New(fmt.Sprintf("The PkgMappingHelper failed with: %v.", err)) + } + + // obj.State == "installed" || "uninstalled" || "newest" || "4.2-1.fc23" switch obj.State { case "installed": if data.Installed { @@ -248,8 +286,26 @@ func (obj *PkgRes) CheckApply(apply bool) (stateok bool, err error) { return false, nil // success } +type PkgUUID struct { + BaseUUID + name string // pkg name + state string // pkg state or "version" +} + +// if and only if they are equivalent, return true +// if they are not equivalent, return false +func (obj *PkgUUID) IFF(uuid ResUUID) bool { + res, ok := uuid.(*PkgUUID) + if !ok { + return false + } + // FIXME: match on obj.state vs. res.state ? + return obj.name == res.name +} + type PkgResAutoEdges struct { fileList []string + svcUUIDs []ResUUID testIsNext bool // safety name string // saved data from PkgRes obj kind string @@ -260,8 +316,13 @@ func (obj *PkgResAutoEdges) Next() []ResUUID { log.Fatal("Expecting a call to Test()") } obj.testIsNext = true // set after all the errors paths are past - var result []ResUUID + // first return any matching svcUUIDs + if x := obj.svcUUIDs; len(x) > 0 { + return x + } + + var result []ResUUID // return UUID's for whatever is in obj.fileList for _, x := range obj.fileList { var reversed bool = false // cheat by passing a pointer @@ -281,6 +342,17 @@ func (obj *PkgResAutoEdges) Test(input []bool) bool { if !obj.testIsNext { log.Fatal("Expecting a call to Next()") } + + // ack the svcUUID's... + if x := obj.svcUUIDs; len(x) > 0 { + if y := len(x); y != len(input) { + log.Fatalf("Expecting %d value(s)!", y) + } + obj.svcUUIDs = []ResUUID{} // empty + obj.testIsNext = false + return true + } + count := len(obj.fileList) if count != len(input) { log.Fatalf("Expecting %d value(s)!", count) @@ -316,27 +388,29 @@ func (obj *PkgResAutoEdges) Test(input []bool) bool { return true // continue, there are more files! } -type PkgUUID struct { - BaseUUID -} - -// if and only if they are equivalent, return true -// if they are not equivalent, return false -func (obj *PkgUUID) IFF(uuid ResUUID) bool { - res, ok := uuid.(*PkgUUID) - if !ok { - return false - } - return obj.name == res.name -} - // produce an object which generates a minimal pkg file optimization sequence func (obj *PkgRes) AutoEdges() AutoEdge { // in contrast with the FileRes AutoEdges() function which contains // more of the mechanics, most of the AutoEdge mechanics for the PkgRes // is contained in the Test() method! This design is completely okay! + + // add matches for any svc resources found in pkg definition! + var svcUUIDs []ResUUID + for _, x := range ReturnSvcInFileList(obj.fileList) { + var reversed bool = false + svcUUIDs = append(svcUUIDs, &SvcUUID{ + BaseUUID: BaseUUID{ + name: obj.GetName(), + kind: obj.Kind(), + reversed: &reversed, + }, + name: x, // the svc name itself in the SvcUUID object! + }) // build list + } + return &PkgResAutoEdges{ - fileList: obj.fileList, + fileList: RemoveCommonFilePrefixes(obj.fileList), // clean start! + svcUUIDs: svcUUIDs, testIsNext: false, // start with Next() call name: obj.GetName(), // save data for PkgResAutoEdges obj kind: obj.Kind(), @@ -347,15 +421,10 @@ func (obj *PkgRes) AutoEdges() AutoEdge { func (obj *PkgRes) GetUUIDs() []ResUUID { x := &PkgUUID{ BaseUUID: BaseUUID{name: obj.GetName(), kind: obj.Kind()}, + name: obj.Name, + state: obj.State, } result := []ResUUID{x} - for _, path := range obj.fileList { - x := &FileUUID{ - BaseUUID: BaseUUID{name: obj.GetName(), kind: obj.Kind()}, - path: path, - } - result = append(result, x) - } return result } @@ -383,3 +452,22 @@ func (obj *PkgRes) Compare(res Res) bool { } return true } + +// return a list of svc names for matches like /usr/lib/systemd/system/*.service +func ReturnSvcInFileList(fileList []string) []string { + result := []string{} + for _, x := range fileList { + dirname, basename := path.Split(path.Clean(x)) + // TODO: do we also want to look for /etc/systemd/system/ ? + if dirname != "/usr/lib/systemd/system/" { + continue + } + if !strings.HasSuffix(basename, ".service") { + continue + } + if s := strings.TrimSuffix(basename, ".service"); !StrInList(s, result) { + result = append(result, s) + } + } + return result +} diff --git a/resources.go b/resources.go index 8a265474..64ad37c6 100644 --- a/resources.go +++ b/resources.go @@ -52,7 +52,7 @@ type ResUUID interface { } type BaseUUID struct { - name string + name string // name and kind are the values of where this is coming from kind string reversed *bool // piggyback edge information here @@ -467,6 +467,7 @@ func (obj *NoopRes) CheckApply(apply bool) (stateok bool, err error) { type NoopUUID struct { BaseUUID + name string } func (obj *NoopRes) AutoEdges() AutoEdge { @@ -474,10 +475,11 @@ func (obj *NoopRes) AutoEdges() AutoEdge { } // include all params to make a unique identification of this object -// most resources only return one +// most resources only return one, although some resources return multiple func (obj *NoopRes) GetUUIDs() []ResUUID { x := &NoopUUID{ BaseUUID: BaseUUID{name: obj.GetName(), kind: obj.Kind()}, + name: obj.Name, } return []ResUUID{x} } diff --git a/svc.go b/svc.go index 19bd2965..d924c6fd 100644 --- a/svc.go +++ b/svc.go @@ -310,7 +310,12 @@ func (obj *SvcRes) CheckApply(apply bool) (stateok bool, err error) { } type SvcUUID struct { + // NOTE: there is also a name variable in the BaseUUID struct, this is + // information about where this UUID came from, and is unrelated to the + // information about the resource we're matching. That data which is + // used in the IFF function, is what you see in the struct fields here. BaseUUID + name string // the svc name } // if and only if they are equivalent, return true @@ -323,17 +328,74 @@ func (obj *SvcUUID) IFF(uuid ResUUID) bool { return obj.name == res.name } +type SvcResAutoEdges struct { + data []ResUUID + pointer int + found bool +} + +func (obj *SvcResAutoEdges) Next() []ResUUID { + if obj.found { + log.Fatal("Shouldn't be called anymore!") + } + if len(obj.data) == 0 { // check length for rare scenarios + return nil + } + value := obj.data[obj.pointer] + obj.pointer += 1 + return []ResUUID{value} // we return one, even though api supports N +} + +// get results of the earlier Next() call, return if we should continue! +func (obj *SvcResAutoEdges) Test(input []bool) bool { + // if there aren't any more remaining + if len(obj.data) <= obj.pointer { + return false + } + if obj.found { // already found, done! + return false + } + if len(input) != 1 { // in case we get given bad data + log.Fatal("Expecting a single value!") + } + if input[0] { // if a match is found, we're done! + obj.found = true // no more to find! + return false + } + return true // keep going +} + func (obj *SvcRes) AutoEdges() AutoEdge { - // TODO: add auto edges to the files that provide the service files, - // which might come from a pkg resource perhaps! - return nil + var data []ResUUID + svcFiles := []string{ + fmt.Sprintf("/etc/systemd/system/%s.service", obj.Name), // takes precedence + fmt.Sprintf("/usr/lib/systemd/system/%s.service", obj.Name), // pkg default + } + for _, x := range svcFiles { + var reversed bool = true + data = append(data, &FileUUID{ + BaseUUID: BaseUUID{ + name: obj.GetName(), + kind: obj.Kind(), + reversed: &reversed, + }, + path: x, // what matters + }) + } + return &FileResAutoEdges{ + data: data, + pointer: 0, + found: false, + } } // include all params to make a unique identification of this object func (obj *SvcRes) GetUUIDs() []ResUUID { - x := &SvcUUID{BaseUUID: BaseUUID{name: obj.GetName(), kind: obj.Kind()}} + x := &SvcUUID{ + BaseUUID: BaseUUID{name: obj.GetName(), kind: obj.Kind()}, + name: obj.Name, // svc name + } return []ResUUID{x} - } func (obj *SvcRes) Compare(res Res) bool {