-
Notifications
You must be signed in to change notification settings - Fork 12
🐛 Stage AgentRuns inherit the parent AgentWorkflowRun's labels #113
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,6 @@ | ||
| kind: bugfix | ||
|
|
||
| description: > | ||
| Stage AgentRuns now inherit all of the parent AgentWorkflowRun's labels | ||
| (controller-owned keys still win), so label-selector queries such as | ||
| konveyor.io/application match the runs that actually execute. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -58,8 +58,9 @@ func waitForWorkflowReady(workflowName string) { | |
|
|
||
| var _ = Describe("AgentWorkflowRun Controller", func() { | ||
| const ( | ||
| timeout = 10 * time.Second | ||
| interval = 250 * time.Millisecond | ||
| timeout = 10 * time.Second | ||
| interval = 250 * time.Millisecond | ||
| stageAName = "stage-a" | ||
| ) | ||
|
|
||
| Context("when the referenced AgentWorkflow does not exist", func() { | ||
|
|
@@ -121,7 +122,7 @@ var _ = Describe("AgentWorkflowRun Controller", func() { | |
| Spec: konveyoriov1alpha1.AgentWorkflowSpec{ | ||
| Guide: "Sequential test workflow", | ||
| Stages: []konveyoriov1alpha1.AgentWorkflowStage{ | ||
| {Name: "stage-a", AgentRef: agentName, Instructions: "Do stage A"}, | ||
| {Name: stageAName, AgentRef: agentName, Instructions: "Do stage A"}, | ||
| {Name: "stage-b", AgentRef: agentName, Instructions: "Do stage B"}, | ||
| }, | ||
| }, | ||
|
|
@@ -144,12 +145,12 @@ var _ = Describe("AgentWorkflowRun Controller", func() { | |
|
|
||
| By("verifying stage-a AgentRun is created with deterministic name") | ||
| pbRunKey := types.NamespacedName{Name: pbRunName, Namespace: testNamespace} | ||
| expectedStageAName := stageAgentRunName(pbRunName, "stage-a") | ||
| expectedStageAName := stageAgentRunName(pbRunName, stageAName) | ||
| Eventually(func(g Gomega) { | ||
| var fetched konveyoriov1alpha1.AgentWorkflowRun | ||
| g.Expect(k8sClient.Get(ctx, pbRunKey, &fetched)).To(Succeed()) | ||
| g.Expect(fetched.Status.Phase).To(Equal(konveyoriov1alpha1.AgentRunPhaseRunning)) | ||
| g.Expect(fetched.Status.CurrentStage).To(Equal("stage-a")) | ||
| g.Expect(fetched.Status.CurrentStage).To(Equal(stageAName)) | ||
| g.Expect(fetched.Status.Stages).To(HaveLen(2)) | ||
| g.Expect(fetched.Status.Stages[0].AgentRunName).To(Equal(expectedStageAName)) | ||
| }, timeout, interval).Should(Succeed()) | ||
|
|
@@ -169,7 +170,7 @@ var _ = Describe("AgentWorkflowRun Controller", func() { | |
|
|
||
| By("verifying stage-a AgentRun has correct labels") | ||
| Expect(stageARun.Labels).To(HaveKeyWithValue(labelAgentWorkflowRun, pbRunName)) | ||
| Expect(stageARun.Labels).To(HaveKeyWithValue(labelStage, "stage-a")) | ||
| Expect(stageARun.Labels).To(HaveKeyWithValue(labelStage, stageAName)) | ||
|
|
||
| By("verifying stage-b is not started yet") | ||
| var fetchedPBRun konveyoriov1alpha1.AgentWorkflowRun | ||
|
|
@@ -291,7 +292,7 @@ var _ = Describe("AgentWorkflowRun Controller", func() { | |
| ObjectMeta: metav1.ObjectMeta{Name: workflowName, Namespace: testNamespace}, | ||
| Spec: konveyoriov1alpha1.AgentWorkflowSpec{ | ||
| Stages: []konveyoriov1alpha1.AgentWorkflowStage{ | ||
| {Name: "stage-a", AgentRef: agentAName}, | ||
| {Name: stageAName, AgentRef: agentAName}, | ||
| {Name: "stage-b", AgentRef: agentBName}, | ||
| }, | ||
| }, | ||
|
|
@@ -315,7 +316,7 @@ var _ = Describe("AgentWorkflowRun Controller", func() { | |
|
|
||
| By("verifying stage-a AgentRun gets only 'source_url'") | ||
| pbRunKey := types.NamespacedName{Name: pbRunName, Namespace: testNamespace} | ||
| expectedStageAName := stageAgentRunName(pbRunName, "stage-a") | ||
| expectedStageAName := stageAgentRunName(pbRunName, stageAName) | ||
| Eventually(func(g Gomega) { | ||
| var fetched konveyoriov1alpha1.AgentWorkflowRun | ||
| g.Expect(k8sClient.Get(ctx, pbRunKey, &fetched)).To(Succeed()) | ||
|
|
@@ -374,6 +375,98 @@ var _ = Describe("AgentWorkflowRun Controller", func() { | |
| }) | ||
| }) | ||
|
|
||
| Context("when the workflow run carries caller-supplied labels", func() { | ||
| const ( | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The test covers propagation (caller labels appear on the stage run) and spoofing (controller-owned keys win). One gap: there's no explicit assertion for the nil-labels case — when the parent AgentWorkflowRun has no labels. The existing sequential test creates a workflow run without explicit labels, implicitly covering this path, but doesn't assert |
||
| workflowName = "apr-ctrl-labels-workflow" | ||
| pbRunName = "apr-ctrl-labels-run" | ||
| agentName = "apr-ctrl-labels-agent" | ||
| gwName = "apr-prov-labels" | ||
| secretName = "apr-secret-labels" | ||
| ) | ||
|
|
||
| It("should propagate parent labels to stage AgentRuns with controller-owned keys winning", func() { | ||
| cleanup := makeReadyGateway(gwName, secretName) | ||
| defer cleanup() | ||
|
|
||
| agent := &konveyoriov1alpha1.Agent{ | ||
| ObjectMeta: metav1.ObjectMeta{Name: agentName, Namespace: testNamespace}, | ||
| Spec: konveyoriov1alpha1.AgentSpec{ | ||
| Image: testAgentImage, | ||
| Gateways: []konveyoriov1alpha1.AgentGatewayRef{{Ref: gwName}}, | ||
| }, | ||
| } | ||
| Expect(k8sClient.Create(ctx, agent)).To(Succeed()) | ||
| waitForAgentReady(agentName) | ||
|
|
||
| workflow := &konveyoriov1alpha1.AgentWorkflow{ | ||
| ObjectMeta: metav1.ObjectMeta{Name: workflowName, Namespace: testNamespace}, | ||
| Spec: konveyoriov1alpha1.AgentWorkflowSpec{ | ||
| Stages: []konveyoriov1alpha1.AgentWorkflowStage{ | ||
| {Name: stageAName, AgentRef: agentName, Instructions: "Do stage A"}, | ||
| }, | ||
| }, | ||
| } | ||
| Expect(k8sClient.Create(ctx, workflow)).To(Succeed()) | ||
| waitForWorkflowReady(workflowName) | ||
|
|
||
| By("creating the workflow run with caller labels and spoofed controller-owned keys") | ||
| pbRun := &konveyoriov1alpha1.AgentWorkflowRun{ | ||
| ObjectMeta: metav1.ObjectMeta{ | ||
| Name: pbRunName, | ||
| Namespace: testNamespace, | ||
| Labels: map[string]string{ | ||
| "konveyor.io/application": "42", | ||
| "custom/foo": "bar", | ||
| labelManagedBy: "spoofed-manager", | ||
| labelAgentWorkflowRun: "spoofed-run", | ||
| labelStage: "spoofed-stage", | ||
| }, | ||
| }, | ||
| Spec: konveyoriov1alpha1.AgentWorkflowRunSpec{ | ||
| WorkflowRef: workflowName, | ||
| Gateway: gwName, | ||
| }, | ||
| } | ||
| Expect(k8sClient.Create(ctx, pbRun)).To(Succeed()) | ||
|
|
||
| By("waiting for the stage AgentRun to be created") | ||
| pbRunKey := types.NamespacedName{Name: pbRunName, Namespace: testNamespace} | ||
| expectedStageName := stageAgentRunName(pbRunName, stageAName) | ||
| Eventually(func(g Gomega) { | ||
| var fetched konveyoriov1alpha1.AgentWorkflowRun | ||
| g.Expect(k8sClient.Get(ctx, pbRunKey, &fetched)).To(Succeed()) | ||
| g.Expect(fetched.Status.Stages).To(HaveLen(1)) | ||
| g.Expect(fetched.Status.Stages[0].AgentRunName).To(Equal(expectedStageName)) | ||
| }, timeout, interval).Should(Succeed()) | ||
|
|
||
| By("verifying the stage AgentRun inherits caller labels") | ||
| var stageRun konveyoriov1alpha1.AgentRun | ||
| Expect(k8sClient.Get(ctx, types.NamespacedName{ | ||
| Name: expectedStageName, Namespace: testNamespace, | ||
| }, &stageRun)).To(Succeed()) | ||
| Expect(stageRun.Labels).To(HaveKeyWithValue("konveyor.io/application", "42")) | ||
| Expect(stageRun.Labels).To(HaveKeyWithValue("custom/foo", "bar")) | ||
|
|
||
| By("verifying controller-owned keys keep controller values") | ||
| Expect(stageRun.Labels).To(HaveKeyWithValue(labelManagedBy, managedByLabel)) | ||
| Expect(stageRun.Labels).To(HaveKeyWithValue(labelAgentWorkflowRun, pbRunName)) | ||
| Expect(stageRun.Labels).To(HaveKeyWithValue(labelStage, stageAName)) | ||
|
|
||
| By("cleaning up") | ||
| var runList konveyoriov1alpha1.AgentRunList | ||
| Expect(k8sClient.List(ctx, &runList, | ||
| client.InNamespace(testNamespace), | ||
| client.MatchingLabels{labelAgentWorkflowRun: pbRunName}, | ||
| )).To(Succeed()) | ||
| for i := range runList.Items { | ||
| Expect(k8sClient.Delete(ctx, &runList.Items[i])).To(Succeed()) | ||
| } | ||
| Expect(k8sClient.Delete(ctx, pbRun)).To(Succeed()) | ||
| Expect(k8sClient.Delete(ctx, workflow)).To(Succeed()) | ||
| Expect(k8sClient.Delete(ctx, agent)).To(Succeed()) | ||
| }) | ||
| }) | ||
|
|
||
| Context("when a stage fails", func() { | ||
| const ( | ||
| workflowName = "apr-ctrl-fail-workflow" | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the first usage of
maps.Copyin the codebase — the rest of the controller package uses inlinemap[string]string{...}literals or manual assignment.maps.Copyis the idiomatic Go 1.21+ way to do this. We should file an issue to update the rest of the codebase to use this pattern.