snapshot of https://github.com/seaweedfs/seaweedfs.git (master, 2026-09-16; blobs > 131072B omitted)
Some checks failed
go: build dev binaries / cleanup (push) Successful in 4s
Codespell / Check for spelling errors (push) Failing after 3s
docker: build dev containers / build-rust-binaries (amd64, x86_64-unknown-linux-musl) (push) Failing after 3s
docker: build dev containers / build-dev-containers (push) Has been skipped
docker: build dev containers / build-rust-binaries (arm64, true, aarch64-unknown-linux-musl) (push) Failing after 3s
End to End / FUSE Mount (push) Failing after 2s
EC Integration Tests / EC Integration Tests (push) Failing after 30s
FUSE DLM Integration Tests / FUSE DLM Integration Tests (push) Failing after 3s
FUSE Volume Server Failover Tests / FUSE Volume Server Failover (push) Failing after 3s
FUSE Integration Tests / FUSE Integration Testing (push) Failing after 2s
FUSE P2P Peer Chunk Sharing Integration Tests / FUSE P2P Peer Chunk Sharing (push) Failing after 3s
go: build binary / Go Vet (push) Failing after 2s
go: build binary / Go Vet 32-bit (push) Failing after 3s
go: build binary / Build (push) Failing after 4s
go: build binary / Build cross-platform (freebsd/amd64) (push) Failing after 3s
go: build binary / Build cross-platform (windows/amd64) (push) Failing after 3s
go: build binary / Build cross-platform (darwin/arm64) (push) Failing after 3s
go: build binary / Build cross-platform (windows/arm64) (push) Failing after 3s
go: build binary / Test (push) Failing after 2s
go: build binary / Test 32-bit (push) Failing after 3s
helm: lint and test charts / lint-test (push) Failing after 3s
Java Client Integration Tests / Java Integration Tests (11) (push) Failing after 3s
Java Client Integration Tests / Java Integration Tests (17) (push) Failing after 3s
go: build dev binaries / build_dev_linux_windows (amd64, linux) (push) Failing after 2s
go: build dev binaries / build_dev_linux_windows (amd64, windows) (push) Failing after 3s
go: build dev binaries / build_dev_darwin (amd64, darwin) (push) Has been skipped
go: build dev binaries / build_dev_darwin (arm64, darwin) (push) Has been skipped
Java Client Unit Tests / Java Unit Tests (11) (push) Failing after 3s
Java Client Unit Tests / Java Unit Tests (17) (push) Failing after 2s
Java Client Unit Tests / Java Unit Tests (21) (push) Failing after 3s
Java Client Unit Tests / Java Unit Tests (8) (push) Failing after 3s
Kafka Quick Test (Load Test with Schema Registry) / Kafka Client Load Test (Quick) (push) Failing after 3s
Kafka Gateway Tests / Kafka Unit Tests (unit-tests-1) (push) Failing after 11s
Kafka Gateway Tests / Kafka Integration Tests (Critical) (integration-1) (push) Failing after 3s
Kafka Gateway Tests / Kafka End-to-End Tests (with SMQ) (e2e-1) (push) Failing after 3s
Kafka Gateway Tests / Kafka Consumer Group Tests (Highly Isolated) (consumer-group-1) (push) Failing after 2s
Kafka Gateway Tests / Kafka Client Compatibility (with SMQ) (client-compat-1) (push) Failing after 3s
Kafka Gateway Tests / Kafka SMQ Integration Tests (Full Stack) (smq-integration-1) (push) Failing after 3s
Kafka Gateway Tests / Kafka Protocol Tests (Isolated) (protocol-1) (push) Failing after 3s
KMS Tests / KMS Provider Integration Tests (push) Failing after 2s
KMS Tests / S3 KMS End-to-End Tests (push) Failing after 3s
Master Cold Start Tests / Master Cold Start Tests (push) Failing after 4s
Metadata Subscribe Integration Tests / Metadata Subscribe Integration Tests (push) Failing after 3s
Multi-Master Tests / Multi-Master Failover Tests (push) Failing after 3s
Performance / CPU and Heap Profile (push) Failing after 2s
Performance / S3 Read/Write Benchmark (rust volume) (push) Failing after 3s
pjdfstest POSIX Compliance / pjdfstest (push) Failing after 2s
Plugin Worker Integration Tests / Plugin Worker: erasure_coding (push) Failing after 3s
Plugin Worker Integration Tests / Plugin Worker: vacuum (push) Failing after 3s
Rust Volume Server Tests / Rust Integration Tests (push) Failing after 3s
Rust Volume Server Tests / Go Tests with Rust Volume (grpc - Shard 1) (push) Failing after 2s
Rust Volume Server Tests / Go Tests with Rust Volume (http - Shard 1) (push) Failing after 3s
Rust Volume Server Tests / Go Tests with Rust Volume (grpc - Shard 2) (push) Failing after 3s
Rust Volume Server Tests / Go Tests with Rust Volume (http - Shard 2) (push) Failing after 3s
Rust Volume Server Tests / Go Tests with Rust Volume (grpc - Shard 3) (push) Failing after 3s
S3 IAM Integration Tests / S3 IAM Distributed Tests (push) Failing after 2s
S3 IAM Integration Tests / S3 IAM Performance Tests (push) Failing after 3s
Performance / Throughput Benchmark (go volume) (push) Failing after 3s
Performance / Throughput Benchmark (rust volume) (push) Failing after 2s
Performance / S3 Read/Write Benchmark (go volume) (push) Failing after 3s
Plugin Worker Integration Tests / Plugin Worker: volume_balance (push) Failing after 3s
PostgreSQL Gateway Tests / PostgreSQL Basic Tests (push) Failing after 3s
Rust Volume Server Tests / Rust Unit Tests (push) Failing after 2s
Rust Volume Server Tests / Go Tests with Rust Volume (http - Shard 3) (push) Failing after 3s
Rust Plugin Worker Tests / Rust Plugin Worker Build and Unit Tests (push) Failing after 3s
rust: build dev volume server binaries / cleanup (push) Successful in 3s
S3 ETag and ACL Tests / S3 ETag + ACL Integration Tests (push) Failing after 3s
S3 IAM Integration Tests / IAM Unit Tests (push) Failing after 3s
S3 IAM Integration Tests / S3 IAM Integration Tests (advanced) (push) Failing after 3s
S3 IAM Integration Tests / S3 IAM Integration Tests (basic) (push) Failing after 2s
S3 IAM Integration Tests / S3 IAM Integration Tests (group) (push) Failing after 3s
S3 IAM Integration Tests / S3 IAM Integration Tests (policy-enforcement) (push) Failing after 2s
S3 IAM Integration Tests / S3 IAM Integration Tests (sts) (push) Failing after 4s
S3 Keycloak Integration Tests / S3 Keycloak Integration Tests (push) Failing after 3s
S3 PyArrow Parquet Tests / PyArrow Parquet Tests (Python 3.11) (push) Failing after 3s
S3 PyArrow Parquet Tests / Go Unit Tests (Implicit Directory) (push) Has been cancelled
S3 PyArrow Parquet Tests / PyArrow Parquet Tests (Python 3.12) (push) Has been cancelled
rust: build dev volume server binaries / build-rust-volume-dev-darwin (darwin-amd64, x86_64-apple-darwin) (push) Has been cancelled
rust: build dev volume server binaries / build-rust-volume-dev-darwin (darwin-arm64, aarch64-apple-darwin) (push) Has been cancelled
rust: build dev volume server binaries / build-rust-volume-dev-linux (linux-amd64, x86_64-unknown-linux-gnu) (push) Has been cancelled
S3 PyArrow Parquet Tests / PyArrow Parquet Tests (Python 3.9) (push) Has been cancelled
S3 Proxy Signature Tests / S3 Proxy Signature Verification Tests (push) Has been cancelled
S3 SDK V2 Route Disambiguation Tests / S3 SDK V2 Routing Tests (push) Has been cancelled
S3 SSE Tests / S3 SSE Integration Tests (quick) (push) Has been cancelled
S3 SSE Tests / S3 SSE Compatibility Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Metadata Persistence Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Copy Operations Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Multipart Upload Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Performance Test (push) Has been cancelled
S3 SSE Tests / S3 Volume Encryption Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Integration Tests (comprehensive) (push) Has been cancelled
Spark Integration Tests / Spark Integration Tests (push) Failing after 2s
Telemetry Integration Tests / telemetry-integration-test (push) Failing after 3s
Volume Server Integration Tests / Volume Server Integration Tests (grpc - Shard 1) (push) Failing after 3s
Volume Server Integration Tests / Volume Server Integration Tests (http - Shard 1) (push) Failing after 3s
Ceph S3 tests / Basic S3 tests (KV store) (push) Has been cancelled
Ceph S3 tests / S3 Versioning & Object Lock tests (push) Has been cancelled
S3 Policy Integration Tests / S3 Policy Unit Tests (push) Failing after 3s
Ceph S3 tests / S3 CORS tests (push) Has been cancelled
Ceph S3 tests / SeaweedFS Custom S3 Copy tests (push) Has been cancelled
Ceph S3 tests / Basic S3 tests (SQL store) (push) Has been cancelled
test s3 over https using aws-cli / awscli-tests (push) Has been cancelled
TLS Rotation Integration Tests / TLS Rotation Integration Tests (push) Has been cancelled
Vacuum Integration Tests / Vacuum Integration Tests (push) Has been cancelled
S3 Policy Integration Tests / S3 Policy Variables Integration Tests (push) Failing after 3s
S3 Policy Integration Tests / S3 Policy Enforcement Integration Tests (advanced-policy) (push) Failing after 3s
S3 Policy Integration Tests / S3 Policy Enforcement Integration Tests (basic-policy) (push) Failing after 2s
S3 Policy Integration Tests / S3 Policy Enforcement Integration Tests (contextual-policy) (push) Failing after 4s
S3 Policy Integration Tests / Trusted Proxy Detection Tests (push) Failing after 2s
S3 Policy Integration Tests / S3 Policy Shell Integration Tests (push) Failing after 3s
Samba on FUSE Integration / samba-integration (push) Failing after 2s
SFTP Integration Tests / SFTP Integration Testing (push) Failing after 3s
terraform: validate and test modules / fmt, validate, plan-level tests (push) Failing after 3s
terraform: validate and test modules / local cluster smoke test (real weed) (push) Failing after 2s
Volume Server Integration Tests / Volume Server Integration Tests (grpc - Shard 3) (push) Failing after 3s
Volume Server Integration Tests / Volume Server Integration Tests (grpc - Shard 2) (push) Failing after 3s
Volume Server Integration Tests / Volume Server Integration Tests (http - Shard 2) (push) Failing after 2s
Volume Server Integration Tests / Volume Server Integration Tests (http - Shard 3) (push) Failing after 5s
mount: windows conformance / WinFsp conformance (push) Has been cancelled
mount: windows / Mount on Windows (push) Has been cancelled
Some checks failed
go: build dev binaries / cleanup (push) Successful in 4s
Codespell / Check for spelling errors (push) Failing after 3s
docker: build dev containers / build-rust-binaries (amd64, x86_64-unknown-linux-musl) (push) Failing after 3s
docker: build dev containers / build-dev-containers (push) Has been skipped
docker: build dev containers / build-rust-binaries (arm64, true, aarch64-unknown-linux-musl) (push) Failing after 3s
End to End / FUSE Mount (push) Failing after 2s
EC Integration Tests / EC Integration Tests (push) Failing after 30s
FUSE DLM Integration Tests / FUSE DLM Integration Tests (push) Failing after 3s
FUSE Volume Server Failover Tests / FUSE Volume Server Failover (push) Failing after 3s
FUSE Integration Tests / FUSE Integration Testing (push) Failing after 2s
FUSE P2P Peer Chunk Sharing Integration Tests / FUSE P2P Peer Chunk Sharing (push) Failing after 3s
go: build binary / Go Vet (push) Failing after 2s
go: build binary / Go Vet 32-bit (push) Failing after 3s
go: build binary / Build (push) Failing after 4s
go: build binary / Build cross-platform (freebsd/amd64) (push) Failing after 3s
go: build binary / Build cross-platform (windows/amd64) (push) Failing after 3s
go: build binary / Build cross-platform (darwin/arm64) (push) Failing after 3s
go: build binary / Build cross-platform (windows/arm64) (push) Failing after 3s
go: build binary / Test (push) Failing after 2s
go: build binary / Test 32-bit (push) Failing after 3s
helm: lint and test charts / lint-test (push) Failing after 3s
Java Client Integration Tests / Java Integration Tests (11) (push) Failing after 3s
Java Client Integration Tests / Java Integration Tests (17) (push) Failing after 3s
go: build dev binaries / build_dev_linux_windows (amd64, linux) (push) Failing after 2s
go: build dev binaries / build_dev_linux_windows (amd64, windows) (push) Failing after 3s
go: build dev binaries / build_dev_darwin (amd64, darwin) (push) Has been skipped
go: build dev binaries / build_dev_darwin (arm64, darwin) (push) Has been skipped
Java Client Unit Tests / Java Unit Tests (11) (push) Failing after 3s
Java Client Unit Tests / Java Unit Tests (17) (push) Failing after 2s
Java Client Unit Tests / Java Unit Tests (21) (push) Failing after 3s
Java Client Unit Tests / Java Unit Tests (8) (push) Failing after 3s
Kafka Quick Test (Load Test with Schema Registry) / Kafka Client Load Test (Quick) (push) Failing after 3s
Kafka Gateway Tests / Kafka Unit Tests (unit-tests-1) (push) Failing after 11s
Kafka Gateway Tests / Kafka Integration Tests (Critical) (integration-1) (push) Failing after 3s
Kafka Gateway Tests / Kafka End-to-End Tests (with SMQ) (e2e-1) (push) Failing after 3s
Kafka Gateway Tests / Kafka Consumer Group Tests (Highly Isolated) (consumer-group-1) (push) Failing after 2s
Kafka Gateway Tests / Kafka Client Compatibility (with SMQ) (client-compat-1) (push) Failing after 3s
Kafka Gateway Tests / Kafka SMQ Integration Tests (Full Stack) (smq-integration-1) (push) Failing after 3s
Kafka Gateway Tests / Kafka Protocol Tests (Isolated) (protocol-1) (push) Failing after 3s
KMS Tests / KMS Provider Integration Tests (push) Failing after 2s
KMS Tests / S3 KMS End-to-End Tests (push) Failing after 3s
Master Cold Start Tests / Master Cold Start Tests (push) Failing after 4s
Metadata Subscribe Integration Tests / Metadata Subscribe Integration Tests (push) Failing after 3s
Multi-Master Tests / Multi-Master Failover Tests (push) Failing after 3s
Performance / CPU and Heap Profile (push) Failing after 2s
Performance / S3 Read/Write Benchmark (rust volume) (push) Failing after 3s
pjdfstest POSIX Compliance / pjdfstest (push) Failing after 2s
Plugin Worker Integration Tests / Plugin Worker: erasure_coding (push) Failing after 3s
Plugin Worker Integration Tests / Plugin Worker: vacuum (push) Failing after 3s
Rust Volume Server Tests / Rust Integration Tests (push) Failing after 3s
Rust Volume Server Tests / Go Tests with Rust Volume (grpc - Shard 1) (push) Failing after 2s
Rust Volume Server Tests / Go Tests with Rust Volume (http - Shard 1) (push) Failing after 3s
Rust Volume Server Tests / Go Tests with Rust Volume (grpc - Shard 2) (push) Failing after 3s
Rust Volume Server Tests / Go Tests with Rust Volume (http - Shard 2) (push) Failing after 3s
Rust Volume Server Tests / Go Tests with Rust Volume (grpc - Shard 3) (push) Failing after 3s
S3 IAM Integration Tests / S3 IAM Distributed Tests (push) Failing after 2s
S3 IAM Integration Tests / S3 IAM Performance Tests (push) Failing after 3s
Performance / Throughput Benchmark (go volume) (push) Failing after 3s
Performance / Throughput Benchmark (rust volume) (push) Failing after 2s
Performance / S3 Read/Write Benchmark (go volume) (push) Failing after 3s
Plugin Worker Integration Tests / Plugin Worker: volume_balance (push) Failing after 3s
PostgreSQL Gateway Tests / PostgreSQL Basic Tests (push) Failing after 3s
Rust Volume Server Tests / Rust Unit Tests (push) Failing after 2s
Rust Volume Server Tests / Go Tests with Rust Volume (http - Shard 3) (push) Failing after 3s
Rust Plugin Worker Tests / Rust Plugin Worker Build and Unit Tests (push) Failing after 3s
rust: build dev volume server binaries / cleanup (push) Successful in 3s
S3 ETag and ACL Tests / S3 ETag + ACL Integration Tests (push) Failing after 3s
S3 IAM Integration Tests / IAM Unit Tests (push) Failing after 3s
S3 IAM Integration Tests / S3 IAM Integration Tests (advanced) (push) Failing after 3s
S3 IAM Integration Tests / S3 IAM Integration Tests (basic) (push) Failing after 2s
S3 IAM Integration Tests / S3 IAM Integration Tests (group) (push) Failing after 3s
S3 IAM Integration Tests / S3 IAM Integration Tests (policy-enforcement) (push) Failing after 2s
S3 IAM Integration Tests / S3 IAM Integration Tests (sts) (push) Failing after 4s
S3 Keycloak Integration Tests / S3 Keycloak Integration Tests (push) Failing after 3s
S3 PyArrow Parquet Tests / PyArrow Parquet Tests (Python 3.11) (push) Failing after 3s
S3 PyArrow Parquet Tests / Go Unit Tests (Implicit Directory) (push) Has been cancelled
S3 PyArrow Parquet Tests / PyArrow Parquet Tests (Python 3.12) (push) Has been cancelled
rust: build dev volume server binaries / build-rust-volume-dev-darwin (darwin-amd64, x86_64-apple-darwin) (push) Has been cancelled
rust: build dev volume server binaries / build-rust-volume-dev-darwin (darwin-arm64, aarch64-apple-darwin) (push) Has been cancelled
rust: build dev volume server binaries / build-rust-volume-dev-linux (linux-amd64, x86_64-unknown-linux-gnu) (push) Has been cancelled
S3 PyArrow Parquet Tests / PyArrow Parquet Tests (Python 3.9) (push) Has been cancelled
S3 Proxy Signature Tests / S3 Proxy Signature Verification Tests (push) Has been cancelled
S3 SDK V2 Route Disambiguation Tests / S3 SDK V2 Routing Tests (push) Has been cancelled
S3 SSE Tests / S3 SSE Integration Tests (quick) (push) Has been cancelled
S3 SSE Tests / S3 SSE Compatibility Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Metadata Persistence Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Copy Operations Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Multipart Upload Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Performance Test (push) Has been cancelled
S3 SSE Tests / S3 Volume Encryption Test (push) Has been cancelled
S3 SSE Tests / S3 SSE Integration Tests (comprehensive) (push) Has been cancelled
Spark Integration Tests / Spark Integration Tests (push) Failing after 2s
Telemetry Integration Tests / telemetry-integration-test (push) Failing after 3s
Volume Server Integration Tests / Volume Server Integration Tests (grpc - Shard 1) (push) Failing after 3s
Volume Server Integration Tests / Volume Server Integration Tests (http - Shard 1) (push) Failing after 3s
Ceph S3 tests / Basic S3 tests (KV store) (push) Has been cancelled
Ceph S3 tests / S3 Versioning & Object Lock tests (push) Has been cancelled
S3 Policy Integration Tests / S3 Policy Unit Tests (push) Failing after 3s
Ceph S3 tests / S3 CORS tests (push) Has been cancelled
Ceph S3 tests / SeaweedFS Custom S3 Copy tests (push) Has been cancelled
Ceph S3 tests / Basic S3 tests (SQL store) (push) Has been cancelled
test s3 over https using aws-cli / awscli-tests (push) Has been cancelled
TLS Rotation Integration Tests / TLS Rotation Integration Tests (push) Has been cancelled
Vacuum Integration Tests / Vacuum Integration Tests (push) Has been cancelled
S3 Policy Integration Tests / S3 Policy Variables Integration Tests (push) Failing after 3s
S3 Policy Integration Tests / S3 Policy Enforcement Integration Tests (advanced-policy) (push) Failing after 3s
S3 Policy Integration Tests / S3 Policy Enforcement Integration Tests (basic-policy) (push) Failing after 2s
S3 Policy Integration Tests / S3 Policy Enforcement Integration Tests (contextual-policy) (push) Failing after 4s
S3 Policy Integration Tests / Trusted Proxy Detection Tests (push) Failing after 2s
S3 Policy Integration Tests / S3 Policy Shell Integration Tests (push) Failing after 3s
Samba on FUSE Integration / samba-integration (push) Failing after 2s
SFTP Integration Tests / SFTP Integration Testing (push) Failing after 3s
terraform: validate and test modules / fmt, validate, plan-level tests (push) Failing after 3s
terraform: validate and test modules / local cluster smoke test (real weed) (push) Failing after 2s
Volume Server Integration Tests / Volume Server Integration Tests (grpc - Shard 3) (push) Failing after 3s
Volume Server Integration Tests / Volume Server Integration Tests (grpc - Shard 2) (push) Failing after 3s
Volume Server Integration Tests / Volume Server Integration Tests (http - Shard 2) (push) Failing after 2s
Volume Server Integration Tests / Volume Server Integration Tests (http - Shard 3) (push) Failing after 5s
mount: windows conformance / WinFsp conformance (push) Has been cancelled
mount: windows / Mount on Windows (push) Has been cancelled
This commit is contained in:
373
terraform/modules/core/main.tf
Normal file
373
terraform/modules/core/main.tf
Normal file
@@ -0,0 +1,373 @@
|
||||
# =============================================================================
|
||||
# SeaweedFS Terraform core - pure renderer (zero cloud resources).
|
||||
#
|
||||
# Computes, per node: the verified `weed` argv, the full systemd ExecStart,
|
||||
# config files, environment, and rendered systemd unit + cloud-init.
|
||||
# =============================================================================
|
||||
|
||||
locals {
|
||||
# ---- shared security.toml (rendered when mTLS on OR any JWT key set) ----
|
||||
jwt_any = anytrue([
|
||||
var.security.jwt_signing_key != "",
|
||||
var.security.jwt_signing_read_key != "",
|
||||
var.security.jwt_filer_signing_key != "",
|
||||
var.security.jwt_filer_signing_read_key != "",
|
||||
])
|
||||
render_security = var.enable_security || local.jwt_any
|
||||
security_toml = local.render_security ? templatefile("${path.module}/templates/security.toml.tftpl", {
|
||||
enable_security = var.enable_security
|
||||
cert_dir = var.security.cert_dir
|
||||
allowed_wildcard_domain = var.security.allowed_wildcard_domain
|
||||
allowed_common_names = var.security.allowed_common_names
|
||||
jwt_signing_key = var.security.jwt_signing_key
|
||||
jwt_signing_read_key = var.security.jwt_signing_read_key
|
||||
jwt_filer_signing_key = var.security.jwt_filer_signing_key
|
||||
jwt_filer_signing_read_key = var.security.jwt_filer_signing_read_key
|
||||
}) : ""
|
||||
security_files = local.render_security ? { "/etc/seaweedfs/security.toml" = local.security_toml } : {}
|
||||
|
||||
# ---- S3 identity JSON (non-admin identities only) ----
|
||||
# Empty access_key => anonymous identity (no credentials block), per SeaweedFS
|
||||
# convention where the identity literally named "anonymous" grants anon access.
|
||||
s3_config_json = jsonencode({
|
||||
identities = [for id in var.s3_identities : {
|
||||
name = id.name
|
||||
credentials = id.access_key != "" ? [{ accessKey = id.access_key, secretKey = id.secret_key }] : []
|
||||
actions = id.actions
|
||||
}]
|
||||
})
|
||||
|
||||
# ---- global flags (before the subcommand) ----
|
||||
global_flags = compact([
|
||||
format("-v=%d", var.log_level),
|
||||
var.log_to_stderr ? "-logtostderr=true" : "",
|
||||
])
|
||||
|
||||
# ---- master peers (sorted by key for determinism) ----
|
||||
master_keys = sort(keys(var.master.nodes))
|
||||
master_peer_list = [for k in local.master_keys :
|
||||
format("%s:%d", var.master.nodes[k].address, coalesce(var.master.nodes[k].port, var.master.port))
|
||||
]
|
||||
master_peers = join(",", local.master_peer_list)
|
||||
|
||||
# ---- first filer (default s3 target + cluster env) ----
|
||||
filer_keys = sort(keys(var.filer.nodes))
|
||||
first_filer = length(local.filer_keys) > 0 ? format("%s:%d", var.filer.nodes[local.filer_keys[0]].address, coalesce(var.filer.nodes[local.filer_keys[0]].port, var.filer.port)) : ""
|
||||
|
||||
# ---- cluster discovery env (WEED_CLUSTER_*) ----
|
||||
cluster_env = merge(
|
||||
{ WEED_CLUSTER_DEFAULT = var.cluster_name },
|
||||
local.master_peers != "" ? { "WEED_CLUSTER_${replace(upper(var.cluster_name), "/[^A-Z0-9_]/", "_")}_MASTER" = local.master_peers } : {},
|
||||
local.first_filer != "" ? { "WEED_CLUSTER_${replace(upper(var.cluster_name), "/[^A-Z0-9_]/", "_")}_FILER" = local.first_filer } : {},
|
||||
)
|
||||
|
||||
metrics_flags_master = var.monitoring_enabled ? compact([
|
||||
format("-metricsPort=%d", var.master.metrics_port),
|
||||
var.master.metrics_ip != "" ? format("-metricsIp=%s", var.master.metrics_ip) : "",
|
||||
]) : []
|
||||
metrics_flags_volume = var.monitoring_enabled ? compact([
|
||||
format("-metricsPort=%d", var.volume.metrics_port),
|
||||
var.volume.metrics_ip != "" ? format("-metricsIp=%s", var.volume.metrics_ip) : "",
|
||||
]) : []
|
||||
metrics_flags_filer = var.monitoring_enabled ? compact([
|
||||
format("-metricsPort=%d", var.filer.metrics_port),
|
||||
var.filer.metrics_ip != "" ? format("-metricsIp=%s", var.filer.metrics_ip) : "",
|
||||
]) : []
|
||||
metrics_flags_s3 = var.monitoring_enabled ? [format("-metricsPort=%d", var.s3.metrics_port)] : []
|
||||
|
||||
# ===========================================================================
|
||||
# MASTER nodes
|
||||
# ===========================================================================
|
||||
master_nodes = var.master.enabled ? {
|
||||
for k in local.master_keys : "master-${k}" => {
|
||||
role = "master"
|
||||
name = "master-${k}"
|
||||
address = var.master.nodes[k].address
|
||||
disk_mounts = var.master.nodes[k].disk_mounts
|
||||
data_dir = coalesce(var.master.nodes[k].data_dir, var.master.data_dir)
|
||||
data_dirs = [coalesce(var.master.nodes[k].data_dir, var.master.data_dir)]
|
||||
ports = {
|
||||
http = coalesce(var.master.nodes[k].port, var.master.port)
|
||||
metrics = var.master.metrics_port
|
||||
}
|
||||
env = local.cluster_env
|
||||
config_files = local.security_files
|
||||
argv = concat(
|
||||
local.global_flags,
|
||||
["master"],
|
||||
[
|
||||
format("-port=%d", coalesce(var.master.nodes[k].port, var.master.port)),
|
||||
format("-mdir=%s", coalesce(var.master.nodes[k].data_dir, var.master.data_dir)),
|
||||
format("-ip=%s", var.master.nodes[k].address),
|
||||
format("-ip.bind=%s", var.master.ip_bind),
|
||||
format("-peers=%s", local.master_peers),
|
||||
format("-defaultReplication=%s", var.master.default_replication),
|
||||
format("-volumeSizeLimitMB=%d", var.master.volume_size_limit_mb),
|
||||
format("-electionTimeout=%s", var.master.election_timeout),
|
||||
format("-heartbeatInterval=%s", var.master.heartbeat_interval),
|
||||
],
|
||||
var.master.nodes[k].grpc_port != null ? [format("-port.grpc=%d", var.master.nodes[k].grpc_port)] : (
|
||||
var.master.grpc_port != null ? [format("-port.grpc=%d", var.master.grpc_port)] : []),
|
||||
var.master.volume_preallocate ? ["-volumePreallocate"] : [],
|
||||
var.master.garbage_threshold != null ? [format("-garbageThreshold=%s", tostring(var.master.garbage_threshold))] : [],
|
||||
var.master.raft_hashicorp ? ["-raftHashicorp"] : [],
|
||||
var.master.resume_state ? ["-resumeState"] : [],
|
||||
var.master.disable_http ? ["-disableHttp"] : [],
|
||||
var.master.white_list != "" ? [format("-whiteList=%s", var.master.white_list)] : [],
|
||||
local.metrics_flags_master,
|
||||
var.master.extra_args,
|
||||
)
|
||||
}
|
||||
} : {}
|
||||
|
||||
# ===========================================================================
|
||||
# VOLUME nodes
|
||||
# ===========================================================================
|
||||
volume_keys = sort(keys(var.volume.nodes))
|
||||
volume_nodes = var.volume.enabled ? {
|
||||
for k in local.volume_keys : "volume-${k}" => {
|
||||
role = "volume"
|
||||
name = "volume-${k}"
|
||||
address = var.volume.nodes[k].address
|
||||
disk_mounts = var.volume.nodes[k].disk_mounts
|
||||
data_dirs = [for d in(var.volume.nodes[k].data_dirs != null ? var.volume.nodes[k].data_dirs : var.volume.data_dirs) : d.path]
|
||||
data_dir = (var.volume.nodes[k].data_dirs != null ? var.volume.nodes[k].data_dirs : var.volume.data_dirs)[0].path
|
||||
ports = {
|
||||
http = coalesce(var.volume.nodes[k].port, var.volume.port)
|
||||
metrics = var.volume.metrics_port
|
||||
}
|
||||
env = local.cluster_env
|
||||
config_files = local.security_files
|
||||
argv = concat(
|
||||
local.global_flags,
|
||||
["volume"],
|
||||
[
|
||||
format("-port=%d", coalesce(var.volume.nodes[k].port, var.volume.port)),
|
||||
format("-dir=%s", join(",", [for d in(var.volume.nodes[k].data_dirs != null ? var.volume.nodes[k].data_dirs : var.volume.data_dirs) : d.path])),
|
||||
format("-max=%s", join(",", [for d in(var.volume.nodes[k].data_dirs != null ? var.volume.nodes[k].data_dirs : var.volume.data_dirs) : tostring(d.max_volumes)])),
|
||||
format("-ip=%s", var.volume.nodes[k].address),
|
||||
format("-ip.bind=%s", var.volume.ip_bind),
|
||||
format("-mserver=%s", local.master_peers),
|
||||
format("-readMode=%s", var.volume.read_mode),
|
||||
format("-compactionMBps=%d", var.volume.compaction_mbps),
|
||||
format("-minFreeSpacePercent=%s", var.volume.min_free_space_percent),
|
||||
format("-index=%s", var.volume.index),
|
||||
],
|
||||
var.volume.nodes[k].grpc_port != null ? [format("-port.grpc=%d", var.volume.nodes[k].grpc_port)] : [],
|
||||
(var.volume.nodes[k].idx_dir != null && var.volume.nodes[k].idx_dir != "") ? [format("-dir.idx=%s", var.volume.nodes[k].idx_dir)] : (var.volume.idx_dir != "" ? [format("-dir.idx=%s", var.volume.idx_dir)] : []),
|
||||
var.volume.nodes[k].data_center != null ? [format("-dataCenter=%s", var.volume.nodes[k].data_center)] : [],
|
||||
var.volume.nodes[k].rack != null ? [format("-rack=%s", var.volume.nodes[k].rack)] : [],
|
||||
var.volume.nodes[k].public_url != null ? [format("-publicUrl=%s", var.volume.nodes[k].public_url)] : [],
|
||||
var.volume.file_size_limit_mb != null ? [format("-fileSizeLimitMB=%d", var.volume.file_size_limit_mb)] : [],
|
||||
var.volume.images_fix_orientation ? ["-images.fix.orientation"] : [],
|
||||
var.volume.white_list != "" ? [format("-whiteList=%s", var.volume.white_list)] : [],
|
||||
local.metrics_flags_volume,
|
||||
var.volume.extra_args,
|
||||
)
|
||||
}
|
||||
} : {}
|
||||
|
||||
# ===========================================================================
|
||||
# FILER nodes (+ optional embedded S3)
|
||||
# ===========================================================================
|
||||
filer_s3_files = var.filer.s3.enabled ? { (var.filer.s3.config_path) = local.s3_config_json } : {}
|
||||
filer_nodes = var.filer.enabled ? {
|
||||
for k in local.filer_keys : "filer-${k}" => {
|
||||
role = "filer"
|
||||
name = "filer-${k}"
|
||||
address = var.filer.nodes[k].address
|
||||
disk_mounts = var.filer.nodes[k].disk_mounts
|
||||
data_dir = coalesce(var.filer.nodes[k].data_dir, var.filer.data_dir)
|
||||
data_dirs = [coalesce(var.filer.nodes[k].data_dir, var.filer.data_dir)]
|
||||
ports = {
|
||||
http = coalesce(var.filer.nodes[k].port, var.filer.port)
|
||||
metrics = var.filer.metrics_port
|
||||
}
|
||||
env = merge(local.cluster_env, var.filer.extra_env)
|
||||
config_files = merge(local.security_files, local.filer_s3_files)
|
||||
argv = concat(
|
||||
local.global_flags,
|
||||
["filer"],
|
||||
[
|
||||
format("-port=%d", coalesce(var.filer.nodes[k].port, var.filer.port)),
|
||||
format("-ip=%s", var.filer.nodes[k].address),
|
||||
format("-ip.bind=%s", var.filer.ip_bind),
|
||||
format("-master=%s", local.master_peers),
|
||||
format("-defaultReplicaPlacement=%s", var.filer.default_replica_placement),
|
||||
format("-dirListLimit=%d", var.filer.dir_list_limit),
|
||||
format("-defaultStoreDir=%s", coalesce(var.filer.nodes[k].data_dir, var.filer.data_dir)),
|
||||
],
|
||||
var.filer.nodes[k].grpc_port != null ? [format("-port.grpc=%d", var.filer.nodes[k].grpc_port)] : [],
|
||||
var.filer.max_mb != null ? [format("-maxMB=%d", var.filer.max_mb)] : [],
|
||||
var.filer.disable_dir_listing ? ["-disableDirListing"] : [],
|
||||
var.filer.disable_http ? ["-disableHttp"] : [],
|
||||
var.filer.encrypt_volume_data ? ["-encryptVolumeData"] : [],
|
||||
var.filer.rack != "" ? [format("-rack=%s", var.filer.rack)] : [],
|
||||
var.filer.data_center != "" ? [format("-dataCenter=%s", var.filer.data_center)] : [],
|
||||
var.filer.filer_group != "" ? [format("-filerGroup=%s", var.filer.filer_group)] : [],
|
||||
var.filer.s3.enabled ? [
|
||||
"-s3",
|
||||
format("-s3.port=%d", var.filer.s3.port),
|
||||
format("-s3.config=%s", var.filer.s3.config_path),
|
||||
] : [],
|
||||
(var.filer.s3.enabled && var.filer.s3.https_port > 0) ? [format("-s3.port.https=%d", var.filer.s3.https_port)] : [],
|
||||
(var.filer.s3.enabled && var.filer.s3.domain_name != "") ? [format("-s3.domainName=%s", var.filer.s3.domain_name)] : [],
|
||||
local.metrics_flags_filer,
|
||||
var.filer.extra_args,
|
||||
)
|
||||
}
|
||||
} : {}
|
||||
|
||||
# ===========================================================================
|
||||
# S3 standalone nodes
|
||||
# ===========================================================================
|
||||
s3_keys = sort(keys(var.s3.nodes))
|
||||
s3_target = var.s3.filer_address != "" ? var.s3.filer_address : local.first_filer
|
||||
s3_std_files = merge(local.security_files, { (var.s3.config_path) = local.s3_config_json })
|
||||
s3_nodes = var.s3.enabled ? {
|
||||
for k in local.s3_keys : "s3-${k}" => {
|
||||
role = "s3"
|
||||
name = "s3-${k}"
|
||||
address = var.s3.nodes[k].address
|
||||
disk_mounts = []
|
||||
data_dir = ""
|
||||
data_dirs = []
|
||||
ports = {
|
||||
http = coalesce(var.s3.nodes[k].port, var.s3.port)
|
||||
metrics = var.s3.metrics_port
|
||||
}
|
||||
env = local.cluster_env
|
||||
config_files = local.s3_std_files
|
||||
argv = concat(
|
||||
local.global_flags,
|
||||
["s3"],
|
||||
[
|
||||
format("-port=%d", coalesce(var.s3.nodes[k].port, var.s3.port)),
|
||||
format("-ip.bind=%s", var.s3.ip_bind),
|
||||
format("-filer=%s", local.s3_target),
|
||||
format("-config=%s", var.s3.config_path),
|
||||
],
|
||||
var.s3.https_port > 0 ? [format("-port.https=%d", var.s3.https_port)] : [],
|
||||
var.s3.iceberg_port != null ? [format("-port.iceberg=%d", var.s3.iceberg_port)] : [],
|
||||
var.s3.domain_name != "" ? [format("-domainName=%s", var.s3.domain_name)] : [],
|
||||
var.s3.audit_log_config_path != "" ? [format("-auditLogConfig=%s", var.s3.audit_log_config_path)] : [],
|
||||
var.s3.cert_file != "" ? [format("-cert.file=%s", var.s3.cert_file)] : [],
|
||||
var.s3.key_file != "" ? [format("-key.file=%s", var.s3.key_file)] : [],
|
||||
var.s3.cacert_file != "" ? [format("-cacert.file=%s", var.s3.cacert_file)] : [],
|
||||
var.s3.verify_client_cert ? ["-tlsVerifyClientCert"] : [],
|
||||
local.metrics_flags_s3,
|
||||
var.s3.extra_args,
|
||||
)
|
||||
}
|
||||
} : {}
|
||||
|
||||
# ===========================================================================
|
||||
# ALL-IN-ONE nodes (weed server)
|
||||
# ===========================================================================
|
||||
aio_keys = sort(keys(var.all_in_one.nodes))
|
||||
aio_s3_files = var.all_in_one.s3.enabled ? { (var.all_in_one.s3.config_path) = local.s3_config_json } : {}
|
||||
aio_nodes = var.all_in_one.enabled ? {
|
||||
for k in local.aio_keys : "all-in-one-${k}" => {
|
||||
role = "server"
|
||||
name = "all-in-one-${k}"
|
||||
address = var.all_in_one.nodes[k].address
|
||||
disk_mounts = var.all_in_one.nodes[k].disk_mounts
|
||||
data_dir = coalesce(var.all_in_one.nodes[k].data_dir, var.all_in_one.data_dir)
|
||||
data_dirs = [coalesce(var.all_in_one.nodes[k].data_dir, var.all_in_one.data_dir)]
|
||||
ports = {
|
||||
http = var.all_in_one.master_port
|
||||
metrics = var.all_in_one.metrics_port
|
||||
}
|
||||
env = local.cluster_env
|
||||
config_files = merge(local.security_files, local.aio_s3_files)
|
||||
argv = concat(
|
||||
local.global_flags,
|
||||
["server"],
|
||||
[
|
||||
format("-dir=%s", coalesce(var.all_in_one.nodes[k].data_dir, var.all_in_one.data_dir)),
|
||||
format("-ip=%s", var.all_in_one.nodes[k].address),
|
||||
format("-ip.bind=%s", var.all_in_one.ip_bind),
|
||||
"-master",
|
||||
format("-master.port=%d", var.all_in_one.master_port),
|
||||
format("-master.peers=%s:%d", var.all_in_one.nodes[k].address, var.all_in_one.master_port),
|
||||
format("-master.defaultReplication=%s", var.all_in_one.default_replication),
|
||||
format("-master.volumeSizeLimitMB=%d", var.all_in_one.volume_size_limit_mb),
|
||||
"-volume",
|
||||
format("-volume.port=%d", var.all_in_one.volume_port),
|
||||
"-filer",
|
||||
format("-filer.port=%d", var.all_in_one.filer_port),
|
||||
format("-idleTimeout=%d", var.all_in_one.idle_timeout),
|
||||
],
|
||||
var.all_in_one.disable_http ? [format("-disableHttp=%t", var.all_in_one.disable_http)] : [],
|
||||
var.all_in_one.s3.enabled ? [
|
||||
"-s3",
|
||||
format("-s3.port=%d", var.all_in_one.s3.port),
|
||||
format("-s3.config=%s", var.all_in_one.s3.config_path),
|
||||
] : [],
|
||||
(var.all_in_one.s3.enabled && var.all_in_one.s3.domain_name != "") ? [format("-s3.domainName=%s", var.all_in_one.s3.domain_name)] : [],
|
||||
var.monitoring_enabled ? [format("-metricsPort=%d", var.all_in_one.metrics_port)] : [],
|
||||
var.all_in_one.extra_args,
|
||||
)
|
||||
}
|
||||
} : {}
|
||||
|
||||
# ===========================================================================
|
||||
# Merge + render systemd unit and cloud-init per node
|
||||
# ===========================================================================
|
||||
nodes_base = merge(local.master_nodes, local.volume_nodes, local.filer_nodes, local.s3_nodes, local.aio_nodes)
|
||||
|
||||
# Disk-mount script per node (empty unless the node declares disk_mounts).
|
||||
mount_scripts = {
|
||||
for name, n in local.nodes_base : name => length(n.disk_mounts) > 0 ? templatefile("${path.module}/templates/mount-disks.sh.tftpl", {
|
||||
run_as_user = var.hardening.run_as_user
|
||||
mounts = n.disk_mounts
|
||||
}) : ""
|
||||
}
|
||||
|
||||
nodes = {
|
||||
for name, n in local.nodes_base : name => merge(n, {
|
||||
exec_start = "${var.weed_binary} ${join(" ", n.argv)}"
|
||||
# secret_files: the secret-bearing config a wrapper should deliver from a
|
||||
# secret store when render_secret_files=false (else they go in cloud-init).
|
||||
secret_files = n.config_files
|
||||
mount_script = local.mount_scripts[name]
|
||||
file_modes = { for p in keys(n.config_files) : p => "0600" }
|
||||
systemd_unit = templatefile("${path.module}/templates/weed.service.tftpl", {
|
||||
role = n.role
|
||||
name = n.name
|
||||
run_as_user = var.hardening.run_as_user
|
||||
exec_start = "${var.weed_binary} ${join(" ", n.argv)}"
|
||||
no_new_privileges = var.hardening.no_new_privileges
|
||||
protect_system = var.hardening.protect_system
|
||||
cap_drop_all = var.hardening.cap_drop_all
|
||||
read_write_paths = n.data_dirs
|
||||
requires_mounts_for = n.data_dirs
|
||||
env_file = var.env_file
|
||||
environment = n.env
|
||||
})
|
||||
cloud_init = templatefile("${path.module}/templates/cloud-init.yaml.tftpl", {
|
||||
role = n.role
|
||||
name = n.name
|
||||
run_as_user = var.hardening.run_as_user
|
||||
config_files = var.render_secret_files ? n.config_files : {}
|
||||
file_modes = { for p in keys(n.config_files) : p => "0600" }
|
||||
pre_runcmd = [for p in n.data_dirs : "install -d -o ${var.hardening.run_as_user} -g ${var.hardening.run_as_user} ${p}"]
|
||||
mount_script = local.mount_scripts[name]
|
||||
fetch_script = var.boot_fetch_script
|
||||
systemd_unit = templatefile("${path.module}/templates/weed.service.tftpl", {
|
||||
role = n.role
|
||||
name = n.name
|
||||
run_as_user = var.hardening.run_as_user
|
||||
exec_start = "${var.weed_binary} ${join(" ", n.argv)}"
|
||||
no_new_privileges = var.hardening.no_new_privileges
|
||||
protect_system = var.hardening.protect_system
|
||||
cap_drop_all = var.hardening.cap_drop_all
|
||||
read_write_paths = n.data_dirs
|
||||
requires_mounts_for = n.data_dirs
|
||||
env_file = var.env_file
|
||||
environment = n.env
|
||||
})
|
||||
})
|
||||
})
|
||||
}
|
||||
}
|
||||
32
terraform/modules/core/outputs.tf
Normal file
32
terraform/modules/core/outputs.tf
Normal file
@@ -0,0 +1,32 @@
|
||||
output "nodes" {
|
||||
description = "Per-node rendered artifacts keyed by node name. Each value: role, name, address, ports, data_dir(s), argv (list, after the weed binary), exec_start, env, config_files, systemd_unit, cloud_init."
|
||||
value = local.nodes
|
||||
sensitive = true # config_files/env may carry JWT keys or S3 identities
|
||||
}
|
||||
|
||||
output "master_peers" {
|
||||
description = "Comma-separated master peer list (address:port), as passed to -peers / -mserver / -master."
|
||||
value = local.master_peers
|
||||
}
|
||||
|
||||
output "first_filer" {
|
||||
description = "address:port of the lexically-first filer node (default S3 target)."
|
||||
value = local.first_filer
|
||||
}
|
||||
|
||||
output "node_names" {
|
||||
description = "List of rendered node names (non-sensitive)."
|
||||
value = sort(keys(local.nodes))
|
||||
}
|
||||
|
||||
output "cloud_init_by_node" {
|
||||
description = "Map of node name -> rendered cloud-init user_data (for the per-cloud wrappers)."
|
||||
value = { for name, n in local.nodes : name => n.cloud_init }
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
output "secret_files_by_node" {
|
||||
description = "Map of node name -> {path => content} of secret-bearing files (security.toml, S3 identity JSON). Wrappers push these to a secret store and fetch them at boot when render_secret_files=false."
|
||||
value = { for name, n in local.nodes : name => n.secret_files }
|
||||
sensitive = true
|
||||
}
|
||||
44
terraform/modules/core/templates/cloud-init.yaml.tftpl
Normal file
44
terraform/modules/core/templates/cloud-init.yaml.tftpl
Normal file
@@ -0,0 +1,44 @@
|
||||
#cloud-config
|
||||
# Rendered by the SeaweedFS Terraform core module for node ${name} (role ${role}).
|
||||
# When render_secret_files=false, secret-bearing files are NOT here; they are
|
||||
# fetched at boot by fetch-secrets.sh from the cloud secret store.
|
||||
users:
|
||||
- name: ${run_as_user}
|
||||
system: true
|
||||
shell: /usr/sbin/nologin
|
||||
write_files:
|
||||
%{ for path, content in config_files ~}
|
||||
- path: ${path}
|
||||
owner: "${run_as_user}:${run_as_user}"
|
||||
permissions: '${lookup(file_modes, path, "0644")}'
|
||||
content: |
|
||||
${indent(6, content)}
|
||||
%{ endfor ~}
|
||||
%{ if mount_script != "" ~}
|
||||
- path: /opt/seaweedfs/mount-disks.sh
|
||||
permissions: '0755'
|
||||
content: |
|
||||
${indent(6, mount_script)}
|
||||
%{ endif ~}
|
||||
%{ if fetch_script != "" ~}
|
||||
- path: /opt/seaweedfs/fetch-secrets.sh
|
||||
permissions: '0755'
|
||||
content: |
|
||||
${indent(6, fetch_script)}
|
||||
%{ endif ~}
|
||||
- path: /etc/systemd/system/weed-${role}.service
|
||||
permissions: '0644'
|
||||
content: |
|
||||
${indent(6, systemd_unit)}
|
||||
runcmd:
|
||||
%{ if mount_script != "" ~}
|
||||
- /opt/seaweedfs/mount-disks.sh
|
||||
%{ endif ~}
|
||||
%{ if fetch_script != "" ~}
|
||||
- /opt/seaweedfs/fetch-secrets.sh
|
||||
%{ endif ~}
|
||||
%{ for cmd in pre_runcmd ~}
|
||||
- ${cmd}
|
||||
%{ endfor ~}
|
||||
- systemctl daemon-reload
|
||||
- systemctl enable --now weed-${role}.service
|
||||
73
terraform/modules/core/templates/mount-disks.sh.tftpl
Normal file
73
terraform/modules/core/templates/mount-disks.sh.tftpl
Normal file
@@ -0,0 +1,73 @@
|
||||
#!/usr/bin/env bash
|
||||
# Rendered by the SeaweedFS Terraform core module. Formats (only if blank) and
|
||||
# mounts each data disk, persisting by UUID to /etc/fstab. Safe to re-run.
|
||||
set -euo pipefail
|
||||
|
||||
run_as_user="${run_as_user}"
|
||||
|
||||
# Base block device backing "/" so auto-discovery never touches the root disk.
|
||||
root_src="$(findmnt -no SOURCE / 2>/dev/null || true)"
|
||||
root_base="$(lsblk -no pkname "$root_src" 2>/dev/null || true)"
|
||||
[ -n "$root_base" ] && root_base="/dev/$root_base"
|
||||
|
||||
is_mounted() { findmnt -rno TARGET "$1" >/dev/null 2>&1; }
|
||||
|
||||
# Pick the first unmounted, non-root whole disk (single-data-disk node).
|
||||
discover_dev() {
|
||||
local d base
|
||||
for d in /dev/nvme*n1 /dev/xvd[b-z] /dev/sd[b-z] /dev/vd[b-z]; do
|
||||
[ -b "$d" ] || continue
|
||||
[ "$d" = "$root_src" ] && continue
|
||||
[ "$d" = "$root_base" ] && continue
|
||||
base="/dev/$(lsblk -no pkname "$d" 2>/dev/null || true)"
|
||||
[ "$base" = "$root_base" ] && continue
|
||||
is_mounted "$d" && continue
|
||||
echo "$d"; return 0
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
# Wait up to ~120s for one of the explicit candidate devices to appear.
|
||||
wait_dev() {
|
||||
local i d
|
||||
for i in $(seq 1 60); do
|
||||
for d in "$@"; do [ -b "$d" ] && { echo "$d"; return 0; }; done
|
||||
sleep 2
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
mount_one() {
|
||||
local mountpoint="$1" fstype="$2"; shift 2
|
||||
local dev=""
|
||||
if [ "$#" -gt 0 ]; then
|
||||
dev="$(wait_dev "$@" || true)"
|
||||
fi
|
||||
if [ -z "$dev" ]; then
|
||||
dev="$(discover_dev || true)"
|
||||
fi
|
||||
if [ -z "$dev" ]; then
|
||||
echo "mount-disks: no device found for $mountpoint" >&2
|
||||
return 1
|
||||
fi
|
||||
if ! blkid "$dev" >/dev/null 2>&1; then
|
||||
echo "mount-disks: formatting $dev as $fstype"
|
||||
"mkfs.$fstype" -q "$dev"
|
||||
fi
|
||||
mkdir -p "$mountpoint"
|
||||
local uuid; uuid="$(blkid -s UUID -o value "$dev")"
|
||||
if [ -z "$uuid" ]; then
|
||||
echo "mount-disks: failed to read a filesystem UUID for $dev" >&2
|
||||
return 1
|
||||
fi
|
||||
if ! grep -q "$uuid" /etc/fstab; then
|
||||
printf 'UUID=%s %s %s defaults,nofail 0 2\n' "$uuid" "$mountpoint" "$fstype" >> /etc/fstab
|
||||
fi
|
||||
is_mounted "$mountpoint" || mount "$mountpoint"
|
||||
chown -R "$run_as_user:$run_as_user" "$mountpoint"
|
||||
echo "mount-disks: $dev mounted at $mountpoint"
|
||||
}
|
||||
|
||||
%{ for m in mounts ~}
|
||||
mount_one "${m.mountpoint}" "${m.fstype}"${length(m.devices) > 0 ? " ${join(" ", m.devices)}" : ""}
|
||||
%{ endfor ~}
|
||||
53
terraform/modules/core/templates/security.toml.tftpl
Normal file
53
terraform/modules/core/templates/security.toml.tftpl
Normal file
@@ -0,0 +1,53 @@
|
||||
# SeaweedFS security.toml rendered by the Terraform core module.
|
||||
# Rendered when enable_security OR any non-default JWT signing option is set.
|
||||
# Presence of this file does NOT imply mTLS: the [grpc] TLS block is emitted
|
||||
# only under enable_security; a JWT-only config carries [jwt.*] and no TLS.
|
||||
|
||||
%{ if enable_security ~}
|
||||
[grpc]
|
||||
ca = "${cert_dir}/ca/tls.crt"
|
||||
# Peer-identity authorization: without an allow-list, mTLS collapses to
|
||||
# "trusted the CA" with no authZ. Set allowed_wildcard_domain / commonNames.
|
||||
%{ if allowed_wildcard_domain != "" ~}
|
||||
allowed_wildcard_domain = "${allowed_wildcard_domain}"
|
||||
%{ endif ~}
|
||||
|
||||
[grpc.master]
|
||||
cert = "${cert_dir}/master/tls.crt"
|
||||
key = "${cert_dir}/master/tls.key"
|
||||
%{ if allowed_common_names != "" ~}
|
||||
allowed_commonNames = "${allowed_common_names}"
|
||||
%{ endif ~}
|
||||
|
||||
[grpc.volume]
|
||||
cert = "${cert_dir}/volume/tls.crt"
|
||||
key = "${cert_dir}/volume/tls.key"
|
||||
|
||||
[grpc.filer]
|
||||
cert = "${cert_dir}/filer/tls.crt"
|
||||
key = "${cert_dir}/filer/tls.key"
|
||||
|
||||
[grpc.client]
|
||||
cert = "${cert_dir}/client/tls.crt"
|
||||
key = "${cert_dir}/client/tls.key"
|
||||
%{ endif ~}
|
||||
%{ if jwt_signing_key != "" ~}
|
||||
|
||||
[jwt.signing]
|
||||
key = "${jwt_signing_key}"
|
||||
%{ endif ~}
|
||||
%{ if jwt_signing_read_key != "" ~}
|
||||
|
||||
[jwt.signing.read]
|
||||
key = "${jwt_signing_read_key}"
|
||||
%{ endif ~}
|
||||
%{ if jwt_filer_signing_key != "" ~}
|
||||
|
||||
[jwt.filer_signing]
|
||||
key = "${jwt_filer_signing_key}"
|
||||
%{ endif ~}
|
||||
%{ if jwt_filer_signing_read_key != "" ~}
|
||||
|
||||
[jwt.filer_signing.read]
|
||||
key = "${jwt_filer_signing_read_key}"
|
||||
%{ endif ~}
|
||||
39
terraform/modules/core/templates/weed.service.tftpl
Normal file
39
terraform/modules/core/templates/weed.service.tftpl
Normal file
@@ -0,0 +1,39 @@
|
||||
[Unit]
|
||||
Description=SeaweedFS ${role} (${name})
|
||||
Documentation=https://github.com/seaweedfs/seaweedfs/wiki
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
%{ for path in requires_mounts_for ~}
|
||||
RequiresMountsFor=${path}
|
||||
%{ endfor ~}
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=${run_as_user}
|
||||
Group=${run_as_user}
|
||||
ExecStart=${exec_start}
|
||||
Restart=always
|
||||
RestartSec=5
|
||||
LimitNOFILE=1048576
|
||||
TimeoutStopSec=60
|
||||
# Hardening (OpenShift SCC analogs; relax via the hardening variable)
|
||||
NoNewPrivileges=${no_new_privileges}
|
||||
%{ if protect_system ~}
|
||||
ProtectSystem=strict
|
||||
ProtectHome=true
|
||||
PrivateTmp=true
|
||||
%{ for path in read_write_paths ~}
|
||||
ReadWritePaths=${path}
|
||||
%{ endfor ~}
|
||||
%{ endif ~}
|
||||
%{ if cap_drop_all ~}
|
||||
CapabilityBoundingSet=
|
||||
AmbientCapabilities=
|
||||
%{ endif ~}
|
||||
EnvironmentFile=-${env_file}
|
||||
%{ for k, v in environment ~}
|
||||
Environment="${k}=${v}"
|
||||
%{ endfor ~}
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
234
terraform/modules/core/tests/render.tftest.hcl
Normal file
234
terraform/modules/core/tests/render.tftest.hcl
Normal file
@@ -0,0 +1,234 @@
|
||||
# Plan-level tests for the core renderer. No cloud credentials required.
|
||||
# cd terraform/modules/core && tofu test
|
||||
|
||||
variables {
|
||||
weed_binary = "/usr/bin/weed"
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
run "master_peers_and_count" {
|
||||
command = plan
|
||||
variables {
|
||||
master = {
|
||||
nodes = {
|
||||
m0 = { address = "10.0.0.10" }
|
||||
m1 = { address = "10.0.0.11" }
|
||||
m2 = { address = "10.0.0.12" }
|
||||
}
|
||||
}
|
||||
volume = { enabled = false }
|
||||
filer = { enabled = false }
|
||||
}
|
||||
assert {
|
||||
condition = output.master_peers == "10.0.0.10:9333,10.0.0.11:9333,10.0.0.12:9333"
|
||||
error_message = "master -peers list is wrong"
|
||||
}
|
||||
assert {
|
||||
condition = length(output.node_names) == 3
|
||||
error_message = "expected exactly 3 master nodes"
|
||||
}
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
run "volume_uses_mserver_not_master" {
|
||||
command = plan
|
||||
variables {
|
||||
master = { nodes = { m0 = { address = "10.0.0.10" } } }
|
||||
volume = { nodes = { v0 = { address = "10.0.0.20", rack = "rack-a", data_center = "dc1" } } }
|
||||
filer = { enabled = false }
|
||||
}
|
||||
assert {
|
||||
condition = contains(output.nodes["volume-v0"].argv, "-mserver=10.0.0.10:9333")
|
||||
error_message = "volume must pass the master list via -mserver (verified flag), not -master"
|
||||
}
|
||||
assert {
|
||||
condition = !contains(output.nodes["volume-v0"].argv, "-master=10.0.0.10:9333")
|
||||
error_message = "volume should not use -master for the master list"
|
||||
}
|
||||
assert {
|
||||
condition = contains(output.nodes["volume-v0"].argv, "-rack=rack-a") && contains(output.nodes["volume-v0"].argv, "-dataCenter=dc1")
|
||||
error_message = "per-node rack/dataCenter must render"
|
||||
}
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
run "filer_uses_master_and_store_dir" {
|
||||
command = plan
|
||||
variables {
|
||||
master = { nodes = { m0 = { address = "10.0.0.10" } } }
|
||||
volume = { enabled = false }
|
||||
filer = { nodes = { f0 = { address = "10.0.0.30", data_dir = "/srv/filer" } } }
|
||||
}
|
||||
assert {
|
||||
condition = contains(output.nodes["filer-f0"].argv, "-master=10.0.0.10:9333")
|
||||
error_message = "filer must use -master for the master list"
|
||||
}
|
||||
assert {
|
||||
condition = contains(output.nodes["filer-f0"].argv, "-defaultStoreDir=/srv/filer")
|
||||
error_message = "filer leveldb2 store dir must render via -defaultStoreDir"
|
||||
}
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
run "metrics_gated_off_by_default" {
|
||||
command = plan
|
||||
variables {
|
||||
master = { nodes = { m0 = { address = "10.0.0.10" } } }
|
||||
volume = { enabled = false }
|
||||
filer = { enabled = false }
|
||||
}
|
||||
assert {
|
||||
condition = length([for a in output.nodes["master-m0"].argv : a if startswith(a, "-metricsPort")]) == 0
|
||||
error_message = "metrics port must NOT be bound when monitoring is disabled"
|
||||
}
|
||||
}
|
||||
|
||||
run "metrics_on_when_enabled" {
|
||||
command = plan
|
||||
variables {
|
||||
monitoring_enabled = true
|
||||
master = { nodes = { m0 = { address = "10.0.0.10" } }, metrics_port = 9327 }
|
||||
volume = { enabled = false }
|
||||
filer = { enabled = false }
|
||||
}
|
||||
assert {
|
||||
condition = contains(output.nodes["master-m0"].argv, "-metricsPort=9327")
|
||||
error_message = "metrics port must bind when monitoring is enabled"
|
||||
}
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
run "security_toml_off_by_default" {
|
||||
command = plan
|
||||
variables {
|
||||
master = { nodes = { m0 = { address = "10.0.0.10" } } }
|
||||
volume = { enabled = false }
|
||||
filer = { enabled = false }
|
||||
}
|
||||
assert {
|
||||
condition = length(keys(output.nodes["master-m0"].config_files)) == 0
|
||||
error_message = "security.toml must not render when security is off and no JWT keys set"
|
||||
}
|
||||
}
|
||||
|
||||
run "security_toml_on_with_mtls" {
|
||||
command = plan
|
||||
variables {
|
||||
enable_security = true
|
||||
security = {
|
||||
allowed_wildcard_domain = ".seaweedfs.internal"
|
||||
jwt_signing_key = "test-signing-key-not-a-real-secret-0123456789"
|
||||
}
|
||||
master = { nodes = { m0 = { address = "10.0.0.10" } } }
|
||||
volume = { enabled = false }
|
||||
filer = { enabled = false }
|
||||
}
|
||||
assert {
|
||||
condition = contains(keys(output.nodes["master-m0"].config_files), "/etc/seaweedfs/security.toml")
|
||||
error_message = "security.toml must render when enable_security is true"
|
||||
}
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
run "all_in_one_renders_server" {
|
||||
command = plan
|
||||
variables {
|
||||
master = { enabled = false }
|
||||
volume = { enabled = false }
|
||||
filer = { enabled = false }
|
||||
all_in_one = {
|
||||
enabled = true
|
||||
nodes = { a0 = { address = "10.0.0.40" } }
|
||||
s3 = { enabled = true }
|
||||
}
|
||||
}
|
||||
assert {
|
||||
condition = contains(output.nodes["all-in-one-a0"].argv, "server")
|
||||
error_message = "all-in-one must invoke the weed server subcommand"
|
||||
}
|
||||
assert {
|
||||
condition = contains(output.nodes["all-in-one-a0"].argv, "-s3") && contains(output.nodes["all-in-one-a0"].argv, "-s3.port=8333")
|
||||
error_message = "all-in-one S3 must render when enabled"
|
||||
}
|
||||
}
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
run "security_toml_mtls_only_no_jwt" {
|
||||
command = plan
|
||||
variables {
|
||||
enable_security = true
|
||||
master = { nodes = { m0 = { address = "10.0.0.10" } } }
|
||||
volume = { enabled = false }
|
||||
filer = { enabled = false }
|
||||
}
|
||||
assert {
|
||||
condition = contains(keys(output.nodes["master-m0"].config_files), "/etc/seaweedfs/security.toml")
|
||||
error_message = "security.toml must render for mTLS even without JWT keys"
|
||||
}
|
||||
assert {
|
||||
condition = !strcontains(output.nodes["master-m0"].config_files["/etc/seaweedfs/security.toml"], "[jwt.signing]")
|
||||
error_message = "the jwt.signing block must be omitted when no signing key is set"
|
||||
}
|
||||
}
|
||||
|
||||
run "mount_fetch_and_secret_delivery" {
|
||||
command = plan
|
||||
variables {
|
||||
enable_security = true
|
||||
render_secret_files = false
|
||||
boot_fetch_script = "#!/usr/bin/env bash\necho fetch\n"
|
||||
security = {
|
||||
jwt_signing_key = "test-signing-key-not-a-real-secret-0123456789"
|
||||
}
|
||||
master = { nodes = { m0 = { address = "10.0.0.10", disk_mounts = [{ mountpoint = "/data", fstype = "xfs" }] } } }
|
||||
volume = { enabled = false }
|
||||
filer = { enabled = false }
|
||||
}
|
||||
assert {
|
||||
condition = strcontains(output.nodes["master-m0"].cloud_init, "/opt/seaweedfs/mount-disks.sh")
|
||||
error_message = "cloud-init must write+run the mount script when disk_mounts is set"
|
||||
}
|
||||
assert {
|
||||
condition = strcontains(output.nodes["master-m0"].cloud_init, "/opt/seaweedfs/fetch-secrets.sh")
|
||||
error_message = "cloud-init must write+run the fetch script when boot_fetch_script is set"
|
||||
}
|
||||
assert {
|
||||
condition = !strcontains(output.nodes["master-m0"].cloud_init, "[jwt.signing]")
|
||||
error_message = "security.toml must NOT be inlined in cloud-init when render_secret_files=false"
|
||||
}
|
||||
assert {
|
||||
condition = contains(keys(output.nodes["master-m0"].secret_files), "/etc/seaweedfs/security.toml")
|
||||
error_message = "secret_files must expose security.toml for secret-store delivery"
|
||||
}
|
||||
}
|
||||
|
||||
run "mount_script_absent_without_disks" {
|
||||
command = plan
|
||||
variables {
|
||||
master = { nodes = { m0 = { address = "10.0.0.10" } } }
|
||||
volume = { enabled = false }
|
||||
filer = { enabled = false }
|
||||
}
|
||||
assert {
|
||||
condition = !strcontains(output.nodes["master-m0"].cloud_init, "mount-disks.sh")
|
||||
error_message = "no mount script should render when the node declares no disk_mounts"
|
||||
}
|
||||
}
|
||||
|
||||
run "s3_standalone_targets_filer" {
|
||||
command = plan
|
||||
variables {
|
||||
master = { nodes = { m0 = { address = "10.0.0.10" } } }
|
||||
volume = { enabled = false }
|
||||
filer = { nodes = { f0 = { address = "10.0.0.30" } } }
|
||||
s3 = { enabled = true, nodes = { s0 = { address = "10.0.0.50" } } }
|
||||
}
|
||||
assert {
|
||||
condition = contains(output.nodes["s3-s0"].argv, "-filer=10.0.0.30:8888")
|
||||
error_message = "standalone S3 must point -filer at the first filer node"
|
||||
}
|
||||
assert {
|
||||
condition = contains(output.nodes["s3-s0"].argv, "-config=/etc/seaweedfs/s3_config.json")
|
||||
error_message = "standalone S3 must reference the rendered config path"
|
||||
}
|
||||
}
|
||||
318
terraform/modules/core/variables.tf
Normal file
318
terraform/modules/core/variables.tf
Normal file
@@ -0,0 +1,318 @@
|
||||
# =============================================================================
|
||||
# SeaweedFS Terraform core module - input variables
|
||||
#
|
||||
# This module is a PURE RENDERER. It creates zero cloud resources. It takes a
|
||||
# per-node address map plus configuration and emits, per node, the rendered
|
||||
# `weed` argv, systemd unit, cloud-init, and config files. Both the per-cloud
|
||||
# infra wrappers (consume cloud_init/systemd_unit) and the local test harness
|
||||
# (consume argv/config_files) read its `nodes` output.
|
||||
#
|
||||
# Flag names below are verified against the real `weed` binary, not the chart.
|
||||
# Notably: volume uses -mserver for the master list; gRPC is -port.grpc
|
||||
# (auto = http+10000); minFreeSpacePercent is a string.
|
||||
# =============================================================================
|
||||
|
||||
variable "weed_binary" {
|
||||
description = "Path to the weed executable on the target host."
|
||||
type = string
|
||||
default = "/usr/bin/weed"
|
||||
}
|
||||
|
||||
variable "cluster_name" {
|
||||
description = "Logical cluster name (WEED_CLUSTER_DEFAULT)."
|
||||
type = string
|
||||
default = "sw"
|
||||
}
|
||||
|
||||
variable "log_level" {
|
||||
description = "Global glog verbosity (-v)."
|
||||
type = number
|
||||
default = 1
|
||||
}
|
||||
|
||||
variable "log_to_stderr" {
|
||||
description = "Log to stderr (journald) instead of -logdir. Recommended on systemd."
|
||||
type = bool
|
||||
default = true
|
||||
}
|
||||
|
||||
variable "monitoring_enabled" {
|
||||
description = "Gate the -metricsPort/-metrics.address flags. When false the metrics port is not bound, matching the chart."
|
||||
type = bool
|
||||
default = false
|
||||
}
|
||||
|
||||
variable "enable_security" {
|
||||
description = "Emit the security.toml [grpc] mTLS block and reference per-component certs. Independent of JWT."
|
||||
type = bool
|
||||
default = false
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# Security / secrets (the core only references paths + renders security.toml;
|
||||
# cert/secret material is generated by the wrapper, never defaulted here).
|
||||
# ----------------------------------------------------------------------------
|
||||
variable "security" {
|
||||
description = "mTLS + JWT signing configuration. Secret values must be supplied (never defaulted in module code)."
|
||||
type = object({
|
||||
cert_dir = optional(string, "/usr/local/share/ca-certificates")
|
||||
allowed_wildcard_domain = optional(string, "")
|
||||
allowed_common_names = optional(string, "")
|
||||
jwt_signing_key = optional(string, "")
|
||||
jwt_signing_read_key = optional(string, "")
|
||||
jwt_filer_signing_key = optional(string, "")
|
||||
jwt_filer_signing_read_key = optional(string, "")
|
||||
})
|
||||
default = {}
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
variable "hardening" {
|
||||
description = "systemd hardening directives (OpenShift SCC analogs). Relax per field if needed."
|
||||
type = object({
|
||||
run_as_user = optional(string, "seaweedfs")
|
||||
no_new_privileges = optional(bool, true)
|
||||
protect_system = optional(bool, true)
|
||||
cap_drop_all = optional(bool, true)
|
||||
})
|
||||
default = {}
|
||||
}
|
||||
|
||||
variable "env_file" {
|
||||
description = "Path to the systemd EnvironmentFile holding secret env (DB creds, S3 admin key) fetched at boot. Optional (-prefixed in the unit, so a missing file is tolerated)."
|
||||
type = string
|
||||
default = "/etc/seaweedfs/weed.env"
|
||||
}
|
||||
|
||||
variable "render_secret_files" {
|
||||
description = <<-EOT
|
||||
When true (default), secret-bearing config (security.toml, S3 identity JSON)
|
||||
is written directly into cloud-init user_data. Convenient for the local test
|
||||
harness and simple deployments. Set to false to keep secrets OUT of user_data
|
||||
(and out of the cloud metadata service): the files are then exposed only via
|
||||
the secret_files_by_node output, and the wrapper is expected to deliver them
|
||||
from a secret store via boot_fetch_script.
|
||||
EOT
|
||||
type = bool
|
||||
default = true
|
||||
}
|
||||
|
||||
variable "boot_fetch_script" {
|
||||
description = "Optional shell script written to /opt/seaweedfs/fetch-secrets.sh (root, 0755) and run before the weed unit starts. Used by wrappers to pull certs/secrets from a cloud secret store at boot."
|
||||
type = string
|
||||
default = ""
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# Master (Raft quorum). Keyed `nodes` map -> for_each, never count.
|
||||
# ----------------------------------------------------------------------------
|
||||
variable "master" {
|
||||
description = "Master tier. nodes is a map keyed by stable node id (m0/m1/m2)."
|
||||
type = object({
|
||||
enabled = optional(bool, true)
|
||||
nodes = optional(map(object({
|
||||
address = string
|
||||
port = optional(number)
|
||||
grpc_port = optional(number)
|
||||
data_dir = optional(string)
|
||||
disk_mounts = optional(list(object({
|
||||
mountpoint = string
|
||||
fstype = optional(string, "ext4")
|
||||
devices = optional(list(string), [])
|
||||
})), [])
|
||||
})), {})
|
||||
port = optional(number, 9333)
|
||||
grpc_port = optional(number, null) # null => weed auto = port+10000
|
||||
metrics_port = optional(number, 9327)
|
||||
metrics_ip = optional(string, "")
|
||||
ip_bind = optional(string, "0.0.0.0")
|
||||
data_dir = optional(string, "/var/lib/seaweedfs/master")
|
||||
default_replication = optional(string, "000")
|
||||
volume_size_limit_mb = optional(number, 1000)
|
||||
volume_preallocate = optional(bool, false)
|
||||
garbage_threshold = optional(number, null)
|
||||
disable_http = optional(bool, false)
|
||||
raft_hashicorp = optional(bool, false)
|
||||
resume_state = optional(bool, true) # deliberate deviation: binary default false
|
||||
election_timeout = optional(string, "10s")
|
||||
heartbeat_interval = optional(string, "300ms")
|
||||
white_list = optional(string, "")
|
||||
extra_args = optional(list(string), [])
|
||||
})
|
||||
default = {}
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# Volume (stateful disk owners). Keyed `nodes` map.
|
||||
# ----------------------------------------------------------------------------
|
||||
variable "volume" {
|
||||
description = "Volume tier. Each node owns one or more data dirs (-> -dir / -max)."
|
||||
type = object({
|
||||
enabled = optional(bool, true)
|
||||
nodes = optional(map(object({
|
||||
address = string
|
||||
port = optional(number)
|
||||
grpc_port = optional(number)
|
||||
public_url = optional(string)
|
||||
rack = optional(string)
|
||||
data_center = optional(string)
|
||||
data_dirs = optional(list(object({
|
||||
path = string
|
||||
max_volumes = optional(number, 0) # 0 => auto on non-windows
|
||||
})))
|
||||
idx_dir = optional(string)
|
||||
disk_mounts = optional(list(object({
|
||||
mountpoint = string
|
||||
fstype = optional(string, "ext4")
|
||||
devices = optional(list(string), [])
|
||||
})), [])
|
||||
})), {})
|
||||
port = optional(number, 8080)
|
||||
metrics_port = optional(number, 9327)
|
||||
metrics_ip = optional(string, "")
|
||||
ip_bind = optional(string, "0.0.0.0")
|
||||
data_dirs = optional(list(object({
|
||||
path = string
|
||||
max_volumes = optional(number, 0)
|
||||
})), [{ path = "/data", max_volumes = 0 }])
|
||||
idx_dir = optional(string, "")
|
||||
read_mode = optional(string, "proxy")
|
||||
compaction_mbps = optional(number, 50)
|
||||
min_free_space_percent = optional(string, "1")
|
||||
file_size_limit_mb = optional(number, null)
|
||||
index = optional(string, "memory")
|
||||
images_fix_orientation = optional(bool, false)
|
||||
white_list = optional(string, "")
|
||||
extra_args = optional(list(string), [])
|
||||
})
|
||||
default = {}
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# Filer (+ optional embedded S3). Keyed `nodes` map.
|
||||
# ----------------------------------------------------------------------------
|
||||
variable "filer" {
|
||||
description = "Filer tier. Default leveldb2-replicated HA (each filer has its own store)."
|
||||
type = object({
|
||||
enabled = optional(bool, true)
|
||||
nodes = optional(map(object({
|
||||
address = string
|
||||
port = optional(number)
|
||||
grpc_port = optional(number)
|
||||
data_dir = optional(string)
|
||||
disk_mounts = optional(list(object({
|
||||
mountpoint = string
|
||||
fstype = optional(string, "ext4")
|
||||
devices = optional(list(string), [])
|
||||
})), [])
|
||||
})), {})
|
||||
port = optional(number, 8888)
|
||||
metrics_port = optional(number, 9327)
|
||||
metrics_ip = optional(string, "")
|
||||
ip_bind = optional(string, "0.0.0.0")
|
||||
data_dir = optional(string, "/var/lib/seaweedfs/filer") # -defaultStoreDir for leveldb2
|
||||
default_replica_placement = optional(string, "000")
|
||||
dir_list_limit = optional(number, 100000)
|
||||
max_mb = optional(number, null)
|
||||
disable_dir_listing = optional(bool, false)
|
||||
disable_http = optional(bool, false)
|
||||
encrypt_volume_data = optional(bool, false)
|
||||
rack = optional(string, "")
|
||||
data_center = optional(string, "")
|
||||
filer_group = optional(string, "")
|
||||
extra_env = optional(map(string), {})
|
||||
extra_args = optional(list(string), [])
|
||||
s3 = optional(object({
|
||||
enabled = optional(bool, false)
|
||||
port = optional(number, 8333)
|
||||
https_port = optional(number, 0)
|
||||
domain_name = optional(string, "")
|
||||
config_path = optional(string, "/etc/seaweedfs/s3_config.json")
|
||||
}), {})
|
||||
})
|
||||
default = {}
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# S3 gateway (standalone). Keyed `nodes` map (stateless, but kept keyed for
|
||||
# parity; wrappers may instead drive an ASG).
|
||||
# ----------------------------------------------------------------------------
|
||||
variable "s3" {
|
||||
description = "Standalone S3 gateway tier."
|
||||
type = object({
|
||||
enabled = optional(bool, false)
|
||||
nodes = optional(map(object({
|
||||
address = string
|
||||
port = optional(number)
|
||||
grpc_port = optional(number)
|
||||
})), {})
|
||||
port = optional(number, 8333)
|
||||
https_port = optional(number, 0)
|
||||
iceberg_port = optional(number, null)
|
||||
metrics_port = optional(number, 9327)
|
||||
ip_bind = optional(string, "0.0.0.0")
|
||||
domain_name = optional(string, "")
|
||||
filer_address = optional(string, "") # override; else first filer node
|
||||
config_path = optional(string, "/etc/seaweedfs/s3_config.json")
|
||||
audit_log_config_path = optional(string, "")
|
||||
cert_file = optional(string, "")
|
||||
key_file = optional(string, "")
|
||||
cacert_file = optional(string, "")
|
||||
verify_client_cert = optional(bool, false)
|
||||
extra_args = optional(list(string), [])
|
||||
})
|
||||
default = {}
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# S3 identities -> rendered into the s3 config JSON (non-admin only; the admin
|
||||
# credential is delivered via EnvironmentFile, never the JSON).
|
||||
# ----------------------------------------------------------------------------
|
||||
variable "s3_identities" {
|
||||
description = "Non-admin S3 identities rendered into the config JSON. Admin key goes in the EnvironmentFile, not here."
|
||||
type = list(object({
|
||||
name = string
|
||||
access_key = string
|
||||
secret_key = string
|
||||
actions = list(string)
|
||||
}))
|
||||
default = []
|
||||
sensitive = true
|
||||
}
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# All-in-one (single `weed server` process).
|
||||
# ----------------------------------------------------------------------------
|
||||
variable "all_in_one" {
|
||||
description = "All-in-one tier (weed server). Mutually exclusive with the distributed tiers."
|
||||
type = object({
|
||||
enabled = optional(bool, false)
|
||||
nodes = optional(map(object({
|
||||
address = string
|
||||
data_dir = optional(string)
|
||||
disk_mounts = optional(list(object({
|
||||
mountpoint = string
|
||||
fstype = optional(string, "ext4")
|
||||
devices = optional(list(string), [])
|
||||
})), [])
|
||||
})), {})
|
||||
data_dir = optional(string, "/data")
|
||||
ip_bind = optional(string, "0.0.0.0")
|
||||
master_port = optional(number, 9333)
|
||||
volume_port = optional(number, 8080)
|
||||
filer_port = optional(number, 8888)
|
||||
default_replication = optional(string, "000")
|
||||
volume_size_limit_mb = optional(number, 1000)
|
||||
idle_timeout = optional(number, 30)
|
||||
metrics_port = optional(number, 9324)
|
||||
disable_http = optional(bool, false)
|
||||
s3 = optional(object({
|
||||
enabled = optional(bool, false)
|
||||
port = optional(number, 8333)
|
||||
config_path = optional(string, "/etc/seaweedfs/s3/s3_config.json")
|
||||
domain_name = optional(string, "")
|
||||
}), {})
|
||||
extra_args = optional(list(string), [])
|
||||
})
|
||||
default = {}
|
||||
}
|
||||
6
terraform/modules/core/versions.tf
Normal file
6
terraform/modules/core/versions.tf
Normal file
@@ -0,0 +1,6 @@
|
||||
terraform {
|
||||
# 1.3+ is required for optional() object attributes with defaults.
|
||||
# The published wrappers pin a single honest floor;
|
||||
# the core itself only needs language features available since 1.3.
|
||||
required_version = ">= 1.3.0"
|
||||
}
|
||||
Reference in New Issue
Block a user