Today I’m going to show you how to manage Terraform Cloud with .NET Core using the Tfe.NetClient library.

The idea is to create a simple console application that will:

  • Add GitHub as a VCS Provider.
  • Create a Workspace conected to a GitHub repo where your Terraform files live.
  • Create a variable in the workspace.
  • Create a Run (Plan) based on the Terraform files
  • Apply the Run.

Tfe.NetClient is still in alpha and not every Terraform Cloud API or feature is present. Please feel free to submit any issues, bugs or pull requests.

Prerequisites

Create a folder for your new project


Open a command prompt an run:

1mkdir TerraformCloud

Create the project


1cd TerraformCloud
2dotnet new console

Add a reference to Tfe.NetClient


1dotnet add package Tfe.NetClient -v 0.1.0
2dotnet restore

Replace the contents of Program.cs with the following code


  1namespace TerraformCloud
  2{
  3    using System;
  4    using System.Net.Http;
  5    using System.Threading.Tasks;
  6    using Tfe.NetClient;
  7    using Tfe.NetClient.OAuthClients;
  8    using Tfe.NetClient.Runs;
  9    using Tfe.NetClient.Workspaces;
 10    using Tfe.NetClient.WorkspaceVariables;
 11
 12    class Program
 13    {
 14        static async Task Main(string[] args)
 15        {
 16            // The values of this variables are hardcoded here just for simplicity and should be retrieved from configuration.
 17            var organizationName = "<organizationName>";
 18            var organizationToken = "<organizationToken>";
 19            var teamToken = "<teamToken>";
 20            var gitHubToken = "<GitHub Personal Access Token>";
 21            var gitHubRepo = "<github user or organization name>/<repo name>"; // i.e. cmendible/terraform-hello-world
 22
 23            // Create an HttpClient
 24            var httpClient = new HttpClient();
 25
 26            // Create the Configiration used by the TFE client.
 27            // For management tasks you'll need to connect to Terraform Cloud using an Organization Token.
 28            var config = new TfeConfig(organizationToken, httpClient);
 29
 30            // Create the TFE client.
 31            var client = new TfeClient(config);
 32
 33            // Connect Terraform Cloud and GitHub adding GitHub as a VCS Provider.
 34            var oauthClientsRequest = new OAuthClientsRequest();
 35            oauthClientsRequest.Data.Attributes.ServiceProvider = "github";
 36            oauthClientsRequest.Data.Attributes.HttpUrl = new Uri("https://github.com");
 37            oauthClientsRequest.Data.Attributes.ApiUrl = new Uri("https://api.github.com");
 38            oauthClientsRequest.Data.Attributes.OAuthTokenString = gitHubToken; // Use the GitHub Personal Access Token
 39            var oauthResult = await client.OAuthClient.CreateAsync(organizationName, oauthClientsRequest);
 40
 41            // Get the OAuthToken.
 42            var oauthTokenId = oauthResult.Data.Relationships.OAuthTokens.Data[0].Id;
 43
 44            // Create a Workspace connected to a GitHub repo.
 45            var workspacesRequest = new WorkspacesRequest();
 46            workspacesRequest.Data.Attributes.Name = "my-workspace";
 47            workspacesRequest.Data.Attributes.VcsRepo = new RequestVcsRepo();
 48            workspacesRequest.Data.Attributes.VcsRepo.Identifier = gitHubRepo; // Use the GitHub Repo
 49            workspacesRequest.Data.Attributes.VcsRepo.OauthTokenId = oauthTokenId;
 50            workspacesRequest.Data.Attributes.VcsRepo.Branch = "";
 51            workspacesRequest.Data.Attributes.VcsRepo.DefaultBranch = true;
 52            var workspaceResult = await client.Workspace.CreateAsync(organizationName, workspacesRequest);
 53
 54            // Get the Workspace Id so we can add variales or request a plan or apply.
 55            var workspaceId = workspaceResult.Data.Id;
 56
 57            // Create a variable in the workspace.
 58            // You can make the values invible setting the Sensitive attribute to true.
 59            // If you want to se an environement variable change the Category attribute to "env".
 60            // You'll have to create as any variables your script needs.
 61            var workspaceVariablesRequest = new WorkspaceVariablesRequest();
 62            workspaceVariablesRequest.Data.Attributes.Key = "variable_1";
 63            workspaceVariablesRequest.Data.Attributes.Value = "variable_1_value";
 64            workspaceVariablesRequest.Data.Attributes.Description = "variable_1 description";
 65            workspaceVariablesRequest.Data.Attributes.Category = "terraform";
 66            workspaceVariablesRequest.Data.Attributes.Hcl = false;
 67            workspaceVariablesRequest.Data.Attributes.Sensitive = false;
 68            var variableResult = await client.WorkspaceVariable.CreateAsync(workspaceId, workspaceVariablesRequest);
 69
 70            // Get the workspace by name.
 71            var workspace = client.Workspace.ShowAsync(organizationName, "my-workspace");
 72
 73            // To create Runs and Apply thme you need to use a Team Token.
 74            // So create a new TfeClient.
 75            var runsClient = new TfeClient(new TfeConfig(teamToken, new HttpClient()));
 76
 77            // Create the Run.
 78            // This is th equivalent to running: terraform plan. 
 79            var runsRequest = new RunsRequest();
 80            runsRequest.Data.Attributes.IsDestroy = false;
 81            runsRequest.Data.Attributes.Message = "Triggered by .NET Core";
 82            runsRequest.Data.Relationships.Workspace.Data.Type = "workspaces";
 83            runsRequest.Data.Relationships.Workspace.Data.Id = workspace.Result.Data.Id;
 84            var runsResult = await runsClient.Run.CreateAsync(runsRequest);
 85
 86            // Get the Run Id. You'll need it to check teh state of the run and Apply it if possible.
 87            var runId = runsResult.Data.Id;
 88
 89            var ready = false;
 90            while (!ready)
 91            {
 92                // Wait for the Run to be planned .
 93                await Task.Delay(5000);
 94                var run = await client.Run.ShowAsync(runId);
 95                ready = run.Data.Attributes.Status == "planned";
 96
 97                // Throw an exception if the Run status is: errored.
 98                if (run.Data.Attributes.Status == "errored") {
 99                    throw new Exception("Plan failed...");
100                }
101            }
102
103            // If the Run is planned then Apply your configuration.
104            if (ready)
105            {
106                await runsClient.Run.ApplyAsync(runId, null);
107            }
108        }
109    }
110}

Tfe.NetClient is still in early stages of development and the resulting code is very verbose and prone to errors. We will address this in a future relases introducing the use of enums and perhaps a fluent API.

Run the program


Run the following command:

1dotnet run

Check the results


Log In to Terraform Cloud and check the status of the new workspace.

Hope it Helps!

Learn More

Hope it helps! and please find the complete code here