Skip to content

Commit 54c791b

Browse files
committed
MTV-3663 | AAP job template hooks for migration plans
Add optional spec.aap on Hook (url, jobTemplateId, tokenSecret, timeout). Controller launches AAP job templates with migration extra_vars and waits for completion; token read from Secret. Regenerate CRD and operator manifests. Make spec.image optional with CEL: either spec.aap or non-empty image and playbook for local hooks. Hook and plan controllers validate execution mode. Use package logger in AAP client poll loop. Replace ginkgo hook tests with testing.T to avoid running the entire plan package suite from TestHook; align ServiceAccount template tests with current template() behavior. Ref: https://issues.redhat.com/browse/MTV-3663 Resolves: MTV-3663 Made-with: Cursor Signed-off-by: Gwen Casey <gcasey@redhat.com>
1 parent f531650 commit 54c791b

File tree

10 files changed

+708
-103
lines changed

10 files changed

+708
-103
lines changed

operator/.downstream_manifests

Lines changed: 53 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,11 @@ spec:
138138
controller_max_vm_inflight:
139139
description: 'Max concurrent VM migrations (default: 20)'
140140
x-kubernetes-int-or-string: true
141+
controller_migration_service_account:
142+
description: Global default ServiceAccount for migration pods in the
143+
target namespace. Overridden by Plan-level serviceAccount.
144+
example: custom-migration-sa
145+
type: string
141146
controller_ovirt_warm_migration:
142147
description: 'Enable oVirt warm migration (default: true)'
143148
enum:
@@ -572,24 +577,58 @@ spec:
572577
metadata:
573578
type: object
574579
spec:
575-
description: Hook specification.
580+
description: |-
581+
Hook specification.
582+
Local playbook hooks require both image and playbook. AAP hooks require spec.aap (image/playbook omitted).
576583
properties:
584+
aap:
585+
description: |-
586+
AAP (Ansible Automation Platform) configuration for remote job execution.
587+
When specified, the hook will trigger an AAP job template instead of running a local playbook.
588+
properties:
589+
jobTemplateId:
590+
description: ID of the AAP job template to execute.
591+
type: integer
592+
timeout:
593+
description: |-
594+
Timeout for AAP job execution in seconds.
595+
If not specified, defaults to the Hook deadline.
596+
format: int64
597+
type: integer
598+
tokenSecret:
599+
description: |-
600+
Reference to a Secret containing the AAP API token.
601+
The Secret must contain a key named "token" with the Bearer token value.
602+
type: string
603+
url:
604+
description: URL of the AAP instance (e.g., "https://aap.example.com").
605+
type: string
606+
required:
607+
- jobTemplateId
608+
- tokenSecret
609+
- url
610+
type: object
577611
deadline:
578612
description: Hook deadline in seconds.
579613
format: int64
580614
type: integer
581615
image:
582-
description: Image to run.
616+
description: Image to run the hook workload (required for local playbook
617+
hooks; omit for AAP hooks).
583618
type: string
584619
playbook:
585-
description: A base64 encoded Ansible playbook.
620+
description: A base64 encoded Ansible playbook (required for local
621+
hooks; omit for AAP hooks).
586622
type: string
587623
serviceAccount:
588624
description: Service account.
589625
type: string
590-
required:
591-
- image
592626
type: object
627+
x-kubernetes-validations:
628+
- message: either spec.aap must be set, or both spec.image and spec.playbook
629+
(non-empty) for a local hook
630+
rule: has(self.aap) || (has(self.image) && size(self.image) > 0 && has(self.playbook)
631+
&& size(self.playbook) > 0)
593632
status:
594633
description: Hook status.
595634
properties:
@@ -3882,6 +3921,15 @@ spec:
38823921
- true (default): Inspection step runs before transferring any disks and may fail if it detects the migration would fail.
38833922
- false: No inspection is performed before disk transfer.
38843923
type: boolean
3924+
serviceAccount:
3925+
description: |-
3926+
ServiceAccount is the name of the ServiceAccount to use for migration
3927+
pods in the target namespace. Overrides the global setting.
3928+
If empty, falls back to ForkliftController's controller_migration_service_account,
3929+
then to the namespace default.
3930+
maxLength: 253
3931+
pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
3932+
type: string
38853933
skipGuestConversion:
38863934
default: false
38873935
description: Determines if the plan should skip the guest conversion.

operator/.upstream_manifests

Lines changed: 53 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,11 @@ spec:
138138
controller_max_vm_inflight:
139139
description: 'Max concurrent VM migrations (default: 20)'
140140
x-kubernetes-int-or-string: true
141+
controller_migration_service_account:
142+
description: Global default ServiceAccount for migration pods in the
143+
target namespace. Overridden by Plan-level serviceAccount.
144+
example: custom-migration-sa
145+
type: string
141146
controller_ovirt_warm_migration:
142147
description: 'Enable oVirt warm migration (default: true)'
143148
enum:
@@ -572,24 +577,58 @@ spec:
572577
metadata:
573578
type: object
574579
spec:
575-
description: Hook specification.
580+
description: |-
581+
Hook specification.
582+
Local playbook hooks require both image and playbook. AAP hooks require spec.aap (image/playbook omitted).
576583
properties:
584+
aap:
585+
description: |-
586+
AAP (Ansible Automation Platform) configuration for remote job execution.
587+
When specified, the hook will trigger an AAP job template instead of running a local playbook.
588+
properties:
589+
jobTemplateId:
590+
description: ID of the AAP job template to execute.
591+
type: integer
592+
timeout:
593+
description: |-
594+
Timeout for AAP job execution in seconds.
595+
If not specified, defaults to the Hook deadline.
596+
format: int64
597+
type: integer
598+
tokenSecret:
599+
description: |-
600+
Reference to a Secret containing the AAP API token.
601+
The Secret must contain a key named "token" with the Bearer token value.
602+
type: string
603+
url:
604+
description: URL of the AAP instance (e.g., "https://aap.example.com").
605+
type: string
606+
required:
607+
- jobTemplateId
608+
- tokenSecret
609+
- url
610+
type: object
577611
deadline:
578612
description: Hook deadline in seconds.
579613
format: int64
580614
type: integer
581615
image:
582-
description: Image to run.
616+
description: Image to run the hook workload (required for local playbook
617+
hooks; omit for AAP hooks).
583618
type: string
584619
playbook:
585-
description: A base64 encoded Ansible playbook.
620+
description: A base64 encoded Ansible playbook (required for local
621+
hooks; omit for AAP hooks).
586622
type: string
587623
serviceAccount:
588624
description: Service account.
589625
type: string
590-
required:
591-
- image
592626
type: object
627+
x-kubernetes-validations:
628+
- message: either spec.aap must be set, or both spec.image and spec.playbook
629+
(non-empty) for a local hook
630+
rule: has(self.aap) || (has(self.image) && size(self.image) > 0 && has(self.playbook)
631+
&& size(self.playbook) > 0)
593632
status:
594633
description: Hook status.
595634
properties:
@@ -3882,6 +3921,15 @@ spec:
38823921
- true (default): Inspection step runs before transferring any disks and may fail if it detects the migration would fail.
38833922
- false: No inspection is performed before disk transfer.
38843923
type: boolean
3924+
serviceAccount:
3925+
description: |-
3926+
ServiceAccount is the name of the ServiceAccount to use for migration
3927+
pods in the target namespace. Overrides the global setting.
3928+
If empty, falls back to ForkliftController's controller_migration_service_account,
3929+
then to the namespace default.
3930+
maxLength: 253
3931+
pattern: ^[a-z0-9]([-a-z0-9]*[a-z0-9])?$
3932+
type: string
38853933
skipGuestConversion:
38863934
default: false
38873935
description: Determines if the plan should skip the guest conversion.

operator/config/crd/bases/forklift.konveyor.io_hooks.yaml

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -47,24 +47,58 @@ spec:
4747
metadata:
4848
type: object
4949
spec:
50-
description: Hook specification.
50+
description: |-
51+
Hook specification.
52+
Local playbook hooks require both image and playbook. AAP hooks require spec.aap (image/playbook omitted).
5153
properties:
54+
aap:
55+
description: |-
56+
AAP (Ansible Automation Platform) configuration for remote job execution.
57+
When specified, the hook will trigger an AAP job template instead of running a local playbook.
58+
properties:
59+
jobTemplateId:
60+
description: ID of the AAP job template to execute.
61+
type: integer
62+
timeout:
63+
description: |-
64+
Timeout for AAP job execution in seconds.
65+
If not specified, defaults to the Hook deadline.
66+
format: int64
67+
type: integer
68+
tokenSecret:
69+
description: |-
70+
Reference to a Secret containing the AAP API token.
71+
The Secret must contain a key named "token" with the Bearer token value.
72+
type: string
73+
url:
74+
description: URL of the AAP instance (e.g., "https://aap.example.com").
75+
type: string
76+
required:
77+
- jobTemplateId
78+
- tokenSecret
79+
- url
80+
type: object
5281
deadline:
5382
description: Hook deadline in seconds.
5483
format: int64
5584
type: integer
5685
image:
57-
description: Image to run.
86+
description: Image to run the hook workload (required for local playbook
87+
hooks; omit for AAP hooks).
5888
type: string
5989
playbook:
60-
description: A base64 encoded Ansible playbook.
90+
description: A base64 encoded Ansible playbook (required for local
91+
hooks; omit for AAP hooks).
6192
type: string
6293
serviceAccount:
6394
description: Service account.
6495
type: string
65-
required:
66-
- image
6796
type: object
97+
x-kubernetes-validations:
98+
- message: either spec.aap must be set, or both spec.image and spec.playbook
99+
(non-empty) for a local hook
100+
rule: has(self.aap) || (has(self.image) && size(self.image) > 0 && has(self.playbook)
101+
&& size(self.playbook) > 0)
68102
status:
69103
description: Hook status.
70104
properties:

pkg/apis/forklift/v1beta1/hook.go

Lines changed: 29 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,41 @@ import (
66
)
77

88
// Hook specification.
9+
// Local playbook hooks require both image and playbook. AAP hooks require spec.aap (image/playbook omitted).
10+
//
11+
// +kubebuilder:validation:XValidation:rule="has(self.aap) || (has(self.image) && size(self.image) > 0 && has(self.playbook) && size(self.playbook) > 0)",message="either spec.aap must be set, or both spec.image and spec.playbook (non-empty) for a local hook"
912
type HookSpec struct {
1013
// Service account.
1114
ServiceAccount string `json:"serviceAccount,omitempty"`
12-
// Image to run.
13-
Image string `json:"image"`
14-
// A base64 encoded Ansible playbook.
15+
// Image to run the hook workload (required for local playbook hooks; omit for AAP hooks).
16+
// +optional
17+
Image string `json:"image,omitempty"`
18+
// A base64 encoded Ansible playbook (required for local hooks; omit for AAP hooks).
1519
Playbook string `json:"playbook,omitempty"`
1620
// Hook deadline in seconds.
1721
Deadline int64 `json:"deadline,omitempty"`
22+
// AAP (Ansible Automation Platform) configuration for remote job execution.
23+
// When specified, the hook will trigger an AAP job template instead of running a local playbook.
24+
// +optional
25+
AAP *AAPConfig `json:"aap,omitempty"`
26+
}
27+
28+
// AAPConfig defines configuration for executing hooks via Ansible Automation Platform.
29+
type AAPConfig struct {
30+
// URL of the AAP instance (e.g., "https://aap.example.com").
31+
// +kubebuilder:validation:Required
32+
URL string `json:"url"`
33+
// ID of the AAP job template to execute.
34+
// +kubebuilder:validation:Required
35+
JobTemplateID int `json:"jobTemplateId"`
36+
// Reference to a Secret containing the AAP API token.
37+
// The Secret must contain a key named "token" with the Bearer token value.
38+
// +kubebuilder:validation:Required
39+
TokenSecret string `json:"tokenSecret"`
40+
// Timeout for AAP job execution in seconds.
41+
// If not specified, defaults to the Hook deadline.
42+
// +optional
43+
Timeout int64 `json:"timeout,omitempty"`
1844
}
1945

2046
// Hook status.

pkg/apis/forklift/v1beta1/zz_generated.deepcopy.go

Lines changed: 21 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)