Skip to content

Commit

Permalink
Merge pull request getporter#7 from kichristensen/changeToTofu
Browse files Browse the repository at this point in the history
Change from terraform to tofu
  • Loading branch information
kichristensen authored Oct 1, 2024
2 parents ab6f7a7 + 7292454 commit f0b8c4f
Show file tree
Hide file tree
Showing 60 changed files with 289 additions and 314 deletions.
32 changes: 0 additions & 32 deletions .github/workflows/terraform-mixin.yml

This file was deleted.

32 changes: 32 additions & 0 deletions .github/workflows/tofu-mixin.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
name: porter/tofu-mixin
on:
push:
branches:
- main
- v*
pull_request:
branches:
- main
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-go@v5
with:
go-version-file: go.mod
cache: true
- name: Configure Agent
run: go run mage.go ConfigureAgent
- name: Test
run: mage Test
- name: Cross Compile
run: mage XBuildAll
# - name: Publish
# if: success() && github.event_name != 'PullRequest'
# env:
# GITHUB_TOKEN: "${{ secrets.PUBLISH_TOKEN }}"
# run: mage Publish
113 changes: 44 additions & 69 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,25 +1,23 @@
# Terraform Mixin for Porter
# OpenTofu Mixin for Porter

This is a Terraform mixin for [Porter](https://porter.sh).
This is a OpenTofu mixin for [Porter](https://porter.sh).

[![porter/terraform-mixin](https://github.com/getporter/terraform-mixin/actions/workflows/terraform-mixin.yml/badge.svg?branch=main)](https://github.com/getporter/terraform-mixin/actions/workflows/terraform-mixin.yml)

<img src="https://porter.sh/images/mixins/terraform.svg" align="right" width="150px"/>
[![porter/tofu-mixin](https://github.com/getporter/tofu-mixin/actions/workflows/tofu-mixin.yml/badge.svg?branch=main)](https://github.com/getporter/tofu-mixin/actions/workflows/tofu-mixin.yml)

## Install via Porter

This will install the latest mixin release via the Porter CLI.

```
porter mixin install terraform
porter mixin install tofu
```

## Build from source

Following commands build the terraform mixin.
Following commands build the OpenTofu mixin.
```bash
git clone https://github.com/getporter/terraform-mixin.git
cd terraform-mixin
git clone https://github.com/getporter/tofu-mixin.git
cd tofu-mixin
# Learn about Mage in our CONTRIBUTING.md
go run mage.go EnsureMage
mage build
Expand All @@ -32,95 +30,72 @@ Then, to install the resulting mixin into PORTER_HOME, execute

```yaml
mixins:
- terraform:
- tofu:
clientVersion: 1.0.3
workingDir: myinfra
initFile: providers.tf
```
### clientVersion
The Terraform client version can be specified via the `clientVersion` configuration when declaring this mixin.
The OpenTofu client version can be specified via the `clientVersion` configuration when declaring this mixin.

### workingDir
The `workingDir` configuration setting is the relative path to your terraform files. Defaults to "terraform".
The `workingDir` configuration setting is the relative path to your OpenTofu files. Defaults to "opentofu".

### initFile
Terraform providers are installed into the bundle during porter build.
We recommend that you put your provider declarations into a single file, e.g. "terraform/providers.tf".
OpenTofu providers are installed into the bundle during porter build.
We recommend that you put your provider declarations into a single file, e.g. "opentofu/providers.tf".
Then use `initFile` to specify the relative path to this file within workingDir.
This will dramatically improve Docker image layer caching and performance when building, publishing and installing the bundle.
> Note: this approach isn't suitable when using terraform modules as those need to be "initilized" as well but aren't specified in the `initFile`. You shouldn't specifiy an `initFile` in this situation.
> Note: this approach isn't suitable when using OpenTofu modules as those need to be "initilized" as well but aren't specified in the `initFile`. You shouldn't specifiy an `initFile` in this situation.

### User Agent Opt Out

When you declare the mixin, you can disable the mixin from customizing the azure user agent string

```yaml
mixins:
- terraform:
- tofu:
userAgentOptOut: true
```

By default, the terraform mixin adds the porter and mixin version to the user agent string used by the azure provider.
By default, the OpenTofu mixin adds the porter and mixin version to the user agent string used by the azure provider.
We use this to understand which version of porter and the mixin are being used by a bundle, and assist with troubleshooting.
Below is an example of what the user agent string looks like:

```
AZURE_HTTP_USER_AGENT="getporter/porter/v1.0.0 getporter/terraform/v1.2.3"
AZURE_HTTP_USER_AGENT="getporter/porter/v1.0.0 getporter/tofu/v1.2.3"
```

You can add your own custom strings to the user agent string by editing your [template Dockerfile] and setting the AZURE_HTTP_USER_AGENT environment variable.

[template Dockerfile]: https://getporter.org/bundle/custom-dockerfile/

## Terraform state
## OpenTofu state

### Let Porter do the heavy lifting

The simplest way to use this mixin with Porter is to let Porter track the Terraform [state](https://www.terraform.io/docs/state/index.html) as actions are executed. This can be done via a parameter of type `file` that has a source of a corresponding output (of the same `file` type). Each time the bundle is executed, the output will capture the updated state file and inject it into the next action via its parameter correlate.

Here is an example setup that works with Porter v0.38:

```yaml
parameters:
- name: tfstate
type: file
# This designates the path within the installer to place the parameter value
path: /cnab/app/terraform/terraform.tfstate
# Here we tell Porter that the value for this parameter should come from the 'tfstate' output
source:
output: tfstate
outputs:
- name: tfstate
type: file
# This designates the path within the installer to read the output from
path: /cnab/app/terraform/terraform.tfstate
```

If you are working with the Porter v1 prerelease, use the new state section:
The simplest way to use this mixin with Porter is to let Porter track the OpenTofu [state](https://opentofu.org/docs/language/state/) as actions are executed. This can be done through the state section. Each time the bundle is executed, the output will capture the updated state file and inject it into the next action.

```yaml
state:
- name: tfstate
path: terraform/terraform.tfstate
path: opentofu/opentofu.tfstate
- name: tfvars
path: terraform/terraform.tfvars.json
path: opentofu/opentofu.tfvars.json
```

The [TabbyCats Tracker bundle](https://github.com/carolynvs/tabbycat-demo) is a good example of how to use the terraform mixin with the Porter v1 prerelease.

The specified path inside the installer (`/cnab/app/terraform/terraform.tfstate`) should be where Terraform will be looking to read/write its state. For a full example bundle using this approach, see the [basic-tf-example](examples/basic-tf-example).
The specified path inside the installer (`/cnab/app/opentofu/opentofu.tfstate`) should be where OpenTofu will be looking to read/write its state. For a full example bundle using this approach, see the [basic-tofu-example](examples/basic-tofu-example).

### Remote Backends

Alternatively, state can be managed by a remote backend. When doing so, each action step needs to supply the remote backend config via `backendConfig`. In the step examples below, the configuration has key/value pairs according to the [Azurerm](https://www.terraform.io/docs/backends/types/azurerm.html) backend.
Alternatively, state can be managed by a remote backend. When doing so, each action step needs to supply the remote backend config via `backendConfig`. In the step examples below, the configuration has key/value pairs according to the [Azurerm](https://opentofu.org/docs/language/settings/backends/azurerm/) backend.


## Terraform variables file
## OpenTofu variables file

By default the mixin will create a default
[`terraform.tfvars.json`](https://www.terraform.io/docs/language/values/variables.html#variable-definitions-tfvars-files)
[`opentofu.tfvars.json`](https://opentofu.org/docs/language/values/variables/)
file from the `vars` block during during the install step.

To use this file, a `tfvars` file parameter and output must be added to persist it for subsequent steps.
Expand All @@ -134,7 +109,7 @@ parameters:
- name: tfvars
type: file
# This designates the path within the installer to place the parameter value
path: /cnab/app/terraform/terraform.tfvars.json
path: /cnab/app/opentofu/opentofu.tfvars.json
# Here we tell Porter that the value for this parameter should come from the 'tfvars' output
source:
output: tfvars
Expand All @@ -152,23 +127,23 @@ outputs:
- name: tfvars
type: file
# This designates the path within the installer to read the output from
path: /cnab/app/terraform/terraform.tfvars.json
path: /cnab/app/opentofu/opentofu.tfvars.json
install:
- terraform:
- tofu:
description: "Install Azure Key Vault"
vars:
foo: bar
baz: biz
outputs:
- name: vault_uri
upgrade: # No var block required
- terraform:
- tofu:
description: "Install Azure Key Vault"
outputs:
- name: vault_uri
uninstall: # No var block required
- terraform:
- tofu:
description: "Install Azure Key Vault"
outputs:
- name: vault_uri
Expand All @@ -189,7 +164,7 @@ parameters:
- install
install:
- terraform:
- tofu:
description: "Install Azure Key Vault"
disableVarFile: true
vars:
Expand All @@ -198,7 +173,7 @@ install:
outputs:
- name: vault_uri
uninstall: # Var block required
- terraform:
- tofu:
description: "Install Azure Key Vault"
vars:
foo: bar
Expand All @@ -211,7 +186,7 @@ uninstall: # Var block required

```yaml
install:
- terraform:
- tofu:
description: "Install Azure Key Vault"
backendConfig:
key: "mybundle.tfstate"
Expand All @@ -226,7 +201,7 @@ install:

```yaml
upgrade:
- terraform:
- tofu:
description: "Upgrade Azure Key Vault"
backendConfig:
key: "mybundle.tfstate"
Expand All @@ -241,27 +216,27 @@ upgrade:

An invoke step is used for any custom action (not one of `install`, `upgrade` or `uninstall`).

By default, the command given to `terraform` will be the step name. Here it is `show`,
resulting in `terraform show` with the provided configuration.
By default, the command given to `tofu` will be the step name. Here it is `show`,
resulting in `tofu show` with the provided configuration.

```yaml
show:
- terraform:
description: "Invoke 'terraform show'"
- tofu:
description: "Invoke 'tofu show'"
backendConfig:
key: "mybundle.tfstate"
storage_account_name: "mystorageacct"
container_name: "mycontainer"
access_key: "myaccesskey"
```

Or, if the step name does not match the intended terraform command, the command
Or, if the step name does not match the intended OpenTofu command, the command
can be supplied via the `arguments:` section, like so:

```yaml
printVersion:
- terraform:
description: "Invoke 'terraform version'"
- tofu:
description: "Invoke 'opentofu version'"
arguments:
- version
```
Expand All @@ -270,7 +245,7 @@ printVersion:

```yaml
uninstall:
- terraform:
- tofu:
description: "Uninstall Azure Key Vault"
backendConfig:
key: "mybundle.tfstate"
Expand All @@ -285,16 +260,16 @@ See further examples in the [Examples](examples) directory

As seen above, outputs can be declared for a step. All that is needed is the name of the output.

For each output listed, `terraform output <output name>` is invoked to fetch the output value
For each output listed, `opentofu output <output name>` is invoked to fetch the output value
from the state file for use by Porter. Outputs can be saved to the filesystem so that subsequent
steps can use the file by specifying the `destinationFile` field. This is particularly useful
when your terraform module creates a Kubernetes cluster. In the example below, the module
when your OpenTofu module creates a Kubernetes cluster. In the example below, the module
creates a cluster, and then writes the kubeconfig to /root/.kube/config so that the rest of the
bundle can immediately use the cluster.

```yaml
install:
- terraform:
- tofu:
description: "Create a Kubernetes cluster"
outputs:
- name: kubeconfig
Expand Down
4 changes: 2 additions & 2 deletions cmd/terraform/build.go → cmd/tofu/build.go
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
package main

import (
"get.porter.sh/mixin/terraform/pkg/terraform"
"get.porter.sh/mixin/tofu/pkg/tofu"
"github.com/spf13/cobra"
)

func buildBuildCommand(m *terraform.Mixin) *cobra.Command {
func buildBuildCommand(m *tofu.Mixin) *cobra.Command {
cmd := &cobra.Command{
Use: "build",
Short: "Generate Dockerfile lines for the bundle invocation image",
Expand Down
4 changes: 2 additions & 2 deletions cmd/terraform/install.go → cmd/tofu/install.go
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
package main

import (
"get.porter.sh/mixin/terraform/pkg/terraform"
"get.porter.sh/mixin/tofu/pkg/tofu"
"github.com/spf13/cobra"
)

var (
commandFile string
)

func buildInstallCommand(m *terraform.Mixin) *cobra.Command {
func buildInstallCommand(m *tofu.Mixin) *cobra.Command {
cmd := &cobra.Command{
Use: "install",
Short: "Execute the install functionality of this mixin",
Expand Down
6 changes: 3 additions & 3 deletions cmd/terraform/invoke.go → cmd/tofu/invoke.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ package main
import (
"github.com/spf13/cobra"

"get.porter.sh/mixin/terraform/pkg/terraform"
"get.porter.sh/mixin/tofu/pkg/tofu"
)

func buildInvokeCommand(mixin *terraform.Mixin) *cobra.Command {
opts := terraform.InvokeOptions{}
func buildInvokeCommand(mixin *tofu.Mixin) *cobra.Command {
opts := tofu.InvokeOptions{}

cmd := &cobra.Command{
Use: "invoke",
Expand Down
Loading

0 comments on commit f0b8c4f

Please sign in to comment.