Skip to content

feat: allow plan persistence also for Azure environments through Azure storage accounts #1933

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
Apr 4, 2025

Conversation

wenzel-felix
Copy link
Contributor

@wenzel-felix wenzel-felix commented Apr 3, 2025

This PR implements the functionality of plan persistence for the Azure provider. Currently this is only supported for AWS and GCP.

It adds two new configuration options:

  • upload-plan-destination-azure-container
  • upload-plan-destination-azure-storage-account

Summary by CodeRabbit

  • New Features
    • Integrated Azure Blob Storage as an additional destination for managing plan files. Users can now choose Azure for uploading, retrieving, and deleting plans by providing the required container and storage account details.
  • Documentation
    • Updated user guides to include clear instructions on configuring and using Azure Blob Storage for plan outputs, including new input parameters.
  • Chores
    • Refined underlying integrations and updated dependencies to enhance Azure support.

Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

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

PR Summary

This PR adds Azure plan persistence functionality by integrating Azure Blob Storage support and updating configuration options and documentation accordingly.

  • Updated /action.yml to include new inputs: upload-plan-destination-azure-container and upload-plan-destination-azure-storage-account.
  • Modified documentation in /docs/ce/reference/action-inputs.mdx and /docs/ce/howto/store-plans-in-a-bucket.mdx; note naming mismatch (uses "azure-bucket" in docs).
  • Extended /libs/storage/plan_storage.go to include Azure support and added /libs/storage/azure_plan_storage.go with azblob integration.
  • Updated Go module dependencies in /libs/go.mod and /go.work.sum for Azure SDK compatibility.

💡 (1/5) You can manually trigger the bot by mentioning @greptileai in a comment!

7 file(s) reviewed, 1 comment(s)
Edit PR Review Bot Settings | Greptile

Co-authored-by: greptile-apps[bot] <165735046+greptile-apps[bot]@users.noreply.github.com>
Copy link
Contributor

coderabbitai bot commented Apr 3, 2025

Walkthrough

The changes integrate Azure Blob Storage as an additional destination for uploading Terraform plan outputs. The modifications update configuration inputs in the action, enhance documentation to include Azure-specific instructions, and adjust dependency versions to support Azure SDK features. New code files provide methods to interact with Azure Blob Storage for plan existence checks, uploads, retrievals, and deletions. Additionally, the plan storage logic now retrieves the necessary Azure configuration from the environment and establishes connections with Azure services.

Changes

File(s) Change Summary
action.yml Updated input parameters: added upload-plan-destination-azure-container and upload-plan-destination-azure-storage-account; modified upload-plan-destination description to include "azure"; and added Azure-related environment variable mappings.
docs/ce/howto/store-plans-in-a-bucket.mdx, docs/ce/reference/action-inputs.mdx Documentation enhanced to include instructions for configuring Azure Blob Storage; added details for new inputs specific to Azure.
libs/go.mod Upgraded Azure SDK dependencies (e.g., azidentity, azcore), added the azblob dependency, updated other dependencies, and removed an obsolete dependency.
libs/storage/azure_plan_storage.go, libs/storage/plan_storage.go Introduced Azure Blob Storage implementation via a new PlanStorageAzure struct and its methods; extended the storage logic to handle Azure-specific configuration, credentialing, and client initialization.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant PS as PlanStorage (NewPlanStorage)
    participant Env as Environment
    participant AZCred as Azure SDK (azidentity)
    participant AZClient as Azure SDK (azblob)
    
    User->>PS: Request new storage instance ("azure")
    PS->>Env: Retrieve container & account environment variables
    PS->>AZCred: Create default Azure credentials
    AZCred-->>PS: Return credentials
    PS->>AZClient: Initialize Azure Blob client with account & credentials
    AZClient-->>PS: Return blob client
    PS->>PS: Instantiate PlanStorageAzure with client & container
    PS-->>User: Return PlanStorageAzure instance
Loading

Suggested reviewers

  • UtpalJayNadiger

Poem

I’m hopping through code with joyful flair,
Azure’s now in the mix—beyond compare!
Plans zoom to blob storage in the digital sky,
Each change a carrot, oh my, oh my!
With a twitch of my nose and a skip in my day,
I celebrate new features in my rabbit way!
🥕🐇

✨ Finishing Touches
  • 📝 Generate Docstrings

🪧 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 plan to trigger planning for file edits and PR creation.
  • @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.

@wenzel-felix
Copy link
Contributor Author

The feature is also part of the following issue: #1291

And help out with folks using Azure who are currently unable to use the GitHub artifacts. #1702

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)
libs/storage/plan_storage.go (1)

396-429: Azure storage implementation follows consistent patterns.

The Azure storage implementation correctly follows the same patterns as the existing providers:

  1. Validates required parameters are present
  2. Sets up authentication credentials
  3. Creates the client connection
  4. Initializes the appropriate storage implementation

The implementation properly handles error conditions with clear error messages and logging.

However, there's a minor naming convention issue:

- sa_name := strings.ToLower(os.Getenv("PLAN_UPLOAD_AZURE_STORAGE_ACCOUNT_NAME"))
+ accountName := strings.ToLower(os.Getenv("PLAN_UPLOAD_AZURE_STORAGE_ACCOUNT_NAME"))

Consider using camelCase for variable names to be consistent with Go conventions and the rest of the codebase.

libs/storage/azure_plan_storage.go (4)

19-44: Fix context inconsistency in PlanExists method

The method uses context.TODO() instead of the context from the struct (psa.Context). For consistency with other methods, you should use the struct's context.

- resp, err := blobClient.GetProperties(context.TODO(), nil)
+ resp, err := blobClient.GetProperties(psa.Context, nil)

1-147: Consider adding retry logic for cloud operations

Cloud operations can be prone to transient failures. Consider implementing retry logic for Azure Blob Storage operations to improve reliability.

You could use the Azure SDK's built-in retry policy or implement a simple exponential backoff:

// Example of how to configure retry options with Azure SDK
client, err := azblob.NewClientWithSharedKeyCredential(serviceURL, credential, &azblob.ClientOptions{
    Retry: azcore.RetryOptions{
        MaxRetries:    3,
        RetryDelay:    2 * time.Second,
        MaxRetryDelay: 10 * time.Second,
    },
})

75-119: Consider validating the file path before creating the local file

It would be beneficial to validate that the local file path directory exists or create it if it doesn't before attempting to create the file.

+ // Ensure the directory exists
+ dir := filepath.Dir(localPlanFilePath)
+ if err := os.MkdirAll(dir, 0755); err != nil {
+     slog.Error("Unable to create directory for local file",
+         "directory", dir,
+         "error", err)
+     return nil, fmt.Errorf("unable to create directory: %w", err)
+ }

localFile, err := os.Create(localPlanFilePath)

46-73: Enhance error messages with error wrapping

Use %w format verb with fmt.Errorf to preserve the original error for better error handling up the call stack.

Example for improvement:

- return nil, fmt.Errorf("unable to read data from blob: %v", err)
+ return nil, fmt.Errorf("unable to read data from blob: %w", err)

Also applies to: 75-119, 121-146

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 96c9822 and 1e1ef47.

⛔ Files ignored due to path filters (2)
  • go.work.sum is excluded by !**/*.sum
  • libs/go.sum is excluded by !**/*.sum
📒 Files selected for processing (6)
  • action.yml (4 hunks)
  • docs/ce/howto/store-plans-in-a-bucket.mdx (1 hunks)
  • docs/ce/reference/action-inputs.mdx (1 hunks)
  • libs/go.mod (4 hunks)
  • libs/storage/azure_plan_storage.go (1 hunks)
  • libs/storage/plan_storage.go (2 hunks)
🧰 Additional context used
🧬 Code Definitions (1)
libs/storage/plan_storage.go (1)
libs/storage/azure_plan_storage.go (1)
  • PlanStorageAzure (13-17)
🔇 Additional comments (16)
docs/ce/howto/store-plans-in-a-bucket.mdx (1)

34-44: Good addition of Azure storage documentation.

The Azure section follows the same format as the other cloud providers and provides clear instructions for users to configure plan persistence with Azure storage accounts. The parameters are correctly specified according to the changes in action.yml and align with the PR objectives to enable plan persistence for Azure environments.

docs/ce/reference/action-inputs.mdx (2)

87-87: Updated description to include Azure as a supported destination.

The description now accurately reflects the addition of Azure as a supported destination for plan uploads.


92-97: Azure storage parameters documented consistently.

The new Azure parameters are appropriately defined with clear descriptions that instruct users when these parameters should be provided. The documentation follows the same pattern as existing parameters for other cloud providers.

action.yml (4)

98-98: Updated description to include Azure as a supported destination.

The description now correctly includes Azure in the list of supported destinations for plan uploads.


114-119: Azure storage parameters correctly defined.

The new input parameters for Azure blob storage are well defined with appropriate descriptions. The parameters follow the naming convention used for other cloud providers.


391-392: Environment variables for Azure correctly mapped.

The Azure storage container name and account name from inputs are properly mapped to environment variables that will be used by the implementation code.


434-435: Environment variables for Azure correctly mapped (for versioned action).

The Azure environment variables are properly mapped in both build and run digger sections, ensuring consistent behavior regardless of how the action is invoked.

libs/storage/plan_storage.go (1)

18-19: Azure SDK imports correctly added.

The required Azure SDK imports for blob storage and identity authentication are properly included to support the new Azure storage functionality.

libs/go.mod (4)

7-9: Dependencies properly updated for Azure Blob Storage integration

The changes appropriately add and update Azure SDK dependencies necessary for Azure Blob Storage support. The addition of github.com/Azure/azure-sdk-for-go/sdk/storage/azblob v1.6.0 is essential for the new Azure plan persistence functionality.


57-58: Azure SDK core dependencies properly updated

The Azure SDK core dependencies have been updated to compatible versions to support the new Azure Blob Storage functionality.


69-69: Microsoft Authentication Library correctly updated

The Microsoft Authentication Library has been properly updated to work with the latest Azure SDK versions.


37-37: Test library version update looks good

The update to the testify library is a minor version update and should not cause any compatibility issues.

libs/storage/azure_plan_storage.go (4)

13-17: Implementation of Azure storage structure looks good

The PlanStorageAzure struct properly includes the necessary components for Azure Blob Storage interaction: a service client, container name, and context.


46-73: StorePlanFile implementation is correct and efficient

The method correctly uses the Azure Blob SDK to upload the file contents as a buffer, with proper error handling and logging.


75-119: RetrievePlan method includes proper file handling

The implementation correctly creates a local file, downloads the blob content, handles errors appropriately, and cleans up resources with defer.


121-146: DeleteStoredPlan implementation is correct

The method properly handles the deletion of blobs with appropriate error handling and logging.

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: 2

🧹 Nitpick comments (4)
libs/storage/azure_plan_storage.go (4)

1-9: Consider streamlined import grouping and version pinning
It's good to see the Azure SDK imports, but if your organization enforces pinned versions, consider explicitly pinning them in your go.mod file to guard against breaking changes in newer releases.


46-73: Validate plan file name or path
To strengthen security and avoid path injection, consider validating or sanitizing fileName and artifactName before using them in upload operations, especially if they can be externally influenced.


75-119: Beware of partial downloads on large plan files
Using DownloadFile into an os.Create output can block if the file is very large or network conditions degrade. If plan files can be large, consider a streaming approach or chunked reads, plus handling partial downloads with retries or resumable transfers.


121-146: Deletion grace checks
Consider verifying whether a plan file exists prior to attempting DeleteStoredPlan to avoid confusion or potential false alarms in logs. Though your current code simply attempts deletion, you might provide more user-friendly messages if the file does not exist.

📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 1e1ef47 and 493dda5.

📒 Files selected for processing (2)
  • libs/storage/azure_plan_storage.go (1 hunks)
  • libs/storage/plan_storage.go (2 hunks)
🧰 Additional context used
🧬 Code Definitions (1)
libs/storage/plan_storage.go (1)
libs/storage/azure_plan_storage.go (1)
  • PlanStorageAzure (13-17)
🔇 Additional comments (2)
libs/storage/azure_plan_storage.go (1)

13-17: Struct usage is clear and well-defined
Storing the ServiceClient, ContainerName, and Context in a single struct is straightforward and fosters maintainability by consolidating Azure-related references.

libs/storage/plan_storage.go (1)

18-19: Imports for Azure SDK
Adding the Azure SDK aligns well with the new Azure plan storage feature. Confirm that your go.mod and CI pipelines reflect these dependencies so they remain stable over time.

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 (2)
libs/storage/azure_plan_storage.go (2)

55-82: Storage implementation looks good, minor style suggestions.

The implementation correctly uses the Azure Blob Storage API for uploading plan files. The logging is thorough and provides good context for debugging.

There's some extra whitespace at line 69 that could be removed for consistency.

	)
-	
	if err != nil {

84-128: Consider adding input validation for file paths.

The implementation correctly downloads a plan from Azure Blob Storage to a local file. However, consider adding validation for the input paths before attempting to create or access files.

func (psa *PlanStorageAzure) RetrievePlan(localPlanFilePath string, artifactName string, storedPlanFilePath string) (*string, error) {
+	if localPlanFilePath == "" || storedPlanFilePath == "" {
+		return nil, fmt.Errorf("local or stored plan file path cannot be empty")
+	}
+
	slog.Debug("Retrieving plan from Azure Blob Storage",
		"container", psa.ContainerName,
		"path", storedPlanFilePath,
		"artifactName", artifactName,
		"localPath", localPlanFilePath)
📜 Review details

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

📥 Commits

Reviewing files that changed from the base of the PR and between 493dda5 and 569049b.

📒 Files selected for processing (2)
  • libs/go.mod (4 hunks)
  • libs/storage/azure_plan_storage.go (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (1)
  • libs/go.mod
🔇 Additional comments (4)
libs/storage/azure_plan_storage.go (4)

1-13: The imports look appropriate for Azure Blob Storage operations.

The imports include all necessary Azure SDK packages and standard Go libraries required for the implementation. Good job including the specific Azure blob error package for more precise error handling.


15-19: Well-structured type declaration for Azure integration.

The PlanStorageAzure struct contains all the necessary fields for Azure Blob Storage operations: a service client for API interactions, a container name for targeting the correct storage location, and a context for operation management.


21-53: Consider using errors.As() for safer error type checking.

The current implementation uses type assertion (err.(*azcore.ResponseError)) which can panic if the error is not of the expected type. Consider using the safer errors.As() method instead.

if err != nil {
-	if azErr, ok := err.(*azcore.ResponseError); ok && string(azErr.ErrorCode) == string(bloberror.BlobNotFound) {
+	var azErr *azcore.ResponseError
+	if errors.As(err, &azErr) && string(azErr.ErrorCode) == string(bloberror.BlobNotFound) {
		slog.Debug("Blob not found",
			"container", psa.ContainerName,
			"path", storedPlanFilePath,
			"artifactName", artifactName)
		return false, nil
	}

Also, don't forget to add the "errors" package to the imports.


130-155: Delete operation implementation is robust.

The delete method properly handles the deletion of a plan from Azure Blob Storage with adequate error handling and informative logging at each step. The error message provides clear context about what went wrong if the operation fails.

@wenzel-felix
Copy link
Contributor Author

@motatoes, could you look at this change?
I tested it and it is working just fine. Let me know if any adjustments are required.

@motatoes
Copy link
Contributor

motatoes commented Apr 4, 2025

Thanks @wenzel-felix ! Very valuable contribution 💙

@motatoes motatoes merged commit 71aee64 into diggerhq:develop Apr 4, 2025
8 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.

2 participants