Adding a new backend for Terraform or OpenTofu

If you would like to add another backend via a merge request, then read on.

  1. Add a class to terraform-base-plugin/src/main/groovy/org/ysb33r/gradle/terraform/backends or opentofu-base-plugin/src/main/groovy/org/ysb33r/gradle/opentofu/backends which extends TerraformBackend or OpenTofuBackend.

  2. Add an injectable constructor.

  3. Add setters for all the attributes that is available by the backend. (Use S3Backend in either plugin as an example)

Example backend for Terraform
@CompileStatic
class ConsulBackend extends TerraformBackend { (1)
    @Inject
    ConsulBackend(String name, TerraformExtension parent, Project tempProjectRef) { (2)
        super(name, parent, tempProjectRef)
    }

    void setPath(Object consulPath) { (3)
      token('path', consulPath) (4)
    }

    void setHttpAuth(Object authString) { (5)
        secretVariable('CONSUL_HTTP_AUTH', authString) (6)
    }
}
1 For OpenTofu, change TerraformBackend to OpenTofuBackend.
2 For OpenTofu, change TerraformExtension to OpenTofuExtension.
3 Example of implementing a simple token such as Consul’s path
4 Path the name of the name and the lazy-evaluated value. See IacBackendSpec for more details.
5 Example of implementing a secret to be used in a backend - in this case Consul’s http_auth. Instead of creating a token, it will store the secret in encrypted form in memory.
6 Call the secretVariable method with the name of environment variable that will be passed at runtime. Secret variables are not logged by the plugin. See SecretVariables for more details.

Now find the registerBackendFactoriesAndBackends method in TerraformExtension and/or OpenTofuExtension. It will look something like

TerraformExtension.groovy
private void registerBackendFactoriesAndBackends(ObjectFactory objects) {
    backends.registerFactory(GenericBackend) {
        objects.newInstance(GenericBackend, it, owner)
    }
    backends.registerFactory(LocalBackend) {
        objects.newInstance(LocalBackend, it, owner)
    }
    backends.registerFactory(S3Backend) {
        objects.newInstance(S3Backend, it, owner)
    }
}

Add the new backend to be registered. Also update docs/modules/ROOT/pages/terraform/backends.adoc and/or docs/modules/ROOT/pages/opentofu/backends.adoc to document usage of the new backend.

Now you can use it in a test of a build script

import org.ysb33r.gradle.terraform.backends.ConsulBackend

terraform {
  backends {
    consul(ConsulBackend) {
        path = 'full/path'
        httpAuth = grolifantOPs.providerTools.resolveProperty('my.consul.auth')
    }
  }
  sourceSets {
    main {
      usedBackend('consul')
    }
  }
}