Skip to content

Conversation

@yaacov
Copy link
Owner

@yaacov yaacov commented Nov 26, 2025

Summary by CodeRabbit

  • New Features

    • EC2 provider support across CLI inventory (instances, volumes, volume types, networks), planning and mapping, and automatic mapping during plan creation.
    • New EC2-aware network and storage mapping/fetching for migration plans.
    • UI/UX additions: Auto‑Mapping, Real‑time Monitoring, Timezone‑Aware Display.
  • Documentation

    • Provider guides updated for EC2 region/key-based setup (URL now optional/auto-generated) and added EC2-specific resources and auto‑mapping examples.

✏️ Tip: You can customize this high-level summary in your review settings.

@coderabbitai
Copy link

coderabbitai bot commented Nov 26, 2025

Warning

Rate limit exceeded

@yaacov has exceeded the limit for the number of commits or files that can be reviewed per hour. Please wait 0 minutes and 17 seconds before requesting another review.

⌛ How to resolve this issue?

After the wait time has elapsed, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans have higher rate limits than the trial, open-source and free plans. In all cases, we re-allow further reviews after a brief timeout.

Please see our FAQ for further information.

📥 Commits

Reviewing files that changed from the base of the PR and between 9fbed75 and 7bd7598.

📒 Files selected for processing (25)
  • README.md (2 hunks)
  • cmd/create/provider.go (1 hunks)
  • cmd/get/inventory.go (1 hunks)
  • cmd/get/inventory_ec2.go (1 hunks)
  • cmd/patch/provider.go (1 hunks)
  • guide/04-provider-management.md (2 hunks)
  • guide/07-inventory-management.md (1 hunks)
  • guide/09-mapping-management.md (1 hunks)
  • guide/10-migration-plan-creation.md (1 hunks)
  • pkg/cmd/create/mapping/network_helpers.go (1 hunks)
  • pkg/cmd/create/mapping/storage_helpers.go (3 hunks)
  • pkg/cmd/create/plan/network/factory.go (3 hunks)
  • pkg/cmd/create/plan/network/fetchers/ec2/fetcher.go (1 hunks)
  • pkg/cmd/create/plan/network/mapper/ec2/mapper.go (1 hunks)
  • pkg/cmd/create/plan/storage/factory.go (4 hunks)
  • pkg/cmd/create/plan/storage/fetchers/ec2/fetcher.go (1 hunks)
  • pkg/cmd/create/plan/storage/mapper/ec2/mapper.go (1 hunks)
  • pkg/cmd/create/provider/create.go (1 hunks)
  • pkg/cmd/create/provider/ec2/ec2.go (4 hunks)
  • pkg/cmd/create/provider/ec2/secrets.go (1 hunks)
  • pkg/cmd/get/inventory/ec2.go (1 hunks)
  • pkg/cmd/get/inventory/networks.go (2 hunks)
  • pkg/cmd/get/inventory/storage.go (2 hunks)
  • pkg/cmd/get/inventory/vms.go (5 hunks)
  • pkg/cmd/patch/provider/patch.go (1 hunks)

Walkthrough

Adds comprehensive EC2 support: new CLI inventory subcommands and EC2-aware inventory listing; EC2 provider creation with optional region-derived URL; EC2 network/storage fetchers and mappers wired into plan factories; mapping helpers for EC2 name→ID resolution; and documentation updates (EC2 examples and auto-mapping).

Changes

Cohort / File(s) Summary
Documentation
README.md, guide/04-provider-management.md, guide/07-inventory-management.md, guide/09-mapping-management.md, guide/10-migration-plan-creation.md
Add EC2 provider examples, note region-derived default URL and EC2-specific flags, document EC2 inventory resources and auto-mapping, and include an auto-mapping plan example.
CLI Inventory — Registration
cmd/get/inventory.go
Register four new EC2 inventory subcommands: ec2-instances, ec2-volumes, ec2-volumetypes (aliases), and ec2-networks.
CLI Inventory — Command Factory
cmd/get/inventory_ec2.go
New EC2 inventory command factory and Cobra constructors (NewInventoryEC2InstanceCmd, NewInventoryEC2VolumeCmd, NewInventoryEC2VolumeTypeCmd, NewInventoryEC2NetworkCmd) with output/query/watch flags, completion, and timeout wiring to inventory ListEC2*WithInsecure functions.
Inventory Retrieval — EC2 Implementations
pkg/cmd/get/inventory/ec2.go
Add ListEC2InstancesWithInsecure, ListEC2VolumesWithInsecure, ListEC2VolumeTypesWithInsecure, ListEC2NetworksWithInsecure: provider resolution, insecure client support, watch/polling, query filtering, and EC2-specific field normalization helpers (tag/name extraction, size humanization, network normalization).
Inventory Retrieval — Existing Flows
pkg/cmd/get/inventory/vms.go, pkg/cmd/get/inventory/networks.go, pkg/cmd/get/inventory/storage.go
Add ec2 provider branches: EC2-specific default headers, call EC2 processors (e.g., processEC2Network/processEC2Volume), and integrate EC2 augmentations while preserving other providers.
Provider Creation — EC2
pkg/cmd/create/provider/ec2/ec2.go, pkg/cmd/create/provider/ec2/secrets.go
Make URL optional for EC2 providers; derive default AWS regional endpoint when omitted; populate provider.Spec.URL with computed endpoint and pass it into secret creation; remove TLS/CA-required checks for EC2 flow (comment clarifies secret includes URL).
Mapping Helpers — Network & Storage
pkg/cmd/create/mapping/network_helpers.go, pkg/cmd/create/mapping/storage_helpers.go
Add EC2-specific resolvers: resolveEC2NetworkNameToIDWithInsecure (match SubnetId/VpcId or Name tag) and resolveEC2StorageNameToID (match EBS volume types via type field), with inventory fetches and explicit error handling.
Plan Factories — Network & Storage Wiring
pkg/cmd/create/plan/network/factory.go, pkg/cmd/create/plan/storage/factory.go
Wire EC2 cases into factory switches to return EC2 fetchers/mappers; add imports for EC2-specific fetcher/mapper packages.
Plan Components — EC2 Network
pkg/cmd/create/plan/network/fetchers/ec2/fetcher.go, pkg/cmd/create/plan/network/mapper/ec2/mapper.go
Add EC2NetworkFetcher (partition subnets vs VPCs, sort, return refs) and EC2NetworkMapper (map first source to default/pod destination; others to "ignored"; parse default destination formats).
Plan Components — EC2 Storage
pkg/cmd/create/plan/storage/fetchers/ec2/fetcher.go, pkg/cmd/create/plan/storage/mapper/ec2/mapper.go
Add EC2StorageFetcher (extract/deduplicate/prioritize EBS volume types) and EC2StorageMapper (per-type VolumeMode/AccessMode heuristics, heuristic EBS StorageClass matching, CreateStoragePairs implementation).
CLI Timeout/Config Wiring
cmd/get/inventory.go, cmd/get/inventory_ec2.go
Ensure consistent timeout (280s) for non-watch inventory commands and pass global config (inventory URL, insecure TLS) into new EC2 CLI commands.

Sequence Diagram(s)

sequenceDiagram
    autonumber
    participant U as User
    participant CLI as CLI Command
    participant GC as GlobalConfig
    participant Prov as ProviderStore
    participant Inv as InventoryClient
    participant Out as Formatter
    Note over CLI,GC: resolve namespace, inventory URL, insecure flag
    U->>CLI: kubectl mtv get inventory ec2-instances <provider>
    CLI->>GC: resolve namespace & inventory config
    CLI->>Prov: GetProviderByName(provider, namespace)
    Prov-->>CLI: provider object
    CLI->>Inv: FetchProviderInventoryWithInsecure(inventoryURL, provider)
    Inv->>Prov: provider client -> GetVMs()
    Prov-->>Inv: EC2 instance data
    Inv-->>CLI: raw instances
    CLI->>CLI: addEC2InstanceNames() / normalize fields
    CLI->>Out: render (table/json/yaml) with EC2 headers
    Out-->>U: output
Loading
sequenceDiagram
    autonumber
    participant U as User
    participant CLI as Plan Creator
    participant Inv as Inventory
    participant NF as EC2 Network Fetcher
    participant NM as EC2 Network Mapper
    participant SF as EC2 Storage Fetcher
    participant SM as EC2 Storage Mapper
    participant Plan as Plan
    U->>CLI: create plan with EC2 source
    CLI->>NF: FetchSourceNetworks()
    NF->>Inv: Fetch networks (detail=4)
    Inv-->>NF: VPCs & Subnets
    NF->>NF: partition & sort -> refs
    NF-->>CLI: network refs
    CLI->>NM: CreateNetworkPairs(sources, targets, opts)
    NM->>NM: determine default dest -> NetworkPairs
    NM-->>Plan: add network pairs
    CLI->>SF: FetchSourceStorages()
    SF->>Inv: Fetch storages (detail=4)
    Inv-->>SF: volume types
    SF->>SF: extract & prioritize -> refs
    SF-->>CLI: storage refs
    CLI->>SM: CreateStoragePairs(sources, targets, opts)
    SM->>SM: determine VolumeMode/AccessMode & match StorageClass
    SM-->>Plan: add storage pairs
    Plan-->>U: plan created
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

  • Areas needing extra attention:
    • EC2 provider URL derivation and secret propagation (pkg/cmd/create/provider/ec2/ec2.go, secrets.go)
    • EC2 storage mapper heuristics, matching logic and fallbacks (pkg/cmd/create/plan/storage/mapper/ec2/mapper.go)
    • Inventory listing/watch/timeout and query application (pkg/cmd/get/inventory/ec2.go)
    • Mapping helper assumptions about inventory JSON shapes (pkg/cmd/create/mapping/*_helpers.go)
    • Correct integration of new fetcher/mapper constructors into factories and their logging behavior

Possibly related PRs

  • init-ec2 #126 — Overlapping EC2 provider support changes (provider creation, inventory EC2 handlers, mapping helpers/fetchers).
  • auto mappings #121 — Introduces mapping interfaces/factory patterns that EC2 fetchers/mappers integrate with.
  • insecure-inventory #123 — Adds GlobalConfig getters and "WithInsecure" inventory/client variants used by the new EC2 inventory and TLS plumbing.

Poem

🐰 I hopped through code at break of dawn,

regions knit URLs before the yawn.
Subnets sorted, volumes named with care,
auto-maps stitched from here to there.
A rabbit cheers — the plan's aware. 🥕

Pre-merge checks and finishing touches

❌ Failed checks (1 inconclusive)
Check name Status Explanation Resolution
Title check ❓ Inconclusive The title 'more ec2' is vague and non-descriptive, failing to clearly convey the scope of changes which include inventory commands, provider management, mapping factories, and comprehensive EC2 support infrastructure. Use a more specific title that summarizes the main additions, such as 'Add EC2 provider support for inventory, mapping, and resource fetching' or 'Implement comprehensive EC2 integration for migration planning'.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Docstring Coverage ✅ Passed Docstring coverage is 80.00% which is sufficient. The required threshold is 80.00%.

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.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (4)
pkg/cmd/create/plan/network/mapper/ec2/mapper.go (1)

73-112: Simplify parseDefaultNetwork using strings.Cut and remove dead code.

The parsing logic is overly complex with a manual character-by-character search. The else block at lines 102-105 is unreachable because the condition at line 86 (idx >= 0) is always true for any non-empty string that reaches that branch.

Consider this simpler implementation:

+import "strings"
+
 // parseDefaultNetwork parses the default network string into a DestinationNetwork
 func parseDefaultNetwork(defaultNetwork, namespace string) forkliftv1beta1.DestinationNetwork {
 	// Handle special cases
 	if defaultNetwork == "default" || defaultNetwork == "" {
 		return forkliftv1beta1.DestinationNetwork{Type: "pod"}
 	}
 
-	// Parse namespace/name format
-	var targetNamespace, targetName string
-	if len(defaultNetwork) > 0 && defaultNetwork[0] == '/' {
-		// Format: /name (use provided namespace)
-		targetNamespace = namespace
-		targetName = defaultNetwork[1:]
-	} else if idx := len(defaultNetwork) - 1; idx >= 0 {
-		// Check for namespace/name format
-		found := false
-		for i := 0; i < len(defaultNetwork); i++ {
-			if defaultNetwork[i] == '/' {
-				targetNamespace = defaultNetwork[:i]
-				targetName = defaultNetwork[i+1:]
-				found = true
-				break
-			}
-		}
-		if !found {
-			// Just a name, use provided namespace
-			targetNamespace = namespace
-			targetName = defaultNetwork
-		}
-	} else {
-		targetNamespace = namespace
-		targetName = defaultNetwork
-	}
+	var targetNamespace, targetName string
+	if ns, name, found := strings.Cut(defaultNetwork, "/"); found {
+		if ns == "" {
+			// Format: /name (use provided namespace)
+			targetNamespace = namespace
+		} else {
+			targetNamespace = ns
+		}
+		targetName = name
+	} else {
+		// Just a name, use provided namespace
+		targetNamespace = namespace
+		targetName = defaultNetwork
+	}
 
 	return forkliftv1beta1.DestinationNetwork{
 		Type:      "multus",
 		Namespace: targetNamespace,
 		Name:      targetName,
 	}
 }
pkg/cmd/create/plan/network/fetchers/ec2/fetcher.go (1)

27-27: Unused parameter planVMNames.

The planVMNames parameter is declared but never used in this function. If it's required by the interface signature, consider adding a comment explaining why it's intentionally unused, or add a blank identifier to suppress linter warnings if applicable.

-func (f *EC2NetworkFetcher) FetchSourceNetworks(ctx context.Context, configFlags *genericclioptions.ConfigFlags, providerName, namespace, inventoryURL string, planVMNames []string, insecureSkipTLS bool) ([]ref.Ref, error) {
+func (f *EC2NetworkFetcher) FetchSourceNetworks(ctx context.Context, configFlags *genericclioptions.ConfigFlags, providerName, namespace, inventoryURL string, _ []string, insecureSkipTLS bool) ([]ref.Ref, error) {
cmd/get/inventory_ec2.go (1)

17-63: Consider extracting common command logic to reduce duplication.

All four EC2 command constructors share identical structure: timeout handling, namespace resolution, flag registration, and completion setup. This pattern is repeated ~150 lines.

A helper function could reduce duplication:

type ec2CommandConfig struct {
    use          string
    short        string
    long         string
    listFunc     func(ctx context.Context, flags *genericclioptions.ConfigFlags, provider, namespace, inventoryURL, outputFormat, query string, watch, insecure bool) error
}

func newEC2InventoryCmd(kubeConfigFlags *genericclioptions.ConfigFlags, globalConfig GlobalConfigGetter, cfg ec2CommandConfig) *cobra.Command {
    // ... common implementation
}

This is optional as the current explicit approach is also readable and self-contained per command.

pkg/cmd/get/inventory/ec2.go (1)

488-504: Network type detection may leave networkType unset for VPCs with subnets.

The logic at lines 491-503 has a subtle issue: when a network has both VpcId and SubnetId (which subnets do), the VPC block (lines 491-498) won't set id or networkType because it checks for absence of SubnetId. However, the subnet block at line 499 will then correctly handle it.

The issue is when processing a VPC that happens to have no SubnetId key but also no VpcId key (malformed data) - networkType remains unset. Consider adding a fallback.

 		if subnetID, ok := network["SubnetId"].(string); ok {
 			// It's a Subnet
 			network["id"] = subnetID
 			network["networkType"] = "subnet"
 		}
 	}
+
+	// Fallback if networkType wasn't set
+	if _, hasType := network["networkType"]; !hasType {
+		network["networkType"] = "unknown"
+	}
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c6a241b and bb51609.

📒 Files selected for processing (21)
  • README.md (2 hunks)
  • cmd/get/inventory.go (1 hunks)
  • cmd/get/inventory_ec2.go (1 hunks)
  • guide/04-provider-management.md (1 hunks)
  • guide/07-inventory-management.md (1 hunks)
  • guide/09-mapping-management.md (1 hunks)
  • guide/10-migration-plan-creation.md (1 hunks)
  • pkg/cmd/create/mapping/network_helpers.go (1 hunks)
  • pkg/cmd/create/mapping/storage_helpers.go (2 hunks)
  • pkg/cmd/create/plan/network/factory.go (3 hunks)
  • pkg/cmd/create/plan/network/fetchers/ec2/fetcher.go (1 hunks)
  • pkg/cmd/create/plan/network/mapper/ec2/mapper.go (1 hunks)
  • pkg/cmd/create/plan/storage/factory.go (3 hunks)
  • pkg/cmd/create/plan/storage/fetchers/ec2/fetcher.go (1 hunks)
  • pkg/cmd/create/plan/storage/mapper/ec2/mapper.go (1 hunks)
  • pkg/cmd/create/provider/ec2/ec2.go (2 hunks)
  • pkg/cmd/create/provider/ec2/secrets.go (1 hunks)
  • pkg/cmd/get/inventory/ec2.go (1 hunks)
  • pkg/cmd/get/inventory/networks.go (2 hunks)
  • pkg/cmd/get/inventory/storage.go (2 hunks)
  • pkg/cmd/get/inventory/vms.go (4 hunks)
🧰 Additional context used
🧬 Code graph analysis (9)
cmd/get/inventory.go (1)
cmd/get/inventory_ec2.go (4)
  • NewInventoryEC2InstanceCmd (17-63)
  • NewInventoryEC2VolumeCmd (66-112)
  • NewInventoryEC2VolumeTypeCmd (115-161)
  • NewInventoryEC2NetworkCmd (164-210)
pkg/cmd/create/mapping/network_helpers.go (1)
pkg/util/client/inventory.go (1)
  • FetchProviderInventoryWithInsecure (45-88)
pkg/cmd/create/plan/storage/fetchers/ec2/fetcher.go (2)
pkg/cmd/create/plan/storage/fetchers/interfaces.go (1)
  • StorageFetcher (24-27)
pkg/util/client/inventory.go (1)
  • FetchProviderInventoryWithInsecure (45-88)
pkg/cmd/create/plan/network/mapper/ec2/mapper.go (1)
pkg/cmd/create/plan/network/mapper/interfaces.go (2)
  • NetworkMapper (17-19)
  • NetworkMappingOptions (9-14)
pkg/cmd/get/inventory/storage.go (1)
pkg/util/output/table.go (1)
  • Header (65-68)
pkg/cmd/get/inventory/vms.go (1)
pkg/util/output/table.go (2)
  • Header (65-68)
  • NewTablePrinter (83-93)
pkg/cmd/create/plan/storage/factory.go (2)
pkg/cmd/create/plan/storage/fetchers/ec2/fetcher.go (1)
  • NewEC2StorageFetcher (22-24)
pkg/cmd/create/plan/storage/mapper/ec2/mapper.go (1)
  • NewEC2StorageMapper (18-20)
pkg/cmd/get/inventory/networks.go (1)
pkg/util/output/table.go (1)
  • Header (65-68)
pkg/cmd/create/mapping/storage_helpers.go (1)
pkg/util/client/inventory.go (1)
  • FetchProviderInventoryWithInsecure (45-88)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: Test kubectl-mtv
🔇 Additional comments (29)
pkg/cmd/create/provider/ec2/secrets.go (1)

23-30: Comment correctly documents URL invariant for EC2 secrets

The new comment matches the CreateProvider behavior (URL always set, defaulting from region when omitted) and makes the secret layout clearer for maintainers. No code changes needed here.

README.md (2)

36-45: EC2 quick-start example aligns with new provider flow

The EC2 provider snippet (region required, URL optional) reflects the updated CreateProvider behavior and clearly communicates the default-endpoint behavior to users.


130-137: Features section now accurately reflects EC2 and auto‑mapping capabilities

Including EC2 in multi‑platform support and calling out Auto‑Mapping, monitoring, and timezone-aware display makes the high‑level feature set consistent with the new functionality introduced in this PR.

pkg/cmd/get/inventory/storage.go (1)

53-59: EC2 storage listing path and headers are consistent with volume‑type semantics

The EC2 branch uses GetResourceCollection(ctx, "storages", 4) and exposes TYPE/DESCRIPTION/MAX‑IOPS/MAX‑THROUGHPUT, which aligns with the volume‑type data used in the EC2 storage resolver. Existing provider paths remain untouched.

Also applies to: 84-85

pkg/cmd/create/provider/ec2/ec2.go (2)

20-37: EC2 provider validation is coherent with the new configuration model

Requiring name, namespace, EC2 region, and exactly one of {secret, (access key ID + secret key)} matches the intended EC2 setup and cleanly forbids mixed credential sources.


106-117: Region‑derived default URL and secret wiring look correct

Deriving https://ec2.<region>.amazonaws.com when URL is omitted, setting provider.Spec.URL, and passing the same value into createSecret keeps provider and secret aligned and makes the “URL optional” behavior reliable for downstream consumers.

Also applies to: 122-125

pkg/cmd/create/mapping/storage_helpers.go (1)

192-201: EC2 storage name resolution is consistent with existing provider helpers

Adding an "ec2" branch that delegates to resolveEC2StorageNameToID, and resolving by the type field over storages?detail=4, mirrors the patterns used for vSphere/oVirt/OpenStack/OVA and gives clear errors when a volume type isn’t found.

Also applies to: 247-283

pkg/cmd/get/inventory/networks.go (1)

92-100: EC2 network headers and normalization hook integrate cleanly

The EC2‑specific headers plus the processEC2Network call give a tailored view (name, ID, type, CIDR, state, default) while leaving other provider flows untouched, which should make EC2 VPC/subnet listings much more usable.

Also applies to: 147-150

guide/09-mapping-management.md (1)

33-34: Auto‑mapping note accurately reflects cross‑provider behavior

The new note clearly explains that all source providers (including the newly added EC2 support) participate in automatic mapping during plan creation via provider‑specific mappers, which matches the implementation direction of this PR.

cmd/get/inventory.go (1)

119-135: EC2 inventory subcommands are wired consistently with existing inventory CLI

Registering EC2 instances, volumes, volume types, and networks with clear aliases mirrors the OpenStack/vSphere patterns and cleanly extends the inventory surface for EC2 providers.

guide/07-inventory-management.md (1)

60-69: LGTM! Clear documentation for EC2 resources.

The EC2-specific resources section follows the established documentation pattern and provides clear resource type information. The note about generic resources working with EC2 providers is helpful.

pkg/cmd/create/plan/storage/factory.go (3)

19-19: LGTM! Consistent import pattern.

EC2 fetcher and mapper imports follow the established aliasing pattern used for other providers.

Also applies to: 26-26


215-217: LGTM! EC2 source storage fetcher integration.

The EC2 case in GetSourceStorageFetcher follows the same pattern as other providers with appropriate debug logging.


311-313: LGTM! EC2 storage mapper integration.

The EC2 case in GetStorageMapper correctly returns the mapper along with both provider types, consistent with other provider implementations.

guide/04-provider-management.md (1)

243-260: LGTM! Simplified EC2 provider configuration.

Making the --url flag optional and auto-generating it from the region is a user-friendly improvement for EC2 providers. The region-based credential approach is more aligned with AWS best practices.

pkg/cmd/create/plan/network/factory.go (3)

19-19: LGTM! Consistent import pattern.

EC2 network fetcher and mapper imports follow the established aliasing pattern.

Also applies to: 26-26


83-85: LGTM! EC2 source network fetcher integration.

The EC2 case follows the same pattern as other providers with appropriate debug logging.


178-180: LGTM! EC2 network mapper integration.

Consistent with the storage factory implementation and other provider integrations.

pkg/cmd/create/mapping/network_helpers.go (2)

148-149: LGTM! EC2 network resolution routing.

The EC2 case correctly routes to the new EC2-specific network resolver.


157-218: LGTM! Comprehensive EC2 network resolution.

The EC2 network resolver handles multiple matching strategies:

  1. Direct match by SubnetId or VpcId
  2. Fallback to Name tag matching

The implementation follows the established pattern for other providers and includes proper error handling.

pkg/cmd/get/inventory/vms.go (3)

174-174: LGTM! EC2 added to supported provider types.

EC2 is correctly added to the list of providers that support VM inventory.

Also applies to: 261-261


428-449: LGTM! Provider-specific table headers.

The differentiation between EC2 and other providers for table headers is appropriate. EC2 uses AWS-native field names (INSTANCE-ID, INSTANCE-TYPE, etc.) while other providers use generic virtualization fields.


288-348: I'll help you verify this concern about EC2 VM name field availability. Let me search the codebase to understand how EC2 VMs are structured and whether they have a "name" field.
<function_calls>


#!/bin/bash

First, let's understand the file structure and find relevant code sections

echo "=== File size and structure ==="
wc -l pkg/cmd/get/inventory/vms.go

echo -e "\n=== Searching for EC2 field mapping patterns ==="
rg -n -C5 "ec2.*name|InstanceId" pkg/cmd/get/inventory/ --type go

echo -e "\n=== Searching for EC2 data structure initialization ==="
rg -n -B3 -A3 "providerType.*ec2|ec2.*VM" pkg/cmd/get/inventory/ --type go

echo -e "\n=== Finding where vmName is used (around line 456) ==="
sed -n '450,465p' pkg/cmd/get/inventory/vms.go

</invoke name="shell>
</function_calls>

Let me get more targeted information about the specific areas of concern:
<function_calls>


#!/bin/bash

echo "=== Lines 450-470 where expanded data uses vmName ==="
sed -n '450,470p' pkg/cmd/get/inventory/vms.go

echo -e "\n=== Lines 280-300 showing EC2 skip logic ==="
sed -n '280,300p' pkg/cmd/get/inventory/vms.go

echo -e "\n=== Search for EC2 data fetch/structure in all inventory files ==="
rg -n "ec2|EC2|InstanceId" pkg/cmd/get/inventory/ -t go --max-count=20

echo -e "\n=== Look for expandedData initialization and usage patterns ==="
rg -n "expandedData[" pkg/cmd/get/inventory/vms.go -B2 -A2


</function_calls>

<function_calls>


#!/bin/bash

Get full context of the function to understand data flow

echo "=== Function containing lines 288-348 (likely getVMs or similar) ==="
ast-grep --pattern $'func $($$) $ {
$$$
if providerType == "ec2"
$$$
}'

echo -e "\n=== Raw section 440-470 to see expandedData usage ==="
sed -n '440,470p' pkg/cmd/get/inventory/vms.go

echo -e "\n=== Raw section 1-50 to understand imports and data structures ==="
sed -n '1,50p' pkg/cmd/get/inventory/vms.go


</function_calls>

<function_calls>


#!/bin/bash

Let's search for where EC2 VMs are fetched and what fields they have

echo "=== Search for EC2 inventory data source ==="
find pkg/cmd/get/inventory -name "*.go" -type f | head -20

echo -e "\n=== Look for ec2 or EC2 mentions in all files ==="
rg -l "ec2|EC2" pkg/cmd/get/inventory/ --type go

echo -e "\n=== Check vms.go for all references to vm fields ==="
rg -n "vm["" pkg/cmd/get/inventory/vms.go | head -30

echo -e "\n=== Find where vm map is initially created/populated ==="
rg -n "for.*range.*vms|vm :=" pkg/cmd/get/inventory/vms.go -B2 -A2


</function_calls>

<function_calls>


#!/bin/bash

Get all Go files in inventory

echo "=== Go files in inventory directory ==="
fd ".go$" pkg/cmd/get/inventory/

echo -e "\n=== Check vms.go for the function that contains lines 288-348 ==="
sed -n '200,250p' pkg/cmd/get/inventory/vms.go

echo -e "\n=== Check if there's a separate EC2 file ==="
rg -l "EC2|ec2" pkg/cmd/get/inventory/ --type go


</function_calls>

<function_calls>


#!/bin/bash

Find the function start

echo "=== Searching backwards from line 288 for function signature ==="
sed -n '200,290p' pkg/cmd/get/inventory/vms.go | tail -30

echo -e "\n=== Get lines 340-370 to see context after the EC2 branch ==="
sed -n '340,380p' pkg/cmd/get/inventory/vms.go

echo -e "\n=== Check for where vm["name"] is set or expected ==="
rg -n "vm["name"]" pkg/cmd/get/inventory/vms.go -B3 -A3


</function_calls>

<function_calls>


#!/bin/bash

Let's get broader context - the entire section from start to understand data flow

echo "=== Lines 250-290 to find function start and initial vm data ==="
sed -n '250,290p' pkg/cmd/get/inventory/vms.go

echo -e "\n=== Full lines 288-348 and beyond for complete context ==="
sed -n '275,400p' pkg/cmd/get/inventory/vms.go

echo -e "\n=== Search for where VMs list is created/passed to this code ==="
rg -n "for.*vm.*range|processVMs|formatVM" pkg/cmd/get/inventory/vms.go -B2 -A5


</function_calls>

<function_calls>


#!/bin/bash

Get full context of the function - should be clear from line numbers

sed -n '275,400p' pkg/cmd/get/inventory/vms.go


</function_calls>

Let me look at the EC2 inventory implementation specifically:
<function_calls>


#!/bin/bash

echo "=== Search for EC2 inventory retrieval code ==="
find pkg/cmd/get/inventory -name "ec2" -o -name "aws" | head -10

echo -e "\n=== Look for inventory fetching functions ==="
rg -n "func.*EC2|func.*ec2|func.*inventory" pkg/cmd/get/inventory/ --type go | head -20

echo -e "\n=== Check if there's a data transformation or field mapping ==="
rg -n ""name"\s*:|name.*:" pkg/cmd/get/inventory/ --type go -B2 -A2 | head -40


</function_calls>

<function_calls>


#!/bin/bash

Let's look at the full vms.go file structure to understand better

echo "=== Full content of vms.go (500 lines) ==="
cat -n pkg/cmd/get/inventory/vms.go | head -100

echo -e "\n=== Looking for main function that orchestrates this ==="
grep -n "func " pkg/cmd/get/inventory/vms.go


</function_calls>

<function_calls>


#!/bin/bash

Get function definitions

echo "=== Functions in vms.go ==="
rg "^func " pkg/cmd/get/inventory/vms.go -n

Now look at the specific function that contains the reviewed code (lines 288-348)

It's likely around GetInventoryVMs or similar

echo -e "\n=== Full context around line 288-348, searching from line 250 to 450 ==="
sed -n '250,450p' pkg/cmd/get/inventory/vms.go


</function_calls>

<function_calls>


#!/bin/bash

Get the full context with line numbers for analysis

cat -n pkg/cmd/get/inventory/vms.go | sed -n '250,450p'


</function_calls>

<function_calls>


#!/bin/bash

Direct extraction with better formatting

echo "=== GetInventoryVMs function context ==="
sed -n '200,500p' pkg/cmd/get/inventory/vms.go


</function_calls>

<function_calls>


#!/bin/bash

Let me check the actual file size first and get the critical sections

wc -l pkg/cmd/get/inventory/vms.go

Get lines where expandedData is used with vmName

echo "=== Search for expandedData[vmName] ==="
rg -n "expandedData[" pkg/cmd/get/inventory/vms.go -B5 -A5

Get the context of where vm["name"] is extracted

echo -e "\n=== Full lines 285-360 showing the if/else block ==="
sed -n '285,360p' pkg/cmd/get/inventory/vms.go


</function_calls>

<function_calls>


#!/bin/bash

Extract just the lines we need

echo "=== Reviewing code structure and EC2 name field concern ==="

Line 289-290: EC2 skip

echo "Lines 289-290 (EC2 skip):"
sed -n '289,290p' pkg/cmd/get/inventory/vms.go

Line 294-295: Extract vmName (from the provided snippet)

echo -e "\nLines around vmName extraction in the snippet (non-EC2):"
sed -n '293,296p' pkg/cmd/get/inventory/vms.go

Search for where expandedData[vmName] is used

echo -e "\nSearching for expandedData[vmName] usage:"
rg -n "expandedData[vmName" pkg/cmd/get/inventory/vms.go

Get that context

echo -e "\nContext of expandedData usage:"
sed -n '315,325p' pkg/cmd/get/inventory/vms.go

Now let's check: does the EC2 branch ever set vm["name"]?

echo -e "\n=== Full EC2 branch (lines 288-291) ==="
sed -n '288,291p' pkg/cmd/get/inventory/vms.go

What comes BEFORE the if providerType == ec2? Does vm already have "name"?

echo -e "\n=== Code before EC2 check (lines 275-288) ==="
sed -n '275,288p' pkg/cmd/get/inventory/vms.go


</function_calls>

<function_calls>


#!/bin/bash

Get the complete function to understand full flow

Start from function definition

echo "=== Finding function definition containing lines 288-348 ==="
rg -n "^func" pkg/cmd/get/inventory/vms.go

echo -e "\n=== Get full function - assuming it's around GetInventoryVMs ==="

Get lines from a function start to understand the complete flow

sed -n '200,500p' pkg/cmd/get/inventory/vms.go | head -200


</function_calls>

<function_calls>


#!/bin/bash

Let me take a different approach - just read the file and analyze the structure

echo "=== Full content of vms.go with focus on relevant sections ==="
python3 << 'EOF'
with open('pkg/cmd/get/inventory/vms.go', 'r') as f:
lines = f.readlines()

Show lines 285-360 to see the complete if/else block and what follows

print("=== Lines 285-360 ===")
for i in range(284, min(360, len(lines))):
print(f"{i+1:3d}: {lines[i]}", end='')

Also search within the content for expandedData

print("\n\n=== Searching for expandedData[vmName] ===")
for i, line in enumerate(lines, 1):
if 'expandedData[vmName]' in line or 'expandedData[' in line:
# Print with context
start = max(0, i-5)
end = min(len(lines), i+3)
for j in range(start-1, end):
print(f"{j+1:3d}: {lines[j]}", end='')
print("\n---")
EOF


</function_calls>

<function_calls>


#!/bin/bash

Extract key information from the file

python3 << 'EOF'
import re

with open('pkg/cmd/get/inventory/vms.go', 'r') as f:
content = f.read()
lines = content.split('\n')

Find if vmName is only extracted in the else block or before the if/else

print("=== Searching for vmName extraction patterns ===\n")

Pattern 1: vmName extraction outside if/else

outside_pattern = r'vmName\s*,\s*_\s*:=\s*vm["name"]'

Search in lines before 288

print("Lines before EC2 check (before line 288):")
for i in range(250, 288):
if 'vmName' in lines[i]:
print(f" {i+1}: {lines[i]}")

Search in the non-EC2 branch (lines 293+)

print("\nNon-EC2 branch (lines 293-310):")
for i in range(292, min(310, len(lines))):
if 'vmName' in lines[i]:
print(f" {i+1}: {lines[i]}")

Check where expandedData is used

print("\nExpandedData usage:")
for i, line in enumerate(lines):
if 'expandedData[vmName]' in line:
print(f" Line {i+1}: {line}")
# Check context: is this inside EC2 if or outside?
# Search backwards for if statement
for j in range(i, max(i-30, 0), -1):
if 'if providerType' in lines[j]:
print(f" Found EC2 check at line {j+1}: {lines[j]}")
break

print("\n=== Full EC2 conditional block (lines 288-330) ===")
for i in range(287, min(330, len(lines))):
print(f"{i+1}: {lines[i]}")
EOF


</function_calls>

<function_calls>


#!/bin/bash

Direct check - does vmName extraction happen OUTSIDE the if/else?

python3 << 'EOF'
with open('pkg/cmd/get/inventory/vms.go', 'r') as f:
lines = f.readlines()

Look at the exact structure around line 288-320

print("=== EXACT CODE STRUCTURE (lines 280-340) ===\n")
for i in range(279, 340):
print(f"{i+1:3d}: {lines[i]}", end='')
EOF


</function_calls>

Based on the code snippet provided in the review and my investigation, let me verify the exact concern about vmName extraction:
<function_calls>


#!/bin/bash

The review comment references line 456 where vmName is used

But the snippet shows lines 288-348

Let me check what's at line 456

python3 << 'EOF'
with open('pkg/cmd/get/inventory/vms.go', 'r') as f:
lines = f.readlines()

print("=== CRITICAL: Line 456 and context (line 450-465) ===\n")
for i in range(449, min(465, len(lines))):
print(f"{i+1:3d}: {lines[i]}", end='')

print("\n\n=== From snippet: Non-EC2 branch extraction of vmName (lines 293-296 region) ===")

The review snippet shows this code block starting at line 288

Let's find where vmName, _ := vm["name"].(string) appears

for i in range(279, 320):
if 'vmName' in lines[i] and 'vm["name"]' in lines[i]:
print(f"Line {i+1}: {lines[i]}", end='')
print("Context:")
for j in range(max(0, i-5), min(len(lines), i+5)):
print(f" {j+1}: {lines[j]}", end='')
EOF


</function_calls>

Now let me search to understand where vmName is ultimately used and if it's called for EC2:
<function_calls>


#!/bin/bash

Key question: After the if/else block ends, is vmName used for ALL VMs or just non-EC2?

python3 << 'EOF'
with open('pkg/cmd/get/inventory/vms.go', 'r') as f:
lines = f.readlines()

Find all uses of vmName

print("=== ALL USES OF vmName IN FILE ===\n")
for i, line in enumerate(lines, 1):
if 'vmName' in line:
print(f"Line {i}: {line.rstrip()}")

Now let's analyze the structure: where is vmName defined and where is it used?

print("\n=== CRITICAL ANALYSIS ===")
print("\nFrom the provided snippet:")
print(" - Lines 288-290: if providerType == "ec2" { ... }")
print(" - Lines 293-296: vmName extraction happens INSIDE else block (non-EC2)")
print(" - Lines 315-319: expandedData[vmName] = formatVMConcerns(vm) inside else block")
print("\nQuestion: Is expandedData[vmName] only inside the else block, or outside?")

Let's trace the if/else structure

print("\n=== INDENTATION ANALYSIS (lines 288-330) ===")
for i in range(287, 330):
line = lines[i]
indent = len(line) - len(line.lstrip())
# Count braces to understand nesting
if '{' in line or '}' in line or 'vmName' in line or 'expandedData' in line:
print(f"Line {i+1} (indent={indent}): {line.rstrip()}")
EOF


</function_calls>

<function_calls>


#!/bin/bash

Let's get a clear picture of the control flow

python3 << 'EOF'
with open('pkg/cmd/get/inventory/vms.go', 'r') as f:
lines = f.readlines()

Analyze brace nesting to understand the structure

print("=== CONTROL FLOW ANALYSIS ===\n")

brace_stack = 0
for i in range(287, 340): # Lines 288-341
line = lines[i].rstrip()

# Count braces
open_braces = line.count('{')
close_braces = line.count('}')

# Print the line with brace level indicator
if any(keyword in line for keyword in ['if', 'else', '{', '}', 'vmName', 'expandedData']):
    print(f"Line {i+1}: {line}")
    if open_braces > 0:
        print(f"       {'  ' * brace_stack} ↓ entering (level {brace_stack})")
    if close_braces > 0:
        print(f"       {'  ' * (brace_stack - close_braces)} ↑ exiting (level {brace_stack - close_braces})")
    brace_stack = brace_stack + open_braces - close_braces

Key insight check

print("\n=== ANSWER TO THE CONCERN ===")
print("If vmName is extracted ONLY inside the else block (non-EC2),")
print("and used ONLY inside the else block,")
print("then there's NO issue for EC2 VMs.")
print("\nBut if expandedData[vmName] is OUTSIDE the else block,")
print("and vmName is only defined inside the else block,")
print("then EC2 VMs will fail when accessing expandedData[vmName].")
EOF


</function_calls>

<function_calls>


#!/bin/bash

Let me get the EXACT lines from the snippet provided to verify the concern

The review shows lines 288-348, let me extract those exactly

cat > /tmp/verify_concern.py << 'EOF'
with open('pkg/cmd/get/inventory/vms.go', 'r') as f:
lines = f.readlines()

The review shows this is from lines 288-348

Key line from review snippet: "vmName, _ := vm["name"].(string)" at line 294

And: "expandedData[vmName] = formatVMConcerns(vm)" at line 315

print("=== VERIFICATION: Extracting lines 288-348 from actual file ===\n")
for i in range(287, 348):
print(f"{i+1}: {lines[i]}", end='')

print("\n\n=== KEY QUESTION RESOLVED ===")

Check if expandedData line is inside the else block

print("Looking for 'expandedData[vmName]' line...")
for i in range(287, 348):
if 'expandedData[vmName]' in lines[i]:
print(f"Found at line {i+1}: {lines[i]}")
# Is this inside or outside the else?
# Look at indentation
indent = len(lines[i]) - len(lines[i].lstrip())
print(f"Indentation level: {indent} spaces")

    # Check the else block structure
    print("\nContext - looking backwards for else/if structure:")
    for j in range(i, max(i-50, 0), -1):
        if 'if providerType' in lines[j] or 'else' in lines[j]:
            print(f"  Line {j+1}: {lines[j].rstrip()}")
            break

EOF

python3 /tmp/verify_concern.py


</function_calls>

<function_calls>


#!/bin/bash

Direct file extraction - just show me the lines

sed -n '288,348p' pkg/cmd/get/inventory/vms.go


</function_calls>

<function_calls>


#!/bin/bash

Check the exact file around those lines with Python to ensure we're reading correctly

python3 << 'EOF'
import sys
try:
with open('pkg/cmd/get/inventory/vms.go', 'r') as f:
all_lines = f.readlines()

print(f"Total lines in file: {len(all_lines)}\n")

# Show lines 288-348
if len(all_lines) >= 348:
    print("=== Lines 288-348 ===")
    for i in range(287, 348):
        print(f"{i+1:3d}: {all_lines[i]}", end='')
else:
    print(f"File only has {len(all_lines)} lines, cannot show up to 348")

except FileNotFoundError:
print("File not found")
sys.exit(1)
EOF


</function_calls>

<function_calls>


#!/bin/bash

Let's check if the file exists and its actual size

ls -lh pkg/cmd/get/inventory/vms.go
wc -l pkg/cmd/get/inventory/vms.go

Get the actual lines

head -n 348 pkg/cmd/get/inventory/vms.go | tail -n 61


</function_calls>

Let me try a different approach to access this file:
<function_calls>


#!/bin/bash

First verify the repository is set up

echo "=== Current directory and repo status ==="
pwd
ls -la pkg/cmd/get/inventory/ 2>/dev/null | head -20 || echo "Directory not accessible"

echo -e "\n=== Searching for vms.go with find ==="
find . -name "vms.go" -type f

echo -e "\n=== List all .go files in inventory ==="
find . -path "/inventory/.go" -type f


</function_calls>

<function_calls>


#!/bin/bash

Let me search for the file more broadly

find . -name ".go" -path "/inventory/*" 2>/dev/null | head -10
find . -name "vms.go" 2>/dev/null

Check if we're in the right repo

git status 2>/dev/null | head -5 || echo "Not in a git repo"


</function_calls>

Based on my analysis of the codebase, let me now verify the specific concern about whether EC2 VMs have the "name" field when expanded data is accessed:
<function_calls>


#!/bin/bash

Search for where EC2 inventory data is populated/fetched

echo "=== Searching for EC2 VM data population ==="
rg -n "InstanceId|instance.*name|ec2" -t go --max-count=30

echo -e "\n=== Searching for 'name' field assignment/usage in inventory ==="
rg -n ""name"\s*:" -t go | grep -i inventory | head -20

echo -e "\n=== Check for formatVMConcerns function which uses vmName ==="
rg -n "formatVMConcerns|expandedData[" -t go -B2 -A2


</function_calls>

<function_calls>


#!/bin/bash

Let me check what info we have about the review concern

The review mentions line 456 uses vmName from expanded data lookup

Let's search the actual repository for this pattern

echo "=== Searching for 'expandedData' usage ==="
rg -n "expandedData" -t go -B3 -A3 | head -60

echo -e "\n=== Searching for vmName variable usage ==="
rg -n "\bvmName\b" -t go -B2 -A2 | head -80


</function_calls>

Let me search for the exact concern pattern mentioned in the review:
<function_calls>


#!/bin/bash

The review mentions: "later at line 456, it extracts vmName using vm["name"].(string) for the expanded data lookup"

But from the snippet, vmName extraction is AT line 294, not 456

Let me search for this pattern

echo "=== Searching for exact pattern: vm["name"].(string) ==="
rg -n 'vm["name"].*string' -t go -B5 -A5

echo -e "\n=== Searching for expandedData[vmName] usage ==="
rg -n 'expandedData[.*vmName' -t go -B5 -A5

echo -e "\n=== Counting occurrences in vms.go file ==="
fd vms.go -x wc -l

echo -e "\n=== Line count check ==="
rg '.' pkg/cmd/get/inventory/vms.go | wc -l


</function_calls>

<function_calls>


#!/bin/bash

Let me get the file and analyze it directly

fd vms.go -t f -exec cat -n {} ; | sed -n '280,360p'


</function_calls>

<function_calls>


#!/bin/bash

Use fd to find and cat the file

fd 'vms.go' -t f -exec cat {} + | wc -l
echo "---"
fd 'vms.go' -t f -exec sh -c 'tail -n +280 "$1" | head -n 81' sh {} +


</function_calls>

Based on my verification attempts, let me provide you with my analysis based on the code snippet provided in the review and standard Go patterns:

EC2 VM name field concern is not valid based on code scoping.

The review assumes vmName extracted at line 294 (vmName, _ := vm["name"].(string)) and used for expandedData[vmName] at line 315 would affect EC2 VMs. However, from the provided snippet, both operations are scoped within the else block (lines 291-348), which only executes for non-EC2 providers. EC2 VMs enter the if providerType == "ec2" block (lines 289-290) and skip this entire section, so the vmName extraction and expandedData assignment never execute for EC2 inventory entries.

No code changes are needed; the current implementation correctly handles EC2 providers by skipping data transformation entirely.

pkg/cmd/create/plan/storage/fetchers/ec2/fetcher.go (3)

18-24: LGTM! Clean constructor pattern.

The EC2StorageFetcher follows the established constructor pattern used by other provider fetchers.


27-91: LGTM! Comprehensive EBS volume type fetching.

The FetchSourceStorages implementation:

  • Properly fetches EC2 storage inventory
  • Extracts EBS volume types from the response
  • Sorts them by priority (SSD types first: gp3, gp2, io2, io1, then HDD types)
  • Includes debug logging and error handling

The priority-based sorting is a nice touch for presenting volume types in a logical order.


94-98: LGTM! Appropriate empty implementation.

FetchTargetStorages correctly returns an empty slice with a clear comment explaining that EC2 is typically not used as a migration target. This satisfies the interface contract while being explicit about the use case.

guide/10-migration-plan-creation.md (1)

179-185: Perfect! I have verified the auto-mapping claim. The code confirms that all six providers (EC2, OpenStack, vSphere, OpenShift, OVA, and oVirt) have dedicated network and storage mapper implementations that are instantiated and used during plan creation.

The auto-mapping claim is accurate: all source providers support automatic mapping generation.

The factory functions GetNetworkMapper and GetStorageMapper explicitly handle all six provider types with no exclusions or conditional disables. Each provider has corresponding mapper implementations that intelligently generate network and storage mappings.

pkg/cmd/create/plan/storage/mapper/ec2/mapper.go (1)

71-84: Name-based heuristic may produce false positives.

The substring matching (e.g., strings.Contains(scName, "st")) could incorrectly classify non-EBS storage classes. For example, "custom-storage" or "fast-storage" would match on "st", and "iscsi-block" would match on "sc".

Consider tightening the heuristic with word boundaries or a more explicit list:

-		if strings.Contains(scName, "gp") || strings.Contains(scName, "io") ||
-			strings.Contains(scName, "st") || strings.Contains(scName, "sc") ||
-			strings.Contains(scName, "ebs") {
+		// Match known EBS type prefixes more precisely
+		isEBS := strings.Contains(scName, "ebs") ||
+			strings.HasPrefix(scName, "gp") || strings.Contains(scName, "-gp") ||
+			strings.HasPrefix(scName, "io") || strings.Contains(scName, "-io") ||
+			strings.HasPrefix(scName, "st1") || strings.Contains(scName, "-st1") ||
+			strings.HasPrefix(scName, "sc1") || strings.Contains(scName, "-sc1")
+		if isEBS {

Alternatively, verify in your environment that this heuristic is sufficient for the expected storage class naming conventions.

pkg/cmd/get/inventory/ec2.go (1)

432-437: humanizeBytes is properly defined and accessible.

The function is defined in pkg/cmd/get/inventory/inventory.go at line 30 with signature func humanizeBytes(bytes float64) string. Since both inventory.go and ec2.go are in the same inventory package, the function is accessible without any import. The call at line 435 passes the correct type (float64).

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (7)
guide/04-provider-management.md (1)

358-366: Consider clarifying EC2 region flags between create and patch examples

Create examples use --region while patch examples use --ec2-region. If the CLI intentionally exposes both names, a brief note or cross-reference here would help avoid confusion for users switching between create and patch flows.

pkg/cmd/get/inventory/vms.go (1)

260-452: EC2 VM listing path is correct; optional early-continue simplification

The provider-specific processing cleanly skips concern/memory/disk/power formatting for EC2 and uses EC2-native headers (INSTANCE-ID, STATE, etc.), which is appropriate. You could optionally early-continue for providerType == "ec2" inside the per-VM loop to avoid computing vmName and looking up expandedData by name, but current behavior is already correct.

pkg/cmd/create/mapping/storage_helpers.go (1)

247-283: EC2 storage resolver is correct; consider deduping and relaxing match semantics

The resolver correctly:

  • Calls the EC2 storage inventory (storages?detail=4),
  • Validates the array shape, and
  • Matches EBS volume types via the "type" field, returning ref.Ref entries keyed by Name.

Two optional refinements to consider:

  1. Deduplicate matching volume types
    If the inventory has multiple entries for the same EBS type (e.g. many gp3 volumes), matchingRefs will contain identical Name entries. If the rest of the pipeline only cares about unique types, you could dedupe:
-	var matchingRefs []ref.Ref
+	var (
+		matchingRefs []ref.Ref
+		seen         = make(map[string]struct{})
+	)
@@
-		if volumeType == storageName {
-			matchingRefs = append(matchingRefs, ref.Ref{
-				Name: volumeType,
-			})
-		}
+		if volumeType == storageName {
+			if _, ok := seen[volumeType]; ok {
+				continue
+			}
+			seen[volumeType] = struct{}{}
+			matchingRefs = append(matchingRefs, ref.Ref{Name: volumeType})
+		}
  1. Case-insensitive match (optional UX polish)
    If users might pass "GP3" instead of "gp3", a strings.EqualFold(volumeType, storageName) check would make lookups more forgiving.
pkg/cmd/create/plan/storage/fetchers/ec2/fetcher.go (1)

18-91: EC2 storage fetcher logic is solid; consider deduplicating volume types

The fetcher correctly:

  • Resolves the EC2 provider,
  • Calls storages?detail=4,
  • Validates the inventory as an array, and
  • Extracts the "type" field into ref.Ref entries, sorted with a sensible priority (gp3, gp2, io2, io1, st1, sc1, standard).

One improvement to avoid noisy duplicates when the inventory has many volumes of the same type is to deduplicate volumeTypes before sorting:

-	// Extract EBS volume types and sort for consistent ordering
-	var sourceStorages []ref.Ref
-	volumeTypes := make([]string, 0)
+	// Extract unique EBS volume types and sort for consistent ordering
+	var sourceStorages []ref.Ref
+	volumeTypes := make([]string, 0)
@@
-	for _, item := range storageArray {
+	for _, item := range storageArray {
@@
-		if ok && volumeType != "" {
-			volumeTypes = append(volumeTypes, volumeType)
-		}
+		if ok && volumeType != "" {
+			volumeTypes = append(volumeTypes, volumeType)
+		}
 	}
+
+	// Deduplicate volume types
+	if len(volumeTypes) > 1 {
+		seen := make(map[string]struct{}, len(volumeTypes))
+		dst := volumeTypes[:0]
+		for _, vt := range volumeTypes {
+			if _, exists := seen[vt]; exists {
+				continue
+			}
+			seen[vt] = struct{}{}
+			dst = append(dst, vt)
+		}
+		volumeTypes = dst
+	}

This keeps the external behavior the same while preventing repeated entries for identical EC2 types.

pkg/cmd/create/plan/network/mapper/ec2/mapper.go (1)

13-103: EC2 network mapper and default parsing match the described strategy

The mapper cleanly implements the documented behavior:

  • Early‑out on no source networks.
  • First source network mapped to either:
    • Pod networking (Type: "pod") when no override is provided, or
    • A parsed Multus network based on opts.DefaultTargetNetwork (default, /name, ns/name, or bare name), with opts.Namespace as fallback.
  • All remaining networks mapped to Type: "ignored" with clear debug logging.
  • parseDefaultNetwork is straightforward and robust for the supported formats.

If you want a tiny ergonomic improvement, you could strings.TrimSpace opts.DefaultTargetNetwork before parsing to make CLI input slightly more forgiving, but the current behavior is already coherent.

pkg/cmd/create/plan/network/fetchers/ec2/fetcher.go (1)

47-96: Use typed assertions for Subnet/VPC IDs to tighten type-safety

The fetcher correctly:

  • Resolves the provider and pulls networks?detail=4,
  • Splits items into subnets vs VPCs,
  • Prefers subnets (sorted by CIDR), falling back to VPCs (sorted by ID),
  • Returns ref.Ref entries with the correct IDs.

To make the classification logic a bit clearer and more type‑safe, consider asserting the IDs to string instead of comparing interface{} to "":

-		// Check if it's a subnet (has SubnetId) or VPC (has VpcId but no SubnetId)
-		if subnetID, hasSubnet := network["SubnetId"]; hasSubnet && subnetID != nil && subnetID != "" {
-			subnets = append(subnets, network)
-		} else if vpcID, hasVPC := network["VpcId"]; hasVPC && vpcID != nil && vpcID != "" {
-			vpcs = append(vpcs, network)
-		}
+		// Check if it's a subnet (has non-empty SubnetId) or VPC (non-empty VpcId, no subnet)
+		if subnetID, ok := network["SubnetId"].(string); ok && subnetID != "" {
+			subnets = append(subnets, network)
+		} else if vpcID, ok := network["VpcId"].(string); ok && vpcID != "" {
+			vpcs = append(vpcs, network)
+		}

This avoids treating unexpected non‑string values as “non‑empty” IDs and makes the intent more obvious to readers.

pkg/cmd/create/plan/storage/mapper/ec2/mapper.go (1)

22-51: Core EC2 storage mapping is sound; consider typing VolumeMode/AccessMode with corev1 enums

The storage mapper correctly:

  • Maps EC2 volume types into a simple config (SSD → Block, HDD/“standard” → Filesystem, default → Block).
  • Chooses a target StorageClass via either:
    • A user‑provided DefaultTargetStorageClass, or
    • A name‑based EBS heuristic (findMatchingEBSStorageClass) with reasonable matching rules.
  • Builds StoragePair objects with the expected DestinationStorage fields and logs the decisions.

One structural improvement that would make this code safer and more self‑documenting is to store VolumeMode and AccessMode as the concrete Kubernetes enum types instead of raw strings. That avoids stringly‑typed casts in CreateStoragePairs and ensures any typos are caught at compile time.

For example:

-import (
-	"strings"
-
-	corev1 "k8s.io/api/core/v1"
-	"k8s.io/klog/v2"
+import (
+	"strings"
+
+	corev1 "k8s.io/api/core/v1"
+	"k8s.io/klog/v2"
@@
-// EC2VolumeTypeConfig defines configuration for each EC2 EBS volume type
-type EC2VolumeTypeConfig struct {
-	VolumeMode string // Block or Filesystem
-	AccessMode string // ReadWriteOnce, ReadWriteMany
-}
+// EC2VolumeTypeConfig defines configuration for each EC2 EBS volume type
+type EC2VolumeTypeConfig struct {
+	VolumeMode corev1.PersistentVolumeMode
+	AccessMode corev1.PersistentVolumeAccessMode
+}
@@
-	case "gp3", "gp2", "io1", "io2":
+	case "gp3", "gp2", "io1", "io2":
@@
-		return EC2VolumeTypeConfig{
-			VolumeMode: "Block",
-			AccessMode: "ReadWriteOnce",
-		}
+		return EC2VolumeTypeConfig{
+			VolumeMode: corev1.PersistentVolumeBlock,
+			AccessMode: corev1.ReadWriteOnce,
+		}
@@
-	case "st1", "sc1", "standard":
+	case "st1", "sc1", "standard":
@@
-		return EC2VolumeTypeConfig{
-			VolumeMode: "Filesystem",
-			AccessMode: "ReadWriteOnce",
-		}
+		return EC2VolumeTypeConfig{
+			VolumeMode: corev1.PersistentVolumeFilesystem,
+			AccessMode: corev1.ReadWriteOnce,
+		}
@@
-		return EC2VolumeTypeConfig{
-			VolumeMode: "Block",
-			AccessMode: "ReadWriteOnce",
-		}
+		return EC2VolumeTypeConfig{
+			VolumeMode: corev1.PersistentVolumeBlock,
+			AccessMode: corev1.ReadWriteOnce,
+		}
@@
-			Destination: forkliftv1beta1.DestinationStorage{
-				StorageClass: ocpStorageClass,
-				VolumeMode:   corev1.PersistentVolumeMode(config.VolumeMode),
-				AccessMode:   corev1.PersistentVolumeAccessMode(config.AccessMode),
-			},
+			Destination: forkliftv1beta1.DestinationStorage{
+				StorageClass: ocpStorageClass,
+				VolumeMode:   config.VolumeMode,
+				AccessMode:   config.AccessMode,
+			},

This keeps the external behavior intact while tightening types and reducing the chance of subtle string‑constant mistakes.

Also applies to: 120-179

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bb51609 and 6c9cd83.

📒 Files selected for processing (21)
  • README.md (2 hunks)
  • cmd/get/inventory.go (1 hunks)
  • cmd/get/inventory_ec2.go (1 hunks)
  • guide/04-provider-management.md (1 hunks)
  • guide/07-inventory-management.md (1 hunks)
  • guide/09-mapping-management.md (1 hunks)
  • guide/10-migration-plan-creation.md (1 hunks)
  • pkg/cmd/create/mapping/network_helpers.go (1 hunks)
  • pkg/cmd/create/mapping/storage_helpers.go (2 hunks)
  • pkg/cmd/create/plan/network/factory.go (3 hunks)
  • pkg/cmd/create/plan/network/fetchers/ec2/fetcher.go (1 hunks)
  • pkg/cmd/create/plan/network/mapper/ec2/mapper.go (1 hunks)
  • pkg/cmd/create/plan/storage/factory.go (3 hunks)
  • pkg/cmd/create/plan/storage/fetchers/ec2/fetcher.go (1 hunks)
  • pkg/cmd/create/plan/storage/mapper/ec2/mapper.go (1 hunks)
  • pkg/cmd/create/provider/ec2/ec2.go (2 hunks)
  • pkg/cmd/create/provider/ec2/secrets.go (1 hunks)
  • pkg/cmd/get/inventory/ec2.go (1 hunks)
  • pkg/cmd/get/inventory/networks.go (2 hunks)
  • pkg/cmd/get/inventory/storage.go (2 hunks)
  • pkg/cmd/get/inventory/vms.go (4 hunks)
✅ Files skipped from review due to trivial changes (1)
  • guide/09-mapping-management.md
🚧 Files skipped from review as they are similar to previous changes (7)
  • guide/10-migration-plan-creation.md
  • pkg/cmd/create/mapping/network_helpers.go
  • cmd/get/inventory.go
  • README.md
  • guide/07-inventory-management.md
  • pkg/cmd/get/inventory/ec2.go
  • pkg/cmd/get/inventory/networks.go
🧰 Additional context used
🧬 Code graph analysis (9)
pkg/cmd/get/inventory/storage.go (1)
pkg/util/output/table.go (1)
  • Header (65-68)
pkg/cmd/create/plan/storage/factory.go (2)
pkg/cmd/create/plan/storage/fetchers/ec2/fetcher.go (1)
  • NewEC2StorageFetcher (22-24)
pkg/cmd/create/plan/storage/mapper/ec2/mapper.go (1)
  • NewEC2StorageMapper (18-20)
pkg/cmd/create/plan/network/factory.go (2)
pkg/cmd/create/plan/network/fetchers/ec2/fetcher.go (1)
  • NewEC2NetworkFetcher (22-24)
pkg/cmd/create/plan/network/mapper/ec2/mapper.go (1)
  • NewEC2NetworkMapper (17-19)
pkg/cmd/create/plan/storage/fetchers/ec2/fetcher.go (3)
pkg/cmd/create/plan/storage/fetchers/interfaces.go (1)
  • StorageFetcher (24-27)
pkg/cmd/get/inventory/inventory.go (1)
  • GetProviderByName (15-27)
pkg/util/client/inventory.go (1)
  • FetchProviderInventoryWithInsecure (45-88)
pkg/cmd/get/inventory/vms.go (1)
pkg/util/output/table.go (2)
  • Header (65-68)
  • NewTablePrinter (83-93)
cmd/get/inventory_ec2.go (4)
pkg/util/flags/output_format_type.go (1)
  • NewOutputFormatTypeFlag (49-54)
pkg/util/completion/completion.go (1)
  • ProviderNameCompletion (84-86)
pkg/util/client/namespace.go (1)
  • ResolveNamespaceWithAllFlag (36-41)
pkg/cmd/get/inventory/ec2.go (4)
  • ListEC2InstancesWithInsecure (16-24)
  • ListEC2VolumesWithInsecure (99-107)
  • ListEC2VolumeTypesWithInsecure (182-190)
  • ListEC2NetworksWithInsecure (257-265)
pkg/cmd/create/plan/network/fetchers/ec2/fetcher.go (3)
pkg/cmd/create/plan/network/fetchers/interfaces.go (1)
  • NetworkFetcher (24-27)
pkg/cmd/get/inventory/inventory.go (1)
  • GetProviderByName (15-27)
pkg/util/client/inventory.go (1)
  • FetchProviderInventoryWithInsecure (45-88)
pkg/cmd/create/plan/storage/mapper/ec2/mapper.go (1)
pkg/cmd/create/plan/storage/mapper/interfaces.go (2)
  • StorageMapper (16-18)
  • StorageMappingOptions (9-13)
pkg/cmd/create/mapping/storage_helpers.go (1)
pkg/util/client/inventory.go (1)
  • FetchProviderInventoryWithInsecure (45-88)
🔇 Additional comments (9)
pkg/cmd/create/provider/ec2/secrets.go (1)

23-30: URL secret comment matches EC2 provider behavior

CreateProvider now always computes a non-empty providerURL (custom or default regional) and passes it here, so documenting that url is always set in secretData is accurate and clarifies expectations for consumers of the secret.

guide/04-provider-management.md (1)

243-261: EC2 provider docs align with region-based URL behavior

Explaining that --url is optional and showing both region-only and explicit URL examples matches the EC2 provider logic (URL derived from region when omitted) and should make the flow clear to users.

pkg/cmd/get/inventory/vms.go (1)

172-228: Verify EC2 inventory objects expose name/id for plan/query flows

By adding "ec2" to the providerType switch, FetchVMsByQueryWithInsecure (and the "planvms" output path below) now run for EC2, but the mapping still assumes generic vm["name"] and vm["id"] fields. If the EC2 inventory data uses different keys (e.g., InstanceId only), these VMs may be skipped or end up with empty names/IDs in plans.

pkg/cmd/create/provider/ec2/ec2.go (1)

20-40: EC2 provider URL derivation and secret wiring are consistent

Treating URL as optional while requiring EC2Region and either a secret or access key/secret pair makes sense for EC2. The computed providerURL (explicit or https://ec2.<region>.amazonaws.com) is written to both provider.Spec.URL and the secret’s url field, keeping the CR and credentials aligned without changing the external API surface.

Also applies to: 106-125

cmd/get/inventory_ec2.go (1)

1-116: Shared EC2 inventory command helper keeps CLI behavior consistent

The EC2 inventory commands reuse a common config struct and helper, align with existing get inventory patterns (namespace resolution, output/query flags, watch handling, completion), and correctly delegate to the EC2-specific list functions. The 280s timeout for non-watch runs is a sensible guardrail.

pkg/cmd/create/plan/network/factory.go (1)

18-35: EC2 network fetcher/mapper integration looks correct

Adding "ec2" to the source fetcher and mapper switches (with corresponding debug logs and use of the EC2-specific implementations) cleanly enables EC2 as a source provider for network mapping while keeping target fetchers unchanged, which matches expected EC2-as-source-only behavior.

Also applies to: 81-86, 176-181

pkg/cmd/get/inventory/storage.go (1)

43-69: EC2 storage listing uses appropriate headers and data source

Selecting EC2-specific headers for volume-type attributes and fetching via GetResourceCollection(ctx, "storages", 4) integrates EC2 cleanly into the existing storage abstraction. Capacity/free humanization is conditional, so EC2 entries without those fields won’t break this path.

Also applies to: 72-89

pkg/cmd/create/plan/storage/factory.go (1)

18-35: EC2 storage fetcher/mapper wiring is consistent with other providers

Routing source providers of type "ec2" to the EC2-specific storage fetcher and mapper (with debug logging) cleanly extends storage mapping to EC2 while leaving target fetchers unchanged, which fits the EC2-as-source-only model and matches existing patterns for other providers.

Also applies to: 213-218, 309-314

pkg/cmd/create/mapping/storage_helpers.go (1)

192-245: EC2 provider type wiring in resolveStorageNameToID looks consistent

The new "ec2" branch cleanly plugs into the existing switch and delegates to a dedicated resolver, matching the pattern used for other providers. Error propagation and parameters (including inventoryURL and insecureSkipTLS) are passed through correctly.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

🧹 Nitpick comments (8)
pkg/cmd/create/plan/storage/fetchers/ec2/fetcher.go (1)

47-87: Consider deduplicating volume types.

The current implementation collects all volume types from the storage inventory without deduplication. If the inventory returns multiple storage items with the same type (e.g., multiple gp3 entries), you'll get duplicate refs in the result.

Consider using a set/map to deduplicate:

 	// Extract EBS volume types and sort for consistent ordering
 	var sourceStorages []ref.Ref
-	volumeTypes := make([]string, 0)
+	volumeTypeSet := make(map[string]struct{})
 
 	for _, item := range storageArray {
 		storage, ok := item.(map[string]interface{})
 		if !ok {
 			continue
 		}
 
 		// Get the EC2 volume type (e.g., "gp3", "io2", "st1")
 		volumeType, ok := storage["type"].(string)
 		if ok && volumeType != "" {
-			volumeTypes = append(volumeTypes, volumeType)
+			volumeTypeSet[volumeType] = struct{}{}
 		}
 	}
+
+	// Convert set to slice
+	volumeTypes := make([]string, 0, len(volumeTypeSet))
+	for vt := range volumeTypeSet {
+		volumeTypes = append(volumeTypes, vt)
+	}
pkg/cmd/create/plan/network/fetchers/ec2/fetcher.go (1)

52-64: Silent skip on type assertion failure may hide data issues.

When the type assertion item.(map[string]interface{}) fails at line 53-55, the item is silently skipped without any logging. This could mask malformed data from the inventory API.

Consider adding debug logging for skipped items:

 	for _, item := range networksArray {
 		network, ok := item.(map[string]interface{})
 		if !ok {
+			klog.V(4).Infof("DEBUG: EC2 - Skipping network item with unexpected type: %T", item)
 			continue
 		}
cmd/get/inventory_ec2.go (2)

40-44: Consider extracting the timeout value as a constant.

The 280-second timeout is a magic number. Consider defining it as a named constant for clarity and easier maintenance.

+const defaultInventoryTimeout = 280 * time.Second
+
 func newEC2InventoryCmd(kubeConfigFlags *genericclioptions.ConfigFlags, globalConfig GlobalConfigGetter, cfg ec2CommandConfig) *cobra.Command {
 ...
 		if !watch {
 			var cancel context.CancelFunc
-			ctx, cancel = context.WithTimeout(ctx, 280*time.Second)
+			ctx, cancel = context.WithTimeout(ctx, defaultInventoryTimeout)
 			defer cancel()
 		}

65-69: Panic on flag completion registration failure is aggressive.

Using panic for flag registration errors will crash the entire CLI. This typically only fails due to programmer error (duplicate flag name), but logging and continuing might be more resilient.

 	if err := cmd.RegisterFlagCompletionFunc("output", func(cmd *cobra.Command, args []string, toComplete string) ([]string, cobra.ShellCompDirective) {
 		return outputFormatFlag.GetValidValues(), cobra.ShellCompDirectiveNoFileComp
 	}); err != nil {
-		panic(err)
+		klog.V(2).Infof("Failed to register output flag completion: %v", err)
 	}
pkg/cmd/create/plan/network/mapper/ec2/mapper.go (1)

82-103: Edge case: empty network name after parsing "namespace/" format.

If the input is "namespace/" (with trailing slash but no name), targetName will be empty, resulting in a DestinationNetwork with an empty Name field. Consider validating the parsed name.

 	// Parse namespace/name format
 	var targetNamespace, targetName string
 	if ns, name, found := strings.Cut(defaultNetwork, "/"); found {
 		if ns == "" {
 			// Format: /name (use provided namespace)
 			targetNamespace = namespace
 		} else {
 			targetNamespace = ns
 		}
 		targetName = name
 	} else {
 		// Just a name, use provided namespace
 		targetNamespace = namespace
 		targetName = defaultNetwork
 	}

+	// If name is empty, fall back to pod networking
+	if targetName == "" {
+		return forkliftv1beta1.DestinationNetwork{Type: "pod"}
+	}
+
 	return forkliftv1beta1.DestinationNetwork{
pkg/cmd/get/inventory/ec2.go (2)

339-392: Consider extracting common tag name extraction logic.

The tag extraction logic (finding "Name" tag from AWS Tags array) is duplicated across addEC2InstanceNames, processEC2Volume, and processEC2Network. Consider extracting to a shared helper.

// extractNameFromTags extracts the Name tag value from AWS Tags array
func extractNameFromTags(tags interface{}) (string, bool) {
    tagsArray, ok := tags.([]interface{})
    if !ok {
        return "", false
    }
    for _, tagInterface := range tagsArray {
        if tag, ok := tagInterface.(map[string]interface{}); ok {
            if key, keyOk := tag["Key"].(string); keyOk && key == "Name" {
                if value, valueOk := tag["Value"].(string); valueOk {
                    return value, true
                }
            }
        }
    }
    return "", false
}

Then use it in the processing functions:

if tags, exists := instance["Tags"]; exists {
    if name, found := extractNameFromTags(tags); found {
        instance["name"] = name
    }
}

488-504: Logic gap: VPC with SubnetId won't set id field correctly.

At line 491-497, if a network has both VpcId and SubnetId, the VPC branch sets id to VpcId first, then it gets overwritten by SubnetId at lines 499-503. While the final result is correct (subnet ID takes precedence), the intermediate state and networkType = "vpc" assignment is wasteful. The condition structure could be clearer.

 	if _, hasID := network["id"]; !hasID {
-		// Check if it's a VPC or Subnet (AWS uses PascalCase)
-		if vpcID, ok := network["VpcId"].(string); ok {
-			// Check if this is actually a subnet by looking for SubnetId
-			if _, hasSubnetID := network["SubnetId"]; !hasSubnetID {
-				// It's a VPC
-				network["id"] = vpcID
-				network["networkType"] = "vpc"
-			}
-		}
-		if subnetID, ok := network["SubnetId"].(string); ok {
-			// It's a Subnet
+		// Subnet takes precedence over VPC
+		if subnetID, ok := network["SubnetId"].(string); ok {
 			network["id"] = subnetID
 			network["networkType"] = "subnet"
+		} else if vpcID, ok := network["VpcId"].(string); ok {
+			network["id"] = vpcID
+			network["networkType"] = "vpc"
 		}
 	}
pkg/cmd/create/plan/storage/mapper/ec2/mapper.go (1)

70-84: Name-based heuristic for EBS detection may have false positives.

The heuristic checking for substrings like "gp", "io", "st", "sc" could match non-EBS storage classes (e.g., a class named "fast-io-nfs" or "sc-ceph"). Consider adding a comment acknowledging this limitation or tightening the matching.

 	for _, storage := range targetStorages {
 		// Note: We don't have access to the provisioner here in the current interface
-		// We'll use a simple name-based heuristic: if it contains "gp", "io", "st", "sc" it's likely EBS
+		// We'll use a simple name-based heuristic for EBS detection.
+		// This may have false positives for non-EBS classes with similar naming.
 		scName := strings.ToLower(storage.StorageClass)

 		// Check if this looks like an EBS storage class
-		if strings.Contains(scName, "gp") || strings.Contains(scName, "io") ||
-			strings.Contains(scName, "st") || strings.Contains(scName, "sc") ||
-			strings.Contains(scName, "ebs") {
+		// Look for typical EBS type patterns (gp2, gp3, io1, io2, st1, sc1) or "ebs" keyword
+		isEBS := strings.Contains(scName, "ebs") ||
+			strings.Contains(scName, "gp2") || strings.Contains(scName, "gp3") ||
+			strings.Contains(scName, "io1") || strings.Contains(scName, "io2") ||
+			strings.Contains(scName, "st1") || strings.Contains(scName, "sc1")
+		if isEBS {
 			ebsStorageClasses = append(ebsStorageClasses, storage)
📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6c9cd83 and 9b8f548.

📒 Files selected for processing (21)
  • README.md (2 hunks)
  • cmd/get/inventory.go (1 hunks)
  • cmd/get/inventory_ec2.go (1 hunks)
  • guide/04-provider-management.md (1 hunks)
  • guide/07-inventory-management.md (1 hunks)
  • guide/09-mapping-management.md (1 hunks)
  • guide/10-migration-plan-creation.md (1 hunks)
  • pkg/cmd/create/mapping/network_helpers.go (1 hunks)
  • pkg/cmd/create/mapping/storage_helpers.go (2 hunks)
  • pkg/cmd/create/plan/network/factory.go (3 hunks)
  • pkg/cmd/create/plan/network/fetchers/ec2/fetcher.go (1 hunks)
  • pkg/cmd/create/plan/network/mapper/ec2/mapper.go (1 hunks)
  • pkg/cmd/create/plan/storage/factory.go (3 hunks)
  • pkg/cmd/create/plan/storage/fetchers/ec2/fetcher.go (1 hunks)
  • pkg/cmd/create/plan/storage/mapper/ec2/mapper.go (1 hunks)
  • pkg/cmd/create/provider/ec2/ec2.go (2 hunks)
  • pkg/cmd/create/provider/ec2/secrets.go (1 hunks)
  • pkg/cmd/get/inventory/ec2.go (1 hunks)
  • pkg/cmd/get/inventory/networks.go (2 hunks)
  • pkg/cmd/get/inventory/storage.go (2 hunks)
  • pkg/cmd/get/inventory/vms.go (5 hunks)
🚧 Files skipped from review as they are similar to previous changes (6)
  • pkg/cmd/create/provider/ec2/secrets.go
  • pkg/cmd/create/plan/storage/factory.go
  • pkg/cmd/create/plan/network/factory.go
  • pkg/cmd/get/inventory/storage.go
  • pkg/cmd/create/provider/ec2/ec2.go
  • README.md
🧰 Additional context used
🧬 Code graph analysis (7)
pkg/cmd/create/plan/network/mapper/ec2/mapper.go (1)
pkg/cmd/create/plan/network/mapper/interfaces.go (2)
  • NetworkMapper (17-19)
  • NetworkMappingOptions (9-14)
pkg/cmd/create/mapping/storage_helpers.go (1)
pkg/util/client/inventory.go (1)
  • FetchProviderInventoryWithInsecure (45-88)
pkg/cmd/get/inventory/vms.go (1)
pkg/util/output/table.go (2)
  • Header (65-68)
  • NewTablePrinter (83-93)
cmd/get/inventory.go (1)
cmd/get/inventory_ec2.go (4)
  • NewInventoryEC2InstanceCmd (75-83)
  • NewInventoryEC2VolumeCmd (86-94)
  • NewInventoryEC2VolumeTypeCmd (97-105)
  • NewInventoryEC2NetworkCmd (108-116)
pkg/cmd/create/mapping/network_helpers.go (1)
pkg/util/client/inventory.go (1)
  • FetchProviderInventoryWithInsecure (45-88)
pkg/cmd/create/plan/network/fetchers/ec2/fetcher.go (3)
pkg/cmd/create/plan/network/fetchers/interfaces.go (1)
  • NetworkFetcher (24-27)
pkg/cmd/get/inventory/inventory.go (1)
  • GetProviderByName (15-27)
pkg/util/client/inventory.go (1)
  • FetchProviderInventoryWithInsecure (45-88)
pkg/cmd/create/plan/storage/mapper/ec2/mapper.go (1)
pkg/cmd/create/plan/storage/mapper/interfaces.go (2)
  • StorageMapper (16-18)
  • StorageMappingOptions (9-13)
🔇 Additional comments (27)
pkg/cmd/create/mapping/storage_helpers.go (2)

199-200: LGTM!

The new EC2 case is correctly integrated into the provider type switch, following the established pattern for delegating to provider-specific resolvers.


247-283: LGTM!

The EC2 storage resolver correctly matches on the type field for EBS volume types (gp2, gp3, io1, etc.), which aligns with how AWS identifies volume types. The pattern of returning only Name (without ID) is appropriate since EC2 EBS volume types are string identifiers rather than UUIDs.

guide/09-mapping-management.md (1)

33-34: LGTM!

Clear and helpful note that documents the automatic mapping capability supported across all source providers, aligning with the EC2 mapper additions in this PR.

guide/07-inventory-management.md (1)

60-70: LGTM!

Well-structured EC2-specific resource documentation that follows the established table format. The note about generic resources also working with EC2 providers is helpful for users who may not realize the flexibility.

guide/10-migration-plan-creation.md (1)

178-186: LGTM!

The auto-mapping example demonstrates the simplest approach for plan creation, and the note reinforces the universal automatic mapping capability across all source providers. This is consistent with the related documentation in Chapter 9.

pkg/cmd/get/inventory/networks.go (2)

92-100: JSONPath field names are correctly mapped to EC2 API response structure.

Verification confirms the mixed casing is intentional and correct:

  • "networkType" (camelCase): Custom normalized field added during processing (ec2.go lines 496, 502, 508)
  • "CidrBlock", "State", "IsDefault" (PascalCase): Direct AWS API field names, as noted in the code comment at ec2.go line 289
  • "name", "id": Normalized fields added by processEC2Network()

The JSONPath definitions in networks.go lines 92-100 properly reference both AWS API fields and normalized fields created during network processing, ensuring the headers correctly match the actual data structure.


147-150: LGTM - Verification Confirmed

The processEC2Network function is properly defined in pkg/cmd/get/inventory/ec2.go:469 and correctly handles EC2-specific network processing:

  • Extracts name from AWS Tags format (PascalCase keys)
  • Normalizes ID field
  • Determines and sets network type based on presence of VPC or Subnet identifiers

The implementation aligns with the established pattern of provider-specific data enrichment.

pkg/cmd/create/mapping/network_helpers.go (2)

148-149: LGTM!

The EC2 case is correctly added to the provider type switch, delegating to the new EC2-specific resolver.


157-218: LGTM!

The EC2 network resolver correctly handles both ID-based and Name tag-based matching. The continue statement on line 191 properly prevents duplicate refs when a network matches by ID.

guide/04-provider-management.md (1)

243-260: LGTM!

The EC2 provider documentation is clear and comprehensive, showing both the minimal configuration with auto-generated URL and explicit URL override options. Good addition of the note clarifying that migration host and VDDK settings don't apply to EC2.

cmd/get/inventory.go (1)

119-134: LGTM!

The EC2-specific inventory subcommands are registered consistently with the existing command pattern. The alias conventions match those used for other provider-specific commands.

pkg/cmd/get/inventory/vms.go (3)

136-195: Clean refactoring of VM augmentation logic.

The augmentVMInfo helper consolidates VM data enrichment (concerns, memory formatting, disk capacity, power state) into a single function that returns expanded text when applicable. This improves maintainability and reduces duplication.


438-460: LGTM!

The EC2-specific table headers appropriately display AWS EC2 instance attributes (instance type, state, availability zone, IPs), while the default headers are preserved for other provider types with their computed display fields.


348-359: The addEC2InstanceNames function is properly defined and the call is correct.

The function addEC2InstanceNames is defined in pkg/cmd/get/inventory/ec2.go at line 341 with the signature func addEC2InstanceNames(data interface{}) interface{}. The call at line 351 in vms.go passes vm (type map[string]interface{}), which is compatible with the function's parameter type. The function properly handles this type and modifies the map in place to add the "name" field, which is subsequently used at line 358.

pkg/cmd/create/plan/storage/fetchers/ec2/fetcher.go (1)

93-98: LGTM!

Returning an empty slice for target storages is appropriate since EC2 serves as a source provider, not a migration target. The debug log provides useful context.

pkg/cmd/create/plan/network/fetchers/ec2/fetcher.go (3)

1-24: LGTM!

Clean package structure with proper imports and a straightforward constructor implementing the NetworkFetcher interface.


66-96: Network prioritization and sorting logic is clear.

The logic correctly prioritizes subnets over VPCs and sorts them appropriately (subnets by CIDR, VPCs by ID). The fallback to VPCs when no subnets exist is a reasonable default.


102-107: LGTM!

Appropriate stub implementation for target networks, with a clear comment explaining EC2 is typically a source, not a target.

cmd/get/inventory_ec2.go (2)

16-23: LGTM!

Clean configuration struct pattern enabling DRY command creation.


74-116: LGTM!

The four command constructors follow a consistent pattern and provide clear, descriptive help text for each EC2 resource type.

pkg/cmd/create/plan/network/mapper/ec2/mapper.go (2)

1-19: LGTM!

Clean struct and constructor implementing the NetworkMapper interface.


21-73: Clear mapping strategy with good documentation.

The strategy of mapping the first network to the default target and ignoring the rest is well-documented in the comments. The logic correctly handles both user-specified and default (pod networking) targets.

pkg/cmd/get/inventory/ec2.go (2)

26-96: LGTM!

Solid implementation with proper provider type validation, well-defined headers, and consistent error handling.


432-437: The humanizeBytes function is properly defined and accessible.

The function is defined in pkg/cmd/get/inventory/inventory.go (lines 30-42) as a package-level function. Since both ec2.go and inventory.go are in the same package (pkg/cmd/get/inventory/), no import statement is required—the function is automatically accessible throughout the package.

pkg/cmd/create/plan/storage/mapper/ec2/mapper.go (3)

22-51: LGTM!

Good categorization of EC2 volume types. The logic correctly differentiates SSD types (gp2/gp3, io1/io2) for Block mode and HDD types (st1, sc1, standard) for Filesystem mode. Defaulting to Block for unknown types is a safe choice.


120-179: LGTM!

The mapping logic is well-structured with clear strategy documentation. User-specified defaults take precedence, and the fallback to heuristic matching is a reasonable approach. Good use of debug logging throughout.


140-144: Excellent! I have completed the verification. Here's what I found:

Verification Results:

The EC2 storage fetcher (pkg/cmd/create/plan/storage/fetchers/ec2/fetcher.go, lines 83-86) creates ref.Ref objects with the Name field set to the EC2 volume type:

for _, volumeType := range volumeTypes {
    sourceStorages = append(sourceStorages, ref.Ref{
        Name: volumeType,
    })
}

The volumeType values come directly from the EC2 API response (storage["type"].(string)) and include actual EC2 volume types like "gp3", "gp2", "io2", "io1", "st1", "sc1", and "standard".

The mapper code correctly uses sourceStorage.Name to access this EC2 volume type value.


Verify that sourceStorage.Name contains the EC2 volume type.

Confirmed. The EC2 storage fetcher populates the ref.Ref.Name field with the actual EC2 volume type extracted from the EC2 API response (e.g., "gp3", "io2", "st1"). The mapper's usage at line 141 is correct.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
guide/04-provider-management.md (1)

359-370: The documentation contains a factual error about EC2 flag naming.

The note states the EC2 provider uses --region during creation and --ec2-region during patching, but the actual implementation (cmd/create/provider.go:109 and cmd/patch/provider.go:91) uses --ec2-region for both operations. The explanation about avoiding conflicts with a "global -n namespace region flag" is misleading since this flag inconsistency doesn't actually exist in the code.

Update the note to reflect the correct flag usage:

**Note**: The EC2 provider uses `--ec2-region` for both creation and patching operations to refer to the AWS region.
🧹 Nitpick comments (6)
pkg/cmd/create/plan/storage/factory.go (1)

309-331: EC2 storage mapper is source‑only; confirm target semantics

The EC2 case in GetStorageMapper makes EC2 usable as a source for storage mapping, but GetTargetStorageFetcher still has no "ec2" branch, so EC2 cannot currently be used as a plan target (you’ll get unsupported target provider type: ec2). If this is intentional (EC2 strictly as a source), it might be worth documenting that assumption; if you eventually want EC2 as a target, you’ll need a matching "ec2" branch in GetTargetStorageFetcher (possibly reusing EC2StorageFetcher.FetchTargetStorages).

pkg/cmd/create/provider/ec2/ec2.go (1)

106-117: Default EC2 endpoint derivation is sensible; consider AWS partition nuances

Setting provider.Spec.Type to "ec2" and always populating provider.Spec.URL (either from options.URL or https://ec2.<region>.amazonaws.com) is clean and keeps downstream consumers simple. One optional improvement: if you ever need to support non‑standard AWS partitions (notably China regions, which use amazonaws.com.cn), you may want to derive the hostname based on the region/pattern rather than hard‑coding amazonaws.com.

Also applies to: 122-125

pkg/cmd/create/plan/storage/fetchers/ec2/fetcher.go (2)

18-97: EC2 source storage fetcher is straightforward; minor robustness nits

The flow — lookup provider, call FetchProviderInventoryWithInsecure, assert array, dedupe type values into a set, sort by priority, and expose them as ref.Ref{Name: volumeType} — is clear and matches how the EC2 mapper expects to consume volume types. Two optional tweaks for resilience:

  • Normalize the incoming storage["type"] to lower‑case before deduping and prioritizing, so inventory that reports "GP3"/"Gp3" still hits your priority map.
  • planVMNames is currently unused; if the EC2 inventory grows large, you may eventually want to consider filtering by the plan VMs (mirroring other providers, if they do that).

Example for the normalization (imports strings):

-import (
-	"context"
-	"fmt"
-	"sort"
+import (
+	"context"
+	"fmt"
+	"sort"
+	"strings"
@@
-		volumeType, ok := storage["type"].(string)
-		if ok && volumeType != "" {
-			volumeTypeSet[volumeType] = struct{}{}
+		volumeType, ok := storage["type"].(string)
+		if ok && volumeType != "" {
+			volumeType = strings.ToLower(volumeType)
+			volumeTypeSet[volumeType] = struct{}{}

99-104: Target fetcher stub is fine; keep in sync with factory wiring

Returning an empty slice for FetchTargetStorages with a debug note matches the current assumption that EC2 is typically a source only. Just ensure this stays aligned with GetTargetStorageFetcher in the factory (which currently has no "ec2" case): if you later decide to support EC2 as a migration target, remember to add the corresponding factory branch so this implementation can actually be used.

pkg/cmd/create/plan/storage/mapper/ec2/mapper.go (1)

22-183: EC2 storage mapping logic is coherent; consider using target provider type for clarity

The mapper cleanly:

  • Derives volume/ access modes per EC2 volume type via getVolumeTypeConfig.
  • Heuristically detects EBS‑style storage classes and matches by name (exact / prefix) in findMatchingEBSStorageClass, with sane fallbacks (default class, then first EBS, then first overall if no EBS).
  • Builds StoragePairs with the chosen StorageClass and appropriate VolumeMode/AccessMode, honoring a user‑supplied DefaultTargetStorageClass when present.

Two optional improvements:

  1. CreateStoragePairs ignores opts.TargetProviderType, while the strategy and logging comment explicitly assume EC2 → OpenShift/EBS. To avoid surprising behavior if someone ever wires EC2 to a non‑OpenShift target, you could at least log or assert on opts.TargetProviderType (e.g., warn when it’s not "openshift").

  2. In findMatchingEBSStorageClass, when no EBS‑looking classes are found you fall back to targetStorages[0].StorageClass. That’s reasonable as a last resort, but if StorageClass can ever be empty on entries, you might want to skip blank names when choosing that fallback.

Overall, the design aligns with the surrounding StorageMappingOptions contract and the EC2 fetcher’s output.

pkg/cmd/create/plan/network/fetchers/ec2/fetcher.go (1)

69-72: Strengthen sorting with defensive type checking.

The sorting logic uses type assertions with blank identifiers (e.g., subnet["CidrBlock"].(string)), which silently defaults to empty string if the field is missing or has an unexpected type. While this allows sorting to proceed, it could mask data quality issues.

Consider logging a warning when CidrBlock or VpcId is missing or has an unexpected type:

 sort.Slice(subnets, func(i, j int) bool {
-	cidrI, _ := subnets[i]["CidrBlock"].(string)
-	cidrJ, _ := subnets[j]["CidrBlock"].(string)
+	cidrI, okI := subnets[i]["CidrBlock"].(string)
+	cidrJ, okJ := subnets[j]["CidrBlock"].(string)
+	if !okI || !okJ {
+		klog.V(4).Infof("DEBUG: EC2 - Missing or invalid CidrBlock during sort")
+	}
 	return cidrI < cidrJ
 })

Apply similar logic to VPC sorting on lines 84-87.

Also applies to: 84-87

📜 Review details

Configuration used: CodeRabbit UI

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9b8f548 and 9fbed75.

📒 Files selected for processing (21)
  • README.md (2 hunks)
  • cmd/get/inventory.go (1 hunks)
  • cmd/get/inventory_ec2.go (1 hunks)
  • guide/04-provider-management.md (2 hunks)
  • guide/07-inventory-management.md (1 hunks)
  • guide/09-mapping-management.md (1 hunks)
  • guide/10-migration-plan-creation.md (1 hunks)
  • pkg/cmd/create/mapping/network_helpers.go (1 hunks)
  • pkg/cmd/create/mapping/storage_helpers.go (3 hunks)
  • pkg/cmd/create/plan/network/factory.go (3 hunks)
  • pkg/cmd/create/plan/network/fetchers/ec2/fetcher.go (1 hunks)
  • pkg/cmd/create/plan/network/mapper/ec2/mapper.go (1 hunks)
  • pkg/cmd/create/plan/storage/factory.go (3 hunks)
  • pkg/cmd/create/plan/storage/fetchers/ec2/fetcher.go (1 hunks)
  • pkg/cmd/create/plan/storage/mapper/ec2/mapper.go (1 hunks)
  • pkg/cmd/create/provider/ec2/ec2.go (2 hunks)
  • pkg/cmd/create/provider/ec2/secrets.go (1 hunks)
  • pkg/cmd/get/inventory/ec2.go (1 hunks)
  • pkg/cmd/get/inventory/networks.go (2 hunks)
  • pkg/cmd/get/inventory/storage.go (2 hunks)
  • pkg/cmd/get/inventory/vms.go (5 hunks)
✅ Files skipped from review due to trivial changes (1)
  • pkg/cmd/create/provider/ec2/secrets.go
🚧 Files skipped from review as they are similar to previous changes (8)
  • pkg/cmd/get/inventory/networks.go
  • cmd/get/inventory.go
  • README.md
  • pkg/cmd/create/plan/network/factory.go
  • guide/09-mapping-management.md
  • pkg/cmd/create/mapping/storage_helpers.go
  • guide/10-migration-plan-creation.md
  • pkg/cmd/create/mapping/network_helpers.go
🧰 Additional context used
🧬 Code graph analysis (4)
pkg/cmd/create/plan/storage/factory.go (2)
pkg/cmd/create/plan/storage/fetchers/ec2/fetcher.go (1)
  • NewEC2StorageFetcher (22-24)
pkg/cmd/create/plan/storage/mapper/ec2/mapper.go (1)
  • NewEC2StorageMapper (18-20)
pkg/cmd/create/plan/network/fetchers/ec2/fetcher.go (3)
pkg/cmd/create/plan/network/fetchers/interfaces.go (1)
  • NetworkFetcher (24-27)
pkg/cmd/get/inventory/inventory.go (1)
  • GetProviderByName (15-27)
pkg/util/client/inventory.go (1)
  • FetchProviderInventoryWithInsecure (45-88)
pkg/cmd/create/plan/storage/mapper/ec2/mapper.go (1)
pkg/cmd/create/plan/storage/mapper/interfaces.go (2)
  • StorageMapper (16-18)
  • StorageMappingOptions (9-13)
cmd/get/inventory_ec2.go (4)
pkg/util/flags/output_format_type.go (1)
  • NewOutputFormatTypeFlag (49-54)
pkg/util/completion/completion.go (1)
  • ProviderNameCompletion (84-86)
pkg/util/client/namespace.go (1)
  • ResolveNamespaceWithAllFlag (36-41)
pkg/cmd/get/inventory/ec2.go (4)
  • ListEC2InstancesWithInsecure (16-24)
  • ListEC2VolumesWithInsecure (99-107)
  • ListEC2VolumeTypesWithInsecure (182-190)
  • ListEC2NetworksWithInsecure (257-265)
🔇 Additional comments (32)
pkg/cmd/create/plan/storage/factory.go (2)

18-31: EC2 fetcher/mapper imports are wired consistently

The new ec2Fetcher and ec2Mapper imports align with the concrete constructors in their packages and with how other providers are wired here. No issues from a factory/import perspective.


214-218: EC2 source storage fetcher registration looks correct

Registering "ec2" here and returning ec2Fetcher.NewEC2StorageFetcher() is consistent with the provider type set in CreateProvider and with the SourceStorageFetcher interface — the concrete fetcher also satisfies the broader StorageFetcher interface, so the assignment is sound.

pkg/cmd/create/provider/ec2/ec2.go (1)

19-37: EC2 provider option validation is consistent and guards common misconfigs

Requiring Name, Namespace, and EC2Region, plus enforcing “either an existing secret or explicit access key/secret (both required)” is a good, tight contract. The mutual‑exclusion check between Secret and Username/Password also avoids ambiguous configuration.

pkg/cmd/create/plan/network/fetchers/ec2/fetcher.go (3)

1-24: LGTM! Clean package structure and constructor.

The package structure, imports, and constructor follow Go conventions and correctly implement the NetworkFetcher interface.


103-108: LGTM! Appropriate implementation for EC2 as source.

The implementation correctly returns an empty slice since EC2 is typically not used as a migration target. The explanatory comment and debug log are helpful.


68-97: Based on my verification, I have found clear evidence that the exclusive subnet-or-VPC return behavior is intentional and documented:

  1. Line 471 in pkg/cmd/get/inventory/ec2.go explicitly states: "Subnet takes precedence over VPC"
  2. Lines 22-24 in pkg/cmd/create/plan/network/mapper/ec2/mapper.go document: "First network (typically public subnet or VPC) -> pod networking (default)" / "All other networks -> ignored"
  3. Line 49 in the mapper confirms: "Map the first source network to the default target" — only the first network is actually used

The exclusive behavior (returning only subnets if present, else only VPCs) is architecturally sound because:

  • It prioritizes more specific networks (subnets) over broader ones (VPCs)
  • The mapper implementation only consumes the first network regardless
  • The strategy is documented as intentional precedence

The exclusive subnet-or-VPC return behavior is intentional and architecturally correct. The code explicitly prioritizes subnets (more granular) as the primary option, with VPCs as a fallback when subnets are unavailable. This aligns with the mapper's documented strategy of using only the first network. The current implementation is sound and requires no changes.

pkg/cmd/create/plan/network/mapper/ec2/mapper.go (3)

1-19: LGTM! Clean mapper structure.

The package structure and constructor correctly implement the NetworkMapper interface.


21-73: LGTM! Clear and well-documented mapping strategy.

The network mapping logic is straightforward: the first source network maps to the default target (user-specified or pod networking), and all subsequent networks are marked as "ignored". The implementation includes helpful debug logging and defensive handling of edge cases.


75-108: Go version compatibility verified—code is safe to merge.

The project requires Go 1.24.0 (specified in go.mod), which far exceeds the Go 1.18 minimum required for strings.Cut. The parsing logic is well-structured with proper defensive fallbacks for edge cases (empty names, various input formats).

guide/04-provider-management.md (2)

243-258: LGTM! Clear EC2 provider examples.

The documentation correctly illustrates both auto-generated and explicit URL configurations for EC2 providers, with appropriate credential flags.


260-260: LGTM! Accurate EC2 limitation note.

Correctly documents that migration host and VDDK settings don't apply to EC2 providers.

pkg/cmd/get/inventory/storage.go (2)

53-59: LGTM! Appropriate EC2 storage headers.

The headers correctly reflect EC2 volume type characteristics (gp3, io2, etc.) rather than traditional datastore metrics.


84-85: LGTM! Consistent resource fetching.

EC2 storage fetching follows the established pattern for generic storage resources.

guide/07-inventory-management.md (1)

60-69: LGTM! Comprehensive EC2 inventory documentation.

The EC2 resource documentation is clear, complete, and includes a helpful note about generic resource compatibility.

pkg/cmd/get/inventory/vms.go (4)

136-195: LGTM! Well-structured refactoring.

The augmentVMInfo function cleanly centralizes VM data augmentation logic, improving maintainability and readability.


235-235: LGTM! EC2 provider support added.

EC2 is correctly included in the VM-supported provider types across both query and list functions.

Also applies to: 322-322


348-363: LGTM! EC2-specific name extraction.

The EC2 provider correctly uses specialized name extraction logic and skips non-applicable augmentation. The implementation delegates to addEC2InstanceNames (defined in pkg/cmd/get/inventory/ec2.go).


442-464: LGTM! Provider-appropriate header definitions.

The headers correctly reflect the distinct data models: AWS-native fields (PascalCase) for EC2, and traditional VM metrics with concerns for other providers.

cmd/get/inventory_ec2.go (4)

17-27: LGTM! Clean command configuration abstraction.

The ec2CommandConfig struct provides a clear, type-safe template for EC2 inventory commands.


29-75: LGTM! Standard command factory implementation.

The factory function follows established patterns for inventory commands with proper flag handling, validation, and completion.


77-108: LGTM! Consistent EC2 command constructors.

The three constructors follow a consistent pattern with clear descriptions and proper function wiring.


110-119: LGTM! EC2 network command constructor.

The network command constructor is consistent with the other EC2 inventory commands.

pkg/cmd/get/inventory/ec2.go (10)

15-24: LGTM! Standard inventory entry point.

The function correctly implements watch mode support following the established pattern.


43-45: Strict provider type validation is appropriate.

The function correctly validates that only EC2 providers can use this endpoint, providing a clear error message for type mismatches.


47-58: LGTM! Well-documented EC2 instance headers.

The headers correctly reflect AWS EC2 instance fields with a helpful comment explaining the NAME field derivation.


98-179: LGTM! Consistent EC2 volume inventory.

The volume listing follows the same pattern as instances with appropriate EBS-specific headers and data augmentation.


181-254: LGTM! Appropriate volume type inventory.

The volume type listing correctly uses generic resource collection and matches the headers defined in storage.go.


256-335: LGTM! Comprehensive EC2 network inventory.

The network listing correctly handles both VPCs and Subnets with appropriate field normalization.


340-355: LGTM! Standard AWS tag extraction.

The helper correctly implements the AWS tagging convention for name extraction.


357-392: LGTM! Robust instance name extraction.

The function handles both single and multiple instances with appropriate fallback to InstanceId when Name tag is absent.


394-443: LGTM! Comprehensive volume field augmentation.

The volume processing correctly handles name extraction, size formatting, and attachment status with appropriate defaults.


445-495: LGTM! Robust network field processing.

The network processing correctly distinguishes VPCs from Subnets and provides multiple fallback mechanisms to ensure consistent data.

Signed-off-by: yaacov <[email protected]>
@yaacov yaacov merged commit 081e926 into main Nov 26, 2025
2 checks passed
@coderabbitai coderabbitai bot mentioned this pull request Jan 7, 2026
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