Skip to content

MTV-5240 | Annotate AAP hooks with job template name for kubectl#6845

Open
gwencasey96 wants to merge 2 commits into
kubev2v:mainfrom
gwencasey96:add_kubectl_annotation
Open

MTV-5240 | Annotate AAP hooks with job template name for kubectl#6845
gwencasey96 wants to merge 2 commits into
kubev2v:mainfrom
gwencasey96:add_kubectl_annotation

Conversation

@gwencasey96

Copy link
Copy Markdown
Contributor

Resolve AAP job template names on Hook reconcile and store them as annotations so kubectl users see the playbook name, not only the template ID. Add Hook CRD printer columns for terminal visibility.

Ref: https://redhat.atlassian.net/browse/MTV-5240
Resolves: MTV-5240

Resolve AAP job template names on Hook reconcile and store them as
annotations so kubectl users see the playbook name, not only the
template ID. Add Hook CRD printer columns for terminal visibility.

Ref: https://redhat.atlassian.net/browse/MTV-5240
Resolves: MTV-5240
Co-authored-by: Cursor <cursoragent@cursor.com>
Signed-off-by: Gwen Casey <gcasey@redhat.com>
@coderabbitai

coderabbitai Bot commented Jun 1, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Hook resources now expose AAP job template information through Kubernetes display columns. The controller resolves template names via AAP API queries and stores them as annotations, enabling operators to see template details when listing hooks.

Changes

AAP Template Information on Hook Resources

Layer / File(s) Summary
CRD Printer Columns
operator/config/crd/bases/forklift.konveyor.io_hooks.yaml, operator/.downstream_manifests, operator/.kustomized_manifests, operator/.upstream_manifests
Hook CRD adds AAPTemplateID (integer from spec.aap.jobTemplateId) and AAPTemplate (string from forklift.konveyor.io/aap-job-template-name annotation) printer columns across all manifest sources.
AAP Client Helpers
pkg/lib/aap/client.go, pkg/lib/aap/client_test.go
JobTemplateNameForHook resolves AAP template display names by querying the AAP API with hook credentials. newClientFromHook constructs an AAP client from per-hook or cluster-default connection parameters, including timeout and TLS settings. Test validates the template name resolution against mocked AAP discovery and listing endpoints.
Hook Controller Reconciliation
pkg/controller/hook/controller.go
Controller imports strconv and strings, defines annotation constants for AAP template ID and name, and calls ensureAAPJobTemplateAnnotations during reconciliation. The helper validates hook AAP configuration, resolves the template name via the AAP client, and patches Hook annotations using merge patch when values change; resolution failures are non-blocking. Successful patches trigger a requeue to reconcile with updated data.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

Suggested reviewers

  • yaacov
  • mrnold
  • Hazanel

Poem

🐰 A Hook now gleams with template names so bright,
From AAP's distant API, fetched at night.
Annotations dance on columns, bold and wide,
The controller ensures the truth resides.
Template wisdom flows, from query to display!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly describes the main changes: annotating AAP hooks with job template names for kubectl visibility, directly aligned with the primary objective.
Description check ✅ Passed The description is directly related to the changeset, explaining the purpose of annotating hooks with template names and adding printer columns for kubectl visibility.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@pkg/controller/hook/controller.go`:
- Around line 176-197: When exiting early on the skip/failure paths, clear any
stale AAP annotations so the printer column doesn't show outdated data: remove
annAAPJobTemplateID and annAAPJobTemplateName from the hook.Annotations before
returning in the branches where hook.Spec.AAP == nil and where name lookup fails
(the block around aap.JobTemplateNameForHook and the earlier curID/curName
check); apply the mutation via the controller client (use r.Client.Patch or
r.Client.Update on the hook) and handle/log errors from that patch with
r.Log.V(...) but still return the original boolean/result as before.

In `@pkg/lib/aap/client_test.go`:
- Around line 66-89: Add focused unit tests for JobTemplateNameForHook to cover
the new hook-resolution behavior: create an httptest.Server that returns
controlled responses for /api/ and /api/v2/job_templates/ (reuse NewClient to
point at the server) and write at least two subtests—one where a valid hook
(including a name with surrounding whitespace and an exact-ID string) resolves
successfully to the expected template name, and one where the hook cannot be
resolved so the function returns the not-found error; ensure the tests exercise
trimming, exact-ID matching, hook validation paths, and secret-loading behavior
by configuring the client inputs accordingly (use JobTemplateNameForHook and
ListAllJobTemplates symbols to locate where to call the helper).

In `@pkg/lib/aap/client.go`:
- Around line 101-111: The current code resolves hook.Spec.AAP.JobTemplateID by
scanning cl.ListAllJobTemplates limited by defaultMaxJobTemplatesList which can
miss templates past that cap; instead call the API to fetch the job template by
its ID (or use the API's ID filter) rather than ListAllJobTemplates — replace
the loop that compares t.ID to id with a direct get-by-ID call on the client (or
a filtered list request), handle and return the API error if not found, and
remove reliance on defaultMaxJobTemplatesList so the function reliably returns
the template name for hook.Spec.AAP.JobTemplateID.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 07d0ae7c-2bea-45dd-b584-318d976e0089

📥 Commits

Reviewing files that changed from the base of the PR and between 9eb155f and fc6511e.

📒 Files selected for processing (7)
  • operator/.downstream_manifests
  • operator/.kustomized_manifests
  • operator/.upstream_manifests
  • operator/config/crd/bases/forklift.konveyor.io_hooks.yaml
  • pkg/controller/hook/controller.go
  • pkg/lib/aap/client.go
  • pkg/lib/aap/client_test.go

Comment on lines +176 to +197
if hook.Spec.AAP == nil {
return false, nil
}

wantID := strconv.Itoa(hook.Spec.AAP.JobTemplateID)
curID := ""
curName := ""
if hook.Annotations != nil {
curID = strings.TrimSpace(hook.Annotations[annAAPJobTemplateID])
curName = strings.TrimSpace(hook.Annotations[annAAPJobTemplateName])
}
if curID == wantID && curName != "" {
return false, nil
}

name, nameErr := aap.JobTemplateNameForHook(ctx, r.Client, hook)
if nameErr != nil || name == "" {
if nameErr != nil {
r.Log.V(1).Info("AAP job template name lookup skipped", "error", nameErr.Error(), "jobTemplateId", hook.Spec.AAP.JobTemplateID)
}
return false, nil
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Clear stale AAP annotations on the skip/failure paths.

If a Hook already has these annotations and later spec.aap is removed, or the template ID changes but lookup now fails, this helper exits without patching and leaves the old forklift.konveyor.io/aap-job-template-name behind. That means the printer column can keep showing a template name that no longer matches the Hook. Please delete the AAP annotations before returning on those paths.

Possible direction
 func (r *Reconciler) ensureAAPJobTemplateAnnotations(ctx context.Context, hook *api.Hook) (updated bool, err error) {
 	if hook.Spec.AAP == nil {
-		return false, nil
+		return r.clearAAPJobTemplateAnnotations(ctx, hook)
 	}
 ...
 	name, nameErr := aap.JobTemplateNameForHook(ctx, r.Client, hook)
 	if nameErr != nil || name == "" {
 		if nameErr != nil {
 			r.Log.V(1).Info("AAP job template name lookup skipped", "error", nameErr.Error(), "jobTemplateId", hook.Spec.AAP.JobTemplateID)
 		}
-		return false, nil
+		if curID != "" || curName != "" {
+			return r.clearAAPJobTemplateAnnotations(ctx, hook)
+		}
+		return false, nil
 	}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/controller/hook/controller.go` around lines 176 - 197, When exiting early
on the skip/failure paths, clear any stale AAP annotations so the printer column
doesn't show outdated data: remove annAAPJobTemplateID and annAAPJobTemplateName
from the hook.Annotations before returning in the branches where hook.Spec.AAP
== nil and where name lookup fails (the block around aap.JobTemplateNameForHook
and the earlier curID/curName check); apply the mutation via the controller
client (use r.Client.Patch or r.Client.Update on the hook) and handle/log errors
from that patch with r.Log.V(...) but still return the original boolean/result
as before.

Comment on lines +66 to +89
func TestClientJobTemplateName(t *testing.T) {
srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
switch r.URL.Path {
case "/api/", "/api":
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write([]byte(`{"current_version": "/api/v2/"}`))
case "/api/v2/job_templates/":
w.Header().Set("Content-Type", "application/json")
_, _ = w.Write([]byte(`{"count": 1, "next": null, "previous": null, "results": [{"id": 123, "name": "My Playbook Template"}]}`))
default:
t.Fatalf("unexpected path: %s", r.URL.Path)
}
}))
defer srv.Close()

cl := NewClient(srv.URL, "tok", 0, nil)
templates, err := cl.ListAllJobTemplates(context.Background(), 10)
if err != nil {
t.Fatal(err)
}
if len(templates) != 1 || templates[0].Name != "My Playbook Template" {
t.Fatalf("unexpected templates: %#v", templates)
}
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

This test doesn't cover the new hook-resolution behavior.

It only exercises ListAllJobTemplates, so JobTemplateNameForHook can break in hook validation, secret loading, exact-ID matching, or whitespace trimming without any new test failing. Please add a focused unit test for the new helper, ideally with both success and not-found cases.

As per coding guidelines, **/*.go: "coverage: Make sure that the code has unit tests."

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/lib/aap/client_test.go` around lines 66 - 89, Add focused unit tests for
JobTemplateNameForHook to cover the new hook-resolution behavior: create an
httptest.Server that returns controlled responses for /api/ and
/api/v2/job_templates/ (reuse NewClient to point at the server) and write at
least two subtests—one where a valid hook (including a name with surrounding
whitespace and an exact-ID string) resolves successfully to the expected
template name, and one where the hook cannot be resolved so the function returns
the not-found error; ensure the tests exercise trimming, exact-ID matching, hook
validation paths, and secret-loading behavior by configuring the client inputs
accordingly (use JobTemplateNameForHook and ListAllJobTemplates symbols to
locate where to call the helper).

Comment thread pkg/lib/aap/client.go
Comment on lines +101 to +111
id := hook.Spec.AAP.JobTemplateID
templates, err := cl.ListAllJobTemplates(ctx, defaultMaxJobTemplatesList)
if err != nil {
return "", err
}
for _, t := range templates {
if t.ID == id {
return strings.TrimSpace(t.Name), nil
}
}
return "", fmt.Errorf("job template %d not found in AAP", id)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Avoid resolving a specific template ID via a capped full-list scan.

This can return a false "not found" once the AAP instance has more than defaultMaxJobTemplatesList templates and the target ID falls on a later page. In this PR that failure is swallowed upstream, so larger installs will silently never get the kubectl annotation. Please resolve by ID directly, or query the API with an ID filter instead of scanning only the first 500 entries.

Possible direction
-	templates, err := cl.ListAllJobTemplates(ctx, defaultMaxJobTemplatesList)
-	if err != nil {
-		return "", err
-	}
-	for _, t := range templates {
-		if t.ID == id {
-			return strings.TrimSpace(t.Name), nil
-		}
-	}
-	return "", fmt.Errorf("job template %d not found in AAP", id)
+	t, err := cl.GetJobTemplate(ctx, id)
+	if err != nil {
+		return "", err
+	}
+	return strings.TrimSpace(t.Name), nil
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@pkg/lib/aap/client.go` around lines 101 - 111, The current code resolves
hook.Spec.AAP.JobTemplateID by scanning cl.ListAllJobTemplates limited by
defaultMaxJobTemplatesList which can miss templates past that cap; instead call
the API to fetch the job template by its ID (or use the API's ID filter) rather
than ListAllJobTemplates — replace the loop that compares t.ID to id with a
direct get-by-ID call on the client (or a filtered list request), handle and
return the API error if not found, and remove reliance on
defaultMaxJobTemplatesList so the function reliably returns the template name
for hook.Spec.AAP.JobTemplateID.

Add kubebuilder printcolumn markers for AAPTemplateID and AAPTemplate
so make generate/manifests preserves kubectl columns instead of stripping
manually edited CRD YAML.

Ref: https://redhat.atlassian.net/browse/MTV-5240
Resolves: MTV-5240
Co-authored-by: Cursor <cursoragent@cursor.com>
Signed-off-by: Gwen Casey <gcasey@redhat.com>
@sonarqubecloud

sonarqubecloud Bot commented Jun 1, 2026

Copy link
Copy Markdown

@codecov-commenter

Copy link
Copy Markdown

⚠️ Please install the 'codecov app svg image' to ensure uploads and comments are reliably processed by Codecov.

Codecov Report

❌ Patch coverage is 0% with 68 lines in your changes missing coverage. Please review.
✅ Project coverage is 10.47%. Comparing base (f1fe5d0) to head (ea01471).
⚠️ Report is 2572 commits behind head on main.

Files with missing lines Patch % Lines
pkg/lib/aap/client.go 0.00% 37 Missing ⚠️
pkg/controller/hook/controller.go 0.00% 31 Missing ⚠️
❗ Your organization needs to install the Codecov GitHub app to enable full functionality.
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #6845      +/-   ##
==========================================
- Coverage   15.45%   10.47%   -4.99%     
==========================================
  Files         112      521     +409     
  Lines       23377    62038   +38661     
==========================================
+ Hits         3613     6497    +2884     
- Misses      19479    54992   +35513     
- Partials      285      549     +264     
Flag Coverage Δ
unittests 10.47% <0.00%> (-4.99%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants