Skip to content

Commit 8e49c32

Browse files
committed
feat(registry/coder/modules): add archive
1 parent cb990bb commit 8e49c32

File tree

6 files changed

+1153
-0
lines changed

6 files changed

+1153
-0
lines changed
Lines changed: 147 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,147 @@
1+
---
2+
display_name: Archive
3+
description: Create a user-invokable script that archives selected files/folders with gzip, zstd, or none.
4+
icon: ../../../../.icons/tool.svg
5+
verified: false
6+
tags: [backup, archive, tar, helper]
7+
---
8+
9+
# Archive
10+
11+
This module installs a small, robust script in your workspace that you can run to create a tar archive from a list of files and directories. It supports gzip, zstd, or no compression, prints only the resulting archive path to stdout, and writes all status/log output to stderr.
12+
13+
The module can also optionally run on workspace stop to automatically create an archive.
14+
15+
- Depends on: `tar` (and `gzip` or `zstd` if you select those compression modes)
16+
- Script install location: `$CODER_SCRIPT_BIN_DIR/coder-archive-create` and `$CODER_SCRIPT_BIN_DIR/coder-archive-extract`
17+
- Default wrapper names: `coder-archive-create` and `coder-archive-extract` (customize via `create_script_name` and `extract_script_name`)
18+
- The installer script (run_on_start) decodes and writes a library (`archive-lib.sh`) to `$CODER_SCRIPT_DATA_DIR`, and generates wrappers in `$CODER_SCRIPT_BIN_DIR` (default names `coder-archive-create` and `coder-archive-extract`) that:
19+
- injects DEFAULT*\* values from Terraform (via TF*\* variables) into the wrapper
20+
- sources `$CODER_SCRIPT_DATA_DIR/archive-lib.sh`
21+
- executes `create_archive "$@"` (and for extraction, `extract_archive "$@"`)
22+
- The stop script (when `create_archive_on_stop = true`) runs the create wrapper.
23+
24+
## Features
25+
26+
- Archive selected paths into a single `.tar`, `.tar.gz`, or `.tar.zst`.
27+
- Compression algorithms: `gzip`, `zstd`, `none`.
28+
- Optional custom output directory and archive base name.
29+
- Newline-delimited include list, plus extra paths provided at runtime.
30+
- Industry-standard Bash best practices (strict mode, safe path handling, non-clobbering outputs).
31+
- Prints only the final archive path to stdout; all other messages go to stderr.
32+
- Optional `run_on_stop` script to create an archive automatically when the workspace stops.
33+
34+
## Usage
35+
36+
Basic example:
37+
38+
module "archive" {
39+
count = data.coder_workspace.me.start_count
40+
source = "registry.coder.com/coder/archive/coder"
41+
version = "0.0.1"
42+
agent_id = coder_agent.example.id
43+
44+
# Paths to include in the archive (files or directories)
45+
paths = [
46+
"~/project",
47+
"~/notes.txt",
48+
"/var/log/some-app",
49+
]
50+
}
51+
52+
Customize compression and output:
53+
54+
module "archive" {
55+
count = data.coder_workspace.me.start_count
56+
source = "registry.coder.com/coder/archive/coder"
57+
version = "0.0.1"
58+
agent_id = coder_agent.example.id
59+
60+
paths = ["~/project", "~/notes.txt"]
61+
compression = "zstd" # "gzip" | "zstd" | "none"
62+
output_dir = "~/backups" # defaults to /tmp
63+
archive_name = "my-backup" # base name without extension
64+
# script_name = "my-archiver" # optional alternative script filename
65+
}
66+
67+
Enable auto-archive on stop:
68+
69+
module "archive" {
70+
count = data.coder_workspace.me.start_count
71+
source = "registry.coder.com/coder/archive/coder"
72+
version = "0.0.1"
73+
agent_id = coder_agent.example.id
74+
75+
paths = ["~/project", "~/notes.txt"]
76+
compression = "gzip"
77+
run_on_stop = true
78+
}
79+
80+
## Running the script
81+
82+
Once the workspace starts, the module installs a script:
83+
84+
- Paths: `$CODER_SCRIPT_BIN_DIR/coder-archive-create` and `$CODER_SCRIPT_BIN_DIR/coder-archive-extract` (installed by a run_on_start installer)
85+
- Usage:
86+
87+
coder-archive-create [options] [extra_paths...]
88+
-c, --compression <gzip|zstd|none> Compression algorithm (default from module)
89+
-o, --output-dir <dir> Output directory (default: /tmp)
90+
-n, --name <name> Archive base name without extension (default: workspace-backup-<timestamp>)
91+
-h, --help Show help
92+
93+
Examples:
94+
95+
- Use module defaults:
96+
97+
coder-archive-create
98+
99+
- Override compression and output directory at runtime:
100+
101+
coder-archive-create --compression zstd --output-dir ~/backups
102+
103+
- Add extra paths on the fly:
104+
105+
coder-archive-create ~/extra-file.txt /tmp/scratch
106+
107+
- Print archive path to a file (keeps logs out of the captured output):
108+
109+
coder-archive-create 1> ~/last-archive-path.txt
110+
111+
Notes:
112+
113+
- Only the final archive path is printed to stdout. All other output (progress, warnings, errors) goes to stderr.
114+
- The script ensures the output filename does not overwrite existing archives by appending a numeric suffix when necessary.
115+
116+
## Inputs
117+
118+
- `agent_id` (string, required): ID of the Coder agent.
119+
- `paths` (list(string), required): Files/directories to include in the archive.
120+
- `compression` (string, optional, default: `"gzip"`): One of `gzip`, `zstd`, or `none`.
121+
- `archive_name` (string, optional, default: `""`): Base name without extension. If empty, a name like `workspace-backup-<timestamp>` is generated.
122+
- `output_dir` (string, optional, default: `"/tmp"`): Where to write the archive.
123+
- `create_archive_on_stop` (bool, optional, default: `false`): If `true`, creates a `run_on_stop` script that runs the create wrapper on workspace stop.
124+
- `create_script_name` (string, optional, default: `"coder-archive-create"`): The create wrapper filename installed into `$CODER_SCRIPT_BIN_DIR`.<br>
125+
- `extract_script_name` (string, optional, default: `"coder-archive-extract"`): The extract wrapper filename installed into `$CODER_SCRIPT_BIN_DIR`.<br>
126+
- `extract_on_start` (bool, optional, default: `false`): If `true`, waits for a matching archive and extracts it on start.<br>
127+
- `extract_timeout_seconds` (number, optional, default: `60`): Max seconds to wait for an archive when `extract_on_start` is enabled.<br>
128+
- `extract_interval_seconds` (number, optional, default: `2`): Poll interval (seconds) when waiting for an archive on start.
129+
130+
## Outputs
131+
132+
- `archive_path` (string): Expected archive path if `archive_name` is set; empty if `archive_name` is not set.
133+
134+
## Requirements
135+
136+
- `tar` is required.
137+
- `gzip` is required if `compression = "gzip"`.
138+
- `zstd` is required if `compression = "zstd"`.
139+
140+
## Behavior
141+
142+
- Installs `$CODER_SCRIPT_DATA_DIR/archive-lib.sh` and two wrappers in `$CODER_SCRIPT_BIN_DIR`; wrappers set defaults, source the library, and run `create_archive`/`extract_archive`. If `extract_on_start` is true, the installer waits and extracts before finishing.
143+
- Paths with spaces are handled safely by passing them to `tar` as separate arguments (not via a files-from list).
144+
- `~` is expanded to `$HOME` for inputs and outputs.
145+
- Missing or invalid include paths are safely skipped with warnings.
146+
- The module will not overwrite existing archives; it appends a numeric suffix to the filename when necessary.
147+
- The script sets a restrictive umask (`077`) so archives are only readable by the user by default.
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# Minimal terraform tests for the archive module
2+
3+
mock_provider "coder" {}
4+
5+
run "apply_defaults" {
6+
command = apply
7+
8+
variables {
9+
agent_id = "agent-123"
10+
paths = ["~/project", "/etc/hosts"]
11+
}
12+
13+
14+
15+
16+
17+
assert {
18+
condition = output.archive_path == ""
19+
error_message = "archive_path should be empty when archive_name is not set"
20+
}
21+
}
22+
23+
run "apply_with_name" {
24+
command = apply
25+
26+
variables {
27+
agent_id = "agent-123"
28+
paths = ["/etc/hosts"]
29+
archive_name = "nightly"
30+
output_dir = "/tmp/backups"
31+
compression = "zstd"
32+
create_archive_on_stop = true
33+
create_script_name = "custom-archiver"
34+
}
35+
36+
assert {
37+
condition = output.archive_path == "/tmp/backups/nightly.tar.zst"
38+
error_message = "archive_path should be computed from archive_name + output_dir + extension"
39+
}
40+
41+
42+
43+
44+
}

0 commit comments

Comments
 (0)