@@ -25,7 +25,6 @@ import (
25
25
26
26
"github.com/go-logr/logr"
27
27
corev1 "k8s.io/api/core/v1"
28
- apierrors "k8s.io/apimachinery/pkg/api/errors"
29
28
"k8s.io/apimachinery/pkg/runtime"
30
29
"k8s.io/client-go/util/cert"
31
30
"sigs.k8s.io/controller-runtime/pkg/client"
@@ -36,7 +35,9 @@ import (
36
35
vcpki "sigs.k8s.io/cluster-api-provider-nested/virtualcluster/pkg/controller/pki"
37
36
"sigs.k8s.io/cluster-api-provider-nested/virtualcluster/pkg/controller/secret"
38
37
kubeutil "sigs.k8s.io/cluster-api-provider-nested/virtualcluster/pkg/controller/util/kube"
38
+ "sigs.k8s.io/cluster-api-provider-nested/virtualcluster/pkg/syncer/constants"
39
39
"sigs.k8s.io/cluster-api-provider-nested/virtualcluster/pkg/syncer/conversion"
40
+ "sigs.k8s.io/cluster-api-provider-nested/virtualcluster/pkg/syncer/util/featuregate"
40
41
pkiutil "sigs.k8s.io/cluster-api-provider-nested/virtualcluster/pkg/util/pki"
41
42
)
42
43
@@ -45,6 +46,11 @@ const (
45
46
ComponentPollPeriodSec = 2
46
47
)
47
48
49
+ var (
50
+ definitelyTrue = true
51
+ patchOptions = & client.PatchOptions {Force : & definitelyTrue , FieldManager : "virtualcluster/provisioner/native" }
52
+ )
53
+
48
54
type Native struct {
49
55
client.Client
50
56
scheme * runtime.Scheme
@@ -61,60 +67,93 @@ func NewProvisionerNative(mgr manager.Manager, log logr.Logger, provisionerTimeo
61
67
}, nil
62
68
}
63
69
70
+ func updateLabelClusterVersionApplied (vc * tenancyv1alpha1.VirtualCluster , cv * tenancyv1alpha1.ClusterVersion ) {
71
+ if featuregate .DefaultFeatureGate .Enabled (featuregate .VirtualClusterApplyUpdate ) {
72
+ if vc .Labels == nil {
73
+ vc .Labels = map [string ]string {}
74
+ }
75
+ vc .Labels [constants .LabelClusterVersionApplied ] = cv .ObjectMeta .ResourceVersion
76
+ }
77
+ }
78
+
64
79
// CreateVirtualCluster sets up the control plane for vc on meta k8s
65
80
func (mpn * Native ) CreateVirtualCluster (ctx context.Context , vc * tenancyv1alpha1.VirtualCluster ) error {
81
+ cv , err := mpn .fetchClusterVersion (vc )
82
+ if err != nil {
83
+ return err
84
+ }
85
+
86
+ updateLabelClusterVersionApplied (vc , cv )
87
+
88
+ // 1. create the root ns
89
+ _ , err = kubeutil .CreateRootNS (mpn , vc )
90
+ if err != nil {
91
+ return err
92
+ }
93
+ return mpn .applyVirtualCluster (ctx , cv , vc )
94
+ }
95
+
96
+ func (mpn * Native ) fetchClusterVersion (vc * tenancyv1alpha1.VirtualCluster ) (* tenancyv1alpha1.ClusterVersion , error ) {
66
97
cvObjectKey := client.ObjectKey {Name : vc .Spec .ClusterVersionName }
67
98
cv := & tenancyv1alpha1.ClusterVersion {}
68
99
if err := mpn .Get (context .Background (), cvObjectKey , cv ); err != nil {
69
100
err = fmt .Errorf ("desired ClusterVersion %s not found" ,
70
101
vc .Spec .ClusterVersionName )
71
- return err
102
+ return nil , err
72
103
}
104
+ return cv , nil
105
+ }
73
106
74
- // 1. create the root ns
75
- _ , err := kubeutil . CreateRootNS ( mpn , vc )
107
+ func ( mpn * Native ) UpgradeVirtualCluster ( ctx context. Context , vc * tenancyv1alpha1. VirtualCluster ) error {
108
+ cv , err := mpn . fetchClusterVersion ( vc )
76
109
if err != nil {
77
110
return err
78
111
}
112
+ if cvVersion , ok := vc .Labels [constants .LabelClusterVersionApplied ]; ok && cvVersion == cv .ObjectMeta .ResourceVersion {
113
+ mpn .Log .Info ("cluster is already in desired version" )
114
+ return nil
115
+ }
116
+ updateLabelClusterVersionApplied (vc , cv )
117
+ return mpn .applyVirtualCluster (ctx , cv , vc )
118
+ }
119
+
120
+ func (mpn * Native ) applyVirtualCluster (ctx context.Context , cv * tenancyv1alpha1.ClusterVersion , vc * tenancyv1alpha1.VirtualCluster ) error {
121
+ var err error
79
122
isClusterIP := cv .Spec .APIServer .Service != nil && cv .Spec .APIServer .Service .Spec .Type == corev1 .ServiceTypeClusterIP
80
- // if ClusterIP, have to create API Server ahead of time to lay it down in the PKI
123
+ // if ClusterIP, have to update API Server ahead of time to lay it down in the PKI
81
124
if isClusterIP {
82
- mpn .Log .Info ("deploying ClusterIP Service for API component" , "component" , cv .Spec .APIServer .Name )
125
+ mpn .Log .Info ("applying ClusterIP Service for API component" , "component" , cv .Spec .APIServer .Name )
83
126
complementAPIServerTemplate (conversion .ToClusterKey (vc ), cv .Spec .APIServer )
84
- err = mpn .Create ( context . TODO () , cv .Spec .APIServer .Service )
127
+ err : = mpn .Patch ( ctx , cv .Spec .APIServer .Service , client . Apply , patchOptions )
85
128
if err != nil {
86
- if ! apierrors .IsAlreadyExists (err ) {
87
- return err
88
- }
89
- mpn .Log .Info ("service already exist" ,
90
- "service" , cv .Spec .APIServer .Service .GetName ())
129
+ mpn .Log .Error (err , "failed to update service" , "service" , cv .Spec .APIServer .Service .GetName ())
130
+ return err
91
131
}
92
132
}
93
133
94
- // 2. create PKI
95
- err = mpn .createPKI ( vc , cv , isClusterIP )
134
+ // 2. apply PKI
135
+ err = mpn .createAndApplyPKI ( ctx , vc , cv , isClusterIP )
96
136
if err != nil {
97
137
return err
98
138
}
99
139
100
140
// 3. deploy etcd
101
- err = mpn .deployComponent (vc , cv .Spec .ETCD )
141
+ err = mpn .deployComponent (ctx , vc , cv .Spec .ETCD )
102
142
if err != nil {
103
143
return err
104
144
}
105
145
106
146
// 4. deploy apiserver
107
- err = mpn .deployComponent (vc , cv .Spec .APIServer )
147
+ err = mpn .deployComponent (ctx , vc , cv .Spec .APIServer )
108
148
if err != nil {
109
149
return err
110
150
}
111
151
112
152
// 5. deploy controller-manager
113
- err = mpn .deployComponent (vc , cv .Spec .ControllerManager )
153
+ err = mpn .deployComponent (ctx , vc , cv .Spec .ControllerManager )
114
154
if err != nil {
115
155
return err
116
156
}
117
-
118
157
return nil
119
158
}
120
159
@@ -162,7 +201,7 @@ func complementCtrlMgrTemplate(vcns string, ctrlMgrBdl *tenancyv1alpha1.Stateful
162
201
163
202
// deployComponent deploys control plane component in namespace vcName based on the given StatefulSet
164
203
// and Service Bundle ssBdl
165
- func (mpn * Native ) deployComponent (vc * tenancyv1alpha1.VirtualCluster , ssBdl * tenancyv1alpha1.StatefulSetSvcBundle ) error {
204
+ func (mpn * Native ) deployComponent (ctx context. Context , vc * tenancyv1alpha1.VirtualCluster , ssBdl * tenancyv1alpha1.StatefulSetSvcBundle ) error {
166
205
mpn .Log .Info ("deploying StatefulSet for control plane component" , "component" , ssBdl .Name )
167
206
168
207
ns := conversion .ToClusterKey (vc )
@@ -178,26 +217,17 @@ func (mpn *Native) deployComponent(vc *tenancyv1alpha1.VirtualCluster, ssBdl *te
178
217
return fmt .Errorf ("try to deploy unknown component: %s" , ssBdl .Name )
179
218
}
180
219
181
- err := mpn .Create ( context . TODO () , ssBdl .StatefulSet )
220
+ err := mpn .Patch ( ctx , ssBdl .StatefulSet , client . Apply , patchOptions )
182
221
if err != nil {
183
- if ! apierrors .IsAlreadyExists (err ) {
184
- return err
185
- }
186
- mpn .Log .Info ("statefuleset already exist" ,
187
- "statefuleset" , ssBdl .StatefulSet .GetName (),
188
- "namespace" , ssBdl .StatefulSet .GetNamespace ())
222
+ return err
189
223
}
190
224
191
225
// skip apiserver clusterIP service creation as it is already created in CreateVirtualCluster()
192
226
if ssBdl .Service != nil && ! (ssBdl .Name == "apiserver" && ssBdl .Service .Spec .Type == corev1 .ServiceTypeClusterIP ) {
193
227
mpn .Log .Info ("deploying Service for control plane component" , "component" , ssBdl .Name )
194
- err = mpn .Create ( context . TODO () , ssBdl .Service )
228
+ err : = mpn .Patch ( ctx , ssBdl .Service , client . Apply , patchOptions )
195
229
if err != nil {
196
- if ! apierrors .IsAlreadyExists (err ) {
197
- return err
198
- }
199
- mpn .Log .Info ("service already exist" ,
200
- "service" , ssBdl .Service .GetName ())
230
+ return err
201
231
}
202
232
}
203
233
@@ -209,9 +239,9 @@ func (mpn *Native) deployComponent(vc *tenancyv1alpha1.VirtualCluster, ssBdl *te
209
239
return nil
210
240
}
211
241
212
- // createPKISecrets creates secrets to store crt/key pairs and kubeconfigs
242
+ // createOrUpdatePKISecrets creates secrets to store crt/key pairs and kubeconfigs
213
243
// for control plane components of the virtual cluster
214
- func (mpn * Native ) createPKISecrets ( caGroup * vcpki.ClusterCAGroup , namespace string ) error {
244
+ func (mpn * Native ) createOrUpdatePKISecrets ( ctx context. Context , caGroup * vcpki.ClusterCAGroup , namespace string ) error {
215
245
// create secret for root crt/key pair
216
246
rootSrt := secret .CrtKeyPairToSecret (secret .RootCASecretName , namespace , caGroup .RootCA )
217
247
// create secret for apiserver crt/key pair
@@ -240,25 +270,21 @@ func (mpn *Native) createPKISecrets(caGroup *vcpki.ClusterCAGroup, namespace str
240
270
241
271
// create all secrets on metacluster
242
272
for _ , srt := range secrets {
243
- mpn .Log .Info ("creating secret" , "name" ,
273
+ mpn .Log .Info ("applying secret" , "name" ,
244
274
srt .Name , "namespace" , srt .Namespace )
245
- err := mpn .Create (context .TODO (), srt )
275
+
276
+ err := mpn .Patch (ctx , srt , client .Apply , patchOptions )
246
277
if err != nil {
247
- if ! apierrors .IsAlreadyExists (err ) {
248
- return err
249
- }
250
- mpn .Log .Info ("Secret already exists" ,
251
- "secret" , srt .Name ,
252
- "namespace" , srt .Namespace )
278
+ return err
253
279
}
254
280
}
255
281
256
282
return nil
257
283
}
258
284
259
- // createPKI constructs the PKI (all crt/key pair and kubeconfig) for the
285
+ // createAndApplyPKI constructs the PKI (all crt/key pair and kubeconfig) for the
260
286
// virtual clusters, and store them as secrets in the meta cluster
261
- func (mpn * Native ) createPKI ( vc * tenancyv1alpha1.VirtualCluster , cv * tenancyv1alpha1.ClusterVersion , isClusterIP bool ) error {
287
+ func (mpn * Native ) createAndApplyPKI ( ctx context. Context , vc * tenancyv1alpha1.VirtualCluster , cv * tenancyv1alpha1.ClusterVersion , isClusterIP bool ) error {
262
288
ns := conversion .ToClusterKey (vc )
263
289
caGroup := & vcpki.ClusterCAGroup {}
264
290
// create root ca, all components will share a single root ca
@@ -346,15 +372,15 @@ func (mpn *Native) createPKI(vc *tenancyv1alpha1.VirtualCluster, cv *tenancyv1al
346
372
caGroup .ServiceAccountPrivateKey = svcAcctCAPair
347
373
348
374
// store ca and kubeconfig into secrets
349
- genSrtsErr := mpn .createPKISecrets ( caGroup , ns )
375
+ genSrtsErr := mpn .createOrUpdatePKISecrets ( ctx , caGroup , ns )
350
376
if genSrtsErr != nil {
351
377
return genSrtsErr
352
378
}
353
379
354
380
return nil
355
381
}
356
382
357
- func (mpn * Native ) DeleteVirtualCluster (ctx context.Context , vc * tenancyv1alpha1.VirtualCluster ) error {
383
+ func (mpn * Native ) DeleteVirtualCluster (_ context.Context , _ * tenancyv1alpha1.VirtualCluster ) error {
358
384
return nil
359
385
}
360
386
0 commit comments