1
16
17 package scale
18
19 import (
20 "fmt"
21 "strings"
22 "sync"
23
24 "k8s.io/apimachinery/pkg/api/meta"
25 "k8s.io/apimachinery/pkg/runtime"
26 "k8s.io/apimachinery/pkg/runtime/schema"
27 serializer "k8s.io/apimachinery/pkg/runtime/serializer"
28 utilruntime "k8s.io/apimachinery/pkg/util/runtime"
29 "k8s.io/client-go/discovery"
30 scalescheme "k8s.io/client-go/scale/scheme"
31 scaleappsint "k8s.io/client-go/scale/scheme/appsint"
32 scaleappsv1beta1 "k8s.io/client-go/scale/scheme/appsv1beta1"
33 scaleappsv1beta2 "k8s.io/client-go/scale/scheme/appsv1beta2"
34 scaleautoscaling "k8s.io/client-go/scale/scheme/autoscalingv1"
35 scaleextint "k8s.io/client-go/scale/scheme/extensionsint"
36 scaleext "k8s.io/client-go/scale/scheme/extensionsv1beta1"
37 )
38
39
40 type PreferredResourceMapper interface {
41
42 ResourceFor(resource schema.GroupVersionResource) (preferredResource schema.GroupVersionResource, err error)
43 }
44
45
46 var _ PreferredResourceMapper = meta.RESTMapper(nil)
47
48
49
50 type ScaleKindResolver interface {
51
52
53 ScaleForResource(resource schema.GroupVersionResource) (scaleVersion schema.GroupVersionKind, err error)
54 }
55
56
57
58
59 type discoveryScaleResolver struct {
60 discoveryClient discovery.ServerResourcesInterface
61 }
62
63 func (r *discoveryScaleResolver) ScaleForResource(inputRes schema.GroupVersionResource) (scaleVersion schema.GroupVersionKind, err error) {
64 groupVerResources, err := r.discoveryClient.ServerResourcesForGroupVersion(inputRes.GroupVersion().String())
65 if err != nil {
66 return schema.GroupVersionKind{}, fmt.Errorf("unable to fetch discovery information for %s: %v", inputRes.String(), err)
67 }
68
69 for _, resource := range groupVerResources.APIResources {
70 resourceParts := strings.SplitN(resource.Name, "/", 2)
71 if len(resourceParts) != 2 || resourceParts[0] != inputRes.Resource || resourceParts[1] != "scale" {
72
73 continue
74 }
75
76 scaleGV := inputRes.GroupVersion()
77 if resource.Group != "" && resource.Version != "" {
78 scaleGV = schema.GroupVersion{
79 Group: resource.Group,
80 Version: resource.Version,
81 }
82 }
83
84 return scaleGV.WithKind(resource.Kind), nil
85 }
86
87 return schema.GroupVersionKind{}, fmt.Errorf("could not find scale subresource for %s in discovery information", inputRes.String())
88 }
89
90
91
92 type cachedScaleKindResolver struct {
93 base ScaleKindResolver
94
95 cache map[schema.GroupVersionResource]schema.GroupVersionKind
96 mu sync.RWMutex
97 }
98
99 func (r *cachedScaleKindResolver) ScaleForResource(resource schema.GroupVersionResource) (schema.GroupVersionKind, error) {
100 r.mu.RLock()
101 gvk, isCached := r.cache[resource]
102 r.mu.RUnlock()
103 if isCached {
104 return gvk, nil
105 }
106
107
108
109
110
111 gvk, err := r.base.ScaleForResource(resource)
112 if err != nil {
113 return schema.GroupVersionKind{}, err
114 }
115
116 r.mu.Lock()
117 defer r.mu.Unlock()
118 r.cache[resource] = gvk
119
120 return gvk, nil
121 }
122
123
124
125 func NewDiscoveryScaleKindResolver(client discovery.ServerResourcesInterface) ScaleKindResolver {
126 base := &discoveryScaleResolver{
127 discoveryClient: client,
128 }
129
130 return &cachedScaleKindResolver{
131 base: base,
132 cache: make(map[schema.GroupVersionResource]schema.GroupVersionKind),
133 }
134 }
135
136
137 type ScaleConverter struct {
138 scheme *runtime.Scheme
139 codecs serializer.CodecFactory
140 internalVersioner runtime.GroupVersioner
141 }
142
143
144
145 func NewScaleConverter() *ScaleConverter {
146 scheme := runtime.NewScheme()
147 utilruntime.Must(scaleautoscaling.AddToScheme(scheme))
148 utilruntime.Must(scalescheme.AddToScheme(scheme))
149 utilruntime.Must(scaleext.AddToScheme(scheme))
150 utilruntime.Must(scaleextint.AddToScheme(scheme))
151 utilruntime.Must(scaleappsint.AddToScheme(scheme))
152 utilruntime.Must(scaleappsv1beta1.AddToScheme(scheme))
153 utilruntime.Must(scaleappsv1beta2.AddToScheme(scheme))
154
155 return &ScaleConverter{
156 scheme: scheme,
157 codecs: serializer.NewCodecFactory(scheme),
158 internalVersioner: runtime.NewMultiGroupVersioner(
159 scalescheme.SchemeGroupVersion,
160 schema.GroupKind{Group: scaleext.GroupName, Kind: "Scale"},
161 schema.GroupKind{Group: scaleautoscaling.GroupName, Kind: "Scale"},
162 schema.GroupKind{Group: scaleappsv1beta1.GroupName, Kind: "Scale"},
163 schema.GroupKind{Group: scaleappsv1beta2.GroupName, Kind: "Scale"},
164 ),
165 }
166 }
167
168
169 func (c *ScaleConverter) Scheme() *runtime.Scheme {
170 return c.scheme
171 }
172
173 func (c *ScaleConverter) Codecs() serializer.CodecFactory {
174 return c.codecs
175 }
176
177 func (c *ScaleConverter) ScaleVersions() []schema.GroupVersion {
178 return []schema.GroupVersion{
179 scaleautoscaling.SchemeGroupVersion,
180 scalescheme.SchemeGroupVersion,
181 scaleext.SchemeGroupVersion,
182 scaleextint.SchemeGroupVersion,
183 scaleappsint.SchemeGroupVersion,
184 scaleappsv1beta1.SchemeGroupVersion,
185 scaleappsv1beta2.SchemeGroupVersion,
186 }
187 }
188
189
190 func (c *ScaleConverter) ConvertToVersion(in runtime.Object, outVersion schema.GroupVersion) (runtime.Object, error) {
191 scaleInt, err := c.scheme.ConvertToVersion(in, c.internalVersioner)
192 if err != nil {
193 return nil, err
194 }
195
196 return c.scheme.ConvertToVersion(scaleInt, outVersion)
197 }
198
View as plain text