From 4a1078d55d424f415ab628eb527a9573790a5ffa Mon Sep 17 00:00:00 2001
From: Matthew Baggett <matthew@baggett.me>
Date: Mon, 3 Mar 2025 15:46:36 +0100
Subject: [PATCH] Initial nextcloud

---
 products/nextcloud/inputs.tf    | 57 +++++++++++++++++++++++++++++++++
 products/nextcloud/network.tf   |  5 +++
 products/nextcloud/nextcloud.tf | 35 ++++++++++++++++++++
 products/nextcloud/output.tf    |  6 ++++
 products/nextcloud/postgres.tf  | 11 +++++++
 products/nextcloud/redis.tf     |  7 ++++
 products/nextcloud/terraform.tf | 13 ++++++++
 7 files changed, 134 insertions(+)
 create mode 100644 products/nextcloud/inputs.tf
 create mode 100644 products/nextcloud/network.tf
 create mode 100644 products/nextcloud/nextcloud.tf
 create mode 100644 products/nextcloud/output.tf
 create mode 100644 products/nextcloud/postgres.tf
 create mode 100644 products/nextcloud/redis.tf
 create mode 100644 products/nextcloud/terraform.tf

diff --git a/products/nextcloud/inputs.tf b/products/nextcloud/inputs.tf
new file mode 100644
index 0000000..6ca35ab
--- /dev/null
+++ b/products/nextcloud/inputs.tf
@@ -0,0 +1,57 @@
+variable "enable" {
+  type        = bool
+  description = "Whether to enable the service."
+  default     = true
+}
+# Pass-thru variables
+variable "stack_name" {
+  type = string
+}
+variable "service_name" {
+  default     = "postgres"
+  type        = string
+  description = "The name of the service to create."
+}
+variable "networks" {
+  type = list(object({
+    name = string
+    id   = string
+  }))
+  default     = []
+  description = "A list of network names to attach the service to."
+}
+variable "ports" {
+  type = list(object({
+    host         = optional(number, null)
+    container    = number
+    protocol     = optional(string, "tcp")
+    publish_mode = optional(string, "ingress")
+  }))
+  default     = []
+  description = "A map of port mappings to expose on the host. The key is the host port, and the value is the container port."
+}
+variable "postgres_ports" {
+  type = list(object({
+    host         = optional(number, null)
+    container    = number
+    protocol     = optional(string, "tcp")
+    publish_mode = optional(string, "ingress")
+  }))
+  default     = []
+  description = "A map of port mappings to expose on the host. The key is the host port, and the value is the container port."
+}
+variable "mounts" {
+  type        = map(string)
+  default     = {}
+  description = "A map of host paths to container paths to mount. The key is the host path, and the value is the container path."
+}
+variable "placement_constraints" {
+  default     = []
+  type        = list(string)
+  description = "Docker Swarm placement constraints"
+}
+variable "data_persist_path" {
+  default     = null
+  description = "Path on host machine to persist data. Leaving this blank will provision an ephemeral volume."
+  type        = string
+}
diff --git a/products/nextcloud/network.tf b/products/nextcloud/network.tf
new file mode 100644
index 0000000..9d7b29a
--- /dev/null
+++ b/products/nextcloud/network.tf
@@ -0,0 +1,5 @@
+module "network" {
+  source       = "../../docker/network"
+  stack_name   = var.stack_name
+  network_name = "nextcloud"
+}
\ No newline at end of file
diff --git a/products/nextcloud/nextcloud.tf b/products/nextcloud/nextcloud.tf
new file mode 100644
index 0000000..75a6499
--- /dev/null
+++ b/products/nextcloud/nextcloud.tf
@@ -0,0 +1,35 @@
+module "nextcloud" {
+  source                = "../../docker/service"
+  enable                = var.enable
+  stack_name            = var.stack_name
+  service_name          = "nextcloud"
+  image                 = "nextcloud:stable"
+  networks              = [module.network]
+  ports                 = var.ports
+  mounts                = var.mounts
+  placement_constraints = var.placement_constraints
+  environment_variables = {
+    POSTGRES_HOST       = module.postgres.service_name
+    POSTGRES_USER       = module.postgres.username
+    POSTGRES_PASSWORD   = module.postgres.password
+    POSTGRES_DB         = module.postgres.database
+    REDIS_HOST          = module.redis.service_name
+    REDIS_HOST_PASSWORD = module.redis.auth
+    #NEXTCLOUD_ADMIN_USER     = random_pet.admin_user.id
+    #NEXTCLOUD_ADMIN_PASSWORD = nonsensitive(random_password.admin_password.result)
+    NEXTCLOUD_DATA_DIR = "/mnt/data"
+    #NEXTCLOUD_UPDATE         = false
+    #NEXTCLOUD_INIT_HTACCESS  = true
+    NC_setup_create_db_user = false
+  }
+  converge_enable = false # @todo: Implement a healthcheck and change this.
+  start_first     = false
+}
+resource "random_pet" "admin_user" {
+  length    = 2
+  separator = ""
+}
+resource "random_password" "admin_password" {
+  length  = 32
+  special = false
+}
\ No newline at end of file
diff --git a/products/nextcloud/output.tf b/products/nextcloud/output.tf
new file mode 100644
index 0000000..5441ae2
--- /dev/null
+++ b/products/nextcloud/output.tf
@@ -0,0 +1,6 @@
+output "admin" {
+  value = {
+    username = random_pet.admin_user.id
+    password = nonsensitive(random_password.admin_password.result)
+  }
+}
\ No newline at end of file
diff --git a/products/nextcloud/postgres.tf b/products/nextcloud/postgres.tf
new file mode 100644
index 0000000..5386fd3
--- /dev/null
+++ b/products/nextcloud/postgres.tf
@@ -0,0 +1,11 @@
+module "postgres" {
+  source                = "../postgres"
+  enable                = var.enable
+  stack_name            = var.stack_name
+  database              = "nextcloud"
+  username              = "nextcloud"
+  networks              = [module.network]
+  data_persist_path     = "/goliath/nextcloud/postgres"
+  placement_constraints = var.placement_constraints
+  ports                 = var.postgres_ports
+}
\ No newline at end of file
diff --git a/products/nextcloud/redis.tf b/products/nextcloud/redis.tf
new file mode 100644
index 0000000..3fe2164
--- /dev/null
+++ b/products/nextcloud/redis.tf
@@ -0,0 +1,7 @@
+module "redis" {
+  source                = "../redis"
+  enable                = var.enable
+  stack_name            = var.stack_name
+  networks              = [module.network]
+  placement_constraints = var.placement_constraints
+}
\ No newline at end of file
diff --git a/products/nextcloud/terraform.tf b/products/nextcloud/terraform.tf
new file mode 100644
index 0000000..d2a0d07
--- /dev/null
+++ b/products/nextcloud/terraform.tf
@@ -0,0 +1,13 @@
+terraform {
+  required_version = "~> 1.6"
+  required_providers {
+    docker = {
+      source  = "kreuzwerker/docker"
+      version = "~> 3.0"
+    }
+    random = {
+      source  = "hashicorp/random"
+      version = "~> 3.0"
+    }
+  }
+}