k8s.io/kube-openapi@v0.0.0-20240228011516-70dd3763d340/pkg/aggregator/walker.go (about) 1 /* 2 Copyright 2017 The Kubernetes Authors. 3 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 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 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. 15 */ 16 17 package aggregator 18 19 import ( 20 "strings" 21 22 "k8s.io/kube-openapi/pkg/validation/spec" 23 ) 24 25 const ( 26 definitionPrefix = "#/definitions/" 27 parameterPrefix = "#/parameters/" 28 ) 29 30 // Run a readonlyReferenceWalker method on all references of an OpenAPI spec 31 type readonlyReferenceWalker struct { 32 // walkRefCallback will be called on each reference. The input will never be nil. 33 walkRefCallback func(ref *spec.Ref) 34 35 // The spec to walk through. 36 root *spec.Swagger 37 } 38 39 // walkOnAllReferences recursively walks on all references, while following references into definitions. 40 // it calls walkRef on each found reference. 41 func walkOnAllReferences(walkRef func(ref *spec.Ref), root *spec.Swagger) { 42 alreadyVisited := map[string]bool{} 43 44 walker := &readonlyReferenceWalker{ 45 root: root, 46 } 47 walker.walkRefCallback = func(ref *spec.Ref) { 48 walkRef(ref) 49 50 refStr := ref.String() 51 if refStr == "" || !strings.HasPrefix(refStr, definitionPrefix) { 52 return 53 } 54 defName := refStr[len(definitionPrefix):] 55 56 if _, found := root.Definitions[defName]; found && !alreadyVisited[refStr] { 57 alreadyVisited[refStr] = true 58 def := root.Definitions[defName] 59 walker.walkSchema(&def) 60 } 61 } 62 walker.Start() 63 } 64 65 func (s *readonlyReferenceWalker) walkSchema(schema *spec.Schema) { 66 if schema == nil { 67 return 68 } 69 s.walkRefCallback(&schema.Ref) 70 var v *spec.Schema 71 if len(schema.Definitions)+len(schema.Properties)+len(schema.PatternProperties) > 0 { 72 v = &spec.Schema{} 73 } 74 for k := range schema.Definitions { 75 *v = schema.Definitions[k] 76 s.walkSchema(v) 77 } 78 for k := range schema.Properties { 79 *v = schema.Properties[k] 80 s.walkSchema(v) 81 } 82 for k := range schema.PatternProperties { 83 *v = schema.PatternProperties[k] 84 s.walkSchema(v) 85 } 86 for i := range schema.AllOf { 87 s.walkSchema(&schema.AllOf[i]) 88 } 89 for i := range schema.AnyOf { 90 s.walkSchema(&schema.AnyOf[i]) 91 } 92 for i := range schema.OneOf { 93 s.walkSchema(&schema.OneOf[i]) 94 } 95 if schema.Not != nil { 96 s.walkSchema(schema.Not) 97 } 98 if schema.AdditionalProperties != nil && schema.AdditionalProperties.Schema != nil { 99 s.walkSchema(schema.AdditionalProperties.Schema) 100 } 101 if schema.AdditionalItems != nil && schema.AdditionalItems.Schema != nil { 102 s.walkSchema(schema.AdditionalItems.Schema) 103 } 104 if schema.Items != nil { 105 if schema.Items.Schema != nil { 106 s.walkSchema(schema.Items.Schema) 107 } 108 for i := range schema.Items.Schemas { 109 s.walkSchema(&schema.Items.Schemas[i]) 110 } 111 } 112 } 113 114 func (s *readonlyReferenceWalker) walkParams(params []spec.Parameter) { 115 if params == nil { 116 return 117 } 118 for _, param := range params { 119 s.walkRefCallback(¶m.Ref) 120 s.walkSchema(param.Schema) 121 if param.Items != nil { 122 s.walkRefCallback(¶m.Items.Ref) 123 } 124 } 125 } 126 127 func (s *readonlyReferenceWalker) walkResponse(resp *spec.Response) { 128 if resp == nil { 129 return 130 } 131 s.walkRefCallback(&resp.Ref) 132 s.walkSchema(resp.Schema) 133 } 134 135 func (s *readonlyReferenceWalker) walkOperation(op *spec.Operation) { 136 if op == nil { 137 return 138 } 139 s.walkParams(op.Parameters) 140 if op.Responses == nil { 141 return 142 } 143 s.walkResponse(op.Responses.Default) 144 for _, r := range op.Responses.StatusCodeResponses { 145 s.walkResponse(&r) 146 } 147 } 148 149 func (s *readonlyReferenceWalker) Start() { 150 if s.root.Paths == nil { 151 return 152 } 153 for _, pathItem := range s.root.Paths.Paths { 154 s.walkParams(pathItem.Parameters) 155 s.walkOperation(pathItem.Delete) 156 s.walkOperation(pathItem.Get) 157 s.walkOperation(pathItem.Head) 158 s.walkOperation(pathItem.Options) 159 s.walkOperation(pathItem.Patch) 160 s.walkOperation(pathItem.Post) 161 s.walkOperation(pathItem.Put) 162 } 163 }