Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/codespell.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- name: Harden Runner
uses: step-security/harden-runner@c6295a65d1254861815972266d5933fd6e532bdf # v2.11.1
uses: step-security/harden-runner@0634a2670c59f64b4a01f0f96f84700a4088b9f0 # v2.12.0
with:
egress-policy: audit

Expand Down
10 changes: 10 additions & 0 deletions pkg/controllers/rollout/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -1095,6 +1095,15 @@ func handleCRP(newCRPObj, oldCRPObj client.Object, q workqueue.TypedRateLimiting
return
}

// Check if the rollout strategy type has been updated.
if newCRP.Spec.Strategy.Type != oldCRP.Spec.Strategy.Type {
klog.V(2).InfoS("Detected an update to the rollout strategy type on the CRP", "clusterResourcePlacement", klog.KObj(newCRP))
q.Add(reconcile.Request{
NamespacedName: types.NamespacedName{Name: newCRP.GetName()},
})
return
}

// Check if the apply strategy has been updated.
newApplyStrategy := newCRP.Spec.Strategy.ApplyStrategy
oldApplyStrategy := oldCRP.Spec.Strategy.ApplyStrategy
Expand All @@ -1103,6 +1112,7 @@ func handleCRP(newCRPObj, oldCRPObj client.Object, q workqueue.TypedRateLimiting
q.Add(reconcile.Request{
NamespacedName: types.NamespacedName{Name: newCRP.GetName()},
})
return
}

klog.V(2).InfoS("No update to apply strategy detected; ignore the CRP Update event", "clusterResourcePlacement", klog.KObj(newCRP))
Expand Down
383 changes: 217 additions & 166 deletions pkg/controllers/rollout/controller_integration_test.go

Large diffs are not rendered by default.

5 changes: 4 additions & 1 deletion pkg/controllers/workgenerator/controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -1280,8 +1280,11 @@ func extractResFromConfigMap(uConfigMap *unstructured.Unstructured) ([]fleetv1be
klog.ErrorS(unMarshallErr, "manifest has invalid content", "manifestKey", key, "envelopeResource", klog.KObj(uConfigMap))
return nil, fmt.Errorf("the object with manifest key `%s` in envelope config `%s` is malformatted, err: %w", key, klog.KObj(uConfigMap), unMarshallErr)
}
if len(uManifest.GetNamespace()) == 0 {
// Block cluster-scoped resources.
return nil, fmt.Errorf("cannot wrap cluster-scoped resource %s in the envelope %s", uManifest.GetName(), klog.KObj(uConfigMap))
}
if len(uManifest.GetNamespace()) != 0 && uManifest.GetNamespace() != configMap.Namespace {
// if the manifest is a namespaced object but no namespace is specified, it will fail at the apply time instead of here.
return nil, fmt.Errorf("the namespaced object `%s` in envelope config `%s` is placed in a different namespace `%s` ", uManifest.GetName(), klog.KObj(uConfigMap), uManifest.GetNamespace())
}
manifests = append(manifests, fleetv1beta1.Manifest{
Expand Down
3 changes: 1 addition & 2 deletions pkg/controllers/workgenerator/controller_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -698,7 +698,6 @@ var _ = Describe("Test Work Generator Controller", func() {
Workload: placementv1beta1.WorkloadTemplate{
Manifests: []placementv1beta1.Manifest{
{RawExtension: runtime.RawExtension{Raw: testEnvelopeResourceQuota}},
{RawExtension: runtime.RawExtension{Raw: testEnvelopeWebhook}},
},
},
},
Expand Down Expand Up @@ -823,7 +822,7 @@ var _ = Describe("Test Work Generator Controller", func() {
Spec: placementv1beta1.WorkSpec{
Workload: placementv1beta1.WorkloadTemplate{
Manifests: []placementv1beta1.Manifest{
{RawExtension: runtime.RawExtension{Raw: testEnvelopeWebhook}},
{RawExtension: runtime.RawExtension{Raw: testEnvelopeResourceQuota2}},
},
},
},
Expand Down
26 changes: 20 additions & 6 deletions pkg/controllers/workgenerator/controller_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,23 @@ func TestExtractResFromConfigMap(t *testing.T) {
want: nil,
wantErr: true,
},
"config map with cluster scoped resource should fail": {
uConfigMap: &unstructured.Unstructured{
Object: map[string]interface{}{
"apiVersion": "v1",
"kind": "ConfigMap",
"metadata": map[string]interface{}{
"name": "test-config",
"namespace": "default",
},
"data": map[string]interface{}{
"resource": `{"apiVersion": "admissionregistration.k8s.io/v1", "kind": "ValidatingWebhookConfiguration", "metadata": {"name": "test-webhook"}}`,
},
},
},
want: nil,
wantErr: true,
},
"config map with valid and invalid entries should fail": {
uConfigMap: &unstructured.Unstructured{
Object: map[string]interface{}{
Expand All @@ -226,7 +243,7 @@ func TestExtractResFromConfigMap(t *testing.T) {
want: nil,
wantErr: true,
},
"config map with cluster and namespace scoped data in the correct namespace should pass": {
"config map with cluster and namespace scoped data in the correct namespace should fail": {
uConfigMap: &unstructured.Unstructured{
Object: map[string]interface{}{
"apiVersion": "v1",
Expand All @@ -241,11 +258,8 @@ func TestExtractResFromConfigMap(t *testing.T) {
},
},
},
want: []fleetv1beta1.Manifest{
{RawExtension: runtime.RawExtension{Raw: []byte(`{"apiVersion": "v1", "kind": "Pod", "metadata": {"name": "test-pod", "namespace": "default"}}`)}},
{RawExtension: runtime.RawExtension{Raw: []byte(`{"apiVersion": "v1", "kind": "ClusterRole", "metadata": {"name": "test-role"}}`)}},
},
wantErr: false,
want: nil,
wantErr: true,
},
"config map with cluster scoped and cross namespaced resources data in a different namespace should fail": {
uConfigMap: &unstructured.Unstructured{
Expand Down
11 changes: 11 additions & 0 deletions pkg/controllers/workgenerator/manifests/resourcequota2.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
apiVersion: v1
kind: ResourceQuota
metadata:
name: mem-cpu-demo
namespace: app
spec:
hard:
requests.cpu: "2"
requests.memory: 2Gi
limits.cpu: "4"
limits.memory: 4Gi
Original file line number Diff line number Diff line change
Expand Up @@ -18,34 +18,3 @@ data:
requests.memory: 1Gi
limits.cpu: "2"
limits.memory: 2Gi
webhook.yaml: |
apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
metadata:
creationTimestamp: null
labels:
azure-workload-identity.io/system: "true"
name: azure-wi-webhook-mutating-webhook-configuration
webhooks:
- admissionReviewVersions:
- v1
- v1beta1
clientConfig:
service:
name: azure-wi-webhook-webhook-service
namespace: app
path: /mutate-v1-pod
failurePolicy: Fail
matchPolicy: Equivalent
name: mutation.azure-workload-identity.io
rules:
- apiGroups:
- ""
apiVersions:
- v1
operations:
- CREATE
- UPDATE
resources:
- pods
sideEffects: None
Original file line number Diff line number Diff line change
Expand Up @@ -6,34 +6,15 @@ metadata:
annotations:
kubernetes-fleet.io/envelope-configmap: "true"
data:
webhook.yaml: |
apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
resourceQuota.yaml: |
apiVersion: v1
kind: ResourceQuota
metadata:
creationTimestamp: null
labels:
azure-workload-identity.io/system: "true"
name: azure-wi-webhook-mutating-webhook-configuration
webhooks:
- admissionReviewVersions:
- v1
- v1beta1
clientConfig:
service:
name: azure-wi-webhook-webhook-service
namespace: app
path: /mutate-v1-pod
failurePolicy: Fail
matchPolicy: Equivalent
name: mutation.azure-workload-identity.io
rules:
- apiGroups:
- ""
apiVersions:
- v1
operations:
- CREATE
- UPDATE
resources:
- pods
sideEffects: None
name: mem-cpu-demo
namespace: app
spec:
hard:
requests.cpu: "2"
requests.memory: 2Gi
limits.cpu: "4"
limits.memory: 4Gi
14 changes: 7 additions & 7 deletions pkg/controllers/workgenerator/suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ var (
wantOverriddenTestResource []byte

// the content of the enveloped resources
testEnvelopeWebhook, testEnvelopeResourceQuota []byte
testEnvelopeResourceQuota, testEnvelopeResourceQuota2 []byte
)

func TestAPIs(t *testing.T) {
Expand Down Expand Up @@ -365,15 +365,15 @@ func readTestManifests() {
testPdb, err = yaml.ToJSON(rawByte)
Expect(err).Should(Succeed())

By("Read EnvelopeWebhook")
rawByte, err = os.ReadFile("manifests/webhook.yaml")
Expect(err).Should(Succeed())
testEnvelopeWebhook, err = yaml.ToJSON(rawByte)
Expect(err).Should(Succeed())

By("Read ResourceQuota")
rawByte, err = os.ReadFile("manifests/resourcequota.yaml")
Expect(err).Should(Succeed())
testEnvelopeResourceQuota, err = yaml.ToJSON(rawByte)
Expect(err).Should(Succeed())

By("Read ResourceQuota2")
rawByte, err = os.ReadFile("manifests/resourcequota2.yaml")
Expect(err).Should(Succeed())
testEnvelopeResourceQuota2, err = yaml.ToJSON(rawByte)
Expect(err).Should(Succeed())
}
21 changes: 15 additions & 6 deletions test/e2e/actuals_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -613,7 +613,11 @@ func resourcePlacementOverrideFailedConditions(generation int64) []metav1.Condit
}
}

func resourcePlacementWorkSynchronizedFailedConditions(generation int64) []metav1.Condition {
func resourcePlacementWorkSynchronizedFailedConditions(generation int64, hasOverrides bool) []metav1.Condition {
overridenCondReason := condition.OverrideNotSpecifiedReason
if hasOverrides {
overridenCondReason = condition.OverriddenSucceededReason
}
return []metav1.Condition{
{
Type: string(placementv1beta1.ResourceScheduledConditionType),
Expand All @@ -631,7 +635,7 @@ func resourcePlacementWorkSynchronizedFailedConditions(generation int64) []metav
Type: string(placementv1beta1.ResourceOverriddenConditionType),
Status: metav1.ConditionTrue,
ObservedGeneration: generation,
Reason: condition.OverriddenSucceededReason,
Reason: overridenCondReason,
},
{
Type: string(placementv1beta1.ResourceWorkSynchronizedConditionType),
Expand All @@ -642,7 +646,11 @@ func resourcePlacementWorkSynchronizedFailedConditions(generation int64) []metav
}
}

func crpWorkSynchronizedFailedConditions(generation int64) []metav1.Condition {
func crpWorkSynchronizedFailedConditions(generation int64, hasOverrides bool) []metav1.Condition {
overridenCondReason := condition.OverrideNotSpecifiedReason
if hasOverrides {
overridenCondReason = condition.OverriddenSucceededReason
}
return []metav1.Condition{
{
Type: string(placementv1beta1.ClusterResourcePlacementScheduledConditionType),
Expand All @@ -659,7 +667,7 @@ func crpWorkSynchronizedFailedConditions(generation int64) []metav1.Condition {
{
Type: string(placementv1beta1.ClusterResourcePlacementOverriddenConditionType),
Status: metav1.ConditionTrue,
Reason: condition.OverriddenSucceededReason,
Reason: overridenCondReason,
ObservedGeneration: generation,
},
{
Expand Down Expand Up @@ -782,17 +790,18 @@ func crpStatusWithWorkSynchronizedUpdatedFailedActual(
}

var wantPlacementStatus []placementv1beta1.ResourcePlacementStatus
hasOverrides := len(wantResourceOverrides) > 0 || len(wantClusterResourceOverrides) > 0
for _, name := range wantSelectedClusters {
wantPlacementStatus = append(wantPlacementStatus, placementv1beta1.ResourcePlacementStatus{
ClusterName: name,
Conditions: resourcePlacementWorkSynchronizedFailedConditions(crp.Generation),
Conditions: resourcePlacementWorkSynchronizedFailedConditions(crp.Generation, hasOverrides),
ApplicableResourceOverrides: wantResourceOverrides,
ApplicableClusterResourceOverrides: wantClusterResourceOverrides,
})
}

wantStatus := placementv1beta1.ClusterResourcePlacementStatus{
Conditions: crpWorkSynchronizedFailedConditions(crp.Generation),
Conditions: crpWorkSynchronizedFailedConditions(crp.Generation, hasOverrides),
PlacementStatuses: wantPlacementStatus,
SelectedResources: wantSelectedResourceIdentifiers,
ObservedResourceIndex: wantObservedResourceIndex,
Expand Down
Loading
Loading