2 Copyright 2017 The Kubernetes Authors.
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
8 http://www.apache.org/licenses/LICENSE-2.0
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
17 package strategicpatch
23 "k8s.io/apimachinery/pkg/util/mergepatch"
24 openapi "k8s.io/kube-openapi/pkg/util/proto"
28 patchStrategyOpenapiextensionKey = "x-kubernetes-patch-strategy"
29 patchMergeKeyOpenapiextensionKey = "x-kubernetes-patch-merge-key"
32 type LookupPatchItem interface {
39 type kindItem struct {
44 subschema openapi.Schema
48 func NewKindItem(key string, path *openapi.Path) *kindItem {
55 var _ LookupPatchItem = &kindItem{}
57 func (item *kindItem) Error() error {
61 func (item *kindItem) Path() *openapi.Path {
65 func (item *kindItem) VisitPrimitive(schema *openapi.Primitive) {
66 item.err = errors.New("expected kind, but got primitive")
69 func (item *kindItem) VisitArray(schema *openapi.Array) {
70 item.err = errors.New("expected kind, but got slice")
73 func (item *kindItem) VisitMap(schema *openapi.Map) {
74 item.err = errors.New("expected kind, but got map")
77 func (item *kindItem) VisitReference(schema openapi.Reference) {
78 if !item.hasVisitKind {
79 schema.SubSchema().Accept(item)
83 func (item *kindItem) VisitKind(schema *openapi.Kind) {
84 subschema, ok := schema.Fields[item.key]
86 item.err = FieldNotFoundError{Path: schema.GetPath().String(), Field: item.key}
90 mergeKey, patchStrategies, err := parsePatchMetadata(subschema.GetExtensions())
95 item.patchmeta = PatchMeta{
96 patchStrategies: patchStrategies,
97 patchMergeKey: mergeKey,
99 item.subschema = subschema
102 type sliceItem struct {
107 subschema openapi.Schema
111 func NewSliceItem(key string, path *openapi.Path) *sliceItem {
118 var _ LookupPatchItem = &sliceItem{}
120 func (item *sliceItem) Error() error {
124 func (item *sliceItem) Path() *openapi.Path {
128 func (item *sliceItem) VisitPrimitive(schema *openapi.Primitive) {
129 item.err = errors.New("expected slice, but got primitive")
132 func (item *sliceItem) VisitArray(schema *openapi.Array) {
133 if !item.hasVisitKind {
134 item.err = errors.New("expected visit kind first, then visit array")
136 subschema := schema.SubType
137 item.subschema = subschema
140 func (item *sliceItem) VisitMap(schema *openapi.Map) {
141 item.err = errors.New("expected slice, but got map")
144 func (item *sliceItem) VisitReference(schema openapi.Reference) {
145 if !item.hasVisitKind {
146 schema.SubSchema().Accept(item)
148 item.subschema = schema.SubSchema()
152 func (item *sliceItem) VisitKind(schema *openapi.Kind) {
153 subschema, ok := schema.Fields[item.key]
155 item.err = FieldNotFoundError{Path: schema.GetPath().String(), Field: item.key}
159 mergeKey, patchStrategies, err := parsePatchMetadata(subschema.GetExtensions())
164 item.patchmeta = PatchMeta{
165 patchStrategies: patchStrategies,
166 patchMergeKey: mergeKey,
168 item.hasVisitKind = true
169 subschema.Accept(item)
172 func parsePatchMetadata(extensions map[string]interface{}) (string, []string, error) {
173 ps, foundPS := extensions[patchStrategyOpenapiextensionKey]
174 var patchStrategies []string
175 var mergeKey, patchStrategy string
178 patchStrategy, ok = ps.(string)
180 patchStrategies = strings.Split(patchStrategy, ",")
182 return "", nil, mergepatch.ErrBadArgType(patchStrategy, ps)
185 mk, foundMK := extensions[patchMergeKeyOpenapiextensionKey]
187 mergeKey, ok = mk.(string)
189 return "", nil, mergepatch.ErrBadArgType(mergeKey, mk)
192 return mergeKey, patchStrategies, nil