@@ -26,29 +26,19 @@ import (
26
26
27
27
"k8s.io/klog"
28
28
29
+ "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1"
29
30
"k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
30
31
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
31
32
"k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
32
33
"k8s.io/apimachinery/pkg/runtime"
33
34
"k8s.io/apimachinery/pkg/runtime/serializer/json"
35
+ utilruntime "k8s.io/apimachinery/pkg/util/runtime"
34
36
)
35
37
36
38
// convertFunc is the user defined function for any conversion. The code in this file is a
37
39
// template that can be use for any CR conversion given this function.
38
40
type convertFunc func (Object * unstructured.Unstructured , version string ) (* unstructured.Unstructured , metav1.Status )
39
41
40
- // conversionResponseFailureWithMessagef is a helper function to create an AdmissionResponse
41
- // with a formatted embedded error message.
42
- func conversionResponseFailureWithMessagef (msg string , params ... interface {}) * v1beta1.ConversionResponse {
43
- return & v1beta1.ConversionResponse {
44
- Result : metav1.Status {
45
- Message : fmt .Sprintf (msg , params ... ),
46
- Status : metav1 .StatusFailure ,
47
- },
48
- }
49
-
50
- }
51
-
52
42
func statusErrorWithMessage (msg string , params ... interface {}) metav1.Status {
53
43
return metav1.Status {
54
44
Message : fmt .Sprintf (msg , params ... ),
@@ -62,15 +52,20 @@ func statusSucceed() metav1.Status {
62
52
}
63
53
}
64
54
65
- // doConversion converts the requested object given the conversion function and returns a conversion response.
66
- // failures will be reported as Reason in the conversion response.
67
- func doConversion (convertRequest * v1beta1.ConversionRequest , convert convertFunc ) * v1beta1.ConversionResponse {
55
+ // doConversionV1beta1 converts the requested objects in the v1beta1 ConversionRequest using the given conversion function and
56
+ // returns a conversion response. Failures are reported with the Reason in the conversion response.
57
+ func doConversionV1beta1 (convertRequest * v1beta1.ConversionRequest , convert convertFunc ) * v1beta1.ConversionResponse {
68
58
var convertedObjects []runtime.RawExtension
69
59
for _ , obj := range convertRequest .Objects {
70
60
cr := unstructured.Unstructured {}
71
61
if err := cr .UnmarshalJSON (obj .Raw ); err != nil {
72
62
klog .Error (err )
73
- return conversionResponseFailureWithMessagef ("failed to unmarshall object (%v) with error: %v" , string (obj .Raw ), err )
63
+ return & v1beta1.ConversionResponse {
64
+ Result : metav1.Status {
65
+ Message : fmt .Sprintf ("failed to unmarshall object (%v) with error: %v" , string (obj .Raw ), err ),
66
+ Status : metav1 .StatusFailure ,
67
+ },
68
+ }
74
69
}
75
70
convertedCR , status := convert (& cr , convertRequest .DesiredAPIVersion )
76
71
if status .Status != metav1 .StatusSuccess {
@@ -88,6 +83,37 @@ func doConversion(convertRequest *v1beta1.ConversionRequest, convert convertFunc
88
83
}
89
84
}
90
85
86
+ // doConversionV1 converts the requested objects in the v1 ConversionRequest using the given conversion function and
87
+ // returns a conversion response. Failures are reported with the Reason in the conversion response.
88
+ func doConversionV1 (convertRequest * v1.ConversionRequest , convert convertFunc ) * v1.ConversionResponse {
89
+ var convertedObjects []runtime.RawExtension
90
+ for _ , obj := range convertRequest .Objects {
91
+ cr := unstructured.Unstructured {}
92
+ if err := cr .UnmarshalJSON (obj .Raw ); err != nil {
93
+ klog .Error (err )
94
+ return & v1.ConversionResponse {
95
+ Result : metav1.Status {
96
+ Message : fmt .Sprintf ("failed to unmarshall object (%v) with error: %v" , string (obj .Raw ), err ),
97
+ Status : metav1 .StatusFailure ,
98
+ },
99
+ }
100
+ }
101
+ convertedCR , status := convert (& cr , convertRequest .DesiredAPIVersion )
102
+ if status .Status != metav1 .StatusSuccess {
103
+ klog .Error (status .String ())
104
+ return & v1.ConversionResponse {
105
+ Result : status ,
106
+ }
107
+ }
108
+ convertedCR .SetAPIVersion (convertRequest .DesiredAPIVersion )
109
+ convertedObjects = append (convertedObjects , runtime.RawExtension {Object : convertedCR })
110
+ }
111
+ return & v1.ConversionResponse {
112
+ ConvertedObjects : convertedObjects ,
113
+ Result : statusSucceed (),
114
+ }
115
+ }
116
+
91
117
func serve (w http.ResponseWriter , r * http.Request , convert convertFunc ) {
92
118
var body []byte
93
119
if r .Body != nil {
@@ -106,18 +132,52 @@ func serve(w http.ResponseWriter, r *http.Request, convert convertFunc) {
106
132
}
107
133
108
134
klog .V (2 ).Infof ("handling request: %v" , body )
109
- convertReview := v1beta1.ConversionReview {}
110
- if _ , _ , err := serializer .Decode (body , nil , & convertReview ); err != nil {
135
+ obj , gvk , err := serializer .Decode (body , nil , nil )
136
+ if err != nil {
137
+ msg := fmt .Sprintf ("failed to deserialize body (%v) with error %v" , string (body ), err )
111
138
klog .Error (err )
112
- convertReview .Response = conversionResponseFailureWithMessagef ("failed to deserialize body (%v) with error %v" , string (body ), err )
113
- } else {
114
- convertReview .Response = doConversion (convertReview .Request , convert )
115
- convertReview .Response .UID = convertReview .Request .UID
139
+ http .Error (w , msg , http .StatusBadRequest )
140
+ return
116
141
}
117
- klog .V (2 ).Info (fmt .Sprintf ("sending response: %v" , convertReview .Response ))
118
142
119
- // reset the request, it is not needed in a response.
120
- convertReview .Request = & v1beta1.ConversionRequest {}
143
+ var responseObj runtime.Object
144
+ switch * gvk {
145
+ case v1beta1 .SchemeGroupVersion .WithKind ("ConversionReview" ):
146
+ convertReview , ok := obj .(* v1beta1.ConversionReview )
147
+ if ! ok {
148
+ msg := fmt .Sprintf ("Expected v1beta1.ConversionReview but got: %T" , obj )
149
+ klog .Errorf (msg )
150
+ http .Error (w , msg , http .StatusBadRequest )
151
+ return
152
+ }
153
+ convertReview .Response = doConversionV1beta1 (convertReview .Request , convert )
154
+ convertReview .Response .UID = convertReview .Request .UID
155
+ klog .V (2 ).Info (fmt .Sprintf ("sending response: %v" , convertReview .Response ))
156
+
157
+ // reset the request, it is not needed in a response.
158
+ convertReview .Request = & v1beta1.ConversionRequest {}
159
+ responseObj = convertReview
160
+ case v1 .SchemeGroupVersion .WithKind ("ConversionReview" ):
161
+ convertReview , ok := obj .(* v1.ConversionReview )
162
+ if ! ok {
163
+ msg := fmt .Sprintf ("Expected v1.ConversionReview but got: %T" , obj )
164
+ klog .Errorf (msg )
165
+ http .Error (w , msg , http .StatusBadRequest )
166
+ return
167
+ }
168
+ convertReview .Response = doConversionV1 (convertReview .Request , convert )
169
+ convertReview .Response .UID = convertReview .Request .UID
170
+ klog .V (2 ).Info (fmt .Sprintf ("sending response: %v" , convertReview .Response ))
171
+
172
+ // reset the request, it is not needed in a response.
173
+ convertReview .Request = & v1.ConversionRequest {}
174
+ responseObj = convertReview
175
+ default :
176
+ msg := fmt .Sprintf ("Unsupported group version kind: %v" , gvk )
177
+ klog .Error (err )
178
+ http .Error (w , msg , http .StatusBadRequest )
179
+ return
180
+ }
121
181
122
182
accept := r .Header .Get ("Accept" )
123
183
outSerializer := getOutputSerializer (accept )
@@ -127,7 +187,7 @@ func serve(w http.ResponseWriter, r *http.Request, convert convertFunc) {
127
187
http .Error (w , msg , http .StatusBadRequest )
128
188
return
129
189
}
130
- err : = outSerializer .Encode (& convertReview , w )
190
+ err = outSerializer .Encode (responseObj , w )
131
191
if err != nil {
132
192
klog .Error (err )
133
193
http .Error (w , err .Error (), http .StatusInternalServerError )
@@ -145,6 +205,16 @@ type mediaType struct {
145
205
}
146
206
147
207
var scheme = runtime .NewScheme ()
208
+
209
+ func init () {
210
+ addToScheme (scheme )
211
+ }
212
+
213
+ func addToScheme (scheme * runtime.Scheme ) {
214
+ utilruntime .Must (v1 .AddToScheme (scheme ))
215
+ utilruntime .Must (v1beta1 .AddToScheme (scheme ))
216
+ }
217
+
148
218
var serializers = map [mediaType ]runtime.Serializer {
149
219
{"application" , "json" }: json .NewSerializer (json .DefaultMetaFactory , scheme , scheme , false ),
150
220
{"application" , "yaml" }: json .NewYAMLSerializer (json .DefaultMetaFactory , scheme , scheme ),
0 commit comments