Skip to content

Conversation

aknysh
Copy link
Member

@aknysh aknysh commented Apr 23, 2025

what

  • Add atmos terraform generate planfile command
  • Add unit tests
  • Update docs

why

Use the atmos terraform generate planfile command to generate a planfile for an Atmos Terraform/OpenTofu component in a stack in JSON or YAML formats.

Usage

Execute the terraform generate planfile command like this:

atmos terraform generate planfile <component> -s <stack> [options]

This command generates a planfile for an Atmos terraform component in a stack.

Examples

atmos terraform generate planfile component1 -s plat-ue2-dev
atmos terraform generate planfile component1 -s plat-ue2-prod --format=json
atmos terraform generate planfile component1 -s plat-ue2-prod --format=yaml
atmos terraform generate planfile <component> -s <stack> --file=planfile.json
atmos terraform generate planfile <component> -s <stack> --format=yaml --file=planfiles/planfile.yaml
atmos terraform generate planfile <component> -s <stack> --file=/Users/me/Documents/atmos/infra/planfile.json

Validate Terraform/OpenTofu planfiles using Checkov

You can generate a planfile for a component in a stack and validate it using Checkov.

atmos terraform generate planfile <component> -s <stack>
checkov --file components/terraform/<component>/<stack>-<component>.planfile.json --framework terraform_plan

Refer to Evaluate Checkov Policies on Terraform Plan for more information.

Summary by CodeRabbit

  • New Features
    • Introduced a new CLI command to generate Terraform planfiles for specified components, supporting JSON and YAML output formats.
  • Documentation
    • Added comprehensive documentation for the new planfile generation command, including usage instructions, examples, and validation guidance.
    • Updated examples and integration docs to reflect the latest CLI version and improved template usage in documentation.
  • Bug Fixes
    • Improved quoting in template functions and documentation examples to ensure correct string rendering in JSON outputs.
  • Tests
    • Added extensive tests for the new planfile generation feature, covering standard operation and error scenarios.
  • Chores
    • Upgraded multiple dependencies and bumped the CLI version to 1.172.0.
    • Enhanced style consistency in code comments.

@aknysh aknysh added the minor New features that do not break anything label Apr 23, 2025
@aknysh aknysh self-assigned this Apr 23, 2025
@aknysh aknysh requested review from a team as code owners April 23, 2025 14:39
coderabbitai[bot]
coderabbitai bot previously approved these changes Apr 23, 2025
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: 1

♻️ Duplicate comments (1)
internal/exec/terraform_generate_planfile.go (1)

200-200: Inconsistent error wrapping format usage.

This line uses string literal "%w: %w" directly, while elsewhere the code uses the ErrWrappingFormat constant (lines 124, 143, 190).

Update this line to use the constant for consistency:

-		return fmt.Errorf("%w: %w", ErrConvertingJsonToGoType, err)
+		return fmt.Errorf(ErrWrappingFormat, ErrConvertingJsonToGoType, err)
🧹 Nitpick comments (1)
internal/exec/terraform_generate_planfile.go (1)

95-161: Function slightly exceeds maximum line limit - consider further extraction.

The ExecuteTerraformGeneratePlanfile function is 61 lines, which exceeds the maximum of 60 lines identified by the static analyzer. This function has already been improved by extracting helper methods, but could be further streamlined.

Consider extracting the temporary directory creation and cleanup into a helper function:

+// createTempDirectory creates a temporary directory and returns a cleanup function.
+func createTempDirectory() (string, func(), error) {
+    tmpDir, err := os.MkdirTemp("", "atmos-terraform-generate-planfile")
+    if err != nil {
+        return "", nil, fmt.Errorf(ErrWrappingFormat, ErrCreatingTempDirectory, err)
+    }
+
+    cleanup := func() {
+        err = os.RemoveAll(tmpDir)
+        if err != nil {
+            log.Warn("Error removing temporary directory", "path", tmpDir, "error", err)
+        }
+    }
+
+    return tmpDir, cleanup, nil
+}

 func ExecuteTerraformGeneratePlanfile(
     options *PlanfileOptions,
     info *schema.ConfigAndStacksInfo,
 ) error {
     // Existing code...
     
-    // Create a temporary directory for all temporary files.
-    tmpDir, err := os.MkdirTemp("", "atmos-terraform-generate-planfile")
-    if err != nil {
-        return fmt.Errorf(ErrWrappingFormat, ErrCreatingTempDirectory, err)
-    }
-
-    defer func(path string) {
-        err = os.RemoveAll(path)
-        if err != nil {
-            log.Warn("Error removing temporary directory", "path", path, "error", err)
-        }
-    }(tmpDir)
+    // Create a temporary directory for all temporary files.
+    tmpDir, cleanup, err := createTempDirectory()
+    if err != nil {
+        return err
+    }
+    defer cleanup()
     
     // Remaining code...
🧰 Tools
🪛 GitHub Check: golangci-lint

[failure] 96-96:
function-length: maximum number of lines per function exceeded; max 60 but got 61

📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between bae90ed and 8b04c90.

📒 Files selected for processing (1)
  • internal/exec/terraform_generate_planfile.go (1 hunks)
🧰 Additional context used
🪛 GitHub Check: golangci-lint
internal/exec/terraform_generate_planfile.go

[failure] 96-96:
function-length: maximum number of lines per function exceeded; max 60 but got 61

⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: Build (windows-latest, windows)
  • GitHub Check: Summary
🔇 Additional comments (5)
internal/exec/terraform_generate_planfile.go (5)

17-24: Well-organized error definitions with clear naming.

The error variables are defined with descriptive names, making them easily identifiable and useful for error handling throughout the code.


26-35: Good structure design for PlanfileOptions.

Using a dedicated struct to encapsulate the various options is a clean approach that addresses the previous issue of having too many function parameters.


39-41: Proper validation for required component argument.

This validation correctly prevents potential nil pointer dereference when no component is specified.


163-173: Well-implemented format validation with sensible defaults.

The validation function properly sets a default format when none is provided and validates against supported formats, which is good defensive programming.


127-132: Effective cleanup of temporary resources.

The deferred function ensures temporary directories are cleaned up after use, with appropriate logging of any cleanup errors.

coderabbitai[bot]
coderabbitai bot previously approved these changes Apr 23, 2025
@aknysh aknysh requested a review from osterman April 23, 2025 18:29
…e.mdx

Co-authored-by: Erik Osterman (CEO @ Cloud Posse) <erik@cloudposse.com>
coderabbitai[bot]
coderabbitai bot previously approved these changes Apr 23, 2025
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 (1)
internal/exec/terraform_generate_planfile.go (1)

212-212: Use the defined error format constant for consistency

The error wrapping format string is used directly here, while other locations use the ErrWrappingFormat constant.

-		return fmt.Errorf("%w: %w", ErrConvertingJsonToGoType, err)
+		return fmt.Errorf(ErrWrappingFormat, ErrConvertingJsonToGoType, err)
📜 Review details

Configuration used: .coderabbit.yaml
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d4e5f53 and 90c81a9.

📒 Files selected for processing (3)
  • internal/exec/terraform_generate_planfile.go (1 hunks)
  • internal/exec/terraform_generate_planfile_test.go (1 hunks)
  • tests/fixtures/scenarios/terraform-generate-planfile/atmos.yaml (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • tests/fixtures/scenarios/terraform-generate-planfile/atmos.yaml
  • internal/exec/terraform_generate_planfile_test.go
⏰ Context from checks skipped due to timeout of 90000ms (2)
  • GitHub Check: Build (windows-latest, windows)
  • GitHub Check: Summary
🔇 Additional comments (6)
internal/exec/terraform_generate_planfile.go (6)

17-24: Errors are appropriately defined

Good job defining comprehensive error variables to clarify different types of errors that might occur during execution. This improves error handling and makes debugging easier.


26-35: Well-designed options structure

The PlanfileOptions struct provides a clean way to group related parameters, solving the "too many arguments" issue identified in previous reviews. This pattern improves maintainability and readability.


37-93: Command execution function looks solid

The function thoroughly validates inputs, properly extracts flags, and safely passes pointers to the execution function. The early check for empty arguments at line 39 prevents panic conditions.


95-165: Core execution function is well-structured

The function has been nicely refactored into smaller, focused helper functions that follow the single responsibility principle. The temporary directory is properly managed with deferred cleanup.


125-136: Good resource management

Properly creating and cleaning up the temporary directory with a deferred function call. The warning log on cleanup failure is a thoughtful addition.


167-223: Helper functions are well-designed

Breaking the functionality into smaller, focused helper functions improves readability and testability. Each function has a clear purpose and appropriate error handling.

@aknysh aknysh requested a review from osterman April 24, 2025 00:01
@aknysh aknysh merged commit b4203b6 into main Apr 24, 2025
51 checks passed
@aknysh aknysh deleted the terraform-generate-planfile branch April 24, 2025 00:18
@mergify mergify bot removed the needs-cloudposse Needs Cloud Posse assistance label Apr 24, 2025
@cfsb-jrose
Copy link

Hello! I am currently testing this new functionality and finding that it's hanging.

Initializing the backend...

Successfully configured the backend "s3"! Terraform will automatically
use this backend unless the backend configuration changes.
Initializing provider plugins...
- Reusing previous version of hashicorp/aws from the dependency lock file
- Using previously-installed hashicorp/aws v5.96.0

Terraform has been successfully initialized!

Not quite sure how to debug or troubleshoot further. Suggestions?

@osterman
Copy link
Member

@cfsb-jrose can you re-run the command with --log-level=Debug? Can you include the complete command as well?

@cfsb-jrose
Copy link

@osterman sure! I'll add to #1223

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
minor New features that do not break anything
Projects
None yet
Development

Successfully merging this pull request may close these issues.

atmos terraform generate plan should create JSON file
3 participants