9
9
"github.com/go-logr/logr"
10
10
"github.com/pkg/errors"
11
11
"github.com/vmware/alb-sdk/go/models"
12
+ "golang.org/x/mod/semver"
12
13
corev1 "k8s.io/api/core/v1"
13
14
apierrors "k8s.io/apimachinery/pkg/api/errors"
14
15
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
@@ -241,7 +242,7 @@ func (r *AkoUserReconciler) reconcileAviUserNormal(
241
242
aviPassword := string (mcSecret .Data ["password" ][:])
242
243
243
244
// ensures the AVI User exists and matches the mc secret
244
- if _ , err = r .createOrUpdateAviUser (aviUsername , aviPassword , obj .Spec .Tenant .Name ); err != nil {
245
+ if err = r .createOrUpdateAviUser (log , aviUsername , aviPassword , obj .Spec .Tenant .Name ); err != nil {
245
246
log .Error (err , "Failed to create/update cluster avi user" )
246
247
return res , err
247
248
} else {
@@ -263,21 +264,27 @@ func (r *AkoUserReconciler) getAVIControllerCA(ctx context.Context, obj *akoov1a
263
264
}
264
265
265
266
// createOrUpdateAviUser create an avi user in avi controller
266
- func (r * AkoUserReconciler ) createOrUpdateAviUser (aviUsername , aviPassword , tenantName string ) (* models.User , error ) {
267
+ func (r * AkoUserReconciler ) createOrUpdateAviUser (log logr.Logger , aviUsername , aviPassword , tenantName string ) error {
268
+ version , err := r .aviClient .GetControllerVersion ()
269
+ if err != nil {
270
+ return err
271
+ }
272
+
267
273
aviUser , err := r .aviClient .UserGetByName (aviUsername )
268
274
// user not found, create one
269
275
if aviclient .IsAviUserNonExistentError (err ) {
276
+ log .Info ("AVI User not found, creating a new one" )
270
277
// for avi essential version the default tenant is admin
271
278
if tenantName == "" {
272
279
tenantName = "admin"
273
280
}
274
281
tenant , err := r .aviClient .TenantGet (tenantName )
275
282
if err != nil {
276
- return nil , err
283
+ return err
277
284
}
278
- role , err := r .getOrCreateAkoUserRole (tenant .URL )
285
+ role , err := r .getOrCreateAkoUserRole (log , tenant .URL , version )
279
286
if err != nil {
280
- return nil , err
287
+ return err
281
288
}
282
289
aviUser = & models.User {
283
290
Name : & aviUsername ,
@@ -291,50 +298,62 @@ func (r *AkoUserReconciler) createOrUpdateAviUser(aviUsername, aviPassword, tena
291
298
},
292
299
},
293
300
}
294
- return r .aviClient .UserCreate (aviUser )
301
+ if _ , err := r .aviClient .UserCreate (aviUser ); err != nil {
302
+ return err
303
+ }
304
+ return nil
305
+ } else if err != nil {
306
+ log .Info ("Failed to get AVI User" , "user" , aviUsername , "error" , err )
307
+ return err
295
308
}
296
309
297
- if err == nil {
298
- // ensure user's role align with latest essential permission when user found
299
- if _ , err := r .ensureAkoUserRole (); err != nil {
300
- return nil , err
310
+ // ensure user's role align with latest essential permission when user found
311
+ if _ , err := r .ensureAkoUserRole (log , version ); err != nil {
312
+ return err
313
+ }
314
+ // Update the password when user found, this is needed when the AVI user was
315
+ // created before the mc Secret. And this operation will sync
316
+ // the User's password to be the same as mc Secret's
317
+ if * aviUser .Password != aviPassword {
318
+ log .Info ("AVI User found, updating the password" )
319
+ if _ , err := r .aviClient .UserUpdate (aviUser ); err != nil {
320
+ return err
301
321
}
302
- // Update the password when user found, this is needed when the AVI user was
303
- // created before the mc Secret. And this operation will sync
304
- // the User's password to be the same as mc Secret's
305
- aviUser .Password = & aviPassword
306
- return r .aviClient .UserUpdate (aviUser )
307
322
}
308
- return nil , err
323
+ return nil
309
324
}
310
325
311
326
// getOrCreateAkoUserRole get ako user's role, create one if not exist
312
- func (r * AkoUserReconciler ) getOrCreateAkoUserRole (roleTenantRef * string ) (* models.Role , error ) {
327
+ func (r * AkoUserReconciler ) getOrCreateAkoUserRole (log logr.Logger , roleTenantRef * string , version string ) (* models.Role , error ) {
328
+ log .V (3 ).Info ("Ensure AKO User Role" )
313
329
role , err := r .aviClient .RoleGetByName (akoov1alpha1 .AkoUserRoleName )
314
330
// not found ako user role, create one
315
331
if aviclient .IsAviRoleNonExistentError (err ) {
332
+ log .V (3 ).Info ("Creating AKO User Role since it's not found" , "role" , akoov1alpha1 .AkoUserRoleName )
333
+ log .Info ("current avi version" , "version" , version )
316
334
role = & models.Role {
317
335
Name : ptr .To (akoov1alpha1 .AkoUserRoleName ),
318
- Privileges : AkoRolePermission ,
336
+ Privileges : filterAkoRolePermissionByVersion ( log , AkoRolePermission , version ) ,
319
337
TenantRef : roleTenantRef ,
320
338
}
321
339
return r .aviClient .RoleCreate (role )
322
340
}
323
341
if err == nil {
324
- return r .ensureAkoUserRole ()
342
+ return r .ensureAkoUserRole (log , version )
325
343
}
326
344
return role , err
327
345
}
328
346
329
347
// ensureAkoUserRole ensure ako-essential-role has the latest permission
330
- func (r * AkoUserReconciler ) ensureAkoUserRole () (* models.Role , error ) {
348
+ func (r * AkoUserReconciler ) ensureAkoUserRole (log logr. Logger , version string ) (* models.Role , error ) {
331
349
role , err := r .aviClient .RoleGetByName (akoov1alpha1 .AkoUserRoleName )
332
350
if err != nil {
333
351
return role , err
334
352
}
335
353
336
354
// check if role needs to be synced
337
- if syncAkoUserRole (role ) {
355
+ if syncAkoUserRole (role , version ) {
356
+ log .Info ("Syncing AKO User Role with expected permissions" )
338
357
return r .aviClient .RoleUpdate (role )
339
358
}
340
359
@@ -346,15 +365,18 @@ func (r *AkoUserReconciler) ensureAkoUserRole() (*models.Role, error) {
346
365
// Any additional permissions on the Role that are not part of
347
366
// the desired AKO role are left as-is. It returns a bool
348
367
// indicating whether the Role was changed.
349
- func syncAkoUserRole (role * models.Role ) bool {
368
+ // It also filters out permissions that are deprecated in the current AVI version.
369
+ func syncAkoUserRole (role * models.Role , version string ) bool {
350
370
existingResources := sets .New [string ]()
351
371
updated := false
352
372
353
373
for i , permission := range role .Privileges {
354
374
desiredType , ok := AkoRolePermissionMap [* permission .Resource ]
355
375
if ! ok {
356
- // Existing AVI role has a permission that's not part of
357
- // the desired AKO role: leave it as-is.
376
+ // Existing AVI role in AVI Controller has a permission that's not part of
377
+ // the desired AKO role defined in AkoRolePermissionMap: leave it as-is.
378
+ // Since those could come from a new AVI Controller version that AKO-Operator
379
+ // Might not be aware of.
358
380
continue
359
381
}
360
382
@@ -370,6 +392,11 @@ func syncAkoUserRole(role *models.Role) bool {
370
392
371
393
for resource , desiredType := range AkoRolePermissionMap {
372
394
if ! existingResources .Has (resource ) {
395
+ // Filter out permissions that are deprecated in the current AVI version.
396
+ if deprecateVersion , ok := deprecatePermissionMap [resource ]; ok && semver .Compare (version , deprecateVersion ) >= 0 {
397
+ // Skip adding deprecated permissions to the role
398
+ continue
399
+ }
373
400
// Existing AVI role is missing a permission that's
374
401
// part of the desired AKO role: add it.
375
402
role .Privileges = append (role .Privileges , & models.Permission {
0 commit comments