Use OpenAPI when merging (3way) resources

- When merging (3way) resources use the patch strategy from the openAPI if the definition exists for the field
- Allow disabling of guessing patch strategy merge keys when no definition exists
- Support defining strategy and key directly on configuration fields through line and header coments
- Support attaching schema to parent fields of lists, and propagating -- e.g. that a field is a PodTemplate
This commit is contained in:
Phillip Wittrock
2020-02-27 10:08:40 -08:00
parent 8991b193c6
commit 5d1a0346b5
24 changed files with 991 additions and 507 deletions

View File

@@ -6,6 +6,8 @@ package walk
import (
"sort"
"sigs.k8s.io/kustomize/kyaml/fieldmeta"
"sigs.k8s.io/kustomize/kyaml/openapi"
"sigs.k8s.io/kustomize/kyaml/sets"
"sigs.k8s.io/kustomize/kyaml/yaml"
)
@@ -18,15 +20,27 @@ import (
// - set each source field value on l.Dest
func (l Walker) walkMap() (*yaml.RNode, error) {
// get the new map value
dest, err := l.Sources.setDestNode(l.VisitMap(l.Sources))
dest, err := l.Sources.setDestNode(l.VisitMap(l.Sources, l.Schema))
if dest == nil || err != nil {
return nil, err
}
// recursively set the field values on the map
for _, key := range l.fieldNames() {
val, err := Walker{Visitor: l,
Sources: l.fieldValue(key), Path: append(l.Path, key)}.Walk()
var s *openapi.ResourceSchema
if l.Schema != nil {
s = l.Schema.Field(key)
}
fv, commentSch := l.fieldValue(key)
if commentSch != nil {
s = commentSch
}
val, err := Walker{
InferAssociativeLists: l.InferAssociativeLists,
Visitor: l,
Schema: s,
Sources: fv,
Path: append(l.Path, key)}.Walk()
if err != nil {
return nil, err
}
@@ -42,11 +56,40 @@ func (l Walker) walkMap() (*yaml.RNode, error) {
}
// valueIfPresent returns node.Value if node is non-nil, otherwise returns nil
func (l Walker) valueIfPresent(node *yaml.MapNode) *yaml.RNode {
func (l Walker) valueIfPresent(node *yaml.MapNode) (*yaml.RNode, *openapi.ResourceSchema) {
if node == nil {
return nil
return nil, nil
}
return node.Value
// parse the schema for the field if present
var s *openapi.ResourceSchema
fm := fieldmeta.FieldMeta{}
var err error
// check the value for a schema
if err = fm.Read(node.Value); err == nil {
s = &openapi.ResourceSchema{Schema: &fm.Schema}
if fm.Schema.Ref.String() != "" {
r, err := openapi.Resolve(&fm.Schema.Ref)
if err == nil && r != nil {
s.Schema = r
}
}
}
// check the key for a schema -- this will be used
// when the value is a Sequence (comments are attached)
// to the key
if fm.IsEmpty() {
if err = fm.Read(node.Key); err == nil {
s = &openapi.ResourceSchema{Schema: &fm.Schema}
}
if fm.Schema.Ref.String() != "" {
r, err := openapi.Resolve(&fm.Schema.Ref)
if err == nil && r != nil {
s.Schema = r
}
}
}
return node.Value, s
}
// fieldNames returns a sorted slice containing the names of all fields that appear in any of
@@ -67,15 +110,20 @@ func (l Walker) fieldNames() []string {
}
// fieldValue returns a slice containing each source's value for fieldName
func (l Walker) fieldValue(fieldName string) []*yaml.RNode {
func (l Walker) fieldValue(fieldName string) ([]*yaml.RNode, *openapi.ResourceSchema) {
var fields []*yaml.RNode
var sch *openapi.ResourceSchema
for i := range l.Sources {
if l.Sources[i] == nil {
fields = append(fields, nil)
continue
}
field := l.Sources[i].Field(fieldName)
fields = append(fields, l.valueIfPresent(field))
f, s := l.valueIfPresent(field)
fields = append(fields, f)
if sch == nil && !s.IsEmpty() {
sch = s
}
}
return fields
return fields, sch
}