1 /* 2 Copyright 2017 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package util 18 19 import ( 20 "reflect" 21 "strings" 22 ) 23 24 // [DEPRECATED] ToCanonicalName converts Golang package/type canonical name into REST friendly OpenAPI name. 25 // This method is deprecated because it has a misleading name. Please use ToRESTFriendlyName 26 // instead 27 // 28 // NOTE: actually the "canonical name" in this method should be named "REST friendly OpenAPI name", 29 // which is different from "canonical name" defined in GetCanonicalTypeName. The "canonical name" defined 30 // in GetCanonicalTypeName means Go type names with full package path. 31 // 32 // Examples of REST friendly OpenAPI name: 33 // 34 // Input: k8s.io/api/core/v1.Pod 35 // Output: io.k8s.api.core.v1.Pod 36 // 37 // Input: k8s.io/api/core/v1 38 // Output: io.k8s.api.core.v1 39 // 40 // Input: csi.storage.k8s.io/v1alpha1.CSINodeInfo 41 // Output: io.k8s.storage.csi.v1alpha1.CSINodeInfo 42 func ToCanonicalName(name string) string { 43 return ToRESTFriendlyName(name) 44 } 45 46 // ToRESTFriendlyName converts Golang package/type canonical name into REST friendly OpenAPI name. 47 // 48 // Examples of REST friendly OpenAPI name: 49 // 50 // Input: k8s.io/api/core/v1.Pod 51 // Output: io.k8s.api.core.v1.Pod 52 // 53 // Input: k8s.io/api/core/v1 54 // Output: io.k8s.api.core.v1 55 // 56 // Input: csi.storage.k8s.io/v1alpha1.CSINodeInfo 57 // Output: io.k8s.storage.csi.v1alpha1.CSINodeInfo 58 func ToRESTFriendlyName(name string) string { 59 nameParts := strings.Split(name, "/") 60 // Reverse first part. e.g., io.k8s... instead of k8s.io... 61 if len(nameParts) > 0 && strings.Contains(nameParts[0], ".") { 62 parts := strings.Split(nameParts[0], ".") 63 for i, j := 0, len(parts)-1; i < j; i, j = i+1, j-1 { 64 parts[i], parts[j] = parts[j], parts[i] 65 } 66 nameParts[0] = strings.Join(parts, ".") 67 } 68 return strings.Join(nameParts, ".") 69 } 70 71 // OpenAPICanonicalTypeNamer is an interface for models without Go type to seed model name. 72 // 73 // OpenAPI canonical names are Go type names with full package path, for uniquely indentifying 74 // a model / Go type. If a Go type is vendored from another package, only the path after "/vendor/" 75 // should be used. For custom resource definition (CRD), the canonical name is expected to be 76 // 77 // group/version.kind 78 // 79 // Examples of canonical name: 80 // 81 // Go type: k8s.io/kubernetes/pkg/apis/core.Pod 82 // CRD: csi.storage.k8s.io/v1alpha1.CSINodeInfo 83 // 84 // Example for vendored Go type: 85 // 86 // Original full path: k8s.io/kubernetes/vendor/k8s.io/api/core/v1.Pod 87 // Canonical name: k8s.io/api/core/v1.Pod 88 // 89 // Original full path: vendor/k8s.io/api/core/v1.Pod 90 // Canonical name: k8s.io/api/core/v1.Pod 91 type OpenAPICanonicalTypeNamer interface { 92 OpenAPICanonicalTypeName() string 93 } 94 95 // GetCanonicalTypeName will find the canonical type name of a sample object, removing 96 // the "vendor" part of the path 97 func GetCanonicalTypeName(model interface{}) string { 98 if namer, ok := model.(OpenAPICanonicalTypeNamer); ok { 99 return namer.OpenAPICanonicalTypeName() 100 } 101 t := reflect.TypeOf(model) 102 if t.Kind() == reflect.Ptr { 103 t = t.Elem() 104 } 105 if t.PkgPath() == "" { 106 return t.Name() 107 } 108 path := t.PkgPath() 109 if strings.Contains(path, "/vendor/") { 110 path = path[strings.Index(path, "/vendor/")+len("/vendor/"):] 111 } else if strings.HasPrefix(path, "vendor/") { 112 path = strings.TrimPrefix(path, "vendor/") 113 } 114 return path + "." + t.Name() 115 } 116