DEV Community

Cover image for Introducing the Loft Terraform Provider
Lukas Gentele for Loft Labs, Inc.

Posted on • Originally published at loft.sh

Introducing the Loft Terraform Provider

By Russ Centanni

We’re proud to announce our new terraform provider for Loft. For customers already managing infrastructure using Terraform, the terraform-provider-loft allows configuring Loft spaces and virtual clusters as terraform resources. Here’s a quick look at what’s in the release. For more details, head over to the provider’s documentation.

Prerequisites

If you'd like to follow along with these examples, or test drive the provider for your own infrastructure, you'll need the following installed:

Getting Started

The first step is to add the provider to your terraform file.

terraform {
  required_providers {
    loft = {t
      source = "registry.terraform.io/loft-sh/loft"
    }
  }
}

provider "loft" {}
Enter fullscreen mode Exit fullscreen mode

From your terminal, run terraform init. Terraform will download the provider to your system.

$ terraform init
Enter fullscreen mode Exit fullscreen mode

Configuring Loft Authentication

By default, the provider will use your current Loft credentials if you’ve logged in to loft using the loft login command. This is convenient for getting started, but this can be difficult to manage, especially if you frequently switch between different environments and don’t use the same credentials in each environment.

Loft Configuration

One option for managing this is to create a config file for each environment. This can be done with the --config option and the loft login command.

First, log in to Loft with a custom configuration file path:

$ loft login https://localhost:8443 --insecure --config dev.config.json
Enter fullscreen mode Exit fullscreen mode

Then refer to this file path using the config_path attribute:

provider "loft" {
  config_path = "dev.config.json"
}
Enter fullscreen mode Exit fullscreen mode

This option works as long as everyone uses the same file paths for their configuration, but can lead to accidentally leaking credentials if the files aren’t managed properly.

Access Keys

Another option for authentication is to configure the provider using access keys. This allows the credentials to be passed in through Terraform variables and managed as you would any other secrets. This is the recommended option for CI/CD environments. 

First, here’s how you might configure Terraform to use variables:

variable "loft_host" {
  type        = string
  description = "The loft instance host (e.g. https://loft.example.com)"
}

variable "loft_access_key" {
  type        = string
  description = "The Loft access key."
  sensitive   = true
}

variable "loft_insecure" {
  type        = bool
  description = "Allow login into an insecure Loft instance"
}

provider "loft" {
  host       = var.loft_host
  access_key = var.loft_access_key
  insecure   = var.loft_insecure
}
Enter fullscreen mode Exit fullscreen mode

Next we'll create a Loft access key for the provider to use. Head over to the "Users" page in the Loft UI:

Loft User Management screen

Select the user you wish to create an access key for, and click "Create Access Key":

Click the Create Access Key button

In the form, add a description for the Access Key's intended purpose and click create:

Add a description for the new access key

A dialog with the newly generated access key will be shown. This can be copied and then passed to terraform through the command line, environment variables, or .tfvars files

Once the provider is configured to connect to Loft, it's time to manage resources.

Manage a Space

Creating a Loft space using terraform is as simple as providing the cluster and name of the space to a loft_space resource.

resource "loft_space" "basic" {
  name    = "basic-space"
  cluster = "loft-cluster"
}
Enter fullscreen mode Exit fullscreen mode

Sleep Mode

One of the benefits of using Loft is the cost savings of using sleep mode. Configuring sleep mode on a space is done by using the sleep_after attribute.

resource "loft_space" "basic" {
  name        = "basic-space"
  cluster     = "loft-cluster"
  sleep_after = "1h" # Sleep after one hour of inactivity
}
Enter fullscreen mode Exit fullscreen mode

The sleep_after attribute accepts any Golang style duration string. You may already be familiar with this format from kubectl.

Space Objects

A convenient way to manage resources inside a space is by using space objects. Objects are Kubernetes resources that are synchronized by Loft. Here's an example of creating a space with some example config maps:

resource "loft_space" "basic" {
  name    = "basic-space"
  cluster = "loft-cluster"
  objects = <<YAML
apiVersion: v1
kind: ConfigMap
metadata:
  name: config-map-1
data:
  key1: "value1"
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: config-map-2
data:
  key2: "value2"
YAML
}
Enter fullscreen mode Exit fullscreen mode

As you can see, multiple resources can be synced by using the YAML document separator --- in the objects attribute.

Import

If you've been using Loft for a while, you likely have existing spaces that you'd like to start managing with Terraform. To enable this, the provider supports importing existing spaces into your Terraform state.

To import an existing space, add a loft_space resource with the cluster and name attributes:

resource "loft_space" "basic" {
  name    = "basic-space"
  cluster = "loft-cluster"
}
Enter fullscreen mode Exit fullscreen mode

Next, run the terraform import command to import the resource into terraform.

$ terraform import loft_space.basic loft-cluster/basic-space
Enter fullscreen mode Exit fullscreen mode

Finally, run terraform plan to see a diff of other attributes that should be added to your *.tf files to start managing the existing space's configuration.

$ terraform plan
Enter fullscreen mode Exit fullscreen mode

Manage a Virtual Cluster

The loft_virtual_cluster resource enables declarative management of Loft virtual clusters. Here's an example of creating a virtual cluster in the space we created earlier:

resource "loft_space" "basic" {
  name    = "basic-space"
  cluster = "loft-cluster"
}

resource "loft_virtual_cluster" "basic" {
  name      = "basic-virtual-cluster"
  namespace = resource.loft_space.basic.name
  cluster   = resource.loft_space.basic.cluster
}
Enter fullscreen mode Exit fullscreen mode

By using loft_virtual_cluster with the loft_space resource, virtual clusters can take advantage of sleep mode too.

Virtual Cluster Objects

Similar to spaces, it's also possible to synchronize Kubernetes resources to a virtual cluster. One difference to keep in mind is that you'll also need to create namespaces in the Virtual Cluster since you're not already scoped to one. Here's an example of adding a namespace and config map to the example virtual cluster above.

resource "loft_space" "basic" {
  name    = "basic-space"
  cluster = "loft-cluster"
}

resource "loft_virtual_cluster" "basic" {
  name      = "basic-virtual-cluster"
  namespace = resource.loft_space.basic.name
  cluster   = resource.loft_space.basic.cluster
  objects   = <<YAML
apiVersion: v1
kind: Namespace
metadata:
  name: my-namespace
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: my-config-map
  namespace: my-namespace
data:
  key: "value"
YAML
}
Enter fullscreen mode Exit fullscreen mode

Import

Importing an existing virtual cluster so it can be managed with Terraform looks very similar to spaces. The key difference is that you'll need to provide the name of the virtual cluster. As an example, here's a command to import the virtual cluster from the previous examples:

$ terraform import loft_virtual_cluster.basic loft-cluster/basic-space/basic-virtual-cluster
Enter fullscreen mode Exit fullscreen mode

For more advanced configuration options, see the loft_virtual_cluster documentation and the VCluster Helm charts.

Conclusion

If you're a Loft customer using Terraform, this provider enables a more seamless approach to managing Loft spaces and virtual clusters. We're just getting started and we hope you'll give it a try and reach out to us with feature requests:

Top comments (0)