Skip to content

Commit

Permalink
[DPE-5866] Add Charm Terraform Module (#501)
Browse files Browse the repository at this point in the history
This PR extends our current charm to add a terraform module for the
charm. It also adds github workflow to test + a basic test setup.
  • Loading branch information
phvalguima authored Nov 22, 2024
1 parent 727d283 commit 1fa589c
Show file tree
Hide file tree
Showing 11 changed files with 416 additions and 0 deletions.
53 changes: 53 additions & 0 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,59 @@ jobs:
- name: Run tests
run: tox run -e unit

terraform-test:
name: Terraform - Lint and Simple Deployment
runs-on: ubuntu-latest
timeout-minutes: 120
steps:
- name: Checkout repo
uses: actions/checkout@v4
with:
fetch-depth: 0

- name: lint charm module
run: |
pushd ./terraform
terraform init
terraform fmt
terraform validate
pushd ./tests
terraform init
terraform fmt
terraform validate
popd
popd
- name: run checks - prepare
run: |
sudo snap install juju --channel=3.6/beta --classic
sudo snap install juju-wait --channel=latest/stable --classic
sudo snap install jq
- name: LXD setup
run: |
sudo snap refresh lxd --channel=latest/stable
sudo adduser "$USER" 'lxd'
# `newgrp` does not work in GitHub Actions; use `sg` instead
sg 'lxd' -c "lxd waitready"
sg 'lxd' -c "lxd init --auto"
sg 'lxd' -c "lxc network set lxdbr0 ipv6.address none"
sudo iptables -F FORWARD
sudo iptables -P FORWARD ACCEPT
- name: Juju setup
run: |
sg 'lxd' -c "juju bootstrap 'localhost' --config model-logs-size=10G"
juju model-defaults logging-config='<root>=INFO; unit=DEBUG'
juju add-model test
- name: Terraform deploy
run: |
pushd ./terraform/tests/
TF_VAR_model_name="test" terraform apply -target null_resource.simple_deployment_juju_wait_deployment -auto-approve
popd
lib-check:
name: Check libraries
Expand Down
47 changes: 47 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,3 +16,50 @@ cloudinit-userdata.yaml
# Moving to Poetry, we do not need this file to be pushed any longer
/requirements.txt
/requirements-last-build.txt

########################################################
#
# Terraform .gitignore
#
########################################################


# Local .terraform directories
**/.terraform/*
*.terraform.lock.hcl

# .tfstate files
*.tfstate
*.tfstate.*

# Crash log files
crash.log
crash.*.log

# Generated files
*.key
credentials*

# Exclude all .tfvars files, which are likely to contain sensitive data, such as
# password, private keys, and other secrets. These should not be part of version
# control as they are data points which are potentially sensitive and subject
# to change depending on the environment.
*.tfvars
*.tfvars.json

# Ignore override files as they are usually used to override resources locally and so
# are not checked in
override.tf
override.tf.json
*_override.tf
*_override.tf.json

# Include override files you do wish to add to version control using negated pattern
# !example_override.tf

# Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan
# example: *tfplan*

# Ignore CLI configuration files
.terraformrc
terraform.rc
66 changes: 66 additions & 0 deletions terraform/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Terraform module for opensearch-operator

This is a Terraform module facilitating the deployment of the OpenSearch charm with [Terraform juju provider](https://github.com/juju/terraform-provider-juju/). For more information, refer to the provider [documentation](https://registry.terraform.io/providers/juju/juju/latest/docs).

## Requirements
This module requires a `juju` model to be available. Refer to the [usage section](#usage) below for more details.

## API

### Inputs
The module offers the following configurable inputs:

| Name | Type | Description | Required |
| - | - | - | - |
| `app_name`| string | Application name | False |
| `channel`| string | Channel that the charm is deployed from | False |
| `base`| string | The series to be used for this charm | False |
| `config`| map(string) | Map of the charm configuration options | False |
| `model_name`| string | Name of the model that the charm is deployed on | True |
| `resources`| map(string) | Map of the charm resources | False |
| `revision`| number | Revision number of the charm name | False |
| `units`| number | Number of units to be deployed | False |
| `constraints`| string | Machine constraints for the charm | False |
| `storage`| map(string) | Storage description, must follow the juju provider schema | False |


### Outputs
Upon applied, the module exports the following outputs:

| Name | Description |
| - | - |
| `app_name`| Application name |
| `provides`| Map of `provides` endpoints |
| `requires`| Map of `requires` endpoints |

## Usage

This module is intended to be used as part of a higher-level module. When defining one, users should ensure that Terraform is aware of the `juju_model` dependency of the charm module. There are two options to do so when creating a high-level module:

### Define a `juju_model` resource
Define a `juju_model` resource and pass to the `model_name` input a reference to the `juju_model` resource's name. For example:

```
resource "juju_model" "opensearch" {
name = opensearch
}
module "opensearch-operator" {
source = "<path-to-this-directory>"
model_name = juju_model.opensearch.name
}
```

### Define a `data` source
Define a `data` source and pass to the `model_name` input a reference to the `data.juju_model` resource's name. This will enable Terraform to look for a `juju_model` resource with a name attribute equal to the one provided, and apply only if this is present. Otherwise, it will fail before applying anything.

```
data "juju_model" "opensearch" {
name = var.model_name
}
module "opensearch" {
source = "<path-to-this-directory>"
model_name = data.juju_model.opensearch.name
}
```
41 changes: 41 additions & 0 deletions terraform/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Copyright 2024 Canonical Ltd.
# See LICENSE file for licensing details.

resource "juju_application" "opensearch" {

charm {
name = "opensearch"
channel = var.channel
revision = var.revision
base = var.base
}
config = var.config
model = var.model
name = var.app_name
units = var.units
constraints = var.constraints


# TODO: uncomment once final fixes have been added for:
# Error: juju/terraform-provider-juju#443, juju/terraform-provider-juju#182
# placement = join(",", var.machines)

endpoint_bindings = [
for k, v in var.endpoint_bindings : {
endpoint = k, space = v
}
]

storage_directives = var.storage

lifecycle {
precondition {
condition = length(var.machines) == 0 || length(var.machines) == var.units
error_message = "Machine count does not match unit count"
}
precondition {
condition = length(var.storage) == 0 || lookup(var.storage, "count", 0) <= 1
error_message = "Only one storage is supported"
}
}
}
41 changes: 41 additions & 0 deletions terraform/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# Copyright 2024 Canonical Ltd.
# See LICENSE file for licensing details.

output "app_name" {
description = "Name of the deployed application."
value = juju_application.opensearch.name
}

# Required integration endpoints

output "certificates_endpoint" {
description = "Name of the endpoint used to integrate with the TLS certificates provider."
value = "certificates"
}

output "peer_cluster_endpoint" {
description = "Name of the endpoint used to connect with the peer-cluster."
value = "peer-cluster"
}

output "s3_credentials_endpoint" {
description = "Name of the endpoint used to provide s3 support for backups."
value = "s3-credentials"
}

# Provided integration endpoints

output "peer_cluster_orchestrator_endpoint" {
description = "Name of the peer cluster orchestrator endpoint."
value = "peer-cluster-orchestrator"
}

output "opensearch_client_endpoint" {
description = "Name of the endpoint opensearch-client endpoint."
value = "opensearch-client"
}

output "cos_agent_endpoint" {
description = "Name of the endpoint used to provide COS agent integration."
value = "cos-agent-endpoint"
}
18 changes: 18 additions & 0 deletions terraform/tests/preamble.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
resource "null_resource" "preamble" {
provisioner "local-exec" {
command = <<-EOT
sudo snap install juju-wait --classic || true
sudo sysctl -w vm.max_map_count=262144 vm.swappiness=0 net.ipv4.tcp_retries2=5
EOT
}

}

resource "juju_application" "self-signed-certificates" {
charm {
name = "self-signed-certificates"
channel = "latest/stable"
}
model = var.model_name
depends_on = [null_resource.preamble]
}
16 changes: 16 additions & 0 deletions terraform/tests/providers.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
terraform {
required_providers {
juju = {
source = "juju/juju"
version = "~> 0.14.0"
}
http = {
source = "hashicorp/http"
version = "~> 3.4.5"
}
external = {
source = "hashicorp/external"
version = "~> 2.3.4"
}
}
}
39 changes: 39 additions & 0 deletions terraform/tests/simple_deployment.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
module "opensearch" {
source = "../"
app_name = var.app_name
model = var.model_name
units = var.simple_opensearch_units
config = {
profile = "testing"
}

channel = "2/edge"

depends_on = [juju_application.self-signed-certificates]
}

resource "juju_integration" "simple_deployment_tls-operator_opensearch-integration" {
model = var.model_name

application {
name = juju_application.self-signed-certificates.name
}
application {
name = var.app_name
}
depends_on = [
juju_application.self-signed-certificates,
module.opensearch
]

}

resource "null_resource" "simple_deployment_juju_wait_deployment" {
provisioner "local-exec" {
command = <<-EOT
juju-wait -v --model ${var.model_name}
EOT
}

depends_on = [juju_integration.simple_deployment_tls-operator_opensearch-integration]
}
16 changes: 16 additions & 0 deletions terraform/tests/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
variable "model_name" {
description = "Model name"
type = string
}

variable "app_name" {
description = "OpenSearch app name"
type = string
default = "opensearch"
}

variable "simple_opensearch_units" {
description = "Node count"
type = number
default = 1
}
Loading

0 comments on commit 1fa589c

Please sign in to comment.