@@ -14,24 +14,29 @@ See the License for the specific language governing permissions and
14
14
limitations under the License.
15
15
*/
16
16
17
+ /*
18
+ Package conversion provides implementation for CRD conversion webhook that implements handler for version conversion requests for types that are convertible.
19
+
20
+ See pkg/conversion for interface definitions required to ensure a Type is convertible.
21
+ */
17
22
package conversion
18
23
19
24
import (
20
25
"encoding/json"
21
26
"fmt"
22
- "io/ioutil"
23
27
"net/http"
24
28
25
29
apix "k8s.io/apiextensions-apiserver/pkg/apis/apiextensions/v1beta1"
26
30
"k8s.io/apimachinery/pkg/api/meta"
31
+ metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
27
32
"k8s.io/apimachinery/pkg/runtime"
28
33
"k8s.io/apimachinery/pkg/runtime/schema"
29
34
"sigs.k8s.io/controller-runtime/pkg/conversion"
30
35
logf "sigs.k8s.io/controller-runtime/pkg/log"
31
36
)
32
37
33
38
var (
34
- log = logf .Log .WithName ("conversion_webhook " )
39
+ log = logf .Log .WithName ("conversion-webhook " )
35
40
)
36
41
37
42
// Webhook implements a CRD conversion webhook HTTP handler.
@@ -49,22 +54,15 @@ func (wh *Webhook) InjectScheme(s *runtime.Scheme) error {
49
54
return err
50
55
}
51
56
52
- // inject the decoder here too, just in case the order of calling this is not
53
- // scheme first, then inject func
54
- // if w.Handler != nil {
55
- // if _, err := InjectDecoderInto(w.GetDecoder(), w.Handler); err != nil {
56
- // return err
57
- // }
58
- // }
59
-
60
57
return nil
61
58
}
62
59
63
60
// ensure Webhook implements http.Handler
64
61
var _ http.Handler = & Webhook {}
65
62
66
63
func (wh * Webhook ) ServeHTTP (w http.ResponseWriter , r * http.Request ) {
67
- convertReview , err := wh .readRequest (r )
64
+ convertReview := & apix.ConversionReview {}
65
+ err := json .NewDecoder (r .Body ).Decode (convertReview )
68
66
if err != nil {
69
67
log .Error (err , "failed to read conversion request" )
70
68
w .WriteHeader (http .StatusBadRequest )
@@ -89,28 +87,6 @@ func (wh *Webhook) ServeHTTP(w http.ResponseWriter, r *http.Request) {
89
87
}
90
88
}
91
89
92
- func (wh * Webhook ) readRequest (r * http.Request ) (* apix.ConversionReview , error ) {
93
-
94
- var body []byte
95
- if r .Body == nil {
96
- return nil , fmt .Errorf ("nil request body" )
97
- }
98
- data , err := ioutil .ReadAll (r .Body )
99
- if err != nil {
100
- return nil , err
101
- }
102
- body = data
103
-
104
- convertReview := & apix.ConversionReview {}
105
- // TODO(droot): figure out if we want to split decoder for conversion
106
- // request from the objects contained in the request
107
- err = wh .decoder .DecodeInto (body , convertReview )
108
- if err != nil {
109
- return nil , err
110
- }
111
- return convertReview , nil
112
- }
113
-
114
90
// handles a version conversion request.
115
91
func (wh * Webhook ) handleConvertRequest (req * apix.ConversionRequest ) (* apix.ConversionResponse , error ) {
116
92
if req == nil {
@@ -142,58 +118,49 @@ func (wh *Webhook) handleConvertRequest(req *apix.ConversionRequest) (*apix.Conv
142
118
// convertObject will convert given a src object to dst object.
143
119
// Note(droot): couldn't find a way to reduce the cyclomatic complexity under 10
144
120
// without compromising readability, so disabling gocyclo linter
145
- // nolint: gocyclo
146
121
func (wh * Webhook ) convertObject (src , dst runtime.Object ) error {
147
122
srcGVK := src .GetObjectKind ().GroupVersionKind ()
148
123
dstGVK := dst .GetObjectKind ().GroupVersionKind ()
149
124
150
- if srcGVK .GroupKind (). String () != dstGVK .GroupKind (). String () {
125
+ if srcGVK .GroupKind () != dstGVK .GroupKind () {
151
126
return fmt .Errorf ("src %T and dst %T does not belong to same API Group" , src , dst )
152
127
}
153
128
154
- if srcGVK . String () == dstGVK . String () {
129
+ if srcGVK == dstGVK {
155
130
return fmt .Errorf ("conversion is not allowed between same type %T" , src )
156
131
}
157
132
158
133
srcIsHub , dstIsHub := isHub (src ), isHub (dst )
159
134
srcIsConvertible , dstIsConvertible := isConvertible (src ), isConvertible (dst )
160
135
161
- if srcIsHub {
162
- if dstIsConvertible {
163
- return dst .(conversion.Convertible ).ConvertFrom (src .(conversion.Hub ))
164
- }
136
+ switch {
137
+ case srcIsHub && dstIsConvertible :
138
+ return dst .(conversion.Convertible ).ConvertFrom (src .(conversion.Hub ))
139
+ case dstIsHub && srcIsConvertible :
140
+ return src .(conversion.Convertible ).ConvertTo (dst .(conversion.Hub ))
141
+ case srcIsConvertible && dstIsConvertible :
142
+ return wh .convertViaHub (src .(conversion.Convertible ), dst .(conversion.Convertible ))
143
+ default :
165
144
return fmt .Errorf ("%T is not convertible to %T" , src , dst )
166
145
}
146
+ }
167
147
168
- if dstIsHub {
169
- if srcIsConvertible {
170
- return src .(conversion.Convertible ).ConvertTo (dst .(conversion.Hub ))
171
- }
172
- return fmt .Errorf ("%T is not convertible %T" , dst , src )
173
- }
174
-
175
- // neither src nor dst are Hub, means both of them are spoke, so lets get the hub
176
- // version type.
148
+ func (wh * Webhook ) convertViaHub (src , dst conversion.Convertible ) error {
177
149
hub , err := wh .getHub (src )
178
150
if err != nil {
179
151
return err
180
152
}
181
153
182
154
if hub == nil {
183
- return fmt .Errorf ("API Group %s does not have any Hub defined" , srcGVK )
155
+ return fmt .Errorf ("%s does not have any Hub defined" , src )
184
156
}
185
157
186
- // src and dst needs to be convertable for it to work
187
- if ! srcIsConvertible || ! dstIsConvertible {
188
- return fmt .Errorf ("%T and %T needs to be convertable" , src , dst )
189
- }
190
-
191
- err = src .(conversion.Convertible ).ConvertTo (hub )
158
+ err = src .ConvertTo (hub )
192
159
if err != nil {
193
160
return fmt .Errorf ("%T failed to convert to hub version %T : %v" , src , hub , err )
194
161
}
195
162
196
- err = dst .(conversion. Convertible ). ConvertFrom (hub )
163
+ err = dst .ConvertFrom (hub )
197
164
if err != nil {
198
165
return fmt .Errorf ("%T failed to convert from hub version %T : %v" , dst , hub , err )
199
166
}
@@ -256,3 +223,13 @@ func isConvertible(obj runtime.Object) bool {
256
223
_ , yes := obj .(conversion.Convertible )
257
224
return yes
258
225
}
226
+
227
+ // helper to construct error response.
228
+ func errored (err error ) * apix.ConversionResponse {
229
+ return & apix.ConversionResponse {
230
+ Result : metav1.Status {
231
+ Status : metav1 .StatusFailure ,
232
+ Message : err .Error (),
233
+ },
234
+ }
235
+ }
0 commit comments