Skip to content

Commit

Permalink
DCCLIP-913: Restore OpenSearch from snapshot (#384)
Browse files Browse the repository at this point in the history
* DCCLIP-912: Mention in docs that OpenSearch is only supported from Confluence 8.9.0.

* DCCLIP-913: Restore OpenSearch from snapshot if EBS volume snapshot id is provided.

* DCCLIP-913: Added variable for OpenSearch persistence volume size.

* DCCLIP-913: Added docs.

* DCCLIP-913: Made OpenSearch password configurable.
  • Loading branch information
yzha645 authored Apr 29, 2024
1 parent d7a1475 commit a22a7e4
Show file tree
Hide file tree
Showing 13 changed files with 207 additions and 13 deletions.
9 changes: 9 additions & 0 deletions config.tfvars
Original file line number Diff line number Diff line change
Expand Up @@ -407,9 +407,18 @@ confluence_collaborative_editing_enabled = true
#confluence_s3_attachments_storage = true

# Enable OpenSearch as Confluence search engine and configure resource requests and limits
# It is only supported from Confluence 8.9.0. See: https://confluence.atlassian.com/doc/configuring-opensearch-for-confluence-1387594125.html
# confluence_opensearch_enabled = false
# confluence_opensearch_requests_cpu = "<REQUESTS_CPU>"
# confluence_opensearch_requests_memory = "<REQUESTS_MEMORY>"
# confluence_opensearch_persistence_size = "<PERSISTENCE_SIZE>"
# confluence_opensearch_initial_admin_password = "<STRONG_PASSWORD>"

# OpenSearch restore configuration
# To restore OpenSearch dataset, you can provide EBS snapshot ID of the OpenSearch volume.
# This volume will be used to pre-create OpenSearch PVC and PV.
# Make sure the snapshot is available in the region you are deploying to and follows all product requirements.
# confluence_opensearch_snapshot_id = "<OPENSEARCH_SNAPSHOT_ID>"

################################################################################
# Bitbucket Settings
Expand Down
3 changes: 3 additions & 0 deletions dc-infrastructure.tf
Original file line number Diff line number Diff line change
Expand Up @@ -246,6 +246,9 @@ module "confluence" {
opensearch_enabled = var.confluence_opensearch_enabled
opensearch_requests_cpu = var.confluence_opensearch_requests_cpu
opensearch_requests_memory = var.confluence_opensearch_requests_memory
opensearch_snapshot_id = var.confluence_opensearch_snapshot_id
opensearch_persistence_size = var.confluence_opensearch_persistence_size
opensearch_initial_admin_password = var.confluence_opensearch_initial_admin_password
}

module "bitbucket" {
Expand Down
30 changes: 29 additions & 1 deletion docs/docs/userguide/configuration/CONFLUENCE_CONFIGURATION.md
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,9 @@ confluence_shared_home_snapshot_id = "<SHARED_HOME_EBS_SNAPSHOT_IDENTIFIER>"
??? Warning "Snapshot and your environment must be in same region"

## Search engine configuration
Starting from Confluence 8.9.0, OpenSearch is supported as search engine.
See: https://confluence.atlassian.com/doc/configuring-opensearch-for-confluence-1387594125.html

### OpenSearch
`confluence_opensearch_enabled` decides whether to use OpenSearch as Confluence search engine. If set to true,
a single-node OpenSearch will be created as part of the deployment, and Confluence will be configured to connect to this instance.
Expand All @@ -258,4 +261,29 @@ The following variables set number of CPU and amount of memory of OpenSearch ins
```terraform
confluence_opensearch_requests_cpu = "1"
confluence_opensearch_requests_memory = "1Gi"
```
```

### OpenSearch persistent volume size
`confluence_opensearch_persistence_size` sets the size of OpenSearch's persistence volume. (Used default values as example.)

```terraform
confluence_opensearch_persistence_size = "10Gi"
```

### OpenSearch initial admin password
From OpenSearch Helm chart version 2.18.0 and App Version OpenSearch 2.12.0 onwards a custom strong password needs to be provided in order to setup demo admin user.
If no password is specified, a random password will be generated.

```terraform
confluence_opensearch_initial_admin_password = "OpenSearchAtl123!"
```

### OpenSearch restore configuration
To restore OpenSearch dataset, you can provide EBS snapshot ID of the OpenSearch volume. This volume will be used to pre-create OpenSearch PVC and PV.

`confluence_opensearch_snapshot_id` sets the id of OpenSearch EBS snapshot.
Make sure the snapshot is available in the region you are deploying to and follows all product requirements.

```terraform
confluence_opensearch_snapshot_id = "<OPENSEARCH_SNAPSHOT_ID>"
```
3 changes: 2 additions & 1 deletion modules/products/confluence/helm.tf
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ resource "helm_release" "confluence" {
depends_on = [
kubernetes_job.pre_install,
kubernetes_persistent_volume_claim.local_home,
time_sleep.wait_confluence_termination
time_sleep.wait_confluence_termination,
kubernetes_persistent_volume_claim.opensearch,
]
name = local.product_name
namespace = var.namespace
Expand Down
18 changes: 15 additions & 3 deletions modules/products/confluence/locals.tf
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,15 @@ locals {
memory = var.opensearch_requests_memory
}
}
persistence = {
size = var.opensearch_persistence_size
}
credentials = {
createSecret = false
existingSecretRef = {
name = "opensearch-initial-password"
}
}
}
}) : yamlencode({})

Expand Down Expand Up @@ -121,9 +130,11 @@ locals {
# DC App Performance Toolkit analytics
dcapt_analytics_property = ["-Dcom.atlassian.dcapt.deployment=terraform"]

irsa_properties = var.confluence_s3_attachments_storage ? ["-Daws.webIdentityTokenFile=/var/run/secrets/eks.amazonaws.com/serviceaccount/token",
irsa_properties = var.confluence_s3_attachments_storage ? [
"-Daws.webIdentityTokenFile=/var/run/secrets/eks.amazonaws.com/serviceaccount/token",
"-Dconfluence.filestore.attachments.s3.bucket.name=${var.eks.confluence_s3_bucket_name}",
"-Dconfluence.filestore.attachments.s3.bucket.region=${var.region_name}"] : []
"-Dconfluence.filestore.attachments.s3.bucket.region=${var.region_name}"
] : []

service_account_annotations = var.confluence_s3_attachments_storage ? yamlencode({
serviceAccount = {
Expand All @@ -133,5 +144,6 @@ locals {
}
}) : yamlencode({})

storage_class = "gp2"
storage_class = "gp2"
opensearch_storage_class = "gp2"
}
61 changes: 61 additions & 0 deletions modules/products/confluence/opensearch_storage.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
data "aws_ebs_snapshot" "opensearch_snapshot" {
count = var.opensearch_enabled && var.opensearch_snapshot_id != null ? 1 : 0

snapshot_ids = [var.opensearch_snapshot_id]
most_recent = true
}

resource "aws_ebs_volume" "opensearch" {
count = var.opensearch_enabled && var.opensearch_snapshot_id != null ? 1 : 0

availability_zone = var.eks.availability_zone
snapshot_id = var.opensearch_snapshot_id
size = data.aws_ebs_snapshot.opensearch_snapshot[0].volume_size
type = local.opensearch_storage_class
tags = {
Name = "confluence-opensearch"
}
}

resource "kubernetes_persistent_volume" "opensearch" {
count = var.opensearch_enabled && var.opensearch_snapshot_id != null ? 1 : 0

metadata {
name = "confluence-opensearch-pv"
}
spec {
access_modes = ["ReadWriteOnce"]
capacity = {
storage = data.aws_ebs_snapshot.opensearch_snapshot[0].volume_size
}
storage_class_name = local.opensearch_storage_class
persistent_volume_source {
aws_elastic_block_store {
volume_id = aws_ebs_volume.opensearch[0].id
}
}
claim_ref {
name = "opensearch-cluster-master-opensearch-cluster-master-0"
namespace = var.namespace
}
}
}

resource "kubernetes_persistent_volume_claim" "opensearch" {
count = var.opensearch_enabled && var.opensearch_snapshot_id != null ? 1 : 0

metadata {
name = "opensearch-cluster-master-opensearch-cluster-master-0"
namespace = var.namespace
}
spec {
access_modes = ["ReadWriteOnce"]
resources {
requests = {
storage = data.aws_ebs_snapshot.opensearch_snapshot[0].volume_size
}
}
storage_class_name = local.opensearch_storage_class
volume_name = kubernetes_persistent_volume.opensearch[0].metadata.0.name
}
}
4 changes: 4 additions & 0 deletions modules/products/confluence/provider_version.tf
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,9 @@ terraform {
helm = {
version = "~> 2.4"
}
random = {
source = "hashicorp/random"
version = "3.6.1"
}
}
}
21 changes: 21 additions & 0 deletions modules/products/confluence/secrets.tf
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,24 @@ resource "kubernetes_secret" "license_secret" {
license-key = var.confluence_configuration["license"]
}
}

################################################################################
# Kubernetes secret to store OpenSearch initial password
################################################################################
resource "kubernetes_secret" "opensearch_secret" {
count = var.opensearch_enabled ? 1 : 0

metadata {
name = "opensearch-initial-password"
namespace = var.namespace
}

data = {
OPENSEARCH_INITIAL_ADMIN_PASSWORD = var.opensearch_initial_admin_password != null ? var.opensearch_initial_admin_password : random_password.opensearch.result
}
}

resource "random_password" "opensearch" {
length = 16
special = true
}
18 changes: 18 additions & 0 deletions modules/products/confluence/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -193,4 +193,22 @@ variable "opensearch_requests_memory" {
description = "The minimum amount of memory to allocate to the OpenSearch instance"
type = string
default = "1Gi"
}

variable "opensearch_persistence_size" {
description = "OpenSearch persistent volume size"
type = string
default = "10Gi"
}

variable "opensearch_initial_admin_password" {
description = "OpenSearch initial admin password"
type = string
default = null
}

variable "opensearch_snapshot_id" {
description = "EBS Snapshot ID with OpenSearch data."
type = string
default = null
}
4 changes: 4 additions & 0 deletions provider_version.tf
Original file line number Diff line number Diff line change
Expand Up @@ -9,5 +9,9 @@ terraform {
helm = {
version = "~> 2.4"
}
random = {
source = "hashicorp/random"
version = "3.6.1"
}
}
}
4 changes: 4 additions & 0 deletions providers.tf
Original file line number Diff line number Diff line change
Expand Up @@ -28,4 +28,8 @@ provider "helm" {
command = "aws"
}
}
}

provider "random" {
# Configuration options
}
19 changes: 11 additions & 8 deletions test/unittest/confluence_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ func TestConfluenceVariablesPopulatedWithValidValues(t *testing.T) {
tfOptions := GenerateTFOptions(ConfluenceCorrectVariables, t, confluenceModule)
plan := terraform.InitAndPlanAndShowWithStruct(t, tfOptions)

terraform.RequirePlannedValuesMapKeyExists(t, plan, "random_password.opensearch")

confluenceKey := "helm_release.confluence"
terraform.RequirePlannedValuesMapKeyExists(t, plan, confluenceKey)
confluence := plan.ResourcePlannedValuesMap[confluenceKey]
Expand All @@ -24,7 +26,7 @@ func TestConfluenceVariablesPopulatedWithValidValues(t *testing.T) {
assert.Equal(t, float64(testTimeout*60), confluence.AttributeValues["timeout"])
assert.Equal(t, "https://atlassian.github.io/data-center-helm-charts", confluence.AttributeValues["repository"])
openSearchValues := confluence.AttributeValues["values"].([]interface{})[9].(string)
assert.Equal(t, "\"opensearch\":\n \"enabled\": true\n \"resources\":\n \"requests\":\n \"cpu\": \"2\"\n \"memory\": \"2Gi\"\n", openSearchValues)
assert.Equal(t, "\"opensearch\":\n \"credentials\":\n \"createSecret\": false\n \"existingSecretRef\":\n \"name\": \"opensearch-initial-password\"\n \"enabled\": true\n \"persistence\":\n \"size\": \"10Gi\"\n \"resources\":\n \"requests\":\n \"cpu\": \"2\"\n \"memory\": \"2Gi\"\n", openSearchValues)
}

func TestConfluenceVariablesPopulatedWithInvalidValues(t *testing.T) {
Expand Down Expand Up @@ -114,11 +116,12 @@ var ConfluenceCorrectVariables = map[string]interface{}{
"max_heap": "1024m",
"stack_size": "1024k",
},
"enable_synchrony": false,
"db_snapshot_build_number": "1234",
"termination_grace_period": 0,
"additional_jvm_args": []string{},
"opensearch_enabled": true,
"opensearch_requests_cpu": "2",
"opensearch_requests_memory": "2Gi",
"enable_synchrony": false,
"db_snapshot_build_number": "1234",
"termination_grace_period": 0,
"additional_jvm_args": []string{},
"opensearch_enabled": true,
"opensearch_requests_cpu": "2",
"opensearch_requests_memory": "2Gi",
"opensearch_persistence_size": "10Gi",
}
26 changes: 26 additions & 0 deletions variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -752,6 +752,32 @@ variable "confluence_opensearch_requests_memory" {
default = "1Gi"
}

variable "confluence_opensearch_persistence_size" {
description = "OpenSearch persistent volume size"
type = string
default = "10Gi"
}

variable "confluence_opensearch_initial_admin_password" {
description = "Initial admin password for the Confluence OpenSearch instance."
type = string
default = null
validation {
condition = can(regex("^([aA-zZ]|[0-9]|[!@#$% &*()-_=+[]{}<>:?]).{12,}$", var.confluence_opensearch_initial_admin_password)) || var.confluence_opensearch_initial_admin_password == null
error_message = "Confluence OpenSearch initial password must be at least 12 characters long and contain combination of numbers, letters, and special characters."
}
}

variable "confluence_opensearch_snapshot_id" {
description = "EBS Snapshot ID with OpenSearch data."
type = string
default = null
validation {
condition = var.confluence_opensearch_snapshot_id == null || can(regex("^snap-\\w{17}$", var.confluence_opensearch_snapshot_id))
error_message = "Provide correct EBS snapshot ID."
}
}

################################################################################
# Bitbucket Variables
################################################################################
Expand Down

0 comments on commit a22a7e4

Please sign in to comment.