Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add HowTo tutorial to configure Terraform Custom Provider #1162

Merged
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions .github/config/en-custom.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1253,3 +1253,7 @@ envSecrets
RecipeConfigPropertiesEnvSecrets
ProviderConfigPropertiesSecrets
SecretReference
cyrilgdn
secretStore
postgreSQL
postgres
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
---
type: docs
title: "How-To: Configure custom Terraform Providers"
linkTitle: "Custom Terraform Providers"
description: "Learn how to setup your Radius environment with custom Terraform Providers and deploy recipes."
lakshmimsft marked this conversation as resolved.
Show resolved Hide resolved
weight: 500
categories: "How-To"
aliases : ["/guides/recipes/terraform/howto-custom-provider"]
tags: ["recipes", "terraform"]
---

This how-to guide will describe how to:

- Configure a custom [Terraform provider](https://registry.terraform.io/browse/providers) in a Radius environment.
lakshmimsft marked this conversation as resolved.
Show resolved Hide resolved
- Configure credentials to authenticate into the Terraform provider.
- Consume the terraform modules from a custom Terraform provider and use it in a Terraform recipe.
lakshmimsft marked this conversation as resolved.
Show resolved Hide resolved

In this example we're going to configure a [PostgreSQL Terraform provider](https://registry.terraform.io/providers/cyrilgdn/postgresql/latest/docs) in a Radius environment and deploy a recipe.
lakshmimsft marked this conversation as resolved.
Show resolved Hide resolved

### Prerequisites
Reshrahim marked this conversation as resolved.
Show resolved Hide resolved

Before you get started, you'll need to make sure you have the following tools and resources:

- [rad CLI]({{< ref "installation#step-1-install-the-rad-cli" >}})
- [Radius Bicep VSCode extension]({{< ref "installation#step-2-install-the-vs-code-extension" >}})
- [kubectl](https://kubernetes.io/docs/tasks/tools/install-kubectl/)
- [Radius initialized with `rad init`]({{< ref howto-environment >}})
- [Recipes overview]({{< ref "/guides/recipes/overview" >}})

## Step 1: Define a secretStore resource for the custom provider

Configure a [Radius Secret Store]({{< ref "/guides/author-apps/secrets/overview" >}}) with any sensitive information needed as input configuration for the custom Terraform Provider. Define the namespace for the cluster that will contain your [Kubernetes Secret](https://kubernetes.io/docs/concepts/configuration/secret/) with the `resource` property.

> While this example shows a Radius-managed secret store where Radius creates the underlying secrets infrastructure, you can also bring your own existing secrets. Refer to the [secrets documentation]({{< ref "/guides/author-apps/secrets/overview" >}}) for more information.

Create a Bicep file `env.bicep` with the secretStore resource:

{{< rad file="snippets/env.bicep" embed=true marker="//SECRETSTORE" >}}

> In this example, we're creating a secret with keys `username` and `password` as sensitive data required to authenticate into the Terraform Provider `cyrilgdn/postgresql`.
lakshmimsft marked this conversation as resolved.
Show resolved Hide resolved

## Step 2: Configure Terraform Provider

`recipeConfig/terraform/providers` allows you to setup configurations for one or multiple Terraform Providers. For more information refer to the [Radius Environment schema]({{< ref environment-schema >}}) page.

In your `env.bicep` file add an Environment resource, along with Recipe configuration which leverages properties from the previously defined secret store.
In this example you're also passing in `host` as an environment variable to highlight use cases where, depending on provider configuration requirements, users can pass environment variables to the Terraform runtime.
lakshmimsft marked this conversation as resolved.
Show resolved Hide resolved

{{< rad file="snippets/env.bicep" embed=true marker="//ENV" >}}

## Step 3: Define a Terraform Recipe

Create a Terraform recipe which deploys a postgreSQL database instance using custom Terraform provider `cyrilgdn/postgresql`
lakshmimsft marked this conversation as resolved.
Show resolved Hide resolved

{{< rad file="snippets/postgres.tf" embed=true marker="//ENV" >}}

## Step 4: Add a Terraform Recipe to the environment
lakshmimsft marked this conversation as resolved.
Show resolved Hide resolved

Update your Environment with the Terraform Recipe.

{{< rad file="snippets/env-complete.bicep" embed=true marker="//ENV" markdownConfig="{linenos=table,hl_lines=[\"22-30\"],linenostart=30,lineNos=false}" >}}

## Step 5: Deploy your Radius Environment

Deploy your new Radius Environment passing in values for `username` and `password` needed to authenticate into the provider. The superuser for this PostgreSQL recipe is `postgres` which is the expected input for `username`:
lakshmimsft marked this conversation as resolved.
Show resolved Hide resolved

```bash
rad deploy ./env.bicep -p username=****** -p password=******
```

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should there be a note here explaining what username and password fields the reader needs to pass into this command?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added a note. Pls take a look

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thank you, this looks good!

## Done

Your Radius Environment is now configured with a custom Terraform provider which you can use to deploy Radius Terraform recipes. For more information on Radius Recipes visit the [Recipes overview page]({{< ref "/guides/recipes/overview" >}}).
lakshmimsft marked this conversation as resolved.
Show resolved Hide resolved

## Cleanup

You can delete the Radius Environment by running the following command:

```bash
rad env delete my-env
```

## Further reading

- [Recipes overview]({{< ref "/guides/recipes/overview" >}})
- [Radius Environments]({{< ref "/guides/deploy-apps/environments/overview" >}})
- [`rad recipe CLI reference`]({{< ref rad_recipe >}})
- [`rad env CLI reference`]({{< ref rad_env >}})
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
//SECRETSTORE
import radius as radius

@description('username for postgres db')
@secure()
param username string

@description('password for postgres db')
@secure()
param password string

resource pgsSecretStore 'Applications.Core/secretStores@2023-10-01-preview' = {
name: 'my-secret-store'
properties: {
resource: 'my-secret-namespace/my-secret-store'
type: 'generic'
data: {
username: {
value: username
}
password: {
value: password
}
}
}
}
//SECRETSTORE

//ENV
resource env 'Applications.Core/environments@2023-10-01-preview' = {
name: 'my-env'
properties: {
compute: {
kind: 'kubernetes'
resourceId: 'self'
namespace: 'my-namespace'
}
recipeConfig: {
terraform: {
providers: {
postgresql: [ {
sslmode: 'disable'
port: 5432
secrets: {
username: {
source: pgsSecretStore.id
key: username
}
password: {
source: pgsSecretStore.id
key: password
}
}
} ]
}
}
env: {
PGHOST: 'postgres.corerp-resources-terraform-pg-app.svc.cluster.local'
}
}
recipes: {
'Applications.Core/extenders': {
defaultpostgres: {
templateKind: 'terraform'
// Recipe template path
templatePath: 'git::https://github.com/my-org/my-repo'
}
}
}
}
}
//ENV
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
//SECRETSTORE
import radius as radius

@description('username for PostgreSQL db')
@secure()
param username string

@description('password for PostgreSQL db')
@secure()
param password string

resource pgsSecretStore 'Applications.Core/secretStores@2023-10-01-preview' = {
name: 'my-secret-store'
properties: {
resource: 'my-secret-namespace/my-secret-store'
type: 'generic'
data: {
username: {
value: username
}
password: {
value: password
}
}
}
}
//SECRETSTORE

//ENV
resource env 'Applications.Core/environments@2023-10-01-preview' = {
name: 'my-env'
properties: {
compute: {
kind: 'kubernetes'
resourceId: 'self'
namespace: 'my-namespace'
}
recipeConfig: {
terraform: {
providers: {
postgresql: [ {
sslmode: 'disable'
port: 5432
secrets: {
username: {
source: pgsSecretStore.id
key: username
}
password: {
source: pgsSecretStore.id
key: password
}
}
} ]
}
}
env: {
PGHOST: 'postgres.corerp-resources-terraform-pg-app.svc.cluster.local'
}
}
}
}
//ENV
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
terraform {
required_providers {
kubernetes = {
source = "hashicorp/kubernetes"
version = ">= 2.0"
}
postgresql = {
source = "cyrilgdn/postgresql"
version = "1.16.0"
}
}
}

variable "context" {
description = "This variable contains Radius recipe context."
type = any
}

variable "password" {
description = "The password for the PostgreSQL database"
type = string
}

resource "kubernetes_deployment" "postgres" {
metadata {
name = "postgres"
namespace = var.context.runtime.kubernetes.namespace
}

spec {
selector {
match_labels = {
app = "postgres"
}
}

template {
metadata {
labels = {
app = "postgres"
}
}

spec {
container {
image = "postgres:latest"
name = "postgres"

env {
name = "POSTGRES_PASSWORD"
value = var.password
}

port {
container_port = 5432
}
}
}
}
}
}

resource "kubernetes_service" "postgres" {
metadata {
name = "postgres"
namespace = var.context.runtime.kubernetes.namespace
}

spec {
selector = {
app = "postgres"
}

port {
port = 5432
target_port = 5432
}
}
}

resource "time_sleep" "wait_20_seconds" {
depends_on = [kubernetes_service.postgres]
create_duration = "20s"
}

resource "postgresql_database" "pg_db_test" {
depends_on = [time_sleep.wait_20_seconds]
name = "pg_db_test"
}
Loading