Skip to content

init ec2 scanner#19

Merged
jsbroks merged 7 commits intomainfrom
ec2-scanner
Apr 17, 2025
Merged

init ec2 scanner#19
jsbroks merged 7 commits intomainfrom
ec2-scanner

Conversation

@jsbroks
Copy link
Member

@jsbroks jsbroks commented Apr 14, 2025

Summary by CodeRabbit

  • New Features

    • Introduced the ability to synchronize AWS EC2 instance information seamlessly into the platform.
    • Enhanced the command interface to support AWS EC2 sync operations with customizable region and provider options.
  • Chores

    • Updated external dependencies to accommodate the new AWS integration capabilities.

@coderabbitai
Copy link
Contributor

coderabbitai bot commented Apr 14, 2025

Caution

Review failed

The pull request is closed.

Walkthrough

This update introduces a new command for synchronizing AWS EC2 instances into Ctrlplane. A new file defining an EC2Instance struct and the NewSyncEC2Cmd function has been added, which encapsulates the logic for loading AWS configuration, retrieving credentials, and processing EC2 instance data including tags and console URLs. The command integrates with the existing sync command interface, and error handling is implemented throughout. Additionally, multiple AWS SDK for Go v2 dependencies have been added to the module to support this feature.

Changes

File(s) Change Summary
cmd/ctrlc/root/sync/aws/ec2/ec2.go
cmd/ctrlc/root/sync/sync.go
Introduces the EC2Instance struct and the NewSyncEC2Cmd function to implement AWS EC2 synchronization. The new command is integrated into the main sync command by adding it via interval support.
go.mod Adds multiple indirect dependencies for AWS SDK for Go v2 and related packages, enabling support for AWS services such as EC2, SSO, STS, and others.

Sequence Diagram(s)

sequenceDiagram
    participant U as User
    participant S as SyncEC2Cmd
    participant AWS as AWS SDK
    participant CP as Ctrlplane

    U->>S: Execute EC2 sync command
    S->>AWS: Load config & obtain credentials
    AWS-->>S: Return configuration data
    S->>AWS: Call DescribeInstances API
    AWS-->>S: Return EC2 instance details
    S->>CP: Upsert instances with metadata and tags
    CP-->>S: Confirmation response
    S->>U: Display sync result
Loading

Poem

I'm a rabbit with hops so light,
Syncing EC2s from morning 'til night.
New code in place, credentials in tow,
AWS data in a neat little flow.
I dance with commands on the digital plain,
Celebrating changes with each joyful gain.
Hop on, enjoy the carrot-powered code train! 🥕🐇


📜 Recent review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 9598765 and 0eb6b11.

📒 Files selected for processing (1)
  • cmd/ctrlc/root/sync/aws/ec2/ec2.go (1 hunks)

🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link
Contributor

@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 (5)
cmd/ctrlc/root/sync/sync.go (1)

31-31: Check command naming consistency.

The line adds ec2.NewSyncEC2Cmd() under "sync", but the command usage in ec2.go is "aws-ec2", whereas the example references "sync ec2". Consider renaming either the command usage to match "ec2" or updating the docs/examples to use "aws-ec2" to avoid confusion.

cmd/ctrlc/root/sync/aws/ec2/ec2.go (4)

20-38: Model structure looks good, but consider possible simplifications.

Your EC2Instance struct captures the main attributes, and Struct() properly marshals/unmarshals to a map. This extra JSON round-trip might be a bit costly at scale, though it is straightforward. If performance becomes an issue, consider directly constructing the map without a JSON marshal/unmarshal cycle.


40-57: Validate usage name vs. example command.

The Use: "aws-ec2" field of the command clarity is at odds with the example usage lines that mention "ctrlc sync ec2". You might rename "aws-ec2" to just "ec2", or update the example accordingly to ensure consistency for end users.


88-96: Validate workspace, URL, and API key presence.

Here you retrieve url, api-key, and workspace from viper. If these values are critical for upserting resources, consider adding a check that logs or fails early if any are missing, so users get immediate feedback rather than potentially running into a 401 or invalid workspace error.


98-166: Consider paginating large DescribeInstances calls.

ec2Client.DescribeInstances without pagination can yield a large result set if the account has many instances. The SDK provides pagination abstractions to handle extensive data more gracefully. Also, note that the variable name inside the loop shadows the outer name used for the resource provider, which can be confusing. Renaming one would improve clarity.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 2830709 and 30e99d1.

⛔ Files ignored due to path filters (1)
  • go.sum is excluded by !**/*.sum
📒 Files selected for processing (3)
  • cmd/ctrlc/root/sync/aws/ec2/ec2.go (1 hunks)
  • cmd/ctrlc/root/sync/sync.go (2 hunks)
  • go.mod (1 hunks)
🧰 Additional context used
🧬 Code Graph Analysis (2)
cmd/ctrlc/root/sync/sync.go (2)
internal/cliutil/interval.go (1)
  • AddIntervalSupport (10-51)
cmd/ctrlc/root/sync/aws/ec2/ec2.go (1)
  • NewSyncEC2Cmd (40-198)
cmd/ctrlc/root/sync/aws/ec2/ec2.go (2)
internal/api/resource_provider.go (2)
  • AgentResource (57-64)
  • NewResourceProvider (11-49)
internal/api/client.go (1)
  • NewAPIKeyClientWithResponses (10-19)
🔇 Additional comments (5)
go.mod (1)

30-43:

Details

✅ Verification successful

Verify and tidy AWS SDK dependencies.

These newly introduced dependencies for the AWS SDK for Go v2 look correct, but consider running a go mod tidy to remove any transitive dependencies that might not be needed, and keep your module footprint minimal. Additionally, ensure the pinned versions are not subject to known vulnerabilities and are up to date with AWS security advisories.


🏁 Script executed:

#!/bin/bash
# Check for any unnecessary dependencies and perform module tidy
go mod tidy

# Optionally, check for vulnerabilities in pinned dependencies
go list -m -u all | grep "aws/aws-sdk-go-v2"

Length of output: 7419


Action: AWS SDK dependencies verified and approved.

After running go mod tidy and checking dependency updates, the AWS SDK dependencies in go.mod (lines 30-43) appear to be correctly maintained. The pinned versions remain as specified, and no extraneous transitive dependencies were removed. Please continue to monitor AWS security advisories to ensure these versions remain free from vulnerabilities.

cmd/ctrlc/root/sync/sync.go (1)

5-5: Import is consistent with the new EC2 sync logic.

The addition of the ec2 import is correct and aligns with the new EC2 synchronization functionality. No issues here.

cmd/ctrlc/root/sync/aws/ec2/ec2.go (3)

58-80: Properly logging and masking AWS credentials.

The partial mask ([:4]+"****") for the access_key_id is a good security practice. Ensure no other logs inadvertently expose credentials. Also, if you expect repeated runs (via interval), confirm that the credential lifetime is sufficient or refresh logic is in place to handle long-run scenarios.


168-190: Good approach to upserting resources; auto-create resource provider if missing.

Your logic handles resource provider creation or update seamlessly. This is a solid pattern. Be mindful of error messages to confirm if the user’s workspace was valid and whether the resource provider is recognized in the system when debugging. No immediate changes required.


193-195: Flag naming and usage look consistent.

These lines properly register the --provider and --config-region flags and mark the region as required. No concerns here.

Also applies to: 197-198

Copy link
Contributor

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

🧹 Nitpick comments (5)
cmd/ctrlc/root/sync/aws/ec2/ec2.go (5)

36-41: Consider a more efficient approach for struct conversion

The current implementation uses JSON marshaling and unmarshaling to convert the struct to a map, which is inefficient. Consider using a direct mapping approach for better performance.

func (t *EC2Instance) Struct() map[string]interface{} {
-	b, _ := json.Marshal(t)
-	var m map[string]interface{}
-	json.Unmarshal(b, &m)
-	return m
+	return map[string]interface{}{
+		"id":               t.ID,
+		"name":             t.Name,
+		"connectionMethod": map[string]interface{}{
+			"type":       t.ConnectionMethod.Type,
+			"region":     t.ConnectionMethod.Region,
+			"instanceId": t.ConnectionMethod.InstanceID,
+			"accountId":  t.ConnectionMethod.AccountID,
+		},
+	}
}

75-82: Improve logging of sensitive information

The current approach to redacting the access key ID is a good start, but consider using a dedicated method for handling sensitive information consistently throughout the codebase.


117-121: Improve region extraction logic

The current method of extracting the region from the availability zone assumes a specific format (region + letter) which may not always be correct. Consider using the region from the AWS configuration directly.

// Get EC2 region from instance availability zone
-region := ""
-if instance.Placement != nil && instance.Placement.AvailabilityZone != nil {
-	// Region is AZ without the last character
-	region = (*instance.Placement.AvailabilityZone)[:len(*instance.Placement.AvailabilityZone)-1]
-}
+// Use the region provided to the command, which is guaranteed to be correct
+region := cfg.Region

228-228: Improve handling of structured data in metadata

Embedding a JSON string inside metadata requires double serialization/deserialization. Consider using a structured approach that allows for nesting.

-metadata["ctrlplane/links"] = fmt.Sprintf("{ \"AWS Console\": \"%s\" }", consoleUrl)
+metadata["ctrlplane/links/aws-console"] = consoleUrl

269-269: Reconsider flag shorthand choice

The shorthand -c for region is unusual as region typically uses -r. Using -c might clash with other common flags like "config". Consider using a different shorthand.

-cmd.Flags().StringVarP(&region, "region", "c", "", "AWS Region")
+cmd.Flags().StringVarP(&region, "region", "r", "", "AWS Region")
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8beca8c and 2e4fc0c.

📒 Files selected for processing (1)
  • cmd/ctrlc/root/sync/aws/ec2/ec2.go (1 hunks)
🔇 Additional comments (1)
cmd/ctrlc/root/sync/aws/ec2/ec2.go (1)

135-138:

Details

✅ Verification successful

Handle potential variations in AWS console URLs

The URL formation assumes a standard pattern for AWS console URLs, which might change or vary across AWS partitions. Consider using a more robust method for generating console URLs, potentially through AWS SDK's utility functions if available.


🌐 Web query:

Does AWS SDK for Go provide utilities for generating console URLs for resources?

💡 Result:

The AWS SDK for Go does not include built-in utilities for generating console URLs for AWS resources directly. The available utilities focus primarily on API integrations with individual AWS services, such as creating presigned S3 URLs, configuring service clients, and accessing specific API functionalities[1][4][7].

For creating console URLs to access resources, you generally need to construct those URLs manually based on AWS Console patterns or use third-party tools. For instance, tools like aws-console (a third-party utility) can generate temporary AWS Console login URLs using credentials from AWS CLI profiles[3]. This is not a capability integrated into the native AWS SDK for Go.

Citations:


AWS Console URL Generation Issue

Based on our research, the AWS SDK for Go does not provide built-in utilities for generating AWS Console URLs. Thus, manually constructing the URL using fmt.Sprintf (as done in your snippet) remains the only option for now. However, since AWS console URL patterns might differ across partitions or change in the future, it would be prudent to consider making the URL pattern configurable (e.g., via constants, configuration files, or helper functions) to facilitate future updates.

  • Current Approach Acceptable: Manual URL construction is necessary as there is no AWS SDK utility available.
  • Future-Proofing Suggestion: Externalize the URL pattern into a configuration or helper function to handle any potential variations.

Comment on lines +258 to +262
upsertResp, err := rp.UpsertResource(ctx, resources)
log.Info("Response from upserting resources", "status", upsertResp.Status)
if err != nil {
return fmt.Errorf("failed to upsert resources: %w", err)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Enhance error handling for API response

The code logs the response status but doesn't check if the status indicates an error. Consider adding more detailed response validation.

upsertResp, err := rp.UpsertResource(ctx, resources)
log.Info("Response from upserting resources", "status", upsertResp.Status)
if err != nil {
	return fmt.Errorf("failed to upsert resources: %w", err)
}
+
+// Check for non-success status codes
+if upsertResp.Status >= 400 {
+	return fmt.Errorf("failed to upsert resources: unexpected status code %d", upsertResp.Status)
+}
📝 Committable suggestion

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

Suggested change
upsertResp, err := rp.UpsertResource(ctx, resources)
log.Info("Response from upserting resources", "status", upsertResp.Status)
if err != nil {
return fmt.Errorf("failed to upsert resources: %w", err)
}
upsertResp, err := rp.UpsertResource(ctx, resources)
log.Info("Response from upserting resources", "status", upsertResp.Status)
if err != nil {
return fmt.Errorf("failed to upsert resources: %w", err)
}
// Check for non-success status codes
if upsertResp.Status >= 400 {
return fmt.Errorf("failed to upsert resources: unexpected status code %d", upsertResp.Status)
}

Comment on lines +90 to +93
apiURL := viper.GetString("url")
apiKey := viper.GetString("api-key")
workspaceId := viper.GetString("workspace")

Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Add validation for required configuration values

There's no validation that apiURL, apiKey, and workspaceId are actually set. This could lead to cryptic errors when making API calls.

apiURL := viper.GetString("url")
apiKey := viper.GetString("api-key")
workspaceId := viper.GetString("workspace")

+if apiURL == "" || apiKey == "" || workspaceId == "" {
+	return fmt.Errorf("missing required configuration: url, api-key, or workspace")
+}
📝 Committable suggestion

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

Suggested change
apiURL := viper.GetString("url")
apiKey := viper.GetString("api-key")
workspaceId := viper.GetString("workspace")
apiURL := viper.GetString("url")
apiKey := viper.GetString("api-key")
workspaceId := viper.GetString("workspace")
if apiURL == "" || apiKey == "" || workspaceId == "" {
return fmt.Errorf("missing required configuration: url, api-key, or workspace")
}

Comment on lines +95 to +98
result, err := ec2Client.DescribeInstances(ctx, &ec2.DescribeInstancesInput{})
if err != nil {
return fmt.Errorf("failed to describe instances: %w", err)
}
Copy link
Contributor

Choose a reason for hiding this comment

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

🛠️ Refactor suggestion

Implement pagination for DescribeInstances

The AWS EC2 API uses pagination for responses with many items. The current implementation fetches only the first page of results, which may lead to incomplete data if there are many instances.

// Get EC2 instances
-result, err := ec2Client.DescribeInstances(ctx, &ec2.DescribeInstancesInput{})
-if err != nil {
-	return fmt.Errorf("failed to describe instances: %w", err)
-}
+var resources []api.AgentResource
+var nextToken *string
+
+for {
+	result, err := ec2Client.DescribeInstances(ctx, &ec2.DescribeInstancesInput{
+		NextToken: nextToken,
+	})
+	if err != nil {
+		return fmt.Errorf("failed to describe instances: %w", err)
+	}
+
+	// Process instances (existing code from lines 101-241)
+	// ...
+
+	// Check if there are more results
+	if result.NextToken == nil {
+		break
+	}
+	nextToken = result.NextToken
+}
📝 Committable suggestion

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

Suggested change
result, err := ec2Client.DescribeInstances(ctx, &ec2.DescribeInstancesInput{})
if err != nil {
return fmt.Errorf("failed to describe instances: %w", err)
}
var resources []api.AgentResource
var nextToken *string
for {
result, err := ec2Client.DescribeInstances(ctx, &ec2.DescribeInstancesInput{
NextToken: nextToken,
})
if err != nil {
return fmt.Errorf("failed to describe instances: %w", err)
}
// Process instances (existing code from lines 101-241)
// ...
// Check if there are more results
if result.NextToken == nil {
break
}
nextToken = result.NextToken
}

Copy link
Contributor

@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

♻️ Duplicate comments (4)
cmd/ctrlc/root/sync/aws/ec2/ec2.go (4)

90-93: Validate required configuration values.

No check is performed to ensure apiURL, apiKey, and workspaceId are populated. This can lead to cryptic errors later in the process if they are empty.


95-98: Implement pagination for DescribeInstances.

The AWS EC2 API may paginate results. This code only fetches the first page, potentially missing subsequent pages if the user has many instances.


198-200: Fix incorrect metadata key assignment.

Storing instance.PlatformDetails in aws/instance-type is likely incorrect. Use instance.InstanceType for the "instance-type" metadata key, and store platform details under a different key if needed.


258-262: Enhance error handling for API response.

You log the status but do not check if it indicates a downstream error. Consider returning an error if the status is not in the 2xx range.

🧹 Nitpick comments (1)
cmd/ctrlc/root/sync/aws/ec2/ec2.go (1)

75-82: Be cautious with logging credentials.

While partial credential logging may be acceptable in some contexts, ensure that your logs are secured and that truncating to the first 4 characters complies with internal security guidelines to avoid accidental disclosure.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a39b6d8 and 9598765.

📒 Files selected for processing (1)
  • cmd/ctrlc/root/sync/aws/ec2/ec2.go (1 hunks)

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
@jsbroks jsbroks merged commit c9daebd into main Apr 17, 2025
1 of 2 checks passed
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.

1 participant