Skip to content
This repository was archived by the owner on Sep 9, 2026. It is now read-only.

OSAC-1484: Add CLI commands and table rendering for ExternalIP resources - #839

Merged
openshift-merge-bot[bot] merged 8 commits into
osac-project:mainfrom
danmanor:feat/OSAC-1484-externalip-cli
Jul 5, 2026
Merged

openshift-merge-bot[bot] merged 8 commits into
osac-project:mainfrom
danmanor:feat/OSAC-1484-externalip-cli

Conversation

@danmanor

@danmanor danmanor commented Jul 5, 2026 •

Copy link
Copy Markdown
Contributor

OSAC-1484: Add CLI commands and table rendering for ExternalIP resources

Jira: https://redhat.atlassian.net/browse/OSAC-1484
Epic: OSAC-1442 — ExternalIP Resources

Summary

Adds CLI commands and table rendering definitions for ExternalIP, ExternalIPPool, and ExternalIPAttachment resources. This enables tenants to manage external IP allocation and attachment through the CLI, supporting all three target types (ComputeInstance, Cluster, BaremetalInstance) for ExternalIPAttachment.

Changes

Table rendering (6 YAML files):

  • Public and private table definitions for ExternalIP (PROJECT, ID, NAME, POOL, STATE, ADDRESS, ATTACHED; private adds HUB)
  • Public and private table definitions for ExternalIPPool (ID, NAME, IP-FAMILY, AVAILABLE; private adds CIDRS, STRATEGY, STATE, TOTAL, ALLOCATED, FREE, HUB)
  • Public and private table definitions for ExternalIPAttachment (ID, NAME, EXTERNAL-IP, TARGET, TARGET-TYPE, STATE; private adds HUB)

CLI create commands:

  • osac create externalip --name --pool — allocate an external IP from a pool
  • osac create externalipattachment --externalip --compute-instance|--cluster|--baremetal-instance [--target-endpoint api|ingress] [--name] — attach an external IP to a target resource

CLI describe commands:

  • osac describe externalip — key-value detail view
  • osac describe externalipattachment — key-value detail with oneof target type rendering

CLI get subcommand:

  • osac get externalippool — list (table) and detail (key-value) views

Registration:

  • Updated create_cmd.go, describe_cmd.go, get_cmd.go to register new subcommands

Testing

  • Unit tests: CLI commands follow the project convention of no unit tests (consistent with PublicIP, Cluster, etc.)
  • Integration tests: Covered by OSAC-1485 (separate story)
  • Coverage: Table rendering YAML files validated via the existing rendering test suite; both binaries compile successfully

Acceptance Criteria

  • osac create externalip command with --name and --pool flags
  • osac create externalipattachment command with multi-target support (compute-instance, cluster, baremetal-instance) and --target-endpoint for cluster targets
  • osac describe externalip command with key-value rendering
  • osac describe externalipattachment command with oneof target rendering
  • osac get externalippool subcommand with list and detail views
  • Table rendering YAML definitions for all 6 variants (public + private for each resource)
  • Generic get, delete, and edit work via reflection (no code needed)
  • Registration of new commands in create_cmd.go, describe_cmd.go, get_cmd.go

Summary by CodeRabbit

  • New Features
    • Added CLI support for creating, describing, and listing external IP pools, external IPs, and external IP attachments.
    • Added richer output formatting for these resources, including detailed views and table-based summaries.
    • Improved command help and examples for the new external IP workflows.

danmanor added 8 commits July 5, 2026 13:03
Assisted-by: Claude Code <noreply@anthropic.com>
Signed-off-by: Dan Manor <dmanor@redhat.com>
Assisted-by: Claude Code <noreply@anthropic.com>
Signed-off-by: Dan Manor <dmanor@redhat.com>
Assisted-by: Claude Code <noreply@anthropic.com>
Signed-off-by: Dan Manor <dmanor@redhat.com>
Assisted-by: Claude Code <noreply@anthropic.com>
Signed-off-by: Dan Manor <dmanor@redhat.com>
Supports three target types (--compute-instance, --cluster,
--baremetal-instance) and --target-endpoint for cluster targets.

Assisted-by: Claude Code <noreply@anthropic.com>
Signed-off-by: Dan Manor <dmanor@redhat.com>
Assisted-by: Claude Code <noreply@anthropic.com>
Signed-off-by: Dan Manor <dmanor@redhat.com>
Assisted-by: Claude Code <noreply@anthropic.com>
Signed-off-by: Dan Manor <dmanor@redhat.com>
Assisted-by: Claude Code <noreply@anthropic.com>
Signed-off-by: Dan Manor <dmanor@redhat.com>
@openshift-ci-robot

openshift-ci-robot commented Jul 5, 2026 •

Copy link
Copy Markdown

@danmanor: This pull request references OSAC-1484 which is a valid jira issue.

Warning: The referenced jira issue has an invalid target version for the target branch this PR targets: expected the task to target the "5.0.0" version, but no target version was set.

Details

In response to this:

OSAC-1484: Add CLI commands and table rendering for ExternalIP resources

Jira: https://redhat.atlassian.net/browse/OSAC-1484
Epic: OSAC-1442 — ExternalIP Resources

Summary

Adds CLI commands and table rendering definitions for ExternalIP, ExternalIPPool, and ExternalIPAttachment resources. This enables tenants to manage external IP allocation and attachment through the CLI, supporting all three target types (ComputeInstance, Cluster, BaremetalInstance) for ExternalIPAttachment.

Changes

Table rendering (6 YAML files):

  • Public and private table definitions for ExternalIP (PROJECT, ID, NAME, POOL, STATE, ADDRESS, ATTACHED; private adds HUB)
  • Public and private table definitions for ExternalIPPool (ID, NAME, IP-FAMILY, AVAILABLE; private adds CIDRS, STRATEGY, STATE, TOTAL, ALLOCATED, FREE, HUB)
  • Public and private table definitions for ExternalIPAttachment (ID, NAME, EXTERNAL-IP, TARGET, TARGET-TYPE, STATE; private adds HUB)

CLI create commands:

  • osac create externalip --name --pool — allocate an external IP from a pool
  • osac create externalipattachment --externalip --compute-instance|--cluster|--baremetal-instance [--target-endpoint api|ingress] [--name] — attach an external IP to a target resource

CLI describe commands:

  • osac describe externalip — key-value detail view
  • osac describe externalipattachment — key-value detail with oneof target type rendering

CLI get subcommand:

  • osac get externalippool — list (table) and detail (key-value) views

Registration:

  • Updated create_cmd.go, describe_cmd.go, get_cmd.go to register new subcommands

Testing

  • Unit tests: CLI commands follow the project convention of no unit tests (consistent with PublicIP, Cluster, etc.)
  • Integration tests: Covered by OSAC-1485 (separate story)
  • Coverage: Table rendering YAML files validated via the existing rendering test suite; both binaries compile successfully

Acceptance Criteria

  • osac create externalip command with --name and --pool flags
  • osac create externalipattachment command with multi-target support (compute-instance, cluster, baremetal-instance) and --target-endpoint for cluster targets
  • osac describe externalip command with key-value rendering
  • osac describe externalipattachment command with oneof target rendering
  • osac get externalippool subcommand with list and detail views
  • Table rendering YAML definitions for all 6 variants (public + private for each resource)
  • Generic get, delete, and edit work via reflection (no code needed)
  • Registration of new commands in create_cmd.go, describe_cmd.go, get_cmd.go

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the openshift-eng/jira-lifecycle-plugin repository.

@openshift-ci

openshift-ci Bot commented Jul 5, 2026

Copy link
Copy Markdown

Skipping CI for Draft Pull Request.
If you want CI signal for your change, please convert it to an actual PR.
You can still manually trigger a test run with /test all

@coderabbitai

coderabbitai Bot commented Jul 5, 2026 •

Copy link
Copy Markdown

Review Change Stack

Walkthrough

This PR adds new CLI commands for ExternalIP, ExternalIPAttachment, and ExternalIPPool resources: create commands for ExternalIP and ExternalIPAttachment, describe commands for both, and a get command for ExternalIPPool. It also adds corresponding YAML rendering table definitions and wires all new subcommands into parent CLI commands.

Changes

ExternalIP CLI Commands and Rendering

Layer / File(s) Summary
Create externalip command
internal/cmd/cli/create/externalip/create_externalip_cmd.go, internal/cmd/cli/create/create_cmd.go
Adds a Cobra command that validates config, resolves a pool via lookup.Find, and creates an ExternalIP via gRPC, with help text and parent wiring.
Create externalipattachment command
internal/cmd/cli/create/externalipattachment/create_externalipattachment_cmd.go
Adds a Cobra command enforcing mutually exclusive target flags (compute-instance, cluster, baremetal-instance), resolves the external IP and target via lookup.Find, and creates the attachment, including a parseTargetEndpoint helper.
Describe externalip and externalipattachment commands
internal/cmd/cli/describe/externalip/describe_externalip_cmd.go, internal/cmd/cli/describe/externalipattachment/describe_externalipattachment_cmd.go, internal/cmd/cli/describe/describe_cmd.go
Adds describe commands resolving resources via lookup.Find and rendering formatted tabular detail output (RenderExternalIP, RenderExternalIPAttachment), wired into the describe parent command.
Get externalippool command
internal/cmd/cli/get/externalippool/get_externalippool_cmd.go, internal/cmd/cli/get/get_cmd.go
Adds a get command that lists all pools or resolves a specific pool via lookup.Find, with separate table and detail rendering, wired into the get parent command.
Rendering table YAML definitions
internal/rendering/tables/osac.private.v1.ExternalIP*.yaml, internal/rendering/tables/osac.public.v1.ExternalIP*.yaml
Adds table column definitions with value expressions, defaults, and typed fields for ExternalIP, ExternalIPAttachment, and ExternalIPPool in both public and private variants.

Estimated code review effort: 3 (Moderate) | ~30 minutes

Sequence Diagram(s)

sequenceDiagram
  participant CLI as externalipattachment Cmd
  participant Runner as runnerContext.run
  participant EIPAPI as ExternalIPsClient
  participant TargetAPI as Target List Client
  participant AttachAPI as ExternalIPAttachmentsClient
  CLI->>Runner: run(cmd, args)
  Runner->>EIPAPI: List external IPs
  Runner->>Runner: lookup.Find(externalip)
  Runner->>TargetAPI: List target resource (compute/cluster/baremetal)
  Runner->>Runner: lookup.Find(target)
  Runner->>AttachAPI: Create(ExternalIPAttachmentSpec)
  AttachAPI-->>Runner: created attachment
  Runner-->>CLI: print attachment ID, external IP, target
Loading

Possibly related PRs

Suggested reviewers: akshaynadkarni, SiddarthR56, eranco74, larsks

🚥 Pre-merge checks | ✅ 11
✅ Passed checks (11 passed)
Check name Status Explanation
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
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.
No-Hardcoded-Secrets ✅ Passed No hardcoded secrets, credentials, private keys, embedded-creds URLs, or secret-shaped literals were found in the changed files.
No-Weak-Crypto ✅ Passed Changed files add CLI/table wiring only; scans found no MD5/SHA1/DES/RC4/3DES/Blowfish/ECB, custom crypto, or secret comparisons.
No-Injection-Vectors ✅ Passed No injection vectors found: the new CLI code only does gRPC lookups/printing, lookup.Find quotes refs with %q, and YAML is loaded via yaml.Unmarshal, not unsafe loaders.
Container-Privileges ✅ Passed No changed file contains privileged, hostPID, hostNetwork, hostIPC, SYS_ADMIN, or allowPrivilegeEscalation; the PR only touches CLI and table-rendering YAML, not K8s manifests.
No-Sensitive-Data-In-Logs ✅ Passed No new logger/debug statements expose secrets or PII; the added commands only print user-facing resource IDs/names/IPs.
Ai-Attribution ✅ Passed PR commits include Assisted-by: Claude Code trailers, satisfying the AI attribution requirement; no AI Co-authored-by trailers were found.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title accurately summarizes the main change: new CLI commands and table rendering for ExternalIP-related resources.
✨ 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.

@danmanor
danmanor marked this pull request as ready for review July 5, 2026 10:25
@openshift-ci
openshift-ci Bot requested review from akshaynadkarni and jhernand July 5, 2026 10:25
@danmanor danmanor changed the title OSAC-1484: Add CLI commands and table rendering for ExternalIP resources WIP: OSAC-1484: Add CLI commands and table rendering for ExternalIP resources Jul 5, 2026
@danmanor danmanor changed the title WIP: OSAC-1484: Add CLI commands and table rendering for ExternalIP resources OSAC-1484: Add CLI commands and table rendering for ExternalIP resources Jul 5, 2026

@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: 4

🤖 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
`@internal/cmd/cli/create/externalipattachment/create_externalipattachment_cmd.go`:
- Around line 79-82: Move the “at least one target required” validation out of
the gRPC path by adding `MarkFlagsOneRequired` alongside the existing
`MarkFlagRequired`/`MarkFlagsMutuallyExclusive` setup in
`create_externalipattachment_cmd.go`, and remove the manual target check from
`CreateExternalIPAttachmentCmd` so invalid input is rejected during flag parsing
before any dial happens. Use the existing flag names (`compute-instance`,
`cluster`, `baremetal-instance`, `externalip`) in the command builder and keep
the runtime logic focused on constructing the request after validation succeeds.
- Around line 176-182: The `--target-endpoint` flag is currently accepted even
when the target is not a cluster, but `createExternalIPAttachment` silently
drops it for `--compute-instance` and `--baremetal-instance`. Update the
argument handling around `parseTargetEndpoint` and `spec.TargetEndpoint` to
validate that `targetEndpoint` is only allowed for cluster targets, and return a
clear error when it is used with non-cluster targets.

In
`@internal/cmd/cli/describe/externalipattachment/describe_externalipattachment_cmd.go`:
- Around line 92-144: RenderExternalIPAttachment is still printing raw enum
names for the status and target endpoint. Update the state and target endpoint
rendering to trim the EXTERNAL_IP_ATTACHMENT_STATE_ and
EXTERNAL_IP_ATTACHMENT_ENDPOINT_ prefixes before writing them to the tabwriter,
using the existing strings.TrimPrefix logic around
a.GetStatus().GetState().String() and a.GetSpec().GetTargetEndpoint().String().
Keep the fallback values intact so missing fields still render as "-".

In `@internal/rendering/tables/osac.private.v1.ExternalIP.yaml`:
- Around line 32-33: The ADDRESS field uses a different empty-value fallback
idiom than the other columns in this table. Update the value expression in the
ExternalIP table definition to match the existing has(...) pattern used for
PROJECT/NAME, and keep the fallback to '-' when the status address is unset or
empty. Use the ADDRESS entry in this YAML and the other column expressions as
the reference for the consistency change.
🪄 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: Repository: osac-project/coderabbit/.coderabbit.yaml

Review profile: ASSERTIVE

Plan: Enterprise

Run ID: d04ad739-be42-4cb7-82fe-76800d282bbb

📥 Commits

Reviewing files that changed from the base of the PR and between e5c4482 and 9cac53e.

📒 Files selected for processing (14)
  • internal/cmd/cli/create/create_cmd.go
  • internal/cmd/cli/create/externalip/create_externalip_cmd.go
  • internal/cmd/cli/create/externalipattachment/create_externalipattachment_cmd.go
  • internal/cmd/cli/describe/describe_cmd.go
  • internal/cmd/cli/describe/externalip/describe_externalip_cmd.go
  • internal/cmd/cli/describe/externalipattachment/describe_externalipattachment_cmd.go
  • internal/cmd/cli/get/externalippool/get_externalippool_cmd.go
  • internal/cmd/cli/get/get_cmd.go
  • internal/rendering/tables/osac.private.v1.ExternalIP.yaml
  • internal/rendering/tables/osac.private.v1.ExternalIPAttachment.yaml
  • internal/rendering/tables/osac.private.v1.ExternalIPPool.yaml
  • internal/rendering/tables/osac.public.v1.ExternalIP.yaml
  • internal/rendering/tables/osac.public.v1.ExternalIPAttachment.yaml
  • internal/rendering/tables/osac.public.v1.ExternalIPPool.yaml

Comment on lines +79 to +82
result.MarkFlagRequired("externalip") //nolint:errcheck
result.MarkFlagsMutuallyExclusive("compute-instance", "cluster", "baremetal-instance")
return result
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🔵 Trivial | ⚡ Quick win

Validate target flags before dialing gRPC; prefer MarkFlagsOneRequired.

The "at least one target required" check (Lines 114-116) runs only after the gRPC connection is already established (Lines 108-112), wasting a dial on invalid input. Cobra already provides MarkFlagsOneRequired, which enforces this at parse time (like MarkFlagsMutuallyExclusive above it) and removes the need for the manual check entirely.

♻️ Proposed fix
 	result.MarkFlagRequired("externalip") //nolint:errcheck
 	result.MarkFlagsMutuallyExclusive("compute-instance", "cluster", "baremetal-instance")
+	result.MarkFlagsOneRequired("compute-instance", "cluster", "baremetal-instance")
 	return result
 }
 	defer conn.Close()

-	if c.args.computeInstance == "" && c.args.cluster == "" && c.args.baremetalInstance == "" {
-		return fmt.Errorf("exactly one target is required: --compute-instance, --cluster, or --baremetal-instance")
-	}
-
 	eipClient := publicv1.NewExternalIPsClient(conn)
Based on learnings, `MarkFlagsMutuallyExclusive`/`MarkFlagsOneRequired` are void methods that panic on unknown flag names (not error-returning), so this is a safe drop-in.

Also applies to: 108-116

🤖 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
`@internal/cmd/cli/create/externalipattachment/create_externalipattachment_cmd.go`
around lines 79 - 82, Move the “at least one target required” validation out of
the gRPC path by adding `MarkFlagsOneRequired` alongside the existing
`MarkFlagRequired`/`MarkFlagsMutuallyExclusive` setup in
`create_externalipattachment_cmd.go`, and remove the manual target check from
`CreateExternalIPAttachmentCmd` so invalid input is rejected during flag parsing
before any dial happens. Use the existing flag names (`compute-instance`,
`cluster`, `baremetal-instance`, `externalip`) in the command builder and keep
the runtime logic focused on constructing the request after validation succeeds.

Comment on lines +176 to +182
if c.args.targetEndpoint != "" {
endpoint, err := parseTargetEndpoint(c.args.targetEndpoint)
if err != nil {
return err
}
spec.TargetEndpoint = endpoint
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

--target-endpoint silently ignored for non-cluster targets.

If a user passes --target-endpoint together with --compute-instance or --baremetal-instance, it's silently dropped with no error — likely confusing since the help text implies it's cluster-specific.

🐛 Proposed fix
+	if c.args.targetEndpoint != "" && c.args.cluster == "" {
+		return fmt.Errorf("--target-endpoint is only valid together with --cluster")
+	}
+
 	switch {
 	case c.args.computeInstance != "":
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if c.args.targetEndpoint != "" {
endpoint, err := parseTargetEndpoint(c.args.targetEndpoint)
if err != nil {
return err
}
spec.TargetEndpoint = endpoint
}
if c.args.targetEndpoint != "" && c.args.cluster == "" {
return fmt.Errorf("--target-endpoint is only valid together with --cluster")
}
if c.args.targetEndpoint != "" {
endpoint, err := parseTargetEndpoint(c.args.targetEndpoint)
if err != nil {
return err
}
spec.TargetEndpoint = endpoint
}
🤖 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
`@internal/cmd/cli/create/externalipattachment/create_externalipattachment_cmd.go`
around lines 176 - 182, The `--target-endpoint` flag is currently accepted even
when the target is not a cluster, but `createExternalIPAttachment` silently
drops it for `--compute-instance` and `--baremetal-instance`. Update the
argument handling around `parseTargetEndpoint` and `spec.TargetEndpoint` to
validate that `targetEndpoint` is only allowed for cluster targets, and return a
clear error when it is used with non-cluster targets.

Comment on lines +92 to +144
func RenderExternalIPAttachment(w io.Writer, a *publicv1.ExternalIPAttachment) {
writer := tabwriter.NewWriter(w, 0, 0, 2, ' ', 0)

name := "-"
if v := a.GetMetadata().GetName(); v != "" {
name = v
}

externalIP := "-"
if v := a.GetSpec().GetExternalIp(); v != "" {
externalIP = v
}

targetType := "-"
targetID := "-"
if v := a.GetSpec().GetComputeInstance(); v != "" {
targetType = "ComputeInstance"
targetID = v
} else if v := a.GetSpec().GetCluster(); v != "" {
targetType = "Cluster"
targetID = v
} else if v := a.GetSpec().GetBaremetalInstance(); v != "" {
targetType = "BaremetalInstance"
targetID = v
}

state := "-"
externalIPAddress := "-"
message := "-"
if a.GetStatus() != nil {
state = strings.TrimPrefix(a.GetStatus().GetState().String(), "EXTERNAL_IP_ATTACHMENT_STATE_")
if v := a.GetStatus().GetExternalIpAddress(); v != "" {
externalIPAddress = v
}
if v := a.GetStatus().GetMessage(); v != "" {
message = v
}
}

fmt.Fprintf(writer, "ID:\t%s\n", a.GetId())
fmt.Fprintf(writer, "Name:\t%s\n", name)
fmt.Fprintf(writer, "External IP:\t%s\n", externalIP)
fmt.Fprintf(writer, "Target Type:\t%s\n", targetType)
fmt.Fprintf(writer, "Target:\t%s\n", targetID)
if a.GetSpec().GetCluster() != "" {
endpoint := strings.TrimPrefix(a.GetSpec().GetTargetEndpoint().String(), "EXTERNAL_IP_ATTACHMENT_ENDPOINT_")
fmt.Fprintf(writer, "Target Endpoint:\t%s\n", endpoint)
}
fmt.Fprintf(writer, "External IP Address:\t%s\n", externalIPAddress)
fmt.Fprintf(writer, "State:\t%s\n", state)
fmt.Fprintf(writer, "Message:\t%s\n", message)
writer.Flush()
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
fd -e go -p 'internal/api' | xargs rg -n 'ExternalIPAttachmentState_EXTERNAL_IP_ATTACHMENT_STATE|ExternalIPAttachmentEndpoint_EXTERNAL_IP_ATTACHMENT_ENDPOINT' -A1

Repository: osac-project/fulfillment-service

Length of output: 11331


🏁 Script executed:

#!/bin/bash
set -euo pipefail

# Inspect the enum stringers and related generated code for the public API.
file=internal/api/osac/public/v1/external_ip_attachment_type.pb.go
rg -n 'func \(x ExternalIPAttachment(State|Endpoint)\) String\(\)|String\(\) string|ExternalIPAttachment(State|Endpoint)_EXTERNAL_IP_ATTACHMENT_' "$file" -A6 -B2

Repository: osac-project/fulfillment-service

Length of output: 5158


Trim the enum prefixes before rendering

ExternalIPAttachmentState.String() and ExternalIPAttachmentEndpoint.String() return names like EXTERNAL_IP_ATTACHMENT_STATE_READY and EXTERNAL_IP_ATTACHMENT_ENDPOINT_API, so these prefixes need to be removed here; otherwise the CLI prints the raw constant names.

🤖 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
`@internal/cmd/cli/describe/externalipattachment/describe_externalipattachment_cmd.go`
around lines 92 - 144, RenderExternalIPAttachment is still printing raw enum
names for the status and target endpoint. Update the state and target endpoint
rendering to trim the EXTERNAL_IP_ATTACHMENT_STATE_ and
EXTERNAL_IP_ATTACHMENT_ENDPOINT_ prefixes before writing them to the tabwriter,
using the existing strings.TrimPrefix logic around
a.GetStatus().GetState().String() and a.GetSpec().GetTargetEndpoint().String().
Keep the fallback values intact so missing fields still render as "-".

Comment on lines +32 to +33
- header: ADDRESS
value: "this.status.address != ''? this.status.address: '-'"

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Inconsistent CEL idiom for empty-value fallback.

ADDRESS uses != '' while PROJECT/NAME elsewhere in this file use has(...). Based on learnings, has() on a proto3 non-optional string scalar already evaluates to false for the empty default, so this could be unified with the has() idiom used elsewhere for readability/consistency.

♻️ Optional consistency fix
-- header: ADDRESS
-  value: "this.status.address != ''? this.status.address: '-'"
+- header: ADDRESS
+  value: "has(this.status.address)? this.status.address: '-'"
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
- header: ADDRESS
value: "this.status.address != ''? this.status.address: '-'"
- header: ADDRESS
value: "has(this.status.address)? this.status.address: '-'"
🤖 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 `@internal/rendering/tables/osac.private.v1.ExternalIP.yaml` around lines 32 -
33, The ADDRESS field uses a different empty-value fallback idiom than the other
columns in this table. Update the value expression in the ExternalIP table
definition to match the existing has(...) pattern used for PROJECT/NAME, and
keep the fallback to '-' when the status address is unset or empty. Use the
ADDRESS entry in this YAML and the other column expressions as the reference for
the consistency change.

Source: Learnings

@ori-amizur

Copy link
Copy Markdown
Contributor

/lgtm

@openshift-ci

openshift-ci Bot commented Jul 5, 2026

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is APPROVED

Approval requirements bypassed by manually added approval.

This pull-request has been approved by: danmanor

The full list of commands accepted by this bot can be found here.

The pull request process is described here

Details Needs approval from an approver in each of these files:

Approvers can indicate their approval by writing /approve in a comment
Approvers can cancel approval by writing /approve cancel in a comment

@openshift-merge-bot
openshift-merge-bot Bot merged commit 990e2ec into osac-project:main Jul 5, 2026
15 checks passed

This branch was previously deployed

1 inactive deployment
e2e-test — 9cac53e9 Deployed Jul 5, 2026 by danmanor via e2e-vmaas-full-install / e2e #167
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants