diff --git a/pkg/northbound/gnmi/set.go b/pkg/northbound/gnmi/set.go index 94815929d..e77023d14 100644 --- a/pkg/northbound/gnmi/set.go +++ b/pkg/northbound/gnmi/set.go @@ -353,31 +353,43 @@ func (s *Server) checkForReadOnly(target string, deviceType devicetype.Type, ver // Now iterate through the consolidated set of targets and see if any are read-only paths for path := range targetUpdates { // map - just need the key - log.Infof("Testing %s for read only", path) - for ropath := range model { - // Search through for list indices and replace with generic - modelPath := modelregistry.RemovePathIndices(path) - if strings.HasPrefix(modelPath, ropath) { - return fmt.Errorf("update contains a change to a read only path %s. Rejected", path) - } + if err := compareRoPaths(path, model); err != nil { + return fmt.Errorf("update %s", err) } } // Now iterate through the consolidated set of targets and see if any are read-only paths for _, path := range targetRemoves { // map - just need the key - log.Infof("Testing %s for read only", path) - for ropath := range model { - // Search through for list indices and replace with generic - modelPath := modelregistry.RemovePathIndices(path) - if strings.HasPrefix(modelPath, ropath) { - return fmt.Errorf("remove contains a change to a read only path %s. Rejected", path) - } + if err := compareRoPaths(path, model); err != nil { + return fmt.Errorf("remove %s", err) } } return nil } +func compareRoPaths(path string, model modelregistry.ReadOnlyPathMap) error { + log.Infof("Testing %s for read only", path) + for ropath, subpaths := range model { + // Search through for list indices and replace with generic + modelPath := modelregistry.RemovePathIndices(path) + if strings.HasPrefix(modelPath, ropath) { + for s := range subpaths { + fullpath := ropath + if s != "/" { + fullpath = fmt.Sprintf("%s%s", ropath, s) + } + if fullpath == modelPath { + return fmt.Errorf("contains a change to a "+ + "read only path %s. Rejected. %s, %s, %s, %s", + path, modelPath, ropath, s, fullpath) + } + } + } + } + return nil +} + func buildUpdateResult(pathStr string, target string, op gnmi.UpdateResult_Operation) (*gnmi.UpdateResult, error) { path, errInPath := utils.ParseGNMIElements(utils.SplitPath(pathStr)) if errInPath != nil { diff --git a/pkg/northbound/gnmi/set_test.go b/pkg/northbound/gnmi/set_test.go index 6fe466cb6..736ad0954 100644 --- a/pkg/northbound/gnmi/set_test.go +++ b/pkg/northbound/gnmi/set_test.go @@ -521,7 +521,7 @@ func TestSet_checkForReadOnly(t *testing.T) { err := server.checkForReadOnly("device-1", "TestDevice", "1.0.0", updateT1, make([]string, 0)) assert.NilError(t, err, "unexpected error on T1") err = server.checkForReadOnly("device-2", "TestDevice", "1.0.0", updateT2, make([]string, 0)) - assert.Error(t, err, `update contains a change to a read only path /cont1a/cont2a/leaf2c. Rejected`) + assert.Error(t, err, `update contains a change to a read only path /cont1a/cont2a/leaf2c. Rejected. /cont1a/cont2a/leaf2c, /cont1a/cont2a/leaf2c, /, /cont1a/cont2a/leaf2c`) } // Tests giving a new device without specifying a type