Terraform integration

オープン
#2,424 コメント 0 件 リアクション 0 件 担当者 0 名 GitHub で見る

メンテナーはふだん 1 日以内に返信

まだ誰も着手していません。

評価

難易度
5/5
見積もり時間
1週間以上
初心者へのやさしさ
35/100
issue の種類
機能追加
明瞭さ
明確に書かれている
活発さ
活発
技術スタック
csharp
領域
devtools

調査の方向性

The issue describes a new Terraform hosting integration with environment and CLI resource types, configuration helpers, and deployment pipeline steps, but names no source files or tests. Start by locating the hosting integrations and their pipeline step patterns, then read the targeted Aspire version’s ATS exports and adapters. Done means implementing and validating the described resources, helpers, execution behavior, and pipeline support across the listed scenarios.

索引モデルが issue の本文から書いたものです。

説明

integration request :mailbox_with_mail:
Aspire issue link

No response

Overview

Applications often need Terraform-managed configuration or infrastructure alongside their Aspire resources: identity provider configuration, external services, or infrastructure required before deployment.

Today, integrating an existing Terraform module requires manually composing executable resources, propagating input variables and backend settings, ordering commands, and implementing deployment pipeline steps. The local development workflow and CI deployment workflow can easily diverge, particularly when applying a previously reviewed plan.

There is no dedicated Terraform hosting resource that:

  • Models a module with shared variables, backend configuration, and workspace selection
  • Executes Terraform commands as observable Aspire resources with completion dependencies
  • Uses Aspire parameters and reference expressions as Terraform inputs
  • Exposes init, plan, apply, and destroy as Aspire deployment pipeline steps
  • Applies the same saved plan across separate planning and approval stages

A CommunityToolkit.Aspire.Hosting.Terraform integration with the following resource types:

Resource Type Description
TerraformEnvironmentResource Resource Logical Terraform module with shared configuration and declared operations; starts no process
TerraformCliResource ExecutableResource Runs one Terraform command from a configured module directory

AddTerraformEnvironment creates the logical module. WithInit, WithPlan, WithApply, and WithDestroy declare its operations, creating child TerraformCliResource instances through AddTerraformCli and registering corresponding pipeline steps.

AddTerraformCli is also available directly for standalone commands and explicitly composed workflows.

Usage example
Terraform environment
var serviceUrl = builder.AddParameter("service-url");
var serviceToken = builder.AddParameter("service-token", secret: true);

var infrastructure = builder.AddTerraformEnvironment("infrastructure", "./terraform")
    .WithTfVar("service_url", serviceUrl)
    .WithTfVar("service_token", serviceToken)
    .WithTfVarsFile("./configuration/production.tfvars")
    .WithBackendConfigFile("./configuration/backend.hcl")
    .WithWorkspace("production")
    .WithInit()
    .WithPlan(outputPath: "./artifacts/infrastructure.tfplan")
    .WithApply(apply => apply.WithExplicitStart())
    .WithDestroy();

Each operation accepts a callback receiving its IResourceBuilder<TerraformCliResource>:

infrastructure.WithPlan(configure: plan => plan
    .WithArgs("-lock-timeout=60s")
    .WithTfVar("validation_mode", "strict"));

Additional arguments and operation-specific environment values are used by both the local resource and its pipeline step. Repeating an operation declaration reuses its existing resource.

Standalone CLI resources
var init = builder.AddTerraformCli("module-init", "./terraform")
    .WithBackendConfigFile("./configuration/backend.hcl")
    .WithInit();

var plan = builder.AddTerraformCli("module-plan", "./terraform")
    .WithTfVar("service_token", serviceToken)
    .WithPlan("-out=review.tfplan")
    .WaitForCompletion(init);

builder.AddTerraformCli("module-apply", "./terraform")
    .WithApply(args: ["review.tfplan"])
    .WaitForCompletion(plan)
    .WithExplicitStart();

builder.AddTerraformCli("module-validate", "./terraform")
    .WithArgs("validate", "-no-color")
    .WaitForCompletion(init);

Standalone operation helpers select the command on the existing resource. They do not create sibling resources, infer dependencies, or register Terraform pipeline steps.

WithApply(bool autoApprove = false, params string[] args) and WithDestroy(bool autoApprove = false, bool explicitStart = true, params string[] args) support explicitly requested auto-approval. WithExplicitStart controls process startup, not Terraform's interactive approval prompt.

Variables and state backend

Configuration helpers target ITerraformConfigurableResource, implemented by both resource types:

var stateConnection = builder.AddParameter("terraform-state-connection", secret: true);
var stateSchema = builder.AddParameter("terraform-state-schema");

infrastructure
    .WithPostgresBackend(ReferenceExpression.Create($"{stateConnection}"))
    .WithBackendConfig("schema_name", stateSchema)
    .WithTfVar("service_url", serviceUrl)
    .WithTfVar("service_token", serviceToken)
    .WithTfVar("deployment_name", "production");
  • WithTfVar accepts strings, parameter builders, and Aspire values implementing IValueProvider and IManifestExpressionProvider, including endpoint references and reference expressions. It sets TF_VAR_<name>.
  • WithTfVarsFile(path) adds a variable file for plan, apply without a saved plan, and destroy. Multiple calls accumulate in call order.
  • WithBackendConfig(key, value) accepts strings, parameters, or reference expressions; WithBackendConfigFile(path) supplies a backend configuration file. Both apply only to init.
  • WithPostgresBackend(connectionString, schema: null) sets PG_CONN_STR and optionally PG_SCHEMA_NAME. The module must already declare backend "pg" {}.
  • Other backends and provider credential chains use backend configuration and standard WithEnvironment calls.
Deployment pipeline

Every declared environment operation registers a pipeline step:

Declaration Local child resource Pipeline step
WithInit() <name>-init terraform-init-<name>
WithPlan() <name>-plan terraform-plan-<name>
WithApply() <name>-apply terraform-apply-<name>
WithDestroy() <name>-destroy terraform-destroy-<name>

Pipeline attachment and chaining are configurable:

infrastructure.WithPipelineOptions(options =>
{
    options.ChainSteps = false;
    options.RequiredByDeploy = true;
    options.RequiredByDestroy = true;
});

These are the defaults. Operation steps are independent unless ChainSteps is enabled; declared apply and destroy steps participate in aspire deploy and aspire destroy, respectively.

A CI workflow with a separate approval stage can:

  1. Run aspire do terraform-init-infrastructure, then aspire do terraform-plan-infrastructure.
  2. Publish the saved plan as a restricted-access artifact and obtain approval.
  3. Restore the module, provider lock file, and saved plan at the configured path on the apply runner.
  4. Run init on that runner, then aspire deploy or aspire do terraform-apply-infrastructure.

With ChainSteps = true, plan depends on init, apply on plan (or init without a declared plan), and destroy on init. Applying with chaining creates a fresh plan rather than consuming only the previously approved artifact.

Additional context
  • CLI resources as the execution primitive - the environment creates actual TerraformCliResource children. Their command, arguments, and environment configuration are also the source for pipeline execution, avoiding separate configuration paths.
  • Shared configuration evaluated at execution time - environment settings apply to all declared operations regardless of configuration order. Operation-specific environment values override shared values; parameters and expressions resolve when the command executes.
  • Local completion dependencies - plan waits for declared init; apply waits for declared plan, or init without a plan; destroy waits for declared init. These local dependencies are separate from optional pipeline chaining.
  • Saved-plan apply - environment WithPlan saves a binary plan, defaulting to <module>/<name>.tfplan. Environment apply consumes that exact artifact and fails if it is missing; it never silently replans. Variable-file arguments are omitted for saved-plan apply, while unrelated apply settings are preserved. Terraform rejects stale plans.
  • Explicit destructive behavior - environment apply starts automatically after its prerequisites unless configured with WithExplicitStart; without a declared plan it uses -auto-approve. Environment destroy uses -auto-approve but always requires explicit local start. No destroy runs on AppHost shutdown.
  • Pipeline invocation is explicit execution, not dashboard startup - local WithExplicitStart is not a CI approval gate. A declared operation can still execute through its pipeline step or enabled deploy/destroy hook. With default independent steps, CI must initialize the runner and supply the saved plan before invoking apply.
  • Automation and failures - pipeline execution uses -input=false, -no-color, TF_INPUT=false, and TF_IN_AUTOMATION=true. Plan additionally uses -detailed-exitcode, treating 0 and 2 as success. Other nonzero exit codes fail the step; output is reported and cancellation terminates the process tree.
  • AppHost-relative paths - module directories, configuration files, and explicit environment plan paths resolve relative to the AppHost directory. Absolute paths are supported. The plan output directory is created before planning.
  • Local tooling - Terraform must be installed on the AppHost or pipeline runner. WithTerraformExecutablePath selects the environment executable and propagates it to every operation; standalone resources use standard WithCommand.
  • Execution-only resources - the environment and generated CLI children are excluded from deployment manifests. Deployment runs Terraform on the pipeline runner, not as a published application service. Local endpoints are not automatically translated into production endpoints.
  • State and credential ownership - existing modules, workspaces, backends, and provider authentication remain under Terraform's control. The integration does not generate HCL, install Terraform, migrate state, or provision backend storage. State and plan artifacts can contain secrets; backend configuration may be persisted in .terraform. Concurrent operations require isolated working copies and backend state locking.
  • Polyglot AppHosts - compatible resources and methods are exported through Aspire ATS, with adapters for variable unions and optional settings. Operation callbacks and pipeline option exports must be validated against the targeted Aspire version.
Help us help you

Yes, I'd like to be assigned to work on this item

主要言語
C#
スター
632
フォーク
204
平均マージ
2日 18時間
マージ済み PR(30日)
99

環境構築

Codespaces で開く

このプロジェクトの開発コンテナを、あなたの GitHub アカウントでブラウザ上に起動します。

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

CommunityToolkit/Aspire のほかの issue

CommunityToolkit/Aspire の issue をすべて見る

似ている issue

C# の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。