April 18, 2023

HarperDB's New Terraform Provider: Managing Resources Declaratively

Welcome to Community Posts
Click below to read the full article.
Arrow
Summary of What to Expect
Table of Contents

Introduction

There’s a new Terraform provider for HarperDB which I’m excited to introduce. With this new provider, you can integrate your database-configuration into your pre-existing IaC infrastructure (you are using IaC right?).

In this blog post, we will discuss the release of HarperDB's new terraform provider, its benefits, and showcase some of the code that developers can use to manage resources via terraform. Specifically, we will walk through some of the key resources available in this version and deploy out a set of changes to our HarperDB instance.

Preamble

HarperDB's new Terraform provider builds upon their newly re-vamped Go-SDK which I wrote about recently. The Go-SDK was the first step in integrating HarperDB with Terraform. We can now manage these resources in a declarative, infrastructure-as-code manner, enabling us to manage our infrastructure in a more automated and streamlined manner.

This is very much an early release, but we wanted to get it out to you now as we’re excited where people want to take it.

What the Terraform Looks Like

Let's take a look at what the terraform code for managing a HarperDB user might look like:

resource "harperdb_user" "example_user" {
  username = "example_user"
  password = "example_password"
  role     = "dev"
  active   = true
}

The code above creates an active HarperDB user with the username "example_user," password "example_password," and role "dev." With the terraform provider, developers can easily create, update, and delete HarperDB resources.

Demo of Running a Terraform Plan

To demonstrate the terraform provider in action, let's run a terraform plan for configuring a HarperDB instance, but first let’s have a look at what is needed to get started.

If you’re wanting to watch a more visual explanation, I also did a short recording here.

// provider.tf
provider "harperdb" {
  endpoint = var.db_endpoint
  username = var.db_username
  password = var.db_password
}

Initialising the provider requires only a user/pass and the endpoint of your database. Nice and straight-forward. Now let’s create a schema and table

resource "harperdb_schema" "animals" {
  name = "animals"
}

resource "harperdb_table" "dogs" {
  schema = harperdb_schema.animals.name
  name = "dogs"
  hash_attribute = "name"
}

The code above creates a HarperDB schema with the name “animals” with a table called “dogs”. Now let’s create a role specifically for the above schema and table:

resource "harperdb_role" "basic" {
  name = "reader_role"
  schema_permissions = {
    dogs2 = {
      tables = {
        "${harperdb_table.dogs.name}" = {
          read = true
          attribute_permissions = [
            {
              name = "name"
              read = true
            }
          ]
        }
      }
    }
  }
}

The code above creates a HarperDB role “reader_role” with specific permissions on the “dogs2” table, but only the “name” attribute. This gives anyone with this role access to a subset of only the dogs table. It’s explicitly declared, and can be easily tied into user-creation logic, which we see an example of below.

resource "harperdb_user" "user" {
    username = "user"
    password = "password"
    active = true
    role = harperdb_role.basic.name
}

We now have the following defined from our four files above.

  1. a schema
  2. a table
  3. a new read-only role
  4. and a new user “user”

Running the above configuration with Terraform, we get the following plan:

$ terraform plan
Terraform will perform the following actions:

  # harperdb_role.basic will be created
  + resource "harperdb_role" "basic" {
      + id                 = (known after apply)
      + name               = "reader_role"
      + schema_permissions = {
          + "animals" = {
              + tables = {
                  + "dogs" = {
                      + attribute_permissions = [
                          + {
                              + insert = false
                              + name   = "name"
                              + read   = true
                              + update = false
                            },
                        ]
                      + delete                = false
                      + insert                = false
                      + read                  = true
                      + update                = false
                    },
                }
            },
        }
    }

  # harperdb_schema.animals will be created
  + resource "harperdb_schema" "animals" {
      + id   = (known after apply)
      + name = "animals"
    }

  # harperdb_table.dogs will be created
  + resource "harperdb_table" "dogs" {
      + hash_attribute = "name"
      + id             = (known after apply)
      + name           = "dogs"
      + schema         = "animals"
    }

  # harperdb_user.user will be created
  + resource "harperdb_user" "user" {
      + active   = true
      + id       = (known after apply)
      + password = (sensitive value)
      + role     = "reader_role"
      + username = "user"
    }

Plan: 4 to add, 0 to change, 0 to destroy.

This matches what we’re expecting with the four resources we are wanting to create from our terraform files. If we now apply the configuration all our resources are created.

harperdb_schema.animals: Creating...
harperdb_schema.animals: Creation complete after 0s [id=animals]
harperdb_table.dogs: Creating...
harperdb_table.dogs: Creation complete after 0s [id=animals.dogs]
harperdb_role.basic: Creating...
harperdb_role.basic: Creation complete after 0s [id=bf04276a-967d-4a77-82af-69ad225cf7c0]
harperdb_user.user: Creating...
harperdb_user.user: Creation complete after 1s [id=user]

A few seconds later and our HarperDB instance is fully configured with schemas, roles and the users we want. From here we have the flexibility of auditing any and all management changes to our HarperDB instance.

We can test this by changing the permissions on our role to allow inserting only to the “name” attribute, and let’s update the name of the role to match.

resource "harperdb_role" "basic" {
  name = "reader_role_name_inserter"
  schema_permissions = {
    "${harperdb_schema.animals.name}" = {
      tables = {
        "${harperdb_table.dogs.name}" = {
          read = true
          attribute_permissions = [
            {
              name = "name"
              read = true
              insert = true
            }
          ]
        }
      }
    }
  }
}

Our Terraform plan now describes what will change from the current state to our desired state.

Terraform will perform the following actions:

  # harperdb_role.basic will be updated in-place
  ~ resource "harperdb_role" "basic" {
      ~ id                 = "bf04276a-967d-4a77-82af-69ad225cf7c0" -> (known after apply)
      ~ name               = "reader_role" -> "reader_role_name_inserter"
      ~ schema_permissions = {
          ~ "animals" = {
              ~ tables = {
                  ~ "dogs" = {
                      ~ attribute_permissions = [
                          ~ {
                              ~ insert = false -> true
                                name   = "name"
                                # (2 unchanged attributes hidden)
                            },
                        ]
                        # (4 unchanged attributes hidden)
                    },
                }
            },
        }
    }

  # harperdb_user.user will be updated in-place
  ~ resource "harperdb_user" "user" {
      ~ id       = "user" -> (known after apply)
      ~ role     = "reader_role" -> "reader_role_name_inserter"
        # (3 unchanged attributes hidden)
    }

Plan: 0 to add, 2 to change, 0 to destroy.

We’ve only changed the role, but the user is also being updated. This is because terraform is keeping track of which role is bound to which user by reference, so if the name of the referenced role is updated, then the user needs to be updated to use the new role.

Benefits of HarperDB's New Terraform Provider

This new Terraform provider for HarperDB enables management using IaC best-practices. Built on the Go-SDK, this is the first step in building out a robust configuration platform for HarperDB.

This release provides an alternative and industry-standard method to manage HarperDB resources, which is especially important in today's fast-paced development environment. DevOps teams need to be able to move quickly and efficiently, and this release enables them to do so. Additionally, it provides a more scalable approach to platform teams, making it easier to manage resources as the organization grows.

Summary

In summary, HarperDB’s new terraform provider saves time and resources when it comes to management and operations. We’re excited to be releasing this, and to see how we can improve user-onboarding for HarperDB. If you have any issues, reach out on GitHub with an issue and I’ll get back to you.