Skip to content

Commit

Permalink
feat: support label/selector change of employee/employer in resource … (
Browse files Browse the repository at this point in the history
#106)

* feat: support label/selector change of employee/employer in resource consist controller

* fix: remove unused recordedNotSelected map and correct slice comparison
  • Loading branch information
WeichengWang1 committed Oct 16, 2023
1 parent 1817bcb commit ba66d0b
Show file tree
Hide file tree
Showing 6 changed files with 426 additions and 64 deletions.
13 changes: 9 additions & 4 deletions pkg/controllers/alibabacloudslb/alibabacloudslb_controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
)

var _ resourceconsist.ReconcileAdapter = &ReconcileAdapter{}
var _ resourceconsist.ReconcileLifecycleOptions = &ReconcileAdapter{}

type ReconcileAdapter struct {
client.Client
Expand All @@ -49,12 +50,16 @@ func NewReconcileAdapter(c client.Client) (*ReconcileAdapter, error) {
}, nil
}

func (r *ReconcileAdapter) GetControllerName() string {
return "alibaba-cloud-slb-controller"
func (r *ReconcileAdapter) FollowPodOpsLifeCycle() bool {
return true
}

func (r *ReconcileAdapter) NeedRecordEmployees() bool {
return true
}

func (r *ReconcileAdapter) NotFollowPodOpsLifeCycle() bool {
return false
func (r *ReconcileAdapter) GetControllerName() string {
return "alibaba-cloud-slb-controller"
}

func (r *ReconcileAdapter) GetExpectedEmployer(ctx context.Context, employer client.Object) ([]resourceconsist.IEmployer, error) {
Expand Down
59 changes: 57 additions & 2 deletions pkg/controllers/resourceconsist/consister.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import (
"context"
"encoding/json"
"fmt"
"reflect"
"sort"
"strings"

corev1 "k8s.io/api/core/v1"
Expand Down Expand Up @@ -201,13 +203,64 @@ func (r *Consist) syncEmployees(ctx context.Context, employer client.Object, exp
toAddLifecycleFlzEmployees, toDeleteLifecycleFlzEmployees := r.getToAddDeleteLifecycleFlzEmployees(
succCreate, succDelete, succUpdate, toCudEmployees.Unchanged)

lifecycleOptions, lifecycleOptionsImplemented := r.adapter.(ReconcileLifecycleOptions)
needRecordEmployees := lifecycleOptionsImplemented && lifecycleOptions.FollowPodOpsLifeCycle() && lifecycleOptions.NeedRecordEmployees()
if needRecordEmployees {
if employer.GetAnnotations()[lifecycleFinalizerRecordedAnnoKey] != "" {
selectedEmployees, err := r.adapter.GetSelectedEmployeeNames(ctx, employer)
if err != nil {
return false, false, fmt.Errorf("GetSelectedEmployeeNames failed, err: %s", err.Error())
}
recordedEmployees := strings.Split(employer.GetAnnotations()[lifecycleFinalizerRecordedAnnoKey], ",")
selectedSet := sets.NewString(selectedEmployees...)
for _, recordedEmployee := range recordedEmployees {
if !selectedSet.Has(recordedEmployee) {
toDeleteLifecycleFlzEmployees = append(toDeleteLifecycleFlzEmployees, recordedEmployee)
}
}
}
}

ns := employer.GetNamespace()
lifecycleFlz := GenerateLifecycleFinalizer(employer.GetName())
err = r.ensureLifecycleFinalizer(ctx, ns, lifecycleFlz, toAddLifecycleFlzEmployees, toDeleteLifecycleFlzEmployees)
if err != nil {
return false, false, fmt.Errorf("ensureLifecycleFinalizer failed, err: %s", err.Error())
}

if needRecordEmployees {
needUpdate := false
if employer.GetAnnotations()[lifecycleFinalizerRecordedAnnoKey] == "" {
if len(toAddLifecycleFlzEmployees) != 0 {
needUpdate = true
}
} else {
recordedEmployees := strings.Split(employer.GetAnnotations()[lifecycleFinalizerRecordedAnnoKey], ",")
if len(recordedEmployees) != len(toAddLifecycleFlzEmployees) {
needUpdate = true
} else {
sort.Strings(recordedEmployees)
sort.Strings(toAddLifecycleFlzEmployees)
if !reflect.DeepEqual(recordedEmployees, toAddLifecycleFlzEmployees) {
needUpdate = true
}
}
}
if needUpdate {
patch := client.MergeFrom(employer.DeepCopyObject().(client.Object))
annos := employer.GetAnnotations()
if annos == nil {
annos = make(map[string]string)
}
annos[lifecycleFinalizerRecordedAnnoKey] = strings.Join(toAddLifecycleFlzEmployees, ",")
employer.SetAnnotations(annos)
err = r.Client.Patch(ctx, employer, patch)
if err != nil {
return false, false, fmt.Errorf("patch lifecycleFinalizerRecordedAnno failed, err: %s", err.Error())
}
}
}

isClean := len(toCudEmployees.ToCreate) == 0 && len(toCudEmployees.ToUpdate) == 0 && len(toCudEmployees.Unchanged) == 0 && len(failDelete) == 0
cudFailedExist := len(failCreate) > 0 || len(failUpdate) > 0 || len(failDelete) > 0
return isClean, cudFailedExist, nil
Expand All @@ -217,7 +270,8 @@ func (r *Consist) syncEmployees(ctx context.Context, employer client.Object, exp
func (r *Consist) ensureExpectedFinalizer(ctx context.Context, employer client.Object) (bool, error) {
// employee is not pod or not follow PodOpsLifecycle
watchOptions, watchOptionsImplemented := r.adapter.(ReconcileWatchOptions)
if r.adapter.NotFollowPodOpsLifeCycle() || (watchOptionsImplemented && !isPod(watchOptions.NewEmployee())) {
lifecycleOptions, lifecycleOptionsImplemented := r.adapter.(ReconcileLifecycleOptions)
if (lifecycleOptionsImplemented && !lifecycleOptions.FollowPodOpsLifeCycle()) || (watchOptionsImplemented && !isPod(watchOptions.NewEmployee())) {
return true, nil
}

Expand Down Expand Up @@ -550,7 +604,8 @@ func (r *Consist) getToAddDeleteLifecycleFlzEmployees(succCreate, succDelete, su

watchOptions, watchOptionsImplemented := r.adapter.(ReconcileWatchOptions)

if r.adapter.NotFollowPodOpsLifeCycle() || (watchOptionsImplemented && !isPod(watchOptions.NewEmployee())) {
lifecycleOptions, lifecycleOptionsImplemented := r.adapter.(ReconcileLifecycleOptions)
if (lifecycleOptionsImplemented && !lifecycleOptions.FollowPodOpsLifeCycle()) || (watchOptionsImplemented && !isPod(watchOptions.NewEmployee())) {
return toAddLifecycleFlz[:toAddIdx], toDeleteLifecycleFlz[:toDeleteIdx]
}

Expand Down
7 changes: 4 additions & 3 deletions pkg/controllers/resourceconsist/consts.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ limitations under the License.
package resourceconsist

const (
defaultMaxConcurrentReconciles = 5
expectedFinalizerAddedAnnoKey = "resource-consist.kusionstack.io/employees-expected-finalizer-added"
cleanFinalizerPrefix = "resource-consist.kusionstack.io/clean-"
defaultMaxConcurrentReconciles = 5
expectedFinalizerAddedAnnoKey = "resource-consist.kusionstack.io/employees-expected-finalizer-added"
lifecycleFinalizerRecordedAnnoKey = "resource-consist.kusionstack.io/employees-lifecycle-finalizer-recorded"
cleanFinalizerPrefix = "resource-consist.kusionstack.io/clean-"
)
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,9 @@ type DemoReconcile struct {
}

var _ ReconcileAdapter = &DemoReconcile{}
var _ ReconcileLifecycleOptions = &DemoReconcile{}

var needRecordEmployees = false

func NewDemoReconcileAdapter(c client.Client, rc *DemoResourceProviderClient) *DemoReconcile {
return &DemoReconcile{
Expand All @@ -42,6 +45,14 @@ func NewDemoReconcileAdapter(c client.Client, rc *DemoResourceProviderClient) *D
}
}

func (r *DemoReconcile) FollowPodOpsLifeCycle() bool {
return true
}

func (r *DemoReconcile) NeedRecordEmployees() bool {
return needRecordEmployees
}

func (r *DemoReconcile) GetSelectedEmployeeNames(ctx context.Context, employer client.Object) ([]string, error) {
svc, ok := employer.(*corev1.Service)
if !ok {
Expand All @@ -66,10 +77,6 @@ func (r *DemoReconcile) GetControllerName() string {
return "demo-controller"
}

func (r *DemoReconcile) NotFollowPodOpsLifeCycle() bool {
return false
}

func (r *DemoReconcile) GetExpectedEmployer(ctx context.Context, employer client.Object) ([]IEmployer, error) {
if !employer.GetDeletionTimestamp().IsZero() {
return nil, nil
Expand Down
Loading

0 comments on commit ba66d0b

Please sign in to comment.