Skip to content

Commit

Permalink
Merge pull request #6 from Ontotext-AD/TES-303-Backup-Module
Browse files Browse the repository at this point in the history
TES-303 backup module
  • Loading branch information
viktor-ribchev authored Nov 22, 2023
2 parents be32703 + 111b768 commit 6ffa7b7
Show file tree
Hide file tree
Showing 13 changed files with 272 additions and 3 deletions.
4 changes: 3 additions & 1 deletion .terraform.lock.hcl

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

21 changes: 21 additions & 0 deletions main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ module "configuration" {
key_vault_id = module.vault.key_vault_id
identity_principal_id = module.identity.identity_principal_id

graphdb_password = var.graphdb_password
graphdb_license_path = var.graphdb_license_path
graphdb_cluster_token = var.graphdb_cluster_token
graphdb_properties_path = var.graphdb_properties_path
Expand Down Expand Up @@ -221,8 +222,28 @@ module "vm" {

custom_user_data = var.custom_graphdb_vm_user_data

backup_schedule = var.backup_schedule

tags = local.tags

# Wait for configurations to be created in the key vault and roles to be assigned
depends_on = [module.configuration]
}

module "backup" {
source = "./modules/backup"

resource_name_prefix = var.resource_name_prefix
resource_group_name = azurerm_resource_group.graphdb.name
storage_account_tier = var.storage_account_tier
storage_account_replication_type = var.storage_account_replication_type
identity_name = module.identity.identity_name
location = var.location
identity_principal_id = module.identity.identity_principal_id

tags = local.tags

depends_on = [
azurerm_resource_group.graphdb
]
}
Empty file added modules/backup/README.md
Empty file.
56 changes: 56 additions & 0 deletions modules/backup/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
# Create an Azure Storage Account for backups
resource "azurerm_storage_account" "backup" {
name = "${var.resource_name_prefix}2graphdbbackup"
resource_group_name = var.resource_group_name
location = var.location
account_tier = var.storage_account_tier
account_replication_type = var.storage_account_replication_type
enable_https_traffic_only = true
min_tls_version = "TLS1_2"

tags = var.tags
}

# Create an Azure Storage container
resource "azurerm_storage_container" "backup" {
name = "${var.resource_name_prefix}-backup"
storage_account_name = azurerm_storage_account.backup.name
container_access_type = "private"
}

# Create an Azure Storage blob
resource "azurerm_storage_blob" "backup" {
name = "${var.resource_name_prefix}-backup"
type = "Block"
storage_account_name = azurerm_storage_account.backup.name
storage_container_name = azurerm_storage_container.backup.name
}

resource "azurerm_role_assignment" "backup" {
principal_id = var.identity_principal_id
role_definition_name = "Storage Blob Data Contributor"
scope = azurerm_storage_account.backup.id
}

resource "azurerm_storage_management_policy" "retention" {
storage_account_id = azurerm_storage_account.backup.id

rule {
enabled = true
name = "31DayRetention"
filters {
blob_types = ["blockBlob", "appendBlob"]
}
actions {
base_blob {
delete_after_days_since_modification_greater_than = 31
}
snapshot {
delete_after_days_since_creation_greater_than = 31
}
version {
delete_after_days_since_creation = 31
}
}
}
}
8 changes: 8 additions & 0 deletions modules/backup/outputs.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
output "storage_account_name" {
description = "Storage account name for storing GraphDB backups"
value = azurerm_storage_account.backup.name
}

output "container_name" {
value = azurerm_storage_container.backup.name
}
41 changes: 41 additions & 0 deletions modules/backup/variables.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
variable "resource_name_prefix" {
description = "Resource name prefix used for tagging and naming Azure resources"
type = string
}

variable "resource_group_name" {
description = "Specifies the name of the Azure resource group in which the Azure Storage Account will be created"
type = string
}

variable "storage_account_tier" {
default = "Standard"
description = "Specify the performance and redundancy characteristics of the Azure Storage Account that you are creating"
type = string
}

variable "storage_account_replication_type" {
default = "LRS"
description = "Specify the data redundancy strategy for your Azure Storage Account"
}

variable "tags" {
description = "Common resource tags."
type = map(string)
default = {}
}

variable "identity_name" {
description = "Name of a user assigned identity for assigning permissions"
type = string
}

variable "location" {
description = "Azure geographical location where resources will be deployed"
type = string
}

variable "identity_principal_id" {
description = "Principal identifier of a user assigned identity for assigning permissions"
type = string
}
10 changes: 10 additions & 0 deletions modules/backup/versions.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
terraform {
required_version = ">= 1.3.1"

required_providers {
azurerm = {
source = "hashicorp/azurerm"
version = ">=3.76.0"
}
}
}
15 changes: 15 additions & 0 deletions modules/configuration/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,14 @@ resource "random_password" "graphdb-cluster-token" {
special = true
}

resource "random_password" "graphdb-password" {
count = var.graphdb_cluster_token != null ? 0 : 1
length = 8
}

locals {
graphdb_cluster_token = var.graphdb_cluster_token != null ? var.graphdb_cluster_token : random_password.graphdb-cluster-token[0].result
graphdb_password = var.graphdb_password != null ? var.graphdb_password : random_password.graphdb-password[0].result
}

resource "azurerm_key_vault_secret" "graphdb-license" {
Expand All @@ -26,6 +32,15 @@ resource "azurerm_key_vault_secret" "graphdb-cluster-token" {
tags = var.tags
}

resource "azurerm_key_vault_secret" "graphdb-password" {
key_vault_id = var.key_vault_id

name = var.graphdb_cluster_token_name
value = base64encode(local.graphdb_cluster_token)

tags = var.tags
}

resource "azurerm_key_vault_secret" "graphdb-properties" {
count = var.graphdb_properties_path != null ? 1 : 0

Expand Down
6 changes: 6 additions & 0 deletions modules/configuration/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,12 @@ variable "graphdb_cluster_token" {
default = null
}

variable "graphdb_password" {
description = "Secret token used to access GraphDB cluster."
type = string
default = null
}

variable "graphdb_cluster_token_name" {
description = "Name of the Key Vault secret that contains the GraphDB cluster secret token."
type = string
Expand Down
29 changes: 28 additions & 1 deletion modules/vm/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,11 @@ locals {
disk_iops_read_write : var.disk_iops_read_write
disk_mbps_read_write : var.disk_mbps_read_write
disk_size_gb : var.disk_size_gb
backup_schedule : var.backup_schedule
})
}

# Create virtual machine
# Create virtual machine scale set
resource "azurerm_linux_virtual_machine_scale_set" "graphdb" {
name = var.resource_name_prefix
resource_group_name = var.resource_group_name
Expand Down Expand Up @@ -133,3 +134,29 @@ resource "azurerm_role_assignment" "rg-contributor-role" {
role_definition_name = "ManagedDiskManager"
depends_on = [azurerm_role_definition.managed_disk_manager]
}

resource "azurerm_role_definition" "backup_role" {
name = "ReadOnlyVMSSStorageRole"
scope = var.resource_group_id
description = "This is a custom role created via Terraform required for creating backups in GraphDB"

permissions {
actions = [
"Microsoft.Compute/virtualMachineScaleSets/read",
"Microsoft.Storage/storageAccounts/read"
]
not_actions = []
}

assignable_scopes = [
var.resource_group_id
]
}

resource "azurerm_role_assignment" "rg-reader-role" {
principal_id = var.identity_principal_id
scope = var.resource_group_id
role_definition_name = "ReadOnlyVMSSStorageRole"
depends_on = [azurerm_role_definition.backup_role]
}

53 changes: 52 additions & 1 deletion modules/vm/templates/entrypoint.sh.tpl
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,58 @@ if [[ $secrets == *"graphdb-java-options"* ]]; then
)
fi

# TODO: Backup cron
# Configure the GraphDB backup cron job

cat <<-EOF > /usr/bin/graphdb_backup
#!/bin/bash
set -euxo pipefail
az login --identity
RESOURCE_GROUP="\$(az vmss list --query "[0].resourceGroup" --output tsv)"
# TODO change secret name when exists
GRAPHDB_ADMIN_PASSWORD="\$(az keyvault secret show --vault-name ${key_vault_name} --name graphdb-password --query "value" --output tsv)"
NODE_STATE="\$(curl --silent --fail --user "admin:\$GRAPHDB_ADMIN_PASSWORD" localhost:7200/rest/cluster/node/status | jq -r .nodeState)"
if [ "\$NODE_STATE" != "LEADER" ]; then
echo "current node is not a leader, but \$NODE_STATE"
exit 0
fi
BACKUP_NAME="\$(date +'%Y-%m-%d_%H-%M-%S').tar"
TEMP_BACKUP_DIR="/var/opt/graphdb/"
STORAGE_ACCOUNT="\$(az storage account list --resource-group "\$RESOURCE_GROUP" --query "[].name" --output tsv)"
CONTAINER_NAME="\$(az storage container list --account-name "\$STORAGE_ACCOUNT" --query "[].name" --output tsv --auth-mode login)"
BLOB_URL="\$(az storage blob url --account-name "\$STORAGE_ACCOUNT" --container-name "\$CONTAINER_NAME" --name "\$BACKUP_NAME" --auth-mode login --output tsv)"
function trigger_backup {
curl -X POST --output "\$${TEMP_BACKUP_DIR}\$${BACKUP_NAME}" -H 'Content-Type: application/json' 'http://localhost:7200/rest/recovery/backup'
upload_to_azure_storage
}
function upload_to_azure_storage {
az storage blob upload --file "\$${TEMP_BACKUP_DIR}\$${BACKUP_NAME}" --blob-url "\$BLOB_URL" --auth-mode login --validate-content
}
trigger_backup
# Delete local backup file after upload
rm "\$${TEMP_BACKUP_DIR}\$${BACKUP_NAME}"
echo "Backup and upload completed successfully."
EOF

chmod +x /usr/bin/graphdb_backup
echo "${backup_schedule} graphdb /usr/bin/graphdb_backup" > /etc/cron.d/graphdb_backup

# Set keepalive and file max size
echo 'net.ipv4.tcp_keepalive_time = 120' | tee -a /etc/sysctl.conf
echo 'fs.file-max = 262144' | tee -a /etc/sysctl.conf

sysctl -p

# TODO: Monitoring/instrumenting

Expand Down
5 changes: 5 additions & 0 deletions modules/vm/variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -131,3 +131,8 @@ variable "disk_mbps_read_write" {
type = number
default = null
}

variable "backup_schedule" {
description = "Cron expression for the backup job."
type = string
}
27 changes: 27 additions & 0 deletions variables.tf
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,12 @@ variable "graphdb_cluster_token" {
default = null
}

variable "graphdb_password" {
description = "Secret token used to access GraphDB cluster."
type = string
default = null
}

variable "graphdb_properties_path" {
description = "Path to a local file containing GraphDB properties (graphdb.properties) that would be appended to the default in the VM."
type = string
Expand Down Expand Up @@ -131,6 +137,27 @@ variable "custom_graphdb_vm_user_data" {
default = null
}

# Storage account

variable "storage_account_tier" {
default = "Standard"
description = "Specify the performance and redundancy characteristics of the Azure Storage Account that you are creating"
type = string
}

variable "storage_account_replication_type" {
default = "LRS"
description = "Specify the data redundancy strategy for your Azure Storage Account"
}

# Backup configurations

variable "backup_schedule" {
description = "Cron expression for the backup job."
type = string
default = "0 0 * * *"
}

# Data disks

variable "disk_size_gb" {
Expand Down

0 comments on commit 6ffa7b7

Please sign in to comment.