Skip to content

Commit d20b1ce

Browse files
authored
Merge pull request kubernetes-sigs#192 from kevindelgado/no-atomic-to-granular
Unsupport atomic to granular schema reconciliation
2 parents f503776 + 4278010 commit d20b1ce

File tree

3 files changed

+26
-76
lines changed

3 files changed

+26
-76
lines changed

merge/schema_change_test.go

+14-12
Original file line numberDiff line numberDiff line change
@@ -204,24 +204,14 @@ func TestAtomicToGranularSchemaChanges(t *testing.T) {
204204
},
205205
},
206206
ChangeParser{Parser: structParser},
207+
// No conflict after changing struct to a granular schema
207208
Apply{
208209
Manager: "two",
209210
Object: `
210211
struct:
211212
string: "b"
212213
`,
213214
APIVersion: "v1",
214-
Conflicts: merge.Conflicts{
215-
merge.Conflict{Manager: "one", Path: _P("struct", "string")},
216-
},
217-
},
218-
ForceApply{
219-
Manager: "two",
220-
Object: `
221-
struct:
222-
string: "b"
223-
`,
224-
APIVersion: "v1",
225215
},
226216
},
227217
Object: `
@@ -231,9 +221,21 @@ func TestAtomicToGranularSchemaChanges(t *testing.T) {
231221
`,
232222
APIVersion: "v1",
233223
Managed: fieldpath.ManagedFields{
224+
// Note that manager one previously owned
225+
// the top level _P("struct")
226+
// which included all of its subfields
227+
// when the struct field was atomic.
228+
//
229+
// Upon changing the schema of struct from
230+
// atomic to granular, manager one continues
231+
// to own the same fieldset as before,
232+
// but does not retain ownership of any of the subfields.
233+
//
234+
// This is a known limitation due to the inability
235+
// to accurately determine whether an empty field
236+
// was previously atomic or not.
234237
"one": fieldpath.NewVersionedSet(_NS(
235238
_P("struct"),
236-
_P("struct", "numeric"),
237239
), "v1", true),
238240
"two": fieldpath.NewVersionedSet(_NS(
239241
_P("struct", "string"),

typed/reconcile_schema.go

+12-31
Original file line numberDiff line numberDiff line change
@@ -187,19 +187,17 @@ func (v *reconcileWithSchemaWalker) visitListItems(t *schema.List, element *fiel
187187
}
188188

189189
func (v *reconcileWithSchemaWalker) doList(t *schema.List) (errs ValidationErrors) {
190-
// reconcile lists changed from granular to atomic
190+
// reconcile lists changed from granular to atomic.
191+
// Note that migrations from atomic to granular are not recommended and will
192+
// be treated as if they were always granular.
193+
//
194+
// In this case, the manager that owned the previously atomic field (and all subfields),
195+
// will now own just the top-level field and none of the subfields.
191196
if !v.isAtomic && t.ElementRelationship == schema.Atomic {
192197
v.toRemove = fieldpath.NewSet(v.path) // remove all root and all children fields
193198
v.toAdd = fieldpath.NewSet(v.path) // add the root of the atomic
194199
return errs
195200
}
196-
// reconcile lists changed from atomic to granular
197-
if v.isAtomic && t.ElementRelationship == schema.Associative {
198-
v.toAdd, errs = buildGranularFieldSet(v.path, v.value)
199-
if errs != nil {
200-
return errs
201-
}
202-
}
203201
if v.fieldSet != nil {
204202
errs = v.visitListItems(t, v.fieldSet)
205203
}
@@ -231,42 +229,25 @@ func (v *reconcileWithSchemaWalker) visitMapItems(t *schema.Map, element *fieldp
231229
}
232230

233231
func (v *reconcileWithSchemaWalker) doMap(t *schema.Map) (errs ValidationErrors) {
234-
// reconcile maps and structs changed from granular to atomic
232+
// reconcile maps and structs changed from granular to atomic.
233+
// Note that migrations from atomic to granular are not recommended and will
234+
// be treated as if they were always granular.
235+
//
236+
// In this case the manager that owned the previously atomic field (and all subfields),
237+
// will now own just the top-level field and none of the subfields.
235238
if !v.isAtomic && t.ElementRelationship == schema.Atomic {
236239
if v.fieldSet != nil && v.fieldSet.Size() > 0 {
237240
v.toRemove = fieldpath.NewSet(v.path) // remove all root and all children fields
238241
v.toAdd = fieldpath.NewSet(v.path) // add the root of the atomic
239242
}
240243
return errs
241244
}
242-
// reconcile maps changed from atomic to granular
243-
if v.isAtomic && (t.ElementRelationship == schema.Separable || t.ElementRelationship == "") {
244-
v.toAdd, errs = buildGranularFieldSet(v.path, v.value)
245-
if errs != nil {
246-
return errs
247-
}
248-
}
249245
if v.fieldSet != nil {
250246
errs = v.visitMapItems(t, v.fieldSet)
251247
}
252248
return errs
253249
}
254250

255-
func buildGranularFieldSet(path fieldpath.Path, value *TypedValue) (*fieldpath.Set, ValidationErrors) {
256-
257-
valueFieldSet, err := value.ToFieldSet()
258-
if err != nil {
259-
return nil, errorf("toFieldSet: %v", err)
260-
}
261-
if valueFieldSetAtPath, ok := fieldSetAtPath(valueFieldSet, path); ok {
262-
result := fieldpath.NewSet(path)
263-
resultAtPath := descendToPath(result, path)
264-
*resultAtPath = *valueFieldSetAtPath
265-
return result, nil
266-
}
267-
return nil, nil
268-
}
269-
270251
func fieldSetAtPath(node *fieldpath.Set, path fieldpath.Path) (*fieldpath.Set, bool) {
271252
ok := true
272253
for _, pe := range path {

typed/reconcile_schema_test.go

-33
Original file line numberDiff line numberDiff line change
@@ -207,39 +207,6 @@ var reconcileCases = []reconcileTestCase{{
207207
_P("stringMap"),
208208
_P("unchanged", "numeric"),
209209
),
210-
}, {
211-
name: "atomic-to-granular",
212-
rootTypeName: "v1",
213-
oldSchema: atomicSchema("v1"),
214-
newSchema: granularSchema("v1"),
215-
liveObject: basicLiveObject,
216-
oldFields: _NS(
217-
_P("struct"),
218-
_P("list"),
219-
_P("objectList"),
220-
_P("stringMap"),
221-
_P("unchanged", "numeric"),
222-
),
223-
fixedFields: _NS(
224-
_P("struct"),
225-
_P("struct", "numeric"),
226-
_P("struct", "string"),
227-
_P("list"),
228-
_P("list", _V("one")),
229-
_P("list", _V("two")),
230-
_P("objectList"),
231-
_P("objectList", _KBF("keyA", "a1", "keyB", "b1")),
232-
_P("objectList", _KBF("keyA", "a1", "keyB", "b1"), "value"),
233-
_P("objectList", _KBF("keyA", "a1", "keyB", "b1"), "keyA"),
234-
_P("objectList", _KBF("keyA", "a1", "keyB", "b1"), "keyB"),
235-
_P("objectList", _KBF("keyA", "a2", "keyB", "b2")),
236-
_P("objectList", _KBF("keyA", "a2", "keyB", "b2"), "value"),
237-
_P("objectList", _KBF("keyA", "a2", "keyB", "b2"), "keyA"),
238-
_P("objectList", _KBF("keyA", "a2", "keyB", "b2"), "keyB"),
239-
_P("stringMap"),
240-
_P("stringMap", "key1"),
241-
_P("unchanged", "numeric"),
242-
),
243210
}, {
244211
name: "no-change-granular",
245212
rootTypeName: "v1",

0 commit comments

Comments
 (0)