This change adds a new `archive` module to the Coder registry. It can be used to archive user-data from pre-defined locations and restore it as well. Here we also explore: - A new method of passing arrays from Terraform to Bash - A new method of writing Bash scripts that minimizes the interaction with terraform interpolation - Extensive test-suite that not only tests that Terraform options can be selected, but also the resulting script behaviors --------- Co-authored-by: Cian Johnston <cian@coder.com> Co-authored-by: DevCats <christofer@coder.com>
135 lines
4.6 KiB
HCL
135 lines
4.6 KiB
HCL
terraform {
|
|
required_version = ">= 1.0"
|
|
|
|
required_providers {
|
|
coder = {
|
|
source = "coder/coder"
|
|
version = ">= 0.12"
|
|
}
|
|
}
|
|
}
|
|
|
|
variable "agent_id" {
|
|
description = "The ID of a Coder agent."
|
|
type = string
|
|
}
|
|
|
|
variable "paths" {
|
|
description = "List of files/directories to include in the archive. Defaults to the current directory."
|
|
type = list(string)
|
|
default = ["."]
|
|
}
|
|
|
|
variable "exclude_patterns" {
|
|
description = "Exclude patterns for the archive."
|
|
type = list(string)
|
|
default = []
|
|
}
|
|
|
|
variable "compression" {
|
|
description = "Compression algorithm for the archive. Supported: gzip, zstd, none."
|
|
type = string
|
|
default = "gzip"
|
|
validation {
|
|
condition = contains(["gzip", "zstd", "none"], var.compression)
|
|
error_message = "compression must be one of: gzip, zstd, none."
|
|
}
|
|
}
|
|
|
|
variable "archive_name" {
|
|
description = "Optional archive base name without extension. If empty, defaults to \"coder-archive\"."
|
|
type = string
|
|
default = "coder-archive"
|
|
}
|
|
|
|
variable "output_dir" {
|
|
description = "Optional output directory where the archive will be written. Defaults to \"/tmp\"."
|
|
type = string
|
|
default = "/tmp"
|
|
}
|
|
|
|
variable "directory" {
|
|
description = "Change current directory to this path before creating or extracting the archive. Defaults to the user's home directory."
|
|
type = string
|
|
default = "~"
|
|
}
|
|
|
|
variable "create_on_stop" {
|
|
description = "If true, also create a run_on_stop script that creates the archive automatically on workspace stop."
|
|
type = bool
|
|
default = false
|
|
}
|
|
|
|
variable "extract_on_start" {
|
|
description = "If true, the installer will wait for an archive and extract it on start."
|
|
type = bool
|
|
default = false
|
|
}
|
|
|
|
variable "extract_wait_timeout_seconds" {
|
|
description = "Timeout (seconds) to wait for an archive when extract_on_start is true."
|
|
type = number
|
|
default = 5
|
|
}
|
|
|
|
# Provide a stable script filename and sensible defaults.
|
|
locals {
|
|
extension = var.compression == "gzip" ? ".tar.gz" : var.compression == "zstd" ? ".tar.zst" : ".tar"
|
|
|
|
# Ensure ~ is expanded because it cannot be expanded inside quotes in a
|
|
# templated shell script.
|
|
paths = [for v in var.paths : replace(v, "/^~(\\/|$)/", "$$HOME$1")]
|
|
exclude_patterns = [for v in var.exclude_patterns : replace(v, "/^~(\\/|$)/", "$$HOME$1")]
|
|
directory = replace(var.directory, "/^~(\\/|$)/", "$$HOME$1")
|
|
output_dir = replace(var.output_dir, "/^~(\\/|$)/", "$$HOME$1")
|
|
|
|
archive_path = "${local.output_dir}/${var.archive_name}${local.extension}"
|
|
}
|
|
|
|
output "archive_path" {
|
|
description = "Full path to the archive file that will be created, extracted, or both."
|
|
value = local.archive_path
|
|
}
|
|
|
|
# This script installs the user-facing archive script into $CODER_SCRIPT_BIN_DIR.
|
|
# The installed script can be run manually by the user to create an archive.
|
|
resource "coder_script" "archive_start_script" {
|
|
agent_id = var.agent_id
|
|
display_name = "Archive"
|
|
icon = "/icon/folder.svg"
|
|
run_on_start = true
|
|
start_blocks_login = var.extract_on_start
|
|
|
|
# Render the user-facing archive script with Terraform defaults, then write it to $CODER_SCRIPT_BIN_DIR
|
|
script = templatefile("${path.module}/run.sh", {
|
|
TF_LIB_B64 = base64encode(file("${path.module}/scripts/archive-lib.sh")),
|
|
TF_PATHS = join(" ", formatlist("%q", local.paths)),
|
|
TF_EXCLUDE_PATTERNS = join(" ", formatlist("%q", local.exclude_patterns)),
|
|
TF_COMPRESSION = var.compression,
|
|
TF_ARCHIVE_PATH = local.archive_path,
|
|
TF_DIRECTORY = local.directory,
|
|
TF_EXTRACT_ON_START = var.extract_on_start,
|
|
TF_EXTRACT_WAIT_TIMEOUT = var.extract_wait_timeout_seconds,
|
|
})
|
|
}
|
|
|
|
# Optionally, also register a run_on_stop script that creates the archive automatically
|
|
# when the workspace stops. It simply invokes the installed archive script.
|
|
resource "coder_script" "archive_stop_script" {
|
|
count = var.create_on_stop ? 1 : 0
|
|
agent_id = var.agent_id
|
|
display_name = "Archive"
|
|
icon = "/icon/folder.svg"
|
|
run_on_stop = true
|
|
start_blocks_login = false
|
|
|
|
# Call the installed script. It will log to stderr and print the archive path to stdout.
|
|
# We redirect stdout to stderr to avoid surfacing the path in system logs if undesired.
|
|
# Remove the redirection if you want the path to appear in stdout on stop as well.
|
|
script = <<-EOT
|
|
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
"$CODER_SCRIPT_BIN_DIR/coder-archive-create"
|
|
EOT
|
|
}
|