Skip to content

feat: add nodepool commands and align cluster spec with HyperShift CRD#92

Open
typeid wants to merge 1 commit into
openshift-online:mainfrom
typeid:pgruntime
Open

feat: add nodepool commands and align cluster spec with HyperShift CRD#92
typeid wants to merge 1 commit into
openshift-online:mainfrom
typeid:pgruntime

Conversation

@typeid

@typeid typeid commented Jul 10, 2026

Copy link
Copy Markdown
Contributor

Summary

  • Add rosactl nodepool create/list/delete subcommands with SigV4-signed platform API requests
  • Auto-discover subnet, instance profile, and security groups from cluster spec and CloudFormation stacks when flags are omitted
  • Align cluster configuration with HyperShift ClusterSpec CRD (nested rolesRef, subnet arrays, oidcIssuerURL)
  • Harden input handling: path-escape URL path segments, validate pagination flags, return errors on JSON parse failures, fail fast on missing stack outputs

Test plan

  • rosactl nodepool create with auto-discovery from cluster spec
  • rosactl nodepool create with explicit --subnet-id, --instance-profile, --security-groups
  • rosactl nodepool list --cluster-id <id> table and JSON output
  • rosactl nodepool list with invalid --limit / --offset values rejected
  • rosactl nodepool delete <id>
  • rosactl cluster create shows "OIDC Issuer URL" (not "Cloud URL") in summary
  • rosactl cluster create --dry-run generates valid ClusterSpec JSON

🤖 Generated with Claude Code

Summary by CodeRabbit

  • New Features
    • Added nodepool commands to create, list, and delete ROSA hosted cluster node pools.
    • Node pool creation auto-discovers networking and IAM settings when not provided.
    • Node pool listing supports table and JSON output with --limit/--offset, showing key node pool fields.
    • Node pool deletion confirms initiation.
  • Improvements
    • Cluster details now display the OIDC issuer URL instead of the Cloud URL.
    • Cluster configuration now validates required VPC/subnet and IAM instance profile inputs before building the request.

@openshift-ci

openshift-ci Bot commented Jul 10, 2026

Copy link
Copy Markdown

[APPROVALNOTIFIER] This PR is APPROVED

This pull-request has been approved by: typeid

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-ci openshift-ci Bot added the approved Indicates a PR has been approved by an approver from all required OWNERS files. label Jul 10, 2026
@coderabbitai

coderabbitai Bot commented Jul 10, 2026

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository: openshift-online/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: 52247b9c-84f8-4118-942f-f6873ed6673a

📥 Commits

Reviewing files that changed from the base of the PR and between 3b68e9a and deafaf8.

📒 Files selected for processing (9)
  • internal/commands/cluster/create.go
  • internal/commands/cluster/list.go
  • internal/commands/nodepool/api.go
  • internal/commands/nodepool/create.go
  • internal/commands/nodepool/delete.go
  • internal/commands/nodepool/list.go
  • internal/commands/nodepool/nodepool.go
  • internal/commands/root.go
  • internal/services/cluster/service.go
🚧 Files skipped from review as they are similar to previous changes (9)
  • internal/commands/nodepool/nodepool.go
  • internal/commands/cluster/list.go
  • internal/commands/nodepool/api.go
  • internal/commands/root.go
  • internal/commands/nodepool/delete.go
  • internal/commands/cluster/create.go
  • internal/commands/nodepool/list.go
  • internal/services/cluster/service.go
  • internal/commands/nodepool/create.go

Walkthrough

Adds AWS SigV4-backed nodepool create, list, and delete commands, wires them into the CLI, updates cluster OIDC issuer output, and changes hosted cluster AWS payload construction.

Changes

Cluster and node pool workflows

Layer / File(s) Summary
Hosted cluster AWS payload and OIDC fields
internal/services/cluster/service.go, internal/commands/cluster/list.go, internal/commands/cluster/create.go
Validates VPC and IAM outputs, builds the nested hosted cluster AWS specification, and maps and displays oidcIssuerURL instead of the previous cloud URL field.
Signed node pool API transport
internal/commands/nodepool/api.go
Adds timed AWS SigV4-signed GET, POST, and DELETE request helpers.
Node pool creation flow
internal/commands/nodepool/create.go
Implements creation options, AWS and cluster-spec discovery, validation, request construction, signed submission, status handling, and output formatting.
Node pool listing and deletion
internal/commands/nodepool/list.go, internal/commands/nodepool/delete.go
Implements signed list and delete operations with argument validation, response handling, table or JSON output, and deletion confirmation.
Node pool command registration
internal/commands/nodepool/nodepool.go, internal/commands/root.go
Adds the nodepool command group and registers its lifecycle subcommands with the root CLI.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant CreateCommand
  participant AWS
  participant ClusterAPI
  participant PlatformAPI
  User->>CreateCommand: run nodepool create
  CreateCommand->>AWS: load credentials and discover infrastructure
  CreateCommand->>ClusterAPI: fetch cluster spec when subnet discovery is needed
  ClusterAPI-->>CreateCommand: return cluster specification
  CreateCommand->>PlatformAPI: send signed node pool creation request
  PlatformAPI-->>CreateCommand: return created node pool
  CreateCommand-->>User: print JSON or creation summary
Loading

Important

Pre-merge checks failed

Please resolve all errors before merging. Addressing warnings is optional.

❌ Failed checks (1 error, 2 warnings)

Check name Status Explanation Resolution
No-Sensitive-Data-In-Logs ❌ Error New logs print AWS account IDs and raw API response bodies, which can expose internal/customer data. Remove the account-ID printf and avoid including raw response bodies in errors; log only sanitized status codes or request IDs.
Docstring Coverage ⚠️ Warning Docstring coverage is 12.50% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Ai-Attribution ⚠️ Warning PR says it was generated with Claude Code, but the commit uses only Co-Authored-By; no Assisted-by/Generated-by trailer is present. Replace the AI co-author line with an Assisted-by or Generated-by trailer that follows Red Hat attribution rules.
✅ Passed checks (8 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main changes: adding nodepool commands and aligning the cluster spec with the HyperShift CRD.
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-Weak-Crypto ✅ Passed Changed code only uses SHA-256 for AWS SigV4 signing; no MD5/SHA1/DES/RC4/3DES/Blowfish/ECB or secret comparisons found.
Container-Privileges ✅ Passed PR changes only Go code; diff vs main has no container/K8s manifest edits or privilege-related fields.
No-Hardcoded-Secrets ✅ Passed No hardcoded keys, tokens, passwords, base64 blobs, or credentialed URLs were found in changed files; AWS creds are only loaded at runtime.
No-Injection-Vectors ✅ Passed No SQL, shell, eval, pickle, YAML, or DOM injection sinks were added; user input is only JSON-serialized or URL-escaped in HTTP requests.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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

@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

🧹 Nitpick comments (2)
internal/commands/nodepool/create.go (2)

170-183: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Response body parsed twice depending on output branch.

json.Unmarshal(body, &result) is called once for the json output path and again (into an identically-typed map[string]interface{}) for the default text path. Parse once and branch on rendering only.

♻️ Parse once, render per format
+	var result map[string]interface{}
+	if err := json.Unmarshal(body, &result); err != nil {
+		return fmt.Errorf("failed to parse response: %w", err)
+	}
+
 	if opts.output == "json" {
-		var result map[string]interface{}
-		if err := json.Unmarshal(body, &result); err != nil {
-			return fmt.Errorf("failed to parse JSON response: %w", err)
-		}
 		prettyJSON, _ := json.MarshalIndent(result, "", "  ")
 		fmt.Println(string(prettyJSON))
 		return nil
 	}
 
-	var result map[string]interface{}
-	if err := json.Unmarshal(body, &result); err != nil {
-		return fmt.Errorf("failed to parse response: %w", err)
-	}
-
 	fmt.Fprintf(os.Stderr, "\n✓ NodePool created successfully\n")
🤖 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/commands/nodepool/create.go` around lines 170 - 183, Parse the
response body only once before the output-format branch, storing it in the
shared result map and returning the existing parse error on failure. Then, in
the json branch, marshal and print that parsed result; keep the default path
rendering the same result without calling json.Unmarshal again.

76-89: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicated AWS config/credentials/region resolution across all three commands.

This exact block (load config → retrieve credentials → default region to us-east-1) is repeated verbatim in list.go (lines 84-97) and delete.go (lines 37-50). Since all four files share package nodepool, this is a straightforward extraction opportunity.

♻️ Suggested shared helper (e.g., in api.go)
func resolveCredentials(ctx context.Context) (awssdk.Credentials, string, error) {
	cfg, err := aws.NewConfig(ctx)
	if err != nil {
		return awssdk.Credentials{}, "", fmt.Errorf("failed to load AWS config: %w", err)
	}
	creds, err := cfg.Credentials.Retrieve(ctx)
	if err != nil {
		return awssdk.Credentials{}, "", fmt.Errorf("failed to retrieve AWS credentials: %w", err)
	}
	region := cfg.Region
	if region == "" {
		region = "us-east-1"
	}
	return creds, region, nil
}

Then in each run* function:

-	cfg, err := aws.NewConfig(ctx)
-	if err != nil {
-		return fmt.Errorf("failed to load AWS config: %w", err)
-	}
-
-	creds, err := cfg.Credentials.Retrieve(ctx)
-	if err != nil {
-		return fmt.Errorf("failed to retrieve AWS credentials: %w", err)
-	}
-
-	region := cfg.Region
-	if region == "" {
-		region = "us-east-1"
-	}
+	creds, region, err := resolveCredentials(ctx)
+	if err != nil {
+		return err
+	}
🤖 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/commands/nodepool/create.go` around lines 76 - 89, Extract the
repeated AWS config, credential retrieval, and default-region logic from the run
functions in create, list, and delete into a shared package-level helper such as
resolveCredentials. Have it return credentials, the resolved region, and wrapped
errors, then update each run function to call the helper and remove the
duplicated block.
🤖 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/commands/nodepool/create.go`:
- Around line 100-115: Propagate CloudFormation lookup failures instead of
silently ignoring them in the instance profile and security group discovery
block. Update the DescribeStack calls within the node pool creation logic to
return or wrap the underlying error immediately with context identifying the
relevant stack and lookup, while preserving successful output assignment.
- Around line 60-64: Add bounds validation for the replicas option in the create
command’s RunE handler before invoking the creation logic, rejecting zero and
negative values with a clear error. Follow the existing validation pattern used
by list.go while referencing the replicas field and create command flow.

In `@internal/services/cluster/service.go`:
- Around line 93-123: Remove the unused WorkerInstanceProfileName lookup and
validation from the spec-generation function, since workerInstanceProfile is not
referenced in the generated payload. Keep the existing IAM role mappings and
spec construction unchanged unless the profile is explicitly required by the
API, in which case add it to the appropriate spec field and retain the
validation.

---

Nitpick comments:
In `@internal/commands/nodepool/create.go`:
- Around line 170-183: Parse the response body only once before the
output-format branch, storing it in the shared result map and returning the
existing parse error on failure. Then, in the json branch, marshal and print
that parsed result; keep the default path rendering the same result without
calling json.Unmarshal again.
- Around line 76-89: Extract the repeated AWS config, credential retrieval, and
default-region logic from the run functions in create, list, and delete into a
shared package-level helper such as resolveCredentials. Have it return
credentials, the resolved region, and wrapped errors, then update each run
function to call the helper and remove the duplicated block.
🪄 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: openshift-online/coderabbit/.coderabbit.yaml

Review profile: CHILL

Plan: Enterprise

Run ID: aafdca30-aa0e-48fb-9d8a-0985866ec4c6

📥 Commits

Reviewing files that changed from the base of the PR and between 00c3e2a and 3b68e9a.

📒 Files selected for processing (9)
  • internal/commands/cluster/create.go
  • internal/commands/cluster/list.go
  • internal/commands/nodepool/api.go
  • internal/commands/nodepool/create.go
  • internal/commands/nodepool/delete.go
  • internal/commands/nodepool/list.go
  • internal/commands/nodepool/nodepool.go
  • internal/commands/root.go
  • internal/services/cluster/service.go

Comment thread internal/commands/nodepool/create.go
Comment thread internal/commands/nodepool/create.go
Comment thread internal/services/cluster/service.go
@typeid typeid added do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command. and removed do-not-merge/work-in-progress Indicates that a PR should not merge because it is a work in progress. labels Jul 10, 2026
Add rosactl nodepool create/list/delete subcommands that talk to the
platform API with SigV4-signed requests. The create command
auto-discovers subnet, instance profile, and security groups from the
cluster spec and CloudFormation stacks when flags are omitted.

Align the cluster configuration with the HyperShift ClusterSpec CRD:
- Nest IAM role ARNs under platform.aws.rolesRef
- Send privateSubnetIds as an array
- Rename cloudUrl to oidcIssuerURL throughout

Harden commands against malformed or malicious input:
- Path-escape IDs interpolated into API URLs
- Return errors on JSON unmarshal failures instead of swallowing them
- Validate pagination flags (limit 1-100, offset >= 0)
- Fail fast on missing CloudFormation stack outputs

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

approved Indicates a PR has been approved by an approver from all required OWNERS files. do-not-merge/hold Indicates that a PR should not merge because someone has issued a /hold command.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant