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(&param.Ref)
   120  		s.walkSchema(param.Schema)
   121  		if param.Items != nil {
   122  			s.walkRefCallback(&param.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  }