/TerraformPluginDotNet

Write Terraform providers in C#.

Primary LanguageC#MIT LicenseMIT

TerraformPluginDotNet

Build status

Write custom Terraform providers in C#. See the samples directory for an example provider.

For more information on this project, see this blog post.

Packages

Package Version
TerraformPluginDotNet NuGet
TerraformPluginDotNet.Testing NuGet

Features

Currently supports functionality for:

  • Provider configuration
  • Resources:
    • Create
    • Update
    • Delete
    • Import
    • Schema upgrade
  • Data sources

Usage

Defining Resources

To define a custom Terraform resource, create a class to represent the resource:

[SchemaVersion(1)]
[MessagePackObject]
public class MyResource
{
    [Key("id")]
    [Computed]
    [Description("Unique ID for this resource.")]
    [MessagePackFormatter(typeof(ComputedValueFormatter))]
    public string Id { get; set; }

    [Key("some_value")]
    [JsonPropertyName("some_value")]
    [Description("Some value in the resource.")]
    [Required]
    public string SomeValue { get; set; }
}

Please note:

  1. The class must be serializable as MessagePack.
  2. The class must be serializable by System.Text.Json.
    • Currently, JsonPropertyName must be specified to match multi-word property names as snake case.

Create an IResourceProvier<T> for the resource:

public class MyResourceProvider : IResourceProvider<MyResource>
{
    public Task<MyResource> PlanAsync(MyResource prior, MyResource proposed)
    {
        // Do something
    }

    ...
}

See the samples directory for a full example.

Usage In Terraform

This section explains how to use the samples/SampleProvider project with Terraform. To define your own provider and resource types, create your own project following the same structure as SampleProvider.

Instructions are for Linux x64 with Terraform v0.13.3. May work on other platforms and Terraform versions.

  1. In the samples/SampleProvider/SampleProvider directory, publish a self-contained single-file binary:
dotnet publish -r linux-x64 --self-contained -c release -p:PublishSingleFile=true
  1. Copy the binary built above, and serilog.json to your Terraform plugins directory:
# Create plugin directory
mkdir -p ~/.terraform.d/plugins/example.com/example/sampleprovider/1.0.0/linux_amd64/

# Copy binary
cp ./bin/release/net7.0/linux-x64/publish/SampleProvider ~/.terraform.d/plugins/example.com/example/sampleprovider/1.0.0/linux_amd64/terraform-provider-sampleprovider

# Copy log config
cp ./bin/release/net7.0/linux-x64/publish/serilog.json ~/.terraform.d/plugins/example.com/example/sampleprovider/1.0.0/linux_amd64/serilog.json
  1. Create a new Terraform project or open an existing one. The remaining commands are run in this directory.

  2. Add to versions.tf:

terraform {
  required_providers {
    sampleprovider = {
      source = "example.com/example/sampleprovider"
      version = "1.0.0"
    }
  }
}
  1. Add to providers.tf:
provider "sampleprovider" {}
  1. Define a resource in sample.tf
resource "sampleprovider_file" "demo_file" {
  path = "/tmp/file.txt"
  content = "this is a test"
}
  1. Initialize Terraform with the new plugin: terraform init
  2. Run terraform apply
  3. File at /tmp/file.txt should contain the contents this is a test

See log.txt in your working directory for troubleshooting.

Debugging

Terraform can attach to an already started provider by making use of debug mode, which allows debugging in Visual Studio. To do this, start the SampleProvider project with the --DebugMode=true argument. By default, this will also cause log messages to be written to the console in addition to a file.

Once started, it will output an environment variable that can be used to instruct Terraform to connect to this already running provider.

For more information, see Running Terraform With A Provider in Debug Mode.

Testing

Tests that involve running Terraform are marked with Category=Functional. To run these tests, you will need to have Terraform installed and set the environment variable TF_PLUGIN_DOTNET_TEST_TF_BIN.

For example:

$ TF_PLUGIN_DOTNET_TEST_TF_BIN=/usr/bin/terraform dotnet test --filter Category=Functional

In Visual Studio, you can create a test.runsettings file to do this:

<?xml version="1.0" encoding="utf-8"?>
<RunSettings>
  <RunConfiguration>
    <EnvironmentVariables>
      <TF_PLUGIN_DOTNET_TEST_TF_BIN>C:\Path\To\terraform.exe</TF_PLUGIN_DOTNET_TEST_TF_BIN>
    </EnvironmentVariables>
  </RunConfiguration>
</RunSettings>

The TerraformPluginDotNet.Testing package can be used to help with writing tests for custom providers. See samples/SampleProvider/SampleProvider.Test.