From e029576875cc579b030a2dd81012a34a7f81624b Mon Sep 17 00:00:00 2001 From: Ryan Zhang Date: Tue, 13 Aug 2024 17:16:59 -0700 Subject: [PATCH] add take over and drift detection options --- .github/workflows/ci.yml | 8 +- .../v1beta1/clusterresourceplacement_types.go | 73 ++++++++++++++++++- .../v1beta1/zz_generated.deepcopy.go | 38 +++++++++- ...es-fleet.io_clusterresourceplacements.yaml | 36 ++++++++- go.mod | 4 +- go.sum | 8 +- 6 files changed, 151 insertions(+), 16 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5178a0a67..8416d2ecc 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -44,7 +44,7 @@ jobs: - name: Set up Ginkgo CLI run: | - go install github.com/onsi/ginkgo/v2/ginkgo@v2.9.5 + go install github.com/onsi/ginkgo/v2/ginkgo@v2.19.1 - name: Run unit tests & Generate coverage run: make test @@ -86,7 +86,7 @@ jobs: HUB_SERVER_URL: 'https://172.19.0.2:6443' e2e-tests: - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 needs: [ detect-noop, ] @@ -102,13 +102,13 @@ jobs: - name: Install Ginkgo CLI run: | - go install github.com/onsi/ginkgo/v2/ginkgo@v2.13.0 + go install github.com/onsi/ginkgo/v2/ginkgo@v2.19.1 - name: Install Kind # Before updating the kind version to use, verify that the current kind image # is still supported by the version. run: | - go install sigs.k8s.io/kind@v0.20.0 + go install sigs.k8s.io/kind@v0.22.0 - name: Run e2e tests run: | diff --git a/apis/placement/v1beta1/clusterresourceplacement_types.go b/apis/placement/v1beta1/clusterresourceplacement_types.go index 6e1f22b70..1924d7357 100644 --- a/apis/placement/v1beta1/clusterresourceplacement_types.go +++ b/apis/placement/v1beta1/clusterresourceplacement_types.go @@ -420,12 +420,81 @@ type RolloutStrategy struct { // +optional RollingUpdate *RollingUpdateConfig `json:"rollingUpdate,omitempty"` - // ApplyStrategy describes how to resolve the conflict if the resource to be placed already exists in the target cluster - // and is owned by other appliers. + // ConflictResolutionStrategy describes how to resolve conflicts if the resource to be placed already exists in the target cluster. + // +optional + ConflictResolutionStrategy *ConflictResolutionStrategy `json:"conflictResolutionStrategy,omitempty"` + + // ApplyStrategy describes how to apply the resource to the target cluster. // +optional ApplyStrategy *ApplyStrategy `json:"applyStrategy,omitempty"` } +// ConflictResolutionStrategy describes the strategy used to resolve the conflict if the resource +// to be placed already exists in the target cluster. +type ConflictResolutionStrategy struct { + // type describes the type of the strategy used to resolve the conflict + // +kubebuilder:default=AlwaysApply + // +kubebuilder:validation:Enum=AlwaysApply;Report;ApplyIfNoDiff;Recreate + // +optional + Type ConflictResolutionType `json:"type,omitempty"` + + // DiffCalculateStrategy describes how to calculate the diff between the resource on + // the hub cluster and the existing resources on the member cluster. + // +optional + DiffCalculateStrategy DiffCalculateStrategy `json:"whenToDeclearDiff,omitempty"` +} + +// ConflictResolutionType describes the type of the strategy used to resolve the conflict +// if the resource to be placed already exists in the target cluster. +// +enum +type ConflictResolutionType string + +const ( + // ConflictResolutionTypeReport will report the conflict and fail the apply. + ConflictResolutionTypeReport ConflictResolutionType = "Report" + + // ConflictResolutionTypeApplyIfNoDiff will apply the yaml from hub cluster using the + // applyStrategy if there is no difference between the resource on the hub cluster and + // the existing resources on the member cluster. + ConflictResolutionTypeApplyIfNoDiff ConflictResolutionType = "ApplyIfNoDiff" + + // ConflictResolutionTypeAlwaysApply will always apply the resource to the member cluster. + ConflictResolutionTypeAlwaysApply ConflictResolutionType = "AlwaysApply" + + // ConflictResolutionTypeRecreate will delete and recreate the resource based on the hub cluster + // resource manifest to the member cluster. + ConflictResolutionTypeRecreate ConflictResolutionType = "Recreate" +) + +// DiffCalculateStrategy describes how to calculate the diff between the resource on the +// hub cluster and the existing resources on the member cluster. +type DiffCalculateStrategy struct { + // type describes the type of the strategy used to calculate the diff. + // +kubebuilder:default=Never + // +kubebuilder:validation:Enum=Never;ExistingFieldDiffOnly;Recreate + // +optional + Type DiffCalculateStrategyType `json:"type,omitempty"` +} + +// DiffCalculateStrategyType describes the type of the strategy used to calculate the diff. +// +enum +type DiffCalculateStrategyType string + +const ( + // DiffCalculateStrategyTypeNever will never calculate the diff between the resource on the hub cluster + // and the existing resources on the member cluster. + DiffCalculateStrategyTypeNever DiffCalculateStrategyType = "Never" + + // DiffCalculateStrategyTypeHubFieldsOnly will calculate the diff between the resource on the hub cluster + // and the existing resources on the member cluster but the diff will be calculated only on + // the fields that are present in the hub cluster resource manifest. + DiffCalculateStrategyTypeHubFieldsOnly DiffCalculateStrategyType = "HubFieldsOnly" + + // DiffCalculateStrategyTypeAllFields will calculate the diff between the resource on the hub cluster + // and the existing resources on the member cluster on all fields. + DiffCalculateStrategyTypeAllFields DiffCalculateStrategyType = "AllFields" +) + // ApplyStrategy describes how to resolve the conflict if the resource to be placed already exists in the target cluster // and whether it's allowed to be co-owned by other non-fleet appliers. // Note: If multiple CRPs try to place the same resource with different apply strategy, the later ones will fail with the diff --git a/apis/placement/v1beta1/zz_generated.deepcopy.go b/apis/placement/v1beta1/zz_generated.deepcopy.go index 4c48828e9..98f400f09 100644 --- a/apis/placement/v1beta1/zz_generated.deepcopy.go +++ b/apis/placement/v1beta1/zz_generated.deepcopy.go @@ -10,7 +10,7 @@ Licensed under the MIT license. package v1beta1 import ( - v1 "k8s.io/apimachinery/pkg/apis/meta/v1" + "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/runtime" "k8s.io/apimachinery/pkg/util/intstr" ) @@ -614,6 +614,37 @@ func (in *ClusterSelectorTerm) DeepCopy() *ClusterSelectorTerm { return out } +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *ConflictResolutionStrategy) DeepCopyInto(out *ConflictResolutionStrategy) { + *out = *in + out.DiffCalculateStrategy = in.DiffCalculateStrategy +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new ConflictResolutionStrategy. +func (in *ConflictResolutionStrategy) DeepCopy() *ConflictResolutionStrategy { + if in == nil { + return nil + } + out := new(ConflictResolutionStrategy) + in.DeepCopyInto(out) + return out +} + +// DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. +func (in *DiffCalculateStrategy) DeepCopyInto(out *DiffCalculateStrategy) { + *out = *in +} + +// DeepCopy is an autogenerated deepcopy function, copying the receiver, creating a new DiffCalculateStrategy. +func (in *DiffCalculateStrategy) DeepCopy() *DiffCalculateStrategy { + if in == nil { + return nil + } + out := new(DiffCalculateStrategy) + in.DeepCopyInto(out) + return out +} + // DeepCopyInto is an autogenerated deepcopy function, copying the receiver, writing into out. in must be non-nil. func (in *EnvelopeIdentifier) DeepCopyInto(out *EnvelopeIdentifier) { *out = *in @@ -1032,6 +1063,11 @@ func (in *RolloutStrategy) DeepCopyInto(out *RolloutStrategy) { *out = new(RollingUpdateConfig) (*in).DeepCopyInto(*out) } + if in.ConflictResolutionStrategy != nil { + in, out := &in.ConflictResolutionStrategy, &out.ConflictResolutionStrategy + *out = new(ConflictResolutionStrategy) + **out = **in + } if in.ApplyStrategy != nil { in, out := &in.ApplyStrategy, &out.ApplyStrategy *out = new(ApplyStrategy) diff --git a/config/crd/bases/placement.kubernetes-fleet.io_clusterresourceplacements.yaml b/config/crd/bases/placement.kubernetes-fleet.io_clusterresourceplacements.yaml index fa2b10f7c..ea1e7131e 100644 --- a/config/crd/bases/placement.kubernetes-fleet.io_clusterresourceplacements.yaml +++ b/config/crd/bases/placement.kubernetes-fleet.io_clusterresourceplacements.yaml @@ -1753,9 +1753,8 @@ spec: with new ones. properties: applyStrategy: - description: |- - ApplyStrategy describes how to resolve the conflict if the resource to be placed already exists in the target cluster - and is owned by other appliers. + description: ApplyStrategy describes how to apply the resource + to the target cluster. properties: allowCoOwnership: description: |- @@ -1791,6 +1790,37 @@ spec: - ServerSideApply type: string type: object + conflictResolutionStrategy: + description: ConflictResolutionStrategy describes how to resolve + conflicts if the resource to be placed already exists in the + target cluster. + properties: + type: + default: AlwaysApply + description: type describes the type of the strategy used + to resolve the conflict + enum: + - AlwaysApply + - Report + - ApplyIfNoDiff + - Recreate + type: string + whenToDeclearDiff: + description: |- + DiffCalculateStrategy describes how to calculate the diff between the resource on + the hub cluster and the existing resources on the member cluster. + properties: + type: + default: Never + description: type describes the type of the strategy used + to calculate the diff. + enum: + - Never + - ExistingFieldDiffOnly + - Recreate + type: string + type: object + type: object rollingUpdate: description: Rolling update config params. Present only if RolloutStrategyType = RollingUpdate. diff --git a/go.mod b/go.mod index 2b3daf637..420801fbd 100644 --- a/go.mod +++ b/go.mod @@ -10,8 +10,8 @@ require ( github.com/evanphx/json-patch/v5 v5.9.0 github.com/go-logr/logr v1.4.2 github.com/google/go-cmp v0.6.0 - github.com/onsi/ginkgo/v2 v2.17.2 - github.com/onsi/gomega v1.33.1 + github.com/onsi/ginkgo/v2 v2.19.1 + github.com/onsi/gomega v1.34.0 github.com/prometheus/client_golang v1.19.1 github.com/prometheus/client_model v0.6.1 github.com/spf13/cobra v1.8.0 diff --git a/go.sum b/go.sum index ed130d06b..bd56c50fc 100644 --- a/go.sum +++ b/go.sum @@ -149,10 +149,10 @@ github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9G github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA= github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ= -github.com/onsi/ginkgo/v2 v2.17.2 h1:7eMhcy3GimbsA3hEnVKdw/PQM9XN9krpKVXsZdph0/g= -github.com/onsi/ginkgo/v2 v2.17.2/go.mod h1:nP2DPOQoNsQmsVyv5rDA8JkXQoCs6goXIvr/PRJ1eCc= -github.com/onsi/gomega v1.33.1 h1:dsYjIxxSR755MDmKVsaFQTE22ChNBcuuTWgkUDSubOk= -github.com/onsi/gomega v1.33.1/go.mod h1:U4R44UsT+9eLIaYRB2a5qajjtQYn0hauxvRm16AVYg0= +github.com/onsi/ginkgo/v2 v2.19.1 h1:QXgq3Z8Crl5EL1WBAC98A5sEBHARrAJNzAmMxzLcRF0= +github.com/onsi/ginkgo/v2 v2.19.1/go.mod h1:O3DtEWQkPa/F7fBMgmZQKKsluAy8pd3rEQdrjkPb9zA= +github.com/onsi/gomega v1.34.0 h1:eSSPsPNp6ZpsG8X1OVmOTxig+CblTc4AxpPBykhe2Os= +github.com/onsi/gomega v1.34.0/go.mod h1:MIKI8c+f+QLWk+hxbePD4i0LMJSExPaZOVfkoex4cAo= github.com/patrickmn/go-cache v2.1.0+incompatible h1:HRMgzkcYKYpi3C8ajMPV8OFXaaRUnok+kx1WdO15EQc= github.com/patrickmn/go-cache v2.1.0+incompatible/go.mod h1:3Qf8kWWT7OJRJbdiICTKqZju1ZixQ/KpMGzzAfe6+WQ= github.com/pkg/browser v0.0.0-20240102092130-5ac0b6a4141c h1:+mdjkGKdHQG3305AYmdv1U2eRNDiU2ErMBj1gwrq8eQ=