mirror of
https://github.com/coder/coder.git
synced 2025-07-12 00:14:10 +00:00
* feat: Create provisioner abstraction Creates a provisioner abstraction that takes prior art from the Terraform plugin system. It's safe to assume this code will change a lot when it becomes integrated with provisionerd. Closes #10. * Ignore generated files in diff view * Check for unstaged file changes * Install protoc-gen-go * Use proper drpc plugin version * Fix serve closed pipe * Install sqlc with curl for speed * Fix install command * Format CI action * Add linguist-generated and closed pipe test * Cleanup code from comments * Add dRPC comment * Add Terraform installer for cross-platform * Build provisioner tests on Linux only
71 lines
2.1 KiB
Go
71 lines
2.1 KiB
Go
package terraform
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
|
|
"github.com/coder/coder/provisionersdk/proto"
|
|
"github.com/hashicorp/terraform-exec/tfexec"
|
|
"golang.org/x/xerrors"
|
|
)
|
|
|
|
// Provision executes `terraform apply`.
|
|
func (t *terraform) Provision(ctx context.Context, request *proto.Provision_Request) (*proto.Provision_Response, error) {
|
|
statefilePath := filepath.Join(request.Directory, "terraform.tfstate")
|
|
err := os.WriteFile(statefilePath, request.State, 0644)
|
|
if err != nil {
|
|
return nil, xerrors.Errorf("write statefile %q: %w", err)
|
|
}
|
|
|
|
terraform, err := tfexec.NewTerraform(request.Directory, t.binaryPath)
|
|
if err != nil {
|
|
return nil, xerrors.Errorf("create new terraform executor: %w", err)
|
|
}
|
|
version, _, err := terraform.Version(ctx, false)
|
|
if err != nil {
|
|
return nil, xerrors.Errorf("get terraform version: %w", err)
|
|
}
|
|
if !version.GreaterThanOrEqual(minimumTerraformVersion) {
|
|
return nil, xerrors.Errorf("terraform version %q is too old. required >= %q", version.String(), minimumTerraformVersion.String())
|
|
}
|
|
|
|
err = terraform.Init(ctx)
|
|
if err != nil {
|
|
return nil, xerrors.Errorf("initialize terraform: %w", err)
|
|
}
|
|
|
|
options := make([]tfexec.ApplyOption, 0)
|
|
for _, params := range request.ParameterValues {
|
|
options = append(options, tfexec.Var(fmt.Sprintf("%s=%s", params.Name, params.Value)))
|
|
}
|
|
err = terraform.Apply(ctx, options...)
|
|
if err != nil {
|
|
return nil, xerrors.Errorf("apply terraform: %w", err)
|
|
}
|
|
|
|
statefileContent, err := os.ReadFile(statefilePath)
|
|
if err != nil {
|
|
return nil, xerrors.Errorf("read file %q: %w", statefilePath, err)
|
|
}
|
|
state, err := terraform.ShowStateFile(ctx, statefilePath)
|
|
if err != nil {
|
|
return nil, xerrors.Errorf("show state file %q: %w", statefilePath, err)
|
|
}
|
|
resources := make([]*proto.Resource, 0)
|
|
if state.Values != nil {
|
|
for _, resource := range state.Values.RootModule.Resources {
|
|
resources = append(resources, &proto.Resource{
|
|
Name: resource.Name,
|
|
Type: resource.Type,
|
|
})
|
|
}
|
|
}
|
|
|
|
return &proto.Provision_Response{
|
|
Resources: resources,
|
|
State: statefileContent,
|
|
}, nil
|
|
}
|