mirror of
				https://github.com/k3s-io/kubernetes.git
				synced 2025-10-30 21:30:16 +00:00 
			
		
		
		
	Update Godeps to use kube-openapi
This commit is contained in:
		
							
								
								
									
										24
									
								
								Godeps/Godeps.json
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										24
									
								
								Godeps/Godeps.json
									
									
									
										generated
									
									
									
								
							| @@ -3032,6 +3032,30 @@ | ||||
| 			"Comment": "v1.2.0-beta.1", | ||||
| 			"Rev": "c2ac40f1adf8c42a79badddb2a2acd673cae3bcb" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"ImportPath": "k8s.io/kube-openapi/pkg/aggregator", | ||||
| 			"Rev": "80f07ef71bb4f781233c65aa8d0369e4ecafab87" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"ImportPath": "k8s.io/kube-openapi/pkg/builder", | ||||
| 			"Rev": "80f07ef71bb4f781233c65aa8d0369e4ecafab87" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"ImportPath": "k8s.io/kube-openapi/pkg/common", | ||||
| 			"Rev": "80f07ef71bb4f781233c65aa8d0369e4ecafab87" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"ImportPath": "k8s.io/kube-openapi/pkg/generators", | ||||
| 			"Rev": "80f07ef71bb4f781233c65aa8d0369e4ecafab87" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"ImportPath": "k8s.io/kube-openapi/pkg/handler", | ||||
| 			"Rev": "80f07ef71bb4f781233c65aa8d0369e4ecafab87" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"ImportPath": "k8s.io/kube-openapi/pkg/util", | ||||
| 			"Rev": "80f07ef71bb4f781233c65aa8d0369e4ecafab87" | ||||
| 		}, | ||||
| 		{ | ||||
| 			"ImportPath": "k8s.io/utils/exec", | ||||
| 			"Rev": "9fdc871a36f37980dd85f96d576b20d564cc0784" | ||||
|   | ||||
							
								
								
									
										1260
									
								
								Godeps/LICENSES
									
									
									
										generated
									
									
									
								
							
							
						
						
									
										1260
									
								
								Godeps/LICENSES
									
									
									
										generated
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										202
									
								
								vendor/k8s.io/kube-openapi/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										202
									
								
								vendor/k8s.io/kube-openapi/LICENSE
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,202 @@ | ||||
|  | ||||
|                                  Apache License | ||||
|                            Version 2.0, January 2004 | ||||
|                         http://www.apache.org/licenses/ | ||||
|  | ||||
|    TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION | ||||
|  | ||||
|    1. Definitions. | ||||
|  | ||||
|       "License" shall mean the terms and conditions for use, reproduction, | ||||
|       and distribution as defined by Sections 1 through 9 of this document. | ||||
|  | ||||
|       "Licensor" shall mean the copyright owner or entity authorized by | ||||
|       the copyright owner that is granting the License. | ||||
|  | ||||
|       "Legal Entity" shall mean the union of the acting entity and all | ||||
|       other entities that control, are controlled by, or are under common | ||||
|       control with that entity. For the purposes of this definition, | ||||
|       "control" means (i) the power, direct or indirect, to cause the | ||||
|       direction or management of such entity, whether by contract or | ||||
|       otherwise, or (ii) ownership of fifty percent (50%) or more of the | ||||
|       outstanding shares, or (iii) beneficial ownership of such entity. | ||||
|  | ||||
|       "You" (or "Your") shall mean an individual or Legal Entity | ||||
|       exercising permissions granted by this License. | ||||
|  | ||||
|       "Source" form shall mean the preferred form for making modifications, | ||||
|       including but not limited to software source code, documentation | ||||
|       source, and configuration files. | ||||
|  | ||||
|       "Object" form shall mean any form resulting from mechanical | ||||
|       transformation or translation of a Source form, including but | ||||
|       not limited to compiled object code, generated documentation, | ||||
|       and conversions to other media types. | ||||
|  | ||||
|       "Work" shall mean the work of authorship, whether in Source or | ||||
|       Object form, made available under the License, as indicated by a | ||||
|       copyright notice that is included in or attached to the work | ||||
|       (an example is provided in the Appendix below). | ||||
|  | ||||
|       "Derivative Works" shall mean any work, whether in Source or Object | ||||
|       form, that is based on (or derived from) the Work and for which the | ||||
|       editorial revisions, annotations, elaborations, or other modifications | ||||
|       represent, as a whole, an original work of authorship. For the purposes | ||||
|       of this License, Derivative Works shall not include works that remain | ||||
|       separable from, or merely link (or bind by name) to the interfaces of, | ||||
|       the Work and Derivative Works thereof. | ||||
|  | ||||
|       "Contribution" shall mean any work of authorship, including | ||||
|       the original version of the Work and any modifications or additions | ||||
|       to that Work or Derivative Works thereof, that is intentionally | ||||
|       submitted to Licensor for inclusion in the Work by the copyright owner | ||||
|       or by an individual or Legal Entity authorized to submit on behalf of | ||||
|       the copyright owner. For the purposes of this definition, "submitted" | ||||
|       means any form of electronic, verbal, or written communication sent | ||||
|       to the Licensor or its representatives, including but not limited to | ||||
|       communication on electronic mailing lists, source code control systems, | ||||
|       and issue tracking systems that are managed by, or on behalf of, the | ||||
|       Licensor for the purpose of discussing and improving the Work, but | ||||
|       excluding communication that is conspicuously marked or otherwise | ||||
|       designated in writing by the copyright owner as "Not a Contribution." | ||||
|  | ||||
|       "Contributor" shall mean Licensor and any individual or Legal Entity | ||||
|       on behalf of whom a Contribution has been received by Licensor and | ||||
|       subsequently incorporated within the Work. | ||||
|  | ||||
|    2. Grant of Copyright License. Subject to the terms and conditions of | ||||
|       this License, each Contributor hereby grants to You a perpetual, | ||||
|       worldwide, non-exclusive, no-charge, royalty-free, irrevocable | ||||
|       copyright license to reproduce, prepare Derivative Works of, | ||||
|       publicly display, publicly perform, sublicense, and distribute the | ||||
|       Work and such Derivative Works in Source or Object form. | ||||
|  | ||||
|    3. Grant of Patent License. Subject to the terms and conditions of | ||||
|       this License, each Contributor hereby grants to You a perpetual, | ||||
|       worldwide, non-exclusive, no-charge, royalty-free, irrevocable | ||||
|       (except as stated in this section) patent license to make, have made, | ||||
|       use, offer to sell, sell, import, and otherwise transfer the Work, | ||||
|       where such license applies only to those patent claims licensable | ||||
|       by such Contributor that are necessarily infringed by their | ||||
|       Contribution(s) alone or by combination of their Contribution(s) | ||||
|       with the Work to which such Contribution(s) was submitted. If You | ||||
|       institute patent litigation against any entity (including a | ||||
|       cross-claim or counterclaim in a lawsuit) alleging that the Work | ||||
|       or a Contribution incorporated within the Work constitutes direct | ||||
|       or contributory patent infringement, then any patent licenses | ||||
|       granted to You under this License for that Work shall terminate | ||||
|       as of the date such litigation is filed. | ||||
|  | ||||
|    4. Redistribution. You may reproduce and distribute copies of the | ||||
|       Work or Derivative Works thereof in any medium, with or without | ||||
|       modifications, and in Source or Object form, provided that You | ||||
|       meet the following conditions: | ||||
|  | ||||
|       (a) You must give any other recipients of the Work or | ||||
|           Derivative Works a copy of this License; and | ||||
|  | ||||
|       (b) You must cause any modified files to carry prominent notices | ||||
|           stating that You changed the files; and | ||||
|  | ||||
|       (c) You must retain, in the Source form of any Derivative Works | ||||
|           that You distribute, all copyright, patent, trademark, and | ||||
|           attribution notices from the Source form of the Work, | ||||
|           excluding those notices that do not pertain to any part of | ||||
|           the Derivative Works; and | ||||
|  | ||||
|       (d) If the Work includes a "NOTICE" text file as part of its | ||||
|           distribution, then any Derivative Works that You distribute must | ||||
|           include a readable copy of the attribution notices contained | ||||
|           within such NOTICE file, excluding those notices that do not | ||||
|           pertain to any part of the Derivative Works, in at least one | ||||
|           of the following places: within a NOTICE text file distributed | ||||
|           as part of the Derivative Works; within the Source form or | ||||
|           documentation, if provided along with the Derivative Works; or, | ||||
|           within a display generated by the Derivative Works, if and | ||||
|           wherever such third-party notices normally appear. The contents | ||||
|           of the NOTICE file are for informational purposes only and | ||||
|           do not modify the License. You may add Your own attribution | ||||
|           notices within Derivative Works that You distribute, alongside | ||||
|           or as an addendum to the NOTICE text from the Work, provided | ||||
|           that such additional attribution notices cannot be construed | ||||
|           as modifying the License. | ||||
|  | ||||
|       You may add Your own copyright statement to Your modifications and | ||||
|       may provide additional or different license terms and conditions | ||||
|       for use, reproduction, or distribution of Your modifications, or | ||||
|       for any such Derivative Works as a whole, provided Your use, | ||||
|       reproduction, and distribution of the Work otherwise complies with | ||||
|       the conditions stated in this License. | ||||
|  | ||||
|    5. Submission of Contributions. Unless You explicitly state otherwise, | ||||
|       any Contribution intentionally submitted for inclusion in the Work | ||||
|       by You to the Licensor shall be under the terms and conditions of | ||||
|       this License, without any additional terms or conditions. | ||||
|       Notwithstanding the above, nothing herein shall supersede or modify | ||||
|       the terms of any separate license agreement you may have executed | ||||
|       with Licensor regarding such Contributions. | ||||
|  | ||||
|    6. Trademarks. This License does not grant permission to use the trade | ||||
|       names, trademarks, service marks, or product names of the Licensor, | ||||
|       except as required for reasonable and customary use in describing the | ||||
|       origin of the Work and reproducing the content of the NOTICE file. | ||||
|  | ||||
|    7. Disclaimer of Warranty. Unless required by applicable law or | ||||
|       agreed to in writing, Licensor provides the Work (and each | ||||
|       Contributor provides its Contributions) on an "AS IS" BASIS, | ||||
|       WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or | ||||
|       implied, including, without limitation, any warranties or conditions | ||||
|       of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A | ||||
|       PARTICULAR PURPOSE. You are solely responsible for determining the | ||||
|       appropriateness of using or redistributing the Work and assume any | ||||
|       risks associated with Your exercise of permissions under this License. | ||||
|  | ||||
|    8. Limitation of Liability. In no event and under no legal theory, | ||||
|       whether in tort (including negligence), contract, or otherwise, | ||||
|       unless required by applicable law (such as deliberate and grossly | ||||
|       negligent acts) or agreed to in writing, shall any Contributor be | ||||
|       liable to You for damages, including any direct, indirect, special, | ||||
|       incidental, or consequential damages of any character arising as a | ||||
|       result of this License or out of the use or inability to use the | ||||
|       Work (including but not limited to damages for loss of goodwill, | ||||
|       work stoppage, computer failure or malfunction, or any and all | ||||
|       other commercial damages or losses), even if such Contributor | ||||
|       has been advised of the possibility of such damages. | ||||
|  | ||||
|    9. Accepting Warranty or Additional Liability. While redistributing | ||||
|       the Work or Derivative Works thereof, You may choose to offer, | ||||
|       and charge a fee for, acceptance of support, warranty, indemnity, | ||||
|       or other liability obligations and/or rights consistent with this | ||||
|       License. However, in accepting such obligations, You may act only | ||||
|       on Your own behalf and on Your sole responsibility, not on behalf | ||||
|       of any other Contributor, and only if You agree to indemnify, | ||||
|       defend, and hold each Contributor harmless for any liability | ||||
|       incurred by, or claims asserted against, such Contributor by reason | ||||
|       of your accepting any such warranty or additional liability. | ||||
|  | ||||
|    END OF TERMS AND CONDITIONS | ||||
|  | ||||
|    APPENDIX: How to apply the Apache License to your work. | ||||
|  | ||||
|       To apply the Apache License to your work, attach the following | ||||
|       boilerplate notice, with the fields enclosed by brackets "[]" | ||||
|       replaced with your own identifying information. (Don't include | ||||
|       the brackets!)  The text should be enclosed in the appropriate | ||||
|       comment syntax for the file format. We also recommend that a | ||||
|       file or class name and description of purpose be included on the | ||||
|       same "printed page" as the copyright notice for easier | ||||
|       identification within third-party archives. | ||||
|  | ||||
|    Copyright [yyyy] [name of copyright owner] | ||||
|  | ||||
|    Licensed under the Apache License, Version 2.0 (the "License"); | ||||
|    you may not use this file except in compliance with the License. | ||||
|    You may obtain a copy of the License at | ||||
|  | ||||
|        http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
|    Unless required by applicable law or agreed to in writing, software | ||||
|    distributed under the License is distributed on an "AS IS" BASIS, | ||||
|    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
|    See the License for the specific language governing permissions and | ||||
|    limitations under the License. | ||||
							
								
								
									
										276
									
								
								vendor/k8s.io/kube-openapi/pkg/aggregator/aggregator.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										276
									
								
								vendor/k8s.io/kube-openapi/pkg/aggregator/aggregator.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,276 @@ | ||||
| /* | ||||
| Copyright 2017 The Kubernetes Authors. | ||||
|  | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
|  | ||||
| package aggregator | ||||
|  | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"reflect" | ||||
| 	"strings" | ||||
|  | ||||
| 	"github.com/go-openapi/spec" | ||||
|  | ||||
| 	"k8s.io/kube-openapi/pkg/util" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	definitionPrefix = "#/definitions/" | ||||
| ) | ||||
|  | ||||
| // Run a walkRefCallback method on all references of an OpenAPI spec | ||||
| type referenceWalker struct { | ||||
| 	// walkRefCallback will be called on each reference and the return value | ||||
| 	// will replace that reference. This will allow the callers to change | ||||
| 	// all/some references of an spec (e.g. useful in renaming definitions). | ||||
| 	walkRefCallback func(ref spec.Ref) spec.Ref | ||||
|  | ||||
| 	// The spec to walk through. | ||||
| 	root *spec.Swagger | ||||
|  | ||||
| 	// Keep track of visited references | ||||
| 	alreadyVisited map[string]bool | ||||
| } | ||||
|  | ||||
| func walkOnAllReferences(walkRef func(ref spec.Ref) spec.Ref, sp *spec.Swagger) { | ||||
| 	walker := &referenceWalker{walkRefCallback: walkRef, root: sp, alreadyVisited: map[string]bool{}} | ||||
| 	walker.Start() | ||||
| } | ||||
|  | ||||
| func (s *referenceWalker) walkRef(ref spec.Ref) spec.Ref { | ||||
| 	refStr := ref.String() | ||||
| 	// References that start with #/definitions/ has a definition | ||||
| 	// inside the same spec file. If that is the case, walk through | ||||
| 	// those definitions too. | ||||
| 	// We do not support external references yet. | ||||
| 	if !s.alreadyVisited[refStr] && strings.HasPrefix(refStr, definitionPrefix) { | ||||
| 		s.alreadyVisited[refStr] = true | ||||
| 		def := s.root.Definitions[refStr[len(definitionPrefix):]] | ||||
| 		s.walkSchema(&def) | ||||
| 	} | ||||
| 	return s.walkRefCallback(ref) | ||||
| } | ||||
|  | ||||
| func (s *referenceWalker) walkSchema(schema *spec.Schema) { | ||||
| 	if schema == nil { | ||||
| 		return | ||||
| 	} | ||||
| 	schema.Ref = s.walkRef(schema.Ref) | ||||
| 	for _, v := range schema.Definitions { | ||||
| 		s.walkSchema(&v) | ||||
| 	} | ||||
| 	for _, v := range schema.Properties { | ||||
| 		s.walkSchema(&v) | ||||
| 	} | ||||
| 	for _, v := range schema.PatternProperties { | ||||
| 		s.walkSchema(&v) | ||||
| 	} | ||||
| 	for _, v := range schema.AllOf { | ||||
| 		s.walkSchema(&v) | ||||
| 	} | ||||
| 	for _, v := range schema.AnyOf { | ||||
| 		s.walkSchema(&v) | ||||
| 	} | ||||
| 	for _, v := range schema.OneOf { | ||||
| 		s.walkSchema(&v) | ||||
| 	} | ||||
| 	if schema.Not != nil { | ||||
| 		s.walkSchema(schema.Not) | ||||
| 	} | ||||
| 	if schema.AdditionalProperties != nil && schema.AdditionalProperties.Schema != nil { | ||||
| 		s.walkSchema(schema.AdditionalProperties.Schema) | ||||
| 	} | ||||
| 	if schema.AdditionalItems != nil && schema.AdditionalItems.Schema != nil { | ||||
| 		s.walkSchema(schema.AdditionalItems.Schema) | ||||
| 	} | ||||
| 	if schema.Items != nil { | ||||
| 		if schema.Items.Schema != nil { | ||||
| 			s.walkSchema(schema.Items.Schema) | ||||
| 		} | ||||
| 		for _, v := range schema.Items.Schemas { | ||||
| 			s.walkSchema(&v) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (s *referenceWalker) walkParams(params []spec.Parameter) { | ||||
| 	if params == nil { | ||||
| 		return | ||||
| 	} | ||||
| 	for _, param := range params { | ||||
| 		param.Ref = s.walkRef(param.Ref) | ||||
| 		s.walkSchema(param.Schema) | ||||
| 		if param.Items != nil { | ||||
| 			param.Items.Ref = s.walkRef(param.Items.Ref) | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (s *referenceWalker) walkResponse(resp *spec.Response) { | ||||
| 	if resp == nil { | ||||
| 		return | ||||
| 	} | ||||
| 	resp.Ref = s.walkRef(resp.Ref) | ||||
| 	s.walkSchema(resp.Schema) | ||||
| } | ||||
|  | ||||
| func (s *referenceWalker) walkOperation(op *spec.Operation) { | ||||
| 	if op == nil { | ||||
| 		return | ||||
| 	} | ||||
| 	s.walkParams(op.Parameters) | ||||
| 	if op.Responses == nil { | ||||
| 		return | ||||
| 	} | ||||
| 	s.walkResponse(op.Responses.Default) | ||||
| 	for _, r := range op.Responses.StatusCodeResponses { | ||||
| 		s.walkResponse(&r) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (s *referenceWalker) Start() { | ||||
| 	for _, pathItem := range s.root.Paths.Paths { | ||||
| 		s.walkParams(pathItem.Parameters) | ||||
| 		s.walkOperation(pathItem.Delete) | ||||
| 		s.walkOperation(pathItem.Get) | ||||
| 		s.walkOperation(pathItem.Head) | ||||
| 		s.walkOperation(pathItem.Options) | ||||
| 		s.walkOperation(pathItem.Patch) | ||||
| 		s.walkOperation(pathItem.Post) | ||||
| 		s.walkOperation(pathItem.Put) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // FilterSpecByPaths remove unnecessary paths and unused definitions. | ||||
| func FilterSpecByPaths(sp *spec.Swagger, keepPathPrefixes []string) { | ||||
| 	// First remove unwanted paths | ||||
| 	prefixes := util.NewTrie(keepPathPrefixes) | ||||
| 	orgPaths := sp.Paths | ||||
| 	if orgPaths == nil { | ||||
| 		return | ||||
| 	} | ||||
| 	sp.Paths = &spec.Paths{ | ||||
| 		VendorExtensible: orgPaths.VendorExtensible, | ||||
| 		Paths:            map[string]spec.PathItem{}, | ||||
| 	} | ||||
| 	for path, pathItem := range orgPaths.Paths { | ||||
| 		if !prefixes.HasPrefix(path) { | ||||
| 			continue | ||||
| 		} | ||||
| 		sp.Paths.Paths[path] = pathItem | ||||
| 	} | ||||
|  | ||||
| 	// Walk all references to find all definition references. | ||||
| 	usedDefinitions := map[string]bool{} | ||||
|  | ||||
| 	walkOnAllReferences(func(ref spec.Ref) spec.Ref { | ||||
| 		if ref.String() != "" { | ||||
| 			refStr := ref.String() | ||||
| 			if strings.HasPrefix(refStr, definitionPrefix) { | ||||
| 				usedDefinitions[refStr[len(definitionPrefix):]] = true | ||||
| 			} | ||||
| 		} | ||||
| 		return ref | ||||
| 	}, sp) | ||||
|  | ||||
| 	// Remove unused definitions | ||||
| 	orgDefinitions := sp.Definitions | ||||
| 	sp.Definitions = spec.Definitions{} | ||||
| 	for k, v := range orgDefinitions { | ||||
| 		if usedDefinitions[k] { | ||||
| 			sp.Definitions[k] = v | ||||
| 		} | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func renameDefinition(s *spec.Swagger, old, new string) { | ||||
| 	old_ref := definitionPrefix + old | ||||
| 	new_ref := definitionPrefix + new | ||||
| 	walkOnAllReferences(func(ref spec.Ref) spec.Ref { | ||||
| 		if ref.String() == old_ref { | ||||
| 			return spec.MustCreateRef(new_ref) | ||||
| 		} | ||||
| 		return ref | ||||
| 	}, s) | ||||
| 	s.Definitions[new] = s.Definitions[old] | ||||
| 	delete(s.Definitions, old) | ||||
| } | ||||
|  | ||||
| // Copy paths and definitions from source to dest, rename definitions if needed. | ||||
| // dest will be mutated, and source will not be changed. | ||||
| func MergeSpecs(dest, source *spec.Swagger) error { | ||||
| 	sourceCopy, err := CloneSpec(source) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	for k, v := range sourceCopy.Paths.Paths { | ||||
| 		if _, found := dest.Paths.Paths[k]; found { | ||||
| 			return fmt.Errorf("unable to merge: duplicated path %s", k) | ||||
| 		} | ||||
| 		dest.Paths.Paths[k] = v | ||||
| 	} | ||||
| 	usedNames := map[string]bool{} | ||||
| 	for k := range dest.Definitions { | ||||
| 		usedNames[k] = true | ||||
| 	} | ||||
| 	type Rename struct { | ||||
| 		from, to string | ||||
| 	} | ||||
| 	renames := []Rename{} | ||||
| 	for k, v := range sourceCopy.Definitions { | ||||
| 		if usedNames[k] { | ||||
| 			v2, found := dest.Definitions[k] | ||||
| 			// Reuse model iff they are exactly the same. | ||||
| 			if found && reflect.DeepEqual(v, v2) { | ||||
| 				continue | ||||
| 			} | ||||
| 			i := 2 | ||||
| 			newName := fmt.Sprintf("%s_v%d", k, i) | ||||
| 			_, foundInSource := sourceCopy.Definitions[newName] | ||||
| 			for usedNames[newName] || foundInSource { | ||||
| 				i += 1 | ||||
| 				newName = fmt.Sprintf("%s_v%d", k, i) | ||||
| 				_, foundInSource = sourceCopy.Definitions[newName] | ||||
| 			} | ||||
| 			renames = append(renames, Rename{from: k, to: newName}) | ||||
| 			usedNames[newName] = true | ||||
| 		} | ||||
| 	} | ||||
| 	for _, r := range renames { | ||||
| 		renameDefinition(sourceCopy, r.from, r.to) | ||||
| 	} | ||||
| 	for k, v := range sourceCopy.Definitions { | ||||
| 		if _, found := dest.Definitions[k]; !found { | ||||
| 			dest.Definitions[k] = v | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // Clone OpenAPI spec | ||||
| func CloneSpec(source *spec.Swagger) (*spec.Swagger, error) { | ||||
| 	// TODO(mehdy): Find a faster way to clone an spec | ||||
| 	bytes, err := json.Marshal(source) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	var ret spec.Swagger | ||||
| 	err = json.Unmarshal(bytes, &ret) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return &ret, nil | ||||
| } | ||||
							
								
								
									
										20
									
								
								vendor/k8s.io/kube-openapi/pkg/builder/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								vendor/k8s.io/kube-openapi/pkg/builder/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | ||||
| /* | ||||
| Copyright 2016 The Kubernetes Authors. | ||||
|  | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
|  | ||||
| // Package builder contains code to generate OpenAPI discovery spec (which | ||||
| // initial version of it also known as Swagger 2.0). | ||||
| // For more details: https://github.com/OAI/OpenAPI-Specification/blob/master/versions/2.0.md | ||||
| package builder | ||||
							
								
								
									
										424
									
								
								vendor/k8s.io/kube-openapi/pkg/builder/openapi.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										424
									
								
								vendor/k8s.io/kube-openapi/pkg/builder/openapi.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,424 @@ | ||||
| /* | ||||
| Copyright 2016 The Kubernetes Authors. | ||||
|  | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
|  | ||||
| package builder | ||||
|  | ||||
| import ( | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"net/http" | ||||
| 	"reflect" | ||||
| 	"strings" | ||||
|  | ||||
| 	restful "github.com/emicklei/go-restful" | ||||
| 	"github.com/go-openapi/spec" | ||||
|  | ||||
| 	"k8s.io/kube-openapi/pkg/common" | ||||
| 	"k8s.io/kube-openapi/pkg/util" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	OpenAPIVersion = "2.0" | ||||
| 	// TODO: Make this configurable. | ||||
| 	extensionPrefix = "x-kubernetes-" | ||||
| ) | ||||
|  | ||||
| type openAPI struct { | ||||
| 	config       *common.Config | ||||
| 	swagger      *spec.Swagger | ||||
| 	protocolList []string | ||||
| 	definitions  map[string]common.OpenAPIDefinition | ||||
| } | ||||
|  | ||||
| // BuildOpenAPISpec builds OpenAPI spec given a list of webservices (containing routes) and common.Config to customize it. | ||||
| func BuildOpenAPISpec(webServices []*restful.WebService, config *common.Config) (*spec.Swagger, error) { | ||||
| 	o := openAPI{ | ||||
| 		config: config, | ||||
| 		swagger: &spec.Swagger{ | ||||
| 			SwaggerProps: spec.SwaggerProps{ | ||||
| 				Swagger:     OpenAPIVersion, | ||||
| 				Definitions: spec.Definitions{}, | ||||
| 				Paths:       &spec.Paths{Paths: map[string]spec.PathItem{}}, | ||||
| 				Info:        config.Info, | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
|  | ||||
| 	err := o.init(webServices) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	return o.swagger, nil | ||||
| } | ||||
|  | ||||
| func (o *openAPI) init(webServices []*restful.WebService) error { | ||||
| 	if o.config.GetOperationIDAndTags == nil { | ||||
| 		o.config.GetOperationIDAndTags = func(r *restful.Route) (string, []string, error) { | ||||
| 			return r.Operation, nil, nil | ||||
| 		} | ||||
| 	} | ||||
| 	if o.config.GetDefinitionName == nil { | ||||
| 		o.config.GetDefinitionName = func(name string) (string, spec.Extensions) { | ||||
| 			return name[strings.LastIndex(name, "/")+1:], nil | ||||
| 		} | ||||
| 	} | ||||
| 	o.definitions = o.config.GetDefinitions(func(name string) spec.Ref { | ||||
| 		defName, _ := o.config.GetDefinitionName(name) | ||||
| 		return spec.MustCreateRef("#/definitions/" + common.EscapeJsonPointer(defName)) | ||||
| 	}) | ||||
| 	if o.config.CommonResponses == nil { | ||||
| 		o.config.CommonResponses = map[int]spec.Response{} | ||||
| 	} | ||||
| 	err := o.buildPaths(webServices) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if o.config.SecurityDefinitions != nil { | ||||
| 		o.swagger.SecurityDefinitions = *o.config.SecurityDefinitions | ||||
| 		o.swagger.Security = o.config.DefaultSecurity | ||||
| 	} | ||||
| 	if o.config.PostProcessSpec != nil { | ||||
| 		o.swagger, err = o.config.PostProcessSpec(o.swagger) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func getCanonicalizeTypeName(t reflect.Type) string { | ||||
| 	if t.PkgPath() == "" { | ||||
| 		return t.Name() | ||||
| 	} | ||||
| 	path := t.PkgPath() | ||||
| 	if strings.Contains(path, "/vendor/") { | ||||
| 		path = path[strings.Index(path, "/vendor/")+len("/vendor/"):] | ||||
| 	} | ||||
| 	return path + "." + t.Name() | ||||
| } | ||||
|  | ||||
| func (o *openAPI) buildDefinitionRecursively(name string) error { | ||||
| 	uniqueName, extensions := o.config.GetDefinitionName(name) | ||||
| 	if _, ok := o.swagger.Definitions[uniqueName]; ok { | ||||
| 		return nil | ||||
| 	} | ||||
| 	if item, ok := o.definitions[name]; ok { | ||||
| 		schema := spec.Schema{ | ||||
| 			VendorExtensible:   item.Schema.VendorExtensible, | ||||
| 			SchemaProps:        item.Schema.SchemaProps, | ||||
| 			SwaggerSchemaProps: item.Schema.SwaggerSchemaProps, | ||||
| 		} | ||||
| 		if extensions != nil { | ||||
| 			if schema.Extensions == nil { | ||||
| 				schema.Extensions = spec.Extensions{} | ||||
| 			} | ||||
| 			for k, v := range extensions { | ||||
| 				schema.Extensions[k] = v | ||||
| 			} | ||||
| 		} | ||||
| 		o.swagger.Definitions[uniqueName] = schema | ||||
| 		for _, v := range item.Dependencies { | ||||
| 			if err := o.buildDefinitionRecursively(v); err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 		} | ||||
| 	} else { | ||||
| 		return fmt.Errorf("cannot find model definition for %v. If you added a new type, you may need to add +k8s:openapi-gen=true to the package or type and run code-gen again", name) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // buildDefinitionForType build a definition for a given type and return a referable name to it's definition. | ||||
| // This is the main function that keep track of definitions used in this spec and is depend on code generated | ||||
| // by k8s.io/kubernetes/cmd/libs/go2idl/openapi-gen. | ||||
| func (o *openAPI) buildDefinitionForType(sample interface{}) (string, error) { | ||||
| 	t := reflect.TypeOf(sample) | ||||
| 	if t.Kind() == reflect.Ptr { | ||||
| 		t = t.Elem() | ||||
| 	} | ||||
| 	name := getCanonicalizeTypeName(t) | ||||
| 	if err := o.buildDefinitionRecursively(name); err != nil { | ||||
| 		return "", err | ||||
| 	} | ||||
| 	defName, _ := o.config.GetDefinitionName(name) | ||||
| 	return "#/definitions/" + common.EscapeJsonPointer(defName), nil | ||||
| } | ||||
|  | ||||
| // buildPaths builds OpenAPI paths using go-restful's web services. | ||||
| func (o *openAPI) buildPaths(webServices []*restful.WebService) error { | ||||
| 	pathsToIgnore := util.NewTrie(o.config.IgnorePrefixes) | ||||
| 	duplicateOpId := make(map[string]string) | ||||
| 	for _, w := range webServices { | ||||
| 		rootPath := w.RootPath() | ||||
| 		if pathsToIgnore.HasPrefix(rootPath) { | ||||
| 			continue | ||||
| 		} | ||||
| 		commonParams, err := o.buildParameters(w.PathParameters()) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		for path, routes := range groupRoutesByPath(w.Routes()) { | ||||
| 			// go-swagger has special variable definition {$NAME:*} that can only be | ||||
| 			// used at the end of the path and it is not recognized by OpenAPI. | ||||
| 			if strings.HasSuffix(path, ":*}") { | ||||
| 				path = path[:len(path)-3] + "}" | ||||
| 			} | ||||
| 			if pathsToIgnore.HasPrefix(path) { | ||||
| 				continue | ||||
| 			} | ||||
| 			// Aggregating common parameters make API spec (and generated clients) simpler | ||||
| 			inPathCommonParamsMap, err := o.findCommonParameters(routes) | ||||
| 			if err != nil { | ||||
| 				return err | ||||
| 			} | ||||
| 			pathItem, exists := o.swagger.Paths.Paths[path] | ||||
| 			if exists { | ||||
| 				return fmt.Errorf("duplicate webservice route has been found for path: %v", path) | ||||
| 			} | ||||
| 			pathItem = spec.PathItem{ | ||||
| 				PathItemProps: spec.PathItemProps{ | ||||
| 					Parameters: make([]spec.Parameter, 0), | ||||
| 				}, | ||||
| 			} | ||||
| 			// add web services's parameters as well as any parameters appears in all ops, as common parameters | ||||
| 			pathItem.Parameters = append(pathItem.Parameters, commonParams...) | ||||
| 			for _, p := range inPathCommonParamsMap { | ||||
| 				pathItem.Parameters = append(pathItem.Parameters, p) | ||||
| 			} | ||||
| 			sortParameters(pathItem.Parameters) | ||||
| 			for _, route := range routes { | ||||
| 				op, err := o.buildOperations(route, inPathCommonParamsMap) | ||||
| 				sortParameters(op.Parameters) | ||||
| 				if err != nil { | ||||
| 					return err | ||||
| 				} | ||||
| 				dpath, exists := duplicateOpId[op.ID] | ||||
| 				if exists { | ||||
| 					return fmt.Errorf("duplicate Operation ID %v for path %v and %v", op.ID, dpath, path) | ||||
| 				} else { | ||||
| 					duplicateOpId[op.ID] = path | ||||
| 				} | ||||
| 				switch strings.ToUpper(route.Method) { | ||||
| 				case "GET": | ||||
| 					pathItem.Get = op | ||||
| 				case "POST": | ||||
| 					pathItem.Post = op | ||||
| 				case "HEAD": | ||||
| 					pathItem.Head = op | ||||
| 				case "PUT": | ||||
| 					pathItem.Put = op | ||||
| 				case "DELETE": | ||||
| 					pathItem.Delete = op | ||||
| 				case "OPTIONS": | ||||
| 					pathItem.Options = op | ||||
| 				case "PATCH": | ||||
| 					pathItem.Patch = op | ||||
| 				} | ||||
| 			} | ||||
| 			o.swagger.Paths.Paths[path] = pathItem | ||||
| 		} | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // buildOperations builds operations for each webservice path | ||||
| func (o *openAPI) buildOperations(route restful.Route, inPathCommonParamsMap map[interface{}]spec.Parameter) (ret *spec.Operation, err error) { | ||||
| 	ret = &spec.Operation{ | ||||
| 		OperationProps: spec.OperationProps{ | ||||
| 			Description: route.Doc, | ||||
| 			Consumes:    route.Consumes, | ||||
| 			Produces:    route.Produces, | ||||
| 			Schemes:     o.config.ProtocolList, | ||||
| 			Responses: &spec.Responses{ | ||||
| 				ResponsesProps: spec.ResponsesProps{ | ||||
| 					StatusCodeResponses: make(map[int]spec.Response), | ||||
| 				}, | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
| 	for k, v := range route.Metadata { | ||||
| 		if strings.HasPrefix(k, extensionPrefix) { | ||||
| 			if ret.Extensions == nil { | ||||
| 				ret.Extensions = spec.Extensions{} | ||||
| 			} | ||||
| 			ret.Extensions.Add(k, v) | ||||
| 		} | ||||
| 	} | ||||
| 	if ret.ID, ret.Tags, err = o.config.GetOperationIDAndTags(&route); err != nil { | ||||
| 		return ret, err | ||||
| 	} | ||||
|  | ||||
| 	// Build responses | ||||
| 	for _, resp := range route.ResponseErrors { | ||||
| 		ret.Responses.StatusCodeResponses[resp.Code], err = o.buildResponse(resp.Model, resp.Message) | ||||
| 		if err != nil { | ||||
| 			return ret, err | ||||
| 		} | ||||
| 	} | ||||
| 	// If there is no response but a write sample, assume that write sample is an http.StatusOK response. | ||||
| 	if len(ret.Responses.StatusCodeResponses) == 0 && route.WriteSample != nil { | ||||
| 		ret.Responses.StatusCodeResponses[http.StatusOK], err = o.buildResponse(route.WriteSample, "OK") | ||||
| 		if err != nil { | ||||
| 			return ret, err | ||||
| 		} | ||||
| 	} | ||||
| 	for code, resp := range o.config.CommonResponses { | ||||
| 		if _, exists := ret.Responses.StatusCodeResponses[code]; !exists { | ||||
| 			ret.Responses.StatusCodeResponses[code] = resp | ||||
| 		} | ||||
| 	} | ||||
| 	// If there is still no response, use default response provided. | ||||
| 	if len(ret.Responses.StatusCodeResponses) == 0 { | ||||
| 		ret.Responses.Default = o.config.DefaultResponse | ||||
| 	} | ||||
|  | ||||
| 	// Build non-common Parameters | ||||
| 	ret.Parameters = make([]spec.Parameter, 0) | ||||
| 	for _, param := range route.ParameterDocs { | ||||
| 		if _, isCommon := inPathCommonParamsMap[mapKeyFromParam(param)]; !isCommon { | ||||
| 			openAPIParam, err := o.buildParameter(param.Data(), route.ReadSample) | ||||
| 			if err != nil { | ||||
| 				return ret, err | ||||
| 			} | ||||
| 			ret.Parameters = append(ret.Parameters, openAPIParam) | ||||
| 		} | ||||
| 	} | ||||
| 	return ret, nil | ||||
| } | ||||
|  | ||||
| func (o *openAPI) buildResponse(model interface{}, description string) (spec.Response, error) { | ||||
| 	schema, err := o.toSchema(model) | ||||
| 	if err != nil { | ||||
| 		return spec.Response{}, err | ||||
| 	} | ||||
| 	return spec.Response{ | ||||
| 		ResponseProps: spec.ResponseProps{ | ||||
| 			Description: description, | ||||
| 			Schema:      schema, | ||||
| 		}, | ||||
| 	}, nil | ||||
| } | ||||
|  | ||||
| func (o *openAPI) findCommonParameters(routes []restful.Route) (map[interface{}]spec.Parameter, error) { | ||||
| 	commonParamsMap := make(map[interface{}]spec.Parameter, 0) | ||||
| 	paramOpsCountByName := make(map[interface{}]int, 0) | ||||
| 	paramNameKindToDataMap := make(map[interface{}]restful.ParameterData, 0) | ||||
| 	for _, route := range routes { | ||||
| 		routeParamDuplicateMap := make(map[interface{}]bool) | ||||
| 		s := "" | ||||
| 		for _, param := range route.ParameterDocs { | ||||
| 			m, _ := json.Marshal(param.Data()) | ||||
| 			s += string(m) + "\n" | ||||
| 			key := mapKeyFromParam(param) | ||||
| 			if routeParamDuplicateMap[key] { | ||||
| 				msg, _ := json.Marshal(route.ParameterDocs) | ||||
| 				return commonParamsMap, fmt.Errorf("duplicate parameter %v for route %v, %v", param.Data().Name, string(msg), s) | ||||
| 			} | ||||
| 			routeParamDuplicateMap[key] = true | ||||
| 			paramOpsCountByName[key]++ | ||||
| 			paramNameKindToDataMap[key] = param.Data() | ||||
| 		} | ||||
| 	} | ||||
| 	for key, count := range paramOpsCountByName { | ||||
| 		paramData := paramNameKindToDataMap[key] | ||||
| 		if count == len(routes) && paramData.Kind != restful.BodyParameterKind { | ||||
| 			openAPIParam, err := o.buildParameter(paramData, nil) | ||||
| 			if err != nil { | ||||
| 				return commonParamsMap, err | ||||
| 			} | ||||
| 			commonParamsMap[key] = openAPIParam | ||||
| 		} | ||||
| 	} | ||||
| 	return commonParamsMap, nil | ||||
| } | ||||
|  | ||||
| func (o *openAPI) toSchema(model interface{}) (_ *spec.Schema, err error) { | ||||
| 	if openAPIType, openAPIFormat := common.GetOpenAPITypeFormat(getCanonicalizeTypeName(reflect.TypeOf(model))); openAPIType != "" { | ||||
| 		return &spec.Schema{ | ||||
| 			SchemaProps: spec.SchemaProps{ | ||||
| 				Type:   []string{openAPIType}, | ||||
| 				Format: openAPIFormat, | ||||
| 			}, | ||||
| 		}, nil | ||||
| 	} else { | ||||
| 		ref, err := o.buildDefinitionForType(model) | ||||
| 		if err != nil { | ||||
| 			return nil, err | ||||
| 		} | ||||
| 		return &spec.Schema{ | ||||
| 			SchemaProps: spec.SchemaProps{ | ||||
| 				Ref: spec.MustCreateRef(ref), | ||||
| 			}, | ||||
| 		}, nil | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (o *openAPI) buildParameter(restParam restful.ParameterData, bodySample interface{}) (ret spec.Parameter, err error) { | ||||
| 	ret = spec.Parameter{ | ||||
| 		ParamProps: spec.ParamProps{ | ||||
| 			Name:        restParam.Name, | ||||
| 			Description: restParam.Description, | ||||
| 			Required:    restParam.Required, | ||||
| 		}, | ||||
| 	} | ||||
| 	switch restParam.Kind { | ||||
| 	case restful.BodyParameterKind: | ||||
| 		if bodySample != nil { | ||||
| 			ret.In = "body" | ||||
| 			ret.Schema, err = o.toSchema(bodySample) | ||||
| 			return ret, err | ||||
| 		} else { | ||||
| 			// There is not enough information in the body parameter to build the definition. | ||||
| 			// Body parameter has a data type that is a short name but we need full package name | ||||
| 			// of the type to create a definition. | ||||
| 			return ret, fmt.Errorf("restful body parameters are not supported: %v", restParam.DataType) | ||||
| 		} | ||||
| 	case restful.PathParameterKind: | ||||
| 		ret.In = "path" | ||||
| 		if !restParam.Required { | ||||
| 			return ret, fmt.Errorf("path parameters should be marked at required for parameter %v", restParam) | ||||
| 		} | ||||
| 	case restful.QueryParameterKind: | ||||
| 		ret.In = "query" | ||||
| 	case restful.HeaderParameterKind: | ||||
| 		ret.In = "header" | ||||
| 	case restful.FormParameterKind: | ||||
| 		ret.In = "formData" | ||||
| 	default: | ||||
| 		return ret, fmt.Errorf("unknown restful operation kind : %v", restParam.Kind) | ||||
| 	} | ||||
| 	openAPIType, openAPIFormat := common.GetOpenAPITypeFormat(restParam.DataType) | ||||
| 	if openAPIType == "" { | ||||
| 		return ret, fmt.Errorf("non-body Restful parameter type should be a simple type, but got : %v", restParam.DataType) | ||||
| 	} | ||||
| 	ret.Type = openAPIType | ||||
| 	ret.Format = openAPIFormat | ||||
| 	ret.UniqueItems = !restParam.AllowMultiple | ||||
| 	return ret, nil | ||||
| } | ||||
|  | ||||
| func (o *openAPI) buildParameters(restParam []*restful.Parameter) (ret []spec.Parameter, err error) { | ||||
| 	ret = make([]spec.Parameter, len(restParam)) | ||||
| 	for i, v := range restParam { | ||||
| 		ret[i], err = o.buildParameter(v.Data(), nil) | ||||
| 		if err != nil { | ||||
| 			return ret, err | ||||
| 		} | ||||
| 	} | ||||
| 	return ret, nil | ||||
| } | ||||
							
								
								
									
										61
									
								
								vendor/k8s.io/kube-openapi/pkg/builder/util.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										61
									
								
								vendor/k8s.io/kube-openapi/pkg/builder/util.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,61 @@ | ||||
| /* | ||||
| Copyright 2016 The Kubernetes Authors. | ||||
|  | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
|  | ||||
| package builder | ||||
|  | ||||
| import ( | ||||
| 	"sort" | ||||
|  | ||||
| 	"github.com/emicklei/go-restful" | ||||
| 	"github.com/go-openapi/spec" | ||||
| ) | ||||
|  | ||||
| type parameters []spec.Parameter | ||||
|  | ||||
| func (s parameters) Len() int      { return len(s) } | ||||
| func (s parameters) Swap(i, j int) { s[i], s[j] = s[j], s[i] } | ||||
|  | ||||
| // byNameIn used in sorting parameters by Name and In fields. | ||||
| type byNameIn struct { | ||||
| 	parameters | ||||
| } | ||||
|  | ||||
| func (s byNameIn) Less(i, j int) bool { | ||||
| 	return s.parameters[i].Name < s.parameters[j].Name || (s.parameters[i].Name == s.parameters[j].Name && s.parameters[i].In < s.parameters[j].In) | ||||
| } | ||||
|  | ||||
| // SortParameters sorts parameters by Name and In fields. | ||||
| func sortParameters(p []spec.Parameter) { | ||||
| 	sort.Sort(byNameIn{p}) | ||||
| } | ||||
|  | ||||
| func groupRoutesByPath(routes []restful.Route) map[string][]restful.Route { | ||||
| 	pathToRoutes := make(map[string][]restful.Route) | ||||
| 	for _, r := range routes { | ||||
| 		pathToRoutes[r.Path] = append(pathToRoutes[r.Path], r) | ||||
| 	} | ||||
| 	return pathToRoutes | ||||
| } | ||||
|  | ||||
| func mapKeyFromParam(param *restful.Parameter) interface{} { | ||||
| 	return struct { | ||||
| 		Name string | ||||
| 		Kind int | ||||
| 	}{ | ||||
| 		Name: param.Data().Name, | ||||
| 		Kind: param.Data().Kind, | ||||
| 	} | ||||
| } | ||||
							
								
								
									
										167
									
								
								vendor/k8s.io/kube-openapi/pkg/common/common.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										167
									
								
								vendor/k8s.io/kube-openapi/pkg/common/common.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,167 @@ | ||||
| /* | ||||
| Copyright 2016 The Kubernetes Authors. | ||||
|  | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
|  | ||||
| package common | ||||
|  | ||||
| import ( | ||||
| 	"net/http" | ||||
| 	"strings" | ||||
|  | ||||
| 	"github.com/emicklei/go-restful" | ||||
| 	"github.com/go-openapi/spec" | ||||
| ) | ||||
|  | ||||
| // OpenAPIDefinition describes single type. Normally these definitions are auto-generated using gen-openapi. | ||||
| type OpenAPIDefinition struct { | ||||
| 	Schema       spec.Schema | ||||
| 	Dependencies []string | ||||
| } | ||||
|  | ||||
| type ReferenceCallback func(path string) spec.Ref | ||||
|  | ||||
| // OpenAPIDefinitions is collection of all definitions. | ||||
| type GetOpenAPIDefinitions func(ReferenceCallback) map[string]OpenAPIDefinition | ||||
|  | ||||
| // OpenAPIDefinitionGetter gets openAPI definitions for a given type. If a type implements this interface, | ||||
| // the definition returned by it will be used, otherwise the auto-generated definitions will be used. See | ||||
| // GetOpenAPITypeFormat for more information about trade-offs of using this interface or GetOpenAPITypeFormat method when | ||||
| // possible. | ||||
| type OpenAPIDefinitionGetter interface { | ||||
| 	OpenAPIDefinition() *OpenAPIDefinition | ||||
| } | ||||
|  | ||||
| type PathHandler interface { | ||||
| 	Handle(path string, handler http.Handler) | ||||
| } | ||||
|  | ||||
| // Config is set of configuration for openAPI spec generation. | ||||
| type Config struct { | ||||
| 	// List of supported protocols such as https, http, etc. | ||||
| 	ProtocolList []string | ||||
|  | ||||
| 	// Info is general information about the API. | ||||
| 	Info *spec.Info | ||||
|  | ||||
| 	// DefaultResponse will be used if an operation does not have any responses listed. It | ||||
| 	// will show up as ... "responses" : {"default" : $DefaultResponse} in the spec. | ||||
| 	DefaultResponse *spec.Response | ||||
|  | ||||
| 	// CommonResponses will be added as a response to all operation specs. This is a good place to add common | ||||
| 	// responses such as authorization failed. | ||||
| 	CommonResponses map[int]spec.Response | ||||
|  | ||||
| 	// List of webservice's path prefixes to ignore | ||||
| 	IgnorePrefixes []string | ||||
|  | ||||
| 	// OpenAPIDefinitions should provide definition for all models used by routes. Failure to provide this map | ||||
| 	// or any of the models will result in spec generation failure. | ||||
| 	GetDefinitions GetOpenAPIDefinitions | ||||
|  | ||||
| 	// GetOperationIDAndTags returns operation id and tags for a restful route. It is an optional function to customize operation IDs. | ||||
| 	GetOperationIDAndTags func(r *restful.Route) (string, []string, error) | ||||
|  | ||||
| 	// GetDefinitionName returns a friendly name for a definition base on the serving path. parameter `name` is the full name of the definition. | ||||
| 	// It is an optional function to customize model names. | ||||
| 	GetDefinitionName func(name string) (string, spec.Extensions) | ||||
|  | ||||
| 	// PostProcessSpec runs after the spec is ready to serve. It allows a final modification to the spec before serving. | ||||
| 	PostProcessSpec func(*spec.Swagger) (*spec.Swagger, error) | ||||
|  | ||||
| 	// SecurityDefinitions is list of all security definitions for OpenAPI service. If this is not nil, the user of config | ||||
| 	// is responsible to provide DefaultSecurity and (maybe) add unauthorized response to CommonResponses. | ||||
| 	SecurityDefinitions *spec.SecurityDefinitions | ||||
|  | ||||
| 	// DefaultSecurity for all operations. This will pass as spec.SwaggerProps.Security to OpenAPI. | ||||
| 	// For most cases, this will be list of acceptable definitions in SecurityDefinitions. | ||||
| 	DefaultSecurity []map[string][]string | ||||
| } | ||||
|  | ||||
| // This function is a reference for converting go (or any custom type) to a simple open API type,format pair. There are | ||||
| // two ways to customize spec for a type. If you add it here, a type will be converted to a simple type and the type | ||||
| // comment (the comment that is added before type definition) will be lost. The spec will still have the property | ||||
| // comment. The second way is to implement OpenAPIDefinitionGetter interface. That function can customize the spec (so | ||||
| // the spec does not need to be simple type,format) or can even return a simple type,format (e.g. IntOrString). For simple | ||||
| // type formats, the benefit of adding OpenAPIDefinitionGetter interface is to keep both type and property documentation. | ||||
| // Example: | ||||
| // type Sample struct { | ||||
| //      ... | ||||
| //      // port of the server | ||||
| //      port IntOrString | ||||
| //      ... | ||||
| // } | ||||
| // // IntOrString documentation... | ||||
| // type IntOrString { ... } | ||||
| // | ||||
| // Adding IntOrString to this function: | ||||
| // "port" : { | ||||
| //           format:      "string", | ||||
| //           type:        "int-or-string", | ||||
| //           Description: "port of the server" | ||||
| // } | ||||
| // | ||||
| // Implement OpenAPIDefinitionGetter for IntOrString: | ||||
| // | ||||
| // "port" : { | ||||
| //           $Ref:    "#/definitions/IntOrString" | ||||
| //           Description: "port of the server" | ||||
| // } | ||||
| // ... | ||||
| // definitions: | ||||
| // { | ||||
| //           "IntOrString": { | ||||
| //                     format:      "string", | ||||
| //                     type:        "int-or-string", | ||||
| //                     Description: "IntOrString documentation..."    // new | ||||
| //           } | ||||
| // } | ||||
| // | ||||
| func GetOpenAPITypeFormat(typeName string) (string, string) { | ||||
| 	schemaTypeFormatMap := map[string][]string{ | ||||
| 		"uint":        {"integer", "int32"}, | ||||
| 		"uint8":       {"integer", "byte"}, | ||||
| 		"uint16":      {"integer", "int32"}, | ||||
| 		"uint32":      {"integer", "int64"}, | ||||
| 		"uint64":      {"integer", "int64"}, | ||||
| 		"int":         {"integer", "int32"}, | ||||
| 		"int8":        {"integer", "byte"}, | ||||
| 		"int16":       {"integer", "int32"}, | ||||
| 		"int32":       {"integer", "int32"}, | ||||
| 		"int64":       {"integer", "int64"}, | ||||
| 		"byte":        {"integer", "byte"}, | ||||
| 		"float64":     {"number", "double"}, | ||||
| 		"float32":     {"number", "float"}, | ||||
| 		"bool":        {"boolean", ""}, | ||||
| 		"time.Time":   {"string", "date-time"}, | ||||
| 		"string":      {"string", ""}, | ||||
| 		"integer":     {"integer", ""}, | ||||
| 		"number":      {"number", ""}, | ||||
| 		"boolean":     {"boolean", ""}, | ||||
| 		"[]byte":      {"string", "byte"}, // base64 encoded characters | ||||
| 		"interface{}": {"object", ""}, | ||||
| 	} | ||||
| 	mapped, ok := schemaTypeFormatMap[typeName] | ||||
| 	if !ok { | ||||
| 		return "", "" | ||||
| 	} | ||||
| 	return mapped[0], mapped[1] | ||||
| } | ||||
|  | ||||
| func EscapeJsonPointer(p string) string { | ||||
| 	// Escaping reference name using rfc6901 | ||||
| 	p = strings.Replace(p, "~", "~0", -1) | ||||
| 	p = strings.Replace(p, "/", "~1", -1) | ||||
| 	return p | ||||
| } | ||||
							
								
								
									
										19
									
								
								vendor/k8s.io/kube-openapi/pkg/common/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								vendor/k8s.io/kube-openapi/pkg/common/doc.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,19 @@ | ||||
| /* | ||||
| Copyright 2016 The Kubernetes Authors. | ||||
|  | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
|  | ||||
| // package common holds shared code and types between open API code | ||||
| // generator and spec generator. | ||||
| package common | ||||
							
								
								
									
										15
									
								
								vendor/k8s.io/kube-openapi/pkg/generators/README
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								vendor/k8s.io/kube-openapi/pkg/generators/README
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| # Generate OpenAPI definitions | ||||
|  | ||||
| - To generate definition for a specific type or package add "+k8s:openapi-gen=true" tag to the type/package comment lines. | ||||
| - To exclude a type or a member from a tagged package/type, add "+k8s:openapi-gen=false" tag to the comment lines. | ||||
|  | ||||
| # OpenAPI Extensions | ||||
| OpenAPI spec can have extensions on types. To define one or more extensions on a type or its member | ||||
| add `+k8s:openapi-gen=x-kubernetes-$NAME:`$VALUE`` to the comment lines before type/member. A type/member can | ||||
| have multiple extensions. The rest of the line in the comment will be used as $VALUE so there is no need to | ||||
| escape or quote the value string. Extensions can be used to pass more information to client generators or | ||||
| documentation generators. For example a type might have a friendly name to be displayed in documentation or | ||||
| being used in a client's fluent interface. | ||||
|  | ||||
|  | ||||
| TODO(mehdy): Make k8s:openapi-gen a parameter to the generator now that OpenAPI has its own repo. | ||||
							
								
								
									
										612
									
								
								vendor/k8s.io/kube-openapi/pkg/generators/openapi.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										612
									
								
								vendor/k8s.io/kube-openapi/pkg/generators/openapi.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,612 @@ | ||||
| /* | ||||
| Copyright 2016 The Kubernetes Authors. | ||||
|  | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
|  | ||||
| package generators | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"fmt" | ||||
| 	"io" | ||||
| 	"path/filepath" | ||||
| 	"reflect" | ||||
| 	"sort" | ||||
| 	"strings" | ||||
|  | ||||
| 	"k8s.io/gengo/args" | ||||
| 	"k8s.io/gengo/generator" | ||||
| 	"k8s.io/gengo/namer" | ||||
| 	"k8s.io/gengo/types" | ||||
| 	openapi "k8s.io/kube-openapi/pkg/common" | ||||
|  | ||||
| 	"github.com/golang/glog" | ||||
| ) | ||||
|  | ||||
| // This is the comment tag that carries parameters for open API generation. | ||||
| const tagName = "k8s:openapi-gen" | ||||
| const tagOptional = "optional" | ||||
|  | ||||
| // Known values for the tag. | ||||
| const ( | ||||
| 	tagValueTrue               = "true" | ||||
| 	tagValueFalse              = "false" | ||||
| 	tagExtensionPrefix         = "x-kubernetes-" | ||||
| 	tagPatchStrategy           = "patchStrategy" | ||||
| 	tagPatchMergeKey           = "patchMergeKey" | ||||
| 	patchStrategyExtensionName = "patch-strategy" | ||||
| 	patchMergeKeyExtensionName = "patch-merge-key" | ||||
| ) | ||||
|  | ||||
| func getOpenAPITagValue(comments []string) []string { | ||||
| 	return types.ExtractCommentTags("+", comments)[tagName] | ||||
| } | ||||
|  | ||||
| func getSingleTagsValue(comments []string, tag string) (string, error) { | ||||
| 	tags, ok := types.ExtractCommentTags("+", comments)[tag] | ||||
| 	if !ok || len(tags) == 0 { | ||||
| 		return "", nil | ||||
| 	} | ||||
| 	if len(tags) > 1 { | ||||
| 		return "", fmt.Errorf("multiple values are not allowed for tag %s", tag) | ||||
| 	} | ||||
| 	return tags[0], nil | ||||
| } | ||||
|  | ||||
| func hasOpenAPITagValue(comments []string, value string) bool { | ||||
| 	tagValues := getOpenAPITagValue(comments) | ||||
| 	for _, val := range tagValues { | ||||
| 		if val == value { | ||||
| 			return true | ||||
| 		} | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| // hasOptionalTag returns true if the member has +optional in its comments or | ||||
| // omitempty in its json tags. | ||||
| func hasOptionalTag(m *types.Member) bool { | ||||
| 	hasOptionalCommentTag := types.ExtractCommentTags( | ||||
| 		"+", m.CommentLines)[tagOptional] != nil | ||||
| 	hasOptionalJsonTag := strings.Contains( | ||||
| 		reflect.StructTag(m.Tags).Get("json"), "omitempty") | ||||
| 	return hasOptionalCommentTag || hasOptionalJsonTag | ||||
| } | ||||
|  | ||||
| type identityNamer struct{} | ||||
|  | ||||
| func (_ identityNamer) Name(t *types.Type) string { | ||||
| 	return t.Name.String() | ||||
| } | ||||
|  | ||||
| var _ namer.Namer = identityNamer{} | ||||
|  | ||||
| // NameSystems returns the name system used by the generators in this package. | ||||
| func NameSystems() namer.NameSystems { | ||||
| 	return namer.NameSystems{ | ||||
| 		"raw":           namer.NewRawNamer("", nil), | ||||
| 		"sorting_namer": identityNamer{}, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| // DefaultNameSystem returns the default name system for ordering the types to be | ||||
| // processed by the generators in this package. | ||||
| func DefaultNameSystem() string { | ||||
| 	return "sorting_namer" | ||||
| } | ||||
|  | ||||
| func Packages(context *generator.Context, arguments *args.GeneratorArgs) generator.Packages { | ||||
| 	boilerplate, err := arguments.LoadGoBoilerplate() | ||||
| 	if err != nil { | ||||
| 		glog.Fatalf("Failed loading boilerplate: %v", err) | ||||
| 	} | ||||
| 	header := append([]byte(fmt.Sprintf("// +build !%s\n\n", arguments.GeneratedBuildTag)), boilerplate...) | ||||
| 	header = append(header, []byte( | ||||
| 		` | ||||
| // This file was autogenerated by openapi-gen. Do not edit it manually! | ||||
|  | ||||
| `)...) | ||||
|  | ||||
| 	if err := context.AddDir(arguments.OutputPackagePath); err != nil { | ||||
| 		glog.Fatalf("Failed to load output package: %v", err) | ||||
| 	} | ||||
| 	pkg := context.Universe[arguments.OutputPackagePath] | ||||
| 	if pkg == nil { | ||||
| 		glog.Fatalf("Got nil output package: %v", err) | ||||
| 	} | ||||
| 	return generator.Packages{ | ||||
| 		&generator.DefaultPackage{ | ||||
| 			PackageName: strings.Split(filepath.Base(pkg.Path), ".")[0], | ||||
| 			PackagePath: pkg.Path, | ||||
| 			HeaderText:  header, | ||||
| 			GeneratorFunc: func(c *generator.Context) (generators []generator.Generator) { | ||||
| 				return []generator.Generator{NewOpenAPIGen(arguments.OutputFileBaseName, pkg, context)} | ||||
| 			}, | ||||
| 			FilterFunc: func(c *generator.Context, t *types.Type) bool { | ||||
| 				// There is a conflict between this codegen and codecgen, we should avoid types generated for codecgen | ||||
| 				if strings.HasPrefix(t.Name.Name, "codecSelfer") { | ||||
| 					return false | ||||
| 				} | ||||
| 				pkg := context.Universe.Package(t.Name.Package) | ||||
| 				if hasOpenAPITagValue(pkg.Comments, tagValueTrue) { | ||||
| 					return !hasOpenAPITagValue(t.CommentLines, tagValueFalse) | ||||
| 				} | ||||
| 				if hasOpenAPITagValue(t.CommentLines, tagValueTrue) { | ||||
| 					return true | ||||
| 				} | ||||
| 				return false | ||||
| 			}, | ||||
| 		}, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| const ( | ||||
| 	specPackagePath          = "github.com/go-openapi/spec" | ||||
| 	openAPICommonPackagePath = "k8s.io/kube-openapi/pkg/common" | ||||
| ) | ||||
|  | ||||
| // openApiGen produces a file with auto-generated OpenAPI functions. | ||||
| type openAPIGen struct { | ||||
| 	generator.DefaultGen | ||||
| 	// TargetPackage is the package that will get GetOpenAPIDefinitions function returns all open API definitions. | ||||
| 	targetPackage *types.Package | ||||
| 	imports       namer.ImportTracker | ||||
| 	context       *generator.Context | ||||
| } | ||||
|  | ||||
| func NewOpenAPIGen(sanitizedName string, targetPackage *types.Package, context *generator.Context) generator.Generator { | ||||
| 	return &openAPIGen{ | ||||
| 		DefaultGen: generator.DefaultGen{ | ||||
| 			OptionalName: sanitizedName, | ||||
| 		}, | ||||
| 		imports:       generator.NewImportTracker(), | ||||
| 		targetPackage: targetPackage, | ||||
| 		context:       context, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (g *openAPIGen) Namers(c *generator.Context) namer.NameSystems { | ||||
| 	// Have the raw namer for this file track what it imports. | ||||
| 	return namer.NameSystems{ | ||||
| 		"raw": namer.NewRawNamer(g.targetPackage.Path, g.imports), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (g *openAPIGen) Filter(c *generator.Context, t *types.Type) bool { | ||||
| 	// There is a conflict between this codegen and codecgen, we should avoid types generated for codecgen | ||||
| 	if strings.HasPrefix(t.Name.Name, "codecSelfer") { | ||||
| 		return false | ||||
| 	} | ||||
| 	return true | ||||
| } | ||||
|  | ||||
| func (g *openAPIGen) isOtherPackage(pkg string) bool { | ||||
| 	if pkg == g.targetPackage.Path { | ||||
| 		return false | ||||
| 	} | ||||
| 	if strings.HasSuffix(pkg, "\""+g.targetPackage.Path+"\"") { | ||||
| 		return false | ||||
| 	} | ||||
| 	return true | ||||
| } | ||||
|  | ||||
| func (g *openAPIGen) Imports(c *generator.Context) []string { | ||||
| 	importLines := []string{} | ||||
| 	for _, singleImport := range g.imports.ImportLines() { | ||||
| 		importLines = append(importLines, singleImport) | ||||
| 	} | ||||
| 	return importLines | ||||
| } | ||||
|  | ||||
| func argsFromType(t *types.Type) generator.Args { | ||||
| 	return generator.Args{ | ||||
| 		"type":              t, | ||||
| 		"ReferenceCallback": types.Ref(openAPICommonPackagePath, "ReferenceCallback"), | ||||
| 		"OpenAPIDefinition": types.Ref(openAPICommonPackagePath, "OpenAPIDefinition"), | ||||
| 		"SpecSchemaType":    types.Ref(specPackagePath, "Schema"), | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (g *openAPIGen) Init(c *generator.Context, w io.Writer) error { | ||||
| 	sw := generator.NewSnippetWriter(w, c, "$", "$") | ||||
| 	sw.Do("func GetOpenAPIDefinitions(ref $.ReferenceCallback|raw$) map[string]$.OpenAPIDefinition|raw$ {\n", argsFromType(nil)) | ||||
| 	sw.Do("return map[string]$.OpenAPIDefinition|raw${\n", argsFromType(nil)) | ||||
| 	return sw.Error() | ||||
| } | ||||
|  | ||||
| func (g *openAPIGen) Finalize(c *generator.Context, w io.Writer) error { | ||||
| 	sw := generator.NewSnippetWriter(w, c, "$", "$") | ||||
| 	sw.Do("}\n", nil) | ||||
| 	sw.Do("}\n", nil) | ||||
| 	return sw.Error() | ||||
| } | ||||
|  | ||||
| func (g *openAPIGen) GenerateType(c *generator.Context, t *types.Type, w io.Writer) error { | ||||
| 	glog.V(5).Infof("generating for type %v", t) | ||||
| 	sw := generator.NewSnippetWriter(w, c, "$", "$") | ||||
| 	err := newOpenAPITypeWriter(sw).generate(t) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	return sw.Error() | ||||
| } | ||||
|  | ||||
| func getJsonTags(m *types.Member) []string { | ||||
| 	jsonTag := reflect.StructTag(m.Tags).Get("json") | ||||
| 	if jsonTag == "" { | ||||
| 		return []string{} | ||||
| 	} | ||||
| 	return strings.Split(jsonTag, ",") | ||||
| } | ||||
|  | ||||
| func getPatchTags(m *types.Member) (string, string) { | ||||
| 	return reflect.StructTag(m.Tags).Get(tagPatchMergeKey), reflect.StructTag(m.Tags).Get(tagPatchStrategy) | ||||
| } | ||||
|  | ||||
| func getReferableName(m *types.Member) string { | ||||
| 	jsonTags := getJsonTags(m) | ||||
| 	if len(jsonTags) > 0 { | ||||
| 		if jsonTags[0] == "-" { | ||||
| 			return "" | ||||
| 		} else { | ||||
| 			return jsonTags[0] | ||||
| 		} | ||||
| 	} else { | ||||
| 		return m.Name | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func shouldInlineMembers(m *types.Member) bool { | ||||
| 	jsonTags := getJsonTags(m) | ||||
| 	return len(jsonTags) > 1 && jsonTags[1] == "inline" | ||||
| } | ||||
|  | ||||
| type openAPITypeWriter struct { | ||||
| 	*generator.SnippetWriter | ||||
| 	refTypes               map[string]*types.Type | ||||
| 	GetDefinitionInterface *types.Type | ||||
| } | ||||
|  | ||||
| func newOpenAPITypeWriter(sw *generator.SnippetWriter) openAPITypeWriter { | ||||
| 	return openAPITypeWriter{ | ||||
| 		SnippetWriter: sw, | ||||
| 		refTypes:      map[string]*types.Type{}, | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func hasOpenAPIDefinitionMethod(t *types.Type) bool { | ||||
| 	for mn, mt := range t.Methods { | ||||
| 		if mn != "OpenAPIDefinition" { | ||||
| 			continue | ||||
| 		} | ||||
| 		if len(mt.Signature.Parameters) != 0 || len(mt.Signature.Results) != 1 { | ||||
| 			return false | ||||
| 		} | ||||
| 		r := mt.Signature.Results[0] | ||||
| 		if r.Name.Name != "OpenAPIDefinition" || r.Name.Package != openAPICommonPackagePath { | ||||
| 			return false | ||||
| 		} | ||||
| 		return true | ||||
| 	} | ||||
| 	return false | ||||
| } | ||||
|  | ||||
| // typeShortName returns short package name (e.g. the name x appears in package x definition) dot type name. | ||||
| func typeShortName(t *types.Type) string { | ||||
| 	return filepath.Base(t.Name.Package) + "." + t.Name.Name | ||||
| } | ||||
|  | ||||
| func (g openAPITypeWriter) generateMembers(t *types.Type, required []string) ([]string, error) { | ||||
| 	var err error | ||||
| 	for _, m := range t.Members { | ||||
| 		if hasOpenAPITagValue(m.CommentLines, tagValueFalse) { | ||||
| 			continue | ||||
| 		} | ||||
| 		if shouldInlineMembers(&m) { | ||||
| 			required, err = g.generateMembers(m.Type, required) | ||||
| 			if err != nil { | ||||
| 				return required, err | ||||
| 			} | ||||
| 			continue | ||||
| 		} | ||||
| 		name := getReferableName(&m) | ||||
| 		if name == "" { | ||||
| 			continue | ||||
| 		} | ||||
| 		if !hasOptionalTag(&m) { | ||||
| 			required = append(required, name) | ||||
| 		} | ||||
| 		if err = g.generateProperty(&m, t); err != nil { | ||||
| 			return required, err | ||||
| 		} | ||||
| 	} | ||||
| 	return required, nil | ||||
| } | ||||
|  | ||||
| func (g openAPITypeWriter) generate(t *types.Type) error { | ||||
| 	// Only generate for struct type and ignore the rest | ||||
| 	switch t.Kind { | ||||
| 	case types.Struct: | ||||
| 		args := argsFromType(t) | ||||
| 		g.Do("\"$.$\": ", t.Name) | ||||
| 		if hasOpenAPIDefinitionMethod(t) { | ||||
| 			g.Do("$.type|raw${}.OpenAPIDefinition(),\n", args) | ||||
| 			return nil | ||||
| 		} | ||||
| 		g.Do("{\nSchema: spec.Schema{\nSchemaProps: spec.SchemaProps{\n", nil) | ||||
| 		g.generateDescription(t.CommentLines) | ||||
| 		g.Do("Properties: map[string]$.SpecSchemaType|raw${\n", args) | ||||
| 		required, err := g.generateMembers(t, []string{}) | ||||
| 		if err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		g.Do("},\n", nil) | ||||
| 		if len(required) > 0 { | ||||
| 			g.Do("Required: []string{\"$.$\"},\n", strings.Join(required, "\",\"")) | ||||
| 		} | ||||
| 		g.Do("},\n", nil) | ||||
| 		if err := g.generateExtensions(t.CommentLines); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 		g.Do("},\n", nil) | ||||
| 		g.Do("Dependencies: []string{\n", args) | ||||
| 		// Map order is undefined, sort them or we may get a different file generated each time. | ||||
| 		keys := []string{} | ||||
| 		for k := range g.refTypes { | ||||
| 			keys = append(keys, k) | ||||
| 		} | ||||
| 		sort.Strings(keys) | ||||
| 		for _, k := range keys { | ||||
| 			v := g.refTypes[k] | ||||
| 			if t, _ := openapi.GetOpenAPITypeFormat(v.String()); t != "" { | ||||
| 				// This is a known type, we do not need a reference to it | ||||
| 				// Will eliminate special case of time.Time | ||||
| 				continue | ||||
| 			} | ||||
| 			g.Do("\"$.$\",", k) | ||||
| 		} | ||||
| 		g.Do("},\n},\n", nil) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (g openAPITypeWriter) generateExtensions(CommentLines []string) error { | ||||
| 	tagValues := getOpenAPITagValue(CommentLines) | ||||
| 	type NameValue struct { | ||||
| 		Name, Value string | ||||
| 	} | ||||
| 	extensions := []NameValue{} | ||||
| 	for _, val := range tagValues { | ||||
| 		if strings.HasPrefix(val, tagExtensionPrefix) { | ||||
| 			parts := strings.SplitN(val, ":", 2) | ||||
| 			if len(parts) != 2 { | ||||
| 				return fmt.Errorf("invalid extension value: %v", val) | ||||
| 			} | ||||
| 			extensions = append(extensions, NameValue{parts[0], parts[1]}) | ||||
| 		} | ||||
| 	} | ||||
| 	patchMergeKeyTag, err := getSingleTagsValue(CommentLines, tagPatchMergeKey) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if len(patchMergeKeyTag) > 0 { | ||||
| 		extensions = append(extensions, NameValue{tagExtensionPrefix + patchMergeKeyExtensionName, patchMergeKeyTag}) | ||||
| 	} | ||||
| 	patchStrategyTag, err := getSingleTagsValue(CommentLines, tagPatchStrategy) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if len(patchStrategyTag) > 0 { | ||||
| 		extensions = append(extensions, NameValue{tagExtensionPrefix + patchStrategyExtensionName, patchStrategyTag}) | ||||
| 	} | ||||
| 	if len(extensions) == 0 { | ||||
| 		return nil | ||||
| 	} | ||||
| 	g.Do("VendorExtensible: spec.VendorExtensible{\nExtensions: spec.Extensions{\n", nil) | ||||
| 	for _, extension := range extensions { | ||||
| 		g.Do("\"$.$\": ", extension.Name) | ||||
| 		g.Do("\"$.$\",\n", extension.Value) | ||||
| 	} | ||||
| 	g.Do("},\n},\n", nil) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| // TODO(#44005): Move this validation outside of this generator (probably to policy verifier) | ||||
| func (g openAPITypeWriter) validatePatchTags(m *types.Member, parent *types.Type) error { | ||||
| 	patchMergeKeyStructTag, patchStrategyStructTag := getPatchTags(m) | ||||
| 	patchMergeKeyCommentTag, err := getSingleTagsValue(m.CommentLines, tagPatchMergeKey) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	patchStrategyCommentTag, err := getSingleTagsValue(m.CommentLines, tagPatchStrategy) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	if patchMergeKeyStructTag != patchMergeKeyCommentTag { | ||||
| 		return fmt.Errorf("patchMergeKey in comment and struct tags should match for member (%s) of (%s)", | ||||
| 			m.Name, parent.Name.String()) | ||||
| 	} | ||||
| 	if patchStrategyStructTag != patchStrategyCommentTag { | ||||
| 		return fmt.Errorf("patchStrategy in comment and struct tags should match for member (%s) of (%s)", | ||||
| 			m.Name, parent.Name.String()) | ||||
| 	} | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (g openAPITypeWriter) generateDescription(CommentLines []string) { | ||||
| 	var buffer bytes.Buffer | ||||
| 	delPrevChar := func() { | ||||
| 		if buffer.Len() > 0 { | ||||
| 			buffer.Truncate(buffer.Len() - 1) // Delete the last " " or "\n" | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	for _, line := range CommentLines { | ||||
| 		// Ignore all lines after --- | ||||
| 		if line == "---" { | ||||
| 			break | ||||
| 		} | ||||
| 		line = strings.TrimRight(line, " ") | ||||
| 		leading := strings.TrimLeft(line, " ") | ||||
| 		switch { | ||||
| 		case len(line) == 0: // Keep paragraphs | ||||
| 			delPrevChar() | ||||
| 			buffer.WriteString("\n\n") | ||||
| 		case strings.HasPrefix(leading, "TODO"): // Ignore one line TODOs | ||||
| 		case strings.HasPrefix(leading, "+"): // Ignore instructions to go2idl | ||||
| 		default: | ||||
| 			if strings.HasPrefix(line, " ") || strings.HasPrefix(line, "\t") { | ||||
| 				delPrevChar() | ||||
| 				line = "\n" + line + "\n" // Replace it with newline. This is useful when we have a line with: "Example:\n\tJSON-someting..." | ||||
| 			} else { | ||||
| 				line += " " | ||||
| 			} | ||||
| 			buffer.WriteString(line) | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	postDoc := strings.TrimRight(buffer.String(), "\n") | ||||
| 	postDoc = strings.Replace(postDoc, "\\\"", "\"", -1) // replace user's \" to " | ||||
| 	postDoc = strings.Replace(postDoc, "\"", "\\\"", -1) // Escape " | ||||
| 	postDoc = strings.Replace(postDoc, "\n", "\\n", -1) | ||||
| 	postDoc = strings.Replace(postDoc, "\t", "\\t", -1) | ||||
| 	postDoc = strings.Trim(postDoc, " ") | ||||
| 	if postDoc != "" { | ||||
| 		g.Do("Description: \"$.$\",\n", postDoc) | ||||
| 	} | ||||
| } | ||||
|  | ||||
| func (g openAPITypeWriter) generateProperty(m *types.Member, parent *types.Type) error { | ||||
| 	name := getReferableName(m) | ||||
| 	if name == "" { | ||||
| 		return nil | ||||
| 	} | ||||
| 	if err := g.validatePatchTags(m, parent); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	g.Do("\"$.$\": {\n", name) | ||||
| 	if err := g.generateExtensions(m.CommentLines); err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	g.Do("SchemaProps: spec.SchemaProps{\n", nil) | ||||
| 	g.generateDescription(m.CommentLines) | ||||
| 	jsonTags := getJsonTags(m) | ||||
| 	if len(jsonTags) > 1 && jsonTags[1] == "string" { | ||||
| 		g.generateSimpleProperty("string", "") | ||||
| 		g.Do("},\n},\n", nil) | ||||
| 		return nil | ||||
| 	} | ||||
| 	t := resolveAliasAndPtrType(m.Type) | ||||
| 	// If we can get a openAPI type and format for this type, we consider it to be simple property | ||||
| 	typeString, format := openapi.GetOpenAPITypeFormat(t.String()) | ||||
| 	if typeString != "" { | ||||
| 		g.generateSimpleProperty(typeString, format) | ||||
| 		g.Do("},\n},\n", nil) | ||||
| 		return nil | ||||
| 	} | ||||
| 	switch t.Kind { | ||||
| 	case types.Builtin: | ||||
| 		return fmt.Errorf("please add type %v to getOpenAPITypeFormat function", t) | ||||
| 	case types.Map: | ||||
| 		if err := g.generateMapProperty(t); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	case types.Slice, types.Array: | ||||
| 		if err := g.generateSliceProperty(t); err != nil { | ||||
| 			return err | ||||
| 		} | ||||
| 	case types.Struct, types.Interface: | ||||
| 		g.generateReferenceProperty(t) | ||||
| 	default: | ||||
| 		return fmt.Errorf("cannot generate spec for type %v", t) | ||||
| 	} | ||||
| 	g.Do("},\n},\n", nil) | ||||
| 	return g.Error() | ||||
| } | ||||
|  | ||||
| func (g openAPITypeWriter) generateSimpleProperty(typeString, format string) { | ||||
| 	g.Do("Type: []string{\"$.$\"},\n", typeString) | ||||
| 	g.Do("Format: \"$.$\",\n", format) | ||||
| } | ||||
|  | ||||
| func (g openAPITypeWriter) generateReferenceProperty(t *types.Type) { | ||||
| 	g.refTypes[t.Name.String()] = t | ||||
| 	g.Do("Ref: ref(\"$.$\"),\n", t.Name.String()) | ||||
| } | ||||
|  | ||||
| func resolveAliasAndPtrType(t *types.Type) *types.Type { | ||||
| 	var prev *types.Type | ||||
| 	for prev != t { | ||||
| 		prev = t | ||||
| 		if t.Kind == types.Alias { | ||||
| 			t = t.Underlying | ||||
| 		} | ||||
| 		if t.Kind == types.Pointer { | ||||
| 			t = t.Elem | ||||
| 		} | ||||
| 	} | ||||
| 	return t | ||||
| } | ||||
|  | ||||
| func (g openAPITypeWriter) generateMapProperty(t *types.Type) error { | ||||
| 	keyType := resolveAliasAndPtrType(t.Key) | ||||
| 	elemType := resolveAliasAndPtrType(t.Elem) | ||||
|  | ||||
| 	// According to OpenAPI examples, only map from string is supported | ||||
| 	if keyType.Name.Name != "string" { | ||||
| 		return fmt.Errorf("map with non-string keys are not supported by OpenAPI in %v", t) | ||||
| 	} | ||||
| 	g.Do("Type: []string{\"object\"},\n", nil) | ||||
| 	g.Do("AdditionalProperties: &spec.SchemaOrBool{\nSchema: &spec.Schema{\nSchemaProps: spec.SchemaProps{\n", nil) | ||||
| 	typeString, format := openapi.GetOpenAPITypeFormat(elemType.String()) | ||||
| 	if typeString != "" { | ||||
| 		g.generateSimpleProperty(typeString, format) | ||||
| 		g.Do("},\n},\n},\n", nil) | ||||
| 		return nil | ||||
| 	} | ||||
| 	switch elemType.Kind { | ||||
| 	case types.Builtin: | ||||
| 		return fmt.Errorf("please add type %v to getOpenAPITypeFormat function", elemType) | ||||
| 	case types.Struct: | ||||
| 		g.generateReferenceProperty(elemType) | ||||
| 	case types.Slice, types.Array: | ||||
| 		g.generateSliceProperty(elemType) | ||||
| 	default: | ||||
| 		return fmt.Errorf("map Element kind %v is not supported in %v", elemType.Kind, t.Name) | ||||
| 	} | ||||
| 	g.Do("},\n},\n},\n", nil) | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func (g openAPITypeWriter) generateSliceProperty(t *types.Type) error { | ||||
| 	elemType := resolveAliasAndPtrType(t.Elem) | ||||
| 	g.Do("Type: []string{\"array\"},\n", nil) | ||||
| 	g.Do("Items: &spec.SchemaOrArray{\nSchema: &spec.Schema{\nSchemaProps: spec.SchemaProps{\n", nil) | ||||
| 	typeString, format := openapi.GetOpenAPITypeFormat(elemType.String()) | ||||
| 	if typeString != "" { | ||||
| 		g.generateSimpleProperty(typeString, format) | ||||
| 		g.Do("},\n},\n},\n", nil) | ||||
| 		return nil | ||||
| 	} | ||||
| 	switch elemType.Kind { | ||||
| 	case types.Builtin: | ||||
| 		return fmt.Errorf("please add type %v to getOpenAPITypeFormat function", elemType) | ||||
| 	case types.Struct: | ||||
| 		g.generateReferenceProperty(elemType) | ||||
| 	default: | ||||
| 		return fmt.Errorf("slice Element kind %v is not supported in %v", elemType.Kind, t) | ||||
| 	} | ||||
| 	g.Do("},\n},\n},\n", nil) | ||||
| 	return nil | ||||
| } | ||||
							
								
								
									
										204
									
								
								vendor/k8s.io/kube-openapi/pkg/handler/handler.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										204
									
								
								vendor/k8s.io/kube-openapi/pkg/handler/handler.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,204 @@ | ||||
| /* | ||||
| Copyright 2017 The Kubernetes Authors. | ||||
|  | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
|  | ||||
| package handler | ||||
|  | ||||
| import ( | ||||
| 	"bytes" | ||||
| 	"compress/gzip" | ||||
| 	"crypto/sha512" | ||||
| 	"encoding/json" | ||||
| 	"fmt" | ||||
| 	"gopkg.in/yaml.v2" | ||||
| 	"mime" | ||||
| 	"net/http" | ||||
| 	"strings" | ||||
| 	"sync" | ||||
| 	"time" | ||||
|  | ||||
| 	"github.com/NYTimes/gziphandler" | ||||
| 	"github.com/emicklei/go-restful" | ||||
| 	"github.com/go-openapi/spec" | ||||
| 	"github.com/golang/protobuf/proto" | ||||
| 	"github.com/googleapis/gnostic/OpenAPIv2" | ||||
| 	"github.com/googleapis/gnostic/compiler" | ||||
|  | ||||
| 	"k8s.io/kube-openapi/pkg/builder" | ||||
| 	"k8s.io/kube-openapi/pkg/common" | ||||
| ) | ||||
|  | ||||
| const ( | ||||
| 	jsonExt = ".json" | ||||
|  | ||||
| 	mimeJson = "application/json" | ||||
| 	// TODO(mehdy): change @68f4ded to a version tag when gnostic add version tags. | ||||
| 	mimePb   = "application/com.github.googleapis.gnostic.OpenAPIv2@68f4ded+protobuf" | ||||
| 	mimePbGz = "application/x-gzip" | ||||
| ) | ||||
|  | ||||
| // OpenAPIService is the service responsible for serving OpenAPI spec. It has | ||||
| // the ability to safely change the spec while serving it. | ||||
| type OpenAPIService struct { | ||||
| 	// rwMutex protects All members of this service. | ||||
| 	rwMutex sync.RWMutex | ||||
|  | ||||
| 	orgSpec      *spec.Swagger | ||||
| 	lastModified time.Time | ||||
|  | ||||
| 	specBytes []byte | ||||
| 	specPb    []byte | ||||
| 	specPbGz  []byte | ||||
|  | ||||
| 	specBytesETag string | ||||
| 	specPbETag    string | ||||
| 	specPbGzETag  string | ||||
| } | ||||
|  | ||||
| func init() { | ||||
| 	mime.AddExtensionType(".json", mimeJson) | ||||
| 	mime.AddExtensionType(".pb-v1", mimePb) | ||||
| 	mime.AddExtensionType(".gz", mimePbGz) | ||||
| } | ||||
|  | ||||
| func computeETag(data []byte) string { | ||||
| 	return fmt.Sprintf("\"%X\"", sha512.Sum512(data)) | ||||
| } | ||||
|  | ||||
| // BuildAndRegisterOpenAPIService builds the spec and registers a handler to provides access to it. | ||||
| // Use this method if your OpenAPI spec is static. If you want to update the spec, use BuildOpenAPISpec then RegisterOpenAPIService. | ||||
| func BuildAndRegisterOpenAPIService(servePath string, webServices []*restful.WebService, config *common.Config, handler common.PathHandler) (*OpenAPIService, error) { | ||||
| 	spec, err := builder.BuildOpenAPISpec(webServices, config) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return RegisterOpenAPIService(spec, servePath, handler) | ||||
| } | ||||
|  | ||||
| // RegisterOpenAPIService registers a handler to provides access to provided swagger spec. | ||||
| // Note: servePath should end with ".json" as the RegisterOpenAPIService assume it is serving a | ||||
| // json file and will also serve .pb and .gz files. | ||||
| func RegisterOpenAPIService(openapiSpec *spec.Swagger, servePath string, handler common.PathHandler) (*OpenAPIService, error) { | ||||
| 	if !strings.HasSuffix(servePath, jsonExt) { | ||||
| 		return nil, fmt.Errorf("serving path must end with \"%s\"", jsonExt) | ||||
| 	} | ||||
|  | ||||
| 	servePathBase := strings.TrimSuffix(servePath, jsonExt) | ||||
|  | ||||
| 	o := OpenAPIService{} | ||||
| 	if err := o.UpdateSpec(openapiSpec); err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
|  | ||||
| 	type fileInfo struct { | ||||
| 		ext            string | ||||
| 		getDataAndETag func() ([]byte, string, time.Time) | ||||
| 	} | ||||
|  | ||||
| 	files := []fileInfo{ | ||||
| 		{".json", o.getSwaggerBytes}, | ||||
| 		{"-2.0.0.json", o.getSwaggerBytes}, | ||||
| 		{"-2.0.0.pb-v1", o.getSwaggerPbBytes}, | ||||
| 		{"-2.0.0.pb-v1.gz", o.getSwaggerPbGzBytes}, | ||||
| 	} | ||||
|  | ||||
| 	for _, file := range files { | ||||
| 		path := servePathBase + file.ext | ||||
| 		getDataAndETag := file.getDataAndETag | ||||
| 		handler.Handle(path, gziphandler.GzipHandler(http.HandlerFunc( | ||||
| 			func(w http.ResponseWriter, r *http.Request) { | ||||
| 				data, etag, lastModified := getDataAndETag() | ||||
| 				w.Header().Set("Etag", etag) | ||||
|  | ||||
| 				// ServeContent will take care of caching using eTag. | ||||
| 				http.ServeContent(w, r, path, lastModified, bytes.NewReader(data)) | ||||
| 			}), | ||||
| 		)) | ||||
| 	} | ||||
|  | ||||
| 	return &o, nil | ||||
| } | ||||
|  | ||||
| func (o *OpenAPIService) getSwaggerBytes() ([]byte, string, time.Time) { | ||||
| 	o.rwMutex.RLock() | ||||
| 	defer o.rwMutex.RUnlock() | ||||
| 	return o.specBytes, o.specBytesETag, o.lastModified | ||||
| } | ||||
|  | ||||
| func (o *OpenAPIService) getSwaggerPbBytes() ([]byte, string, time.Time) { | ||||
| 	o.rwMutex.RLock() | ||||
| 	defer o.rwMutex.RUnlock() | ||||
| 	return o.specPb, o.specPbETag, o.lastModified | ||||
| } | ||||
|  | ||||
| func (o *OpenAPIService) getSwaggerPbGzBytes() ([]byte, string, time.Time) { | ||||
| 	o.rwMutex.RLock() | ||||
| 	defer o.rwMutex.RUnlock() | ||||
| 	return o.specPbGz, o.specPbGzETag, o.lastModified | ||||
| } | ||||
|  | ||||
| func (o *OpenAPIService) UpdateSpec(openapiSpec *spec.Swagger) (err error) { | ||||
| 	orgSpec := openapiSpec | ||||
| 	specBytes, err := json.MarshalIndent(openapiSpec, " ", " ") | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	specPb, err := toProtoBinary(specBytes) | ||||
| 	if err != nil { | ||||
| 		return err | ||||
| 	} | ||||
| 	specPbGz := toGzip(specPb) | ||||
|  | ||||
| 	specBytesETag := computeETag(specBytes) | ||||
| 	specPbETag := computeETag(specPb) | ||||
| 	specPbGzETag := computeETag(specPbGz) | ||||
|  | ||||
| 	lastModified := time.Now() | ||||
|  | ||||
| 	o.rwMutex.Lock() | ||||
| 	defer o.rwMutex.Unlock() | ||||
|  | ||||
| 	o.orgSpec = orgSpec | ||||
| 	o.specBytes = specBytes | ||||
| 	o.specPb = specPb | ||||
| 	o.specPbGz = specPbGz | ||||
| 	o.specBytesETag = specBytesETag | ||||
| 	o.specPbETag = specPbETag | ||||
| 	o.specPbGzETag = specPbGzETag | ||||
| 	o.lastModified = lastModified | ||||
|  | ||||
| 	return nil | ||||
| } | ||||
|  | ||||
| func toProtoBinary(spec []byte) ([]byte, error) { | ||||
| 	var info yaml.MapSlice | ||||
| 	err := yaml.Unmarshal(spec, &info) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	document, err := openapi_v2.NewDocument(info, compiler.NewContext("$root", nil)) | ||||
| 	if err != nil { | ||||
| 		return nil, err | ||||
| 	} | ||||
| 	return proto.Marshal(document) | ||||
| } | ||||
|  | ||||
| func toGzip(data []byte) []byte { | ||||
| 	var buf bytes.Buffer | ||||
| 	zw := gzip.NewWriter(&buf) | ||||
| 	zw.Write(data) | ||||
| 	zw.Close() | ||||
| 	return buf.Bytes() | ||||
| } | ||||
							
								
								
									
										79
									
								
								vendor/k8s.io/kube-openapi/pkg/util/trie.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								vendor/k8s.io/kube-openapi/pkg/util/trie.go
									
									
									
										generated
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,79 @@ | ||||
| /* | ||||
| Copyright 2016 The Kubernetes Authors. | ||||
|  | ||||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| you may not use this file except in compliance with the License. | ||||
| You may obtain a copy of the License at | ||||
|  | ||||
|     http://www.apache.org/licenses/LICENSE-2.0 | ||||
|  | ||||
| Unless required by applicable law or agreed to in writing, software | ||||
| distributed under the License is distributed on an "AS IS" BASIS, | ||||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||||
| See the License for the specific language governing permissions and | ||||
| limitations under the License. | ||||
| */ | ||||
|  | ||||
| package util | ||||
|  | ||||
| // A simple trie implementation with Add and HasPrefix methods only. | ||||
| type Trie struct { | ||||
| 	children map[byte]*Trie | ||||
| 	wordTail bool | ||||
| 	word     string | ||||
| } | ||||
|  | ||||
| // NewTrie creates a Trie and add all strings in the provided list to it. | ||||
| func NewTrie(list []string) Trie { | ||||
| 	ret := Trie{ | ||||
| 		children: make(map[byte]*Trie), | ||||
| 		wordTail: false, | ||||
| 	} | ||||
| 	for _, v := range list { | ||||
| 		ret.Add(v) | ||||
| 	} | ||||
| 	return ret | ||||
| } | ||||
|  | ||||
| // Add adds a word to this trie | ||||
| func (t *Trie) Add(v string) { | ||||
| 	root := t | ||||
| 	for _, b := range []byte(v) { | ||||
| 		child, exists := root.children[b] | ||||
| 		if !exists { | ||||
| 			child = &Trie{ | ||||
| 				children: make(map[byte]*Trie), | ||||
| 				wordTail: false, | ||||
| 			} | ||||
| 			root.children[b] = child | ||||
| 		} | ||||
| 		root = child | ||||
| 	} | ||||
| 	root.wordTail = true | ||||
| 	root.word = v | ||||
| } | ||||
|  | ||||
| // HasPrefix returns true of v has any of the prefixes stored in this trie. | ||||
| func (t *Trie) HasPrefix(v string) bool { | ||||
| 	_, has := t.GetPrefix(v) | ||||
| 	return has | ||||
| } | ||||
|  | ||||
| // GetPrefix is like HasPrefix but return the prefix in case of match or empty string otherwise. | ||||
| func (t *Trie) GetPrefix(v string) (string, bool) { | ||||
| 	root := t | ||||
| 	if root.wordTail { | ||||
| 		return root.word, true | ||||
| 	} | ||||
| 	for _, b := range []byte(v) { | ||||
| 		child, exists := root.children[b] | ||||
| 		if !exists { | ||||
| 			return "", false | ||||
| 		} | ||||
| 		if child.wordTail { | ||||
| 			return child.word, true | ||||
| 		} | ||||
| 		root = child | ||||
| 	} | ||||
| 	return "", false | ||||
| } | ||||
		Reference in New Issue
	
	Block a user