From 11ea1e3b44cb6cfc6d7d2f2771b0b8ea8ac41408 Mon Sep 17 00:00:00 2001 From: Stavros Kois <47820033+stavros-k@users.noreply.github.com> Date: Wed, 10 Jan 2024 11:43:54 +0200 Subject: [PATCH] Add Roundcube (#2011) --- library/ix-dev/community/roundcube/Chart.lock | 6 + library/ix-dev/community/roundcube/Chart.yaml | 26 + library/ix-dev/community/roundcube/README.md | 11 + .../ix-dev/community/roundcube/app-readme.md | 11 + .../roundcube/charts/common-1.2.6.tgz | Bin 0 -> 63145 bytes .../community/roundcube/ci/basic-values.yaml | 17 + library/ix-dev/community/roundcube/item.yaml | 12 + .../ix-dev/community/roundcube/metadata.yaml | 23 + .../ix-dev/community/roundcube/questions.yaml | 743 ++++++++++++++++++ .../community/roundcube/templates/NOTES.txt | 1 + .../roundcube/templates/_configuration.tpl | 54 ++ .../roundcube/templates/_persistence.tpl | 47 ++ .../community/roundcube/templates/_portal.tpl | 12 + .../roundcube/templates/_postgres.tpl | 6 + .../roundcube/templates/_roundcube.tpl | 57 ++ .../roundcube/templates/_service.tpl | 18 + .../community/roundcube/templates/common.yaml | 13 + .../community/roundcube/upgrade_info.json | 1 + .../community/roundcube/upgrade_strategy | 31 + .../ix-dev/community/roundcube/values.yaml | 66 ++ 20 files changed, 1155 insertions(+) create mode 100644 library/ix-dev/community/roundcube/Chart.lock create mode 100644 library/ix-dev/community/roundcube/Chart.yaml create mode 100644 library/ix-dev/community/roundcube/README.md create mode 100644 library/ix-dev/community/roundcube/app-readme.md create mode 100644 library/ix-dev/community/roundcube/charts/common-1.2.6.tgz create mode 100644 library/ix-dev/community/roundcube/ci/basic-values.yaml create mode 100644 library/ix-dev/community/roundcube/item.yaml create mode 100644 library/ix-dev/community/roundcube/metadata.yaml create mode 100644 library/ix-dev/community/roundcube/questions.yaml create mode 100644 library/ix-dev/community/roundcube/templates/NOTES.txt create mode 100644 library/ix-dev/community/roundcube/templates/_configuration.tpl create mode 100644 library/ix-dev/community/roundcube/templates/_persistence.tpl create mode 100644 library/ix-dev/community/roundcube/templates/_portal.tpl create mode 100644 library/ix-dev/community/roundcube/templates/_postgres.tpl create mode 100644 library/ix-dev/community/roundcube/templates/_roundcube.tpl create mode 100644 library/ix-dev/community/roundcube/templates/_service.tpl create mode 100644 library/ix-dev/community/roundcube/templates/common.yaml create mode 100644 library/ix-dev/community/roundcube/upgrade_info.json create mode 100755 library/ix-dev/community/roundcube/upgrade_strategy create mode 100644 library/ix-dev/community/roundcube/values.yaml diff --git a/library/ix-dev/community/roundcube/Chart.lock b/library/ix-dev/community/roundcube/Chart.lock new file mode 100644 index 0000000000..6c92a53db1 --- /dev/null +++ b/library/ix-dev/community/roundcube/Chart.lock @@ -0,0 +1,6 @@ +dependencies: +- name: common + repository: file://../../../common + version: 1.2.6 +digest: sha256:956cef64e364b567d2e5327a00e60b68f3ef765e003d6c35afc143bb81ecc26b +generated: "2023-12-27T13:14:19.924272436+02:00" diff --git a/library/ix-dev/community/roundcube/Chart.yaml b/library/ix-dev/community/roundcube/Chart.yaml new file mode 100644 index 0000000000..e689733ea6 --- /dev/null +++ b/library/ix-dev/community/roundcube/Chart.yaml @@ -0,0 +1,26 @@ +name: roundcube +description: Roundcube is a browser-based multilingual IMAP client with an application-like user interface. +annotations: + title: Roundcube +type: application +version: 1.0.0 +apiVersion: v2 +appVersion: 1.6.5 +kubeVersion: '>=1.16.0-0' +maintainers: + - name: truenas + url: https://www.truenas.com/ + email: dev@ixsystems.com +dependencies: + - name: common + repository: file://../../../common + version: 1.2.6 +home: https://roundcube.net/ +icon: https://media.sys.truenas.net/apps/roundcube/icons/icon.png +sources: + - https://roundcube.net/ + - https://github.com/truenas/charts/tree/master/community/roundcube + - https://hub.docker.com/r/roundcube/roundcubemail/ +keywords: + - webmail + - email diff --git a/library/ix-dev/community/roundcube/README.md b/library/ix-dev/community/roundcube/README.md new file mode 100644 index 0000000000..ebe4a5a535 --- /dev/null +++ b/library/ix-dev/community/roundcube/README.md @@ -0,0 +1,11 @@ +# Roundcube + +[Roundcube](https://roundcube.net/) is a browser-based multilingual IMAP client with an application-like user interface. + +> When application is installed, a container will be launched with **root** privileges. +> This is required in order to apply the correct permissions to the `postgres` directories. +> Afterward, the `postgres` container will run as a **non**-root user (`999`). +> On each upgrade, a container will be launched with **root** privileges in order to apply the correct +> permissions to the `postgres` **backups** directory. Container that performs the backup will run as a **non**-root user (`999`) afterwards. +> Keep in mind the permissions on the backup directory will be changed to `999:999` on **every** update. +> But will only be changed once for the `postgres` data directories. diff --git a/library/ix-dev/community/roundcube/app-readme.md b/library/ix-dev/community/roundcube/app-readme.md new file mode 100644 index 0000000000..ebe4a5a535 --- /dev/null +++ b/library/ix-dev/community/roundcube/app-readme.md @@ -0,0 +1,11 @@ +# Roundcube + +[Roundcube](https://roundcube.net/) is a browser-based multilingual IMAP client with an application-like user interface. + +> When application is installed, a container will be launched with **root** privileges. +> This is required in order to apply the correct permissions to the `postgres` directories. +> Afterward, the `postgres` container will run as a **non**-root user (`999`). +> On each upgrade, a container will be launched with **root** privileges in order to apply the correct +> permissions to the `postgres` **backups** directory. Container that performs the backup will run as a **non**-root user (`999`) afterwards. +> Keep in mind the permissions on the backup directory will be changed to `999:999` on **every** update. +> But will only be changed once for the `postgres` data directories. diff --git a/library/ix-dev/community/roundcube/charts/common-1.2.6.tgz b/library/ix-dev/community/roundcube/charts/common-1.2.6.tgz new file mode 100644 index 0000000000000000000000000000000000000000..aa6d8b92c85bdddfa2bf028aab071f61d2e7b9b5 GIT binary patch literal 63145 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 literal 0 HcmV?d00001 diff --git a/library/ix-dev/community/roundcube/ci/basic-values.yaml b/library/ix-dev/community/roundcube/ci/basic-values.yaml new file mode 100644 index 0000000000..84b39d8b22 --- /dev/null +++ b/library/ix-dev/community/roundcube/ci/basic-values.yaml @@ -0,0 +1,17 @@ +roundcubeNetwork: + webPort: 31000 + +roundcubeStorage: + html: + type: pvc + config: + type: pvc + temps: + type: pvc + pgData: + type: pvc + pgBackup: + type: emptyDir + emptyDirConfig: + medium: "" + size: "" diff --git a/library/ix-dev/community/roundcube/item.yaml b/library/ix-dev/community/roundcube/item.yaml new file mode 100644 index 0000000000..05435084dd --- /dev/null +++ b/library/ix-dev/community/roundcube/item.yaml @@ -0,0 +1,12 @@ +icon_url: https://media.sys.truenas.net/apps/roundcube/icons/icon.png +categories: + - productivity +screenshots: + - https://media.sys.truenas.net/apps/roundcube/screenshots/screenshot1.png + - https://media.sys.truenas.net/apps/roundcube/screenshots/screenshot2.png + - https://media.sys.truenas.net/apps/roundcube/screenshots/screenshot3.png + - https://media.sys.truenas.net/apps/roundcube/screenshots/screenshot4.png + - https://media.sys.truenas.net/apps/roundcube/screenshots/screenshot5.png +tags: + - webmail + - email diff --git a/library/ix-dev/community/roundcube/metadata.yaml b/library/ix-dev/community/roundcube/metadata.yaml new file mode 100644 index 0000000000..a23dc49ec8 --- /dev/null +++ b/library/ix-dev/community/roundcube/metadata.yaml @@ -0,0 +1,23 @@ +runAsContext: + - userName: root + groupName: root + gid: 0 + uid: 0 + description: Roundcube runs as root user + - userName: postgres + groupName: postgres + gid: 999 + uid: 999 + description: Postgres runs as a non-root user. +capabilities: + - name: CHOWN + description: Roundcube is able to chown files. + - name: SETGID + description: Roundcube is able to set group ID for it's sub-processes. + - name: SETUID + description: Roundcube is able to set user ID for it's sub-processes. + - name: FOWNER + description: Roundcube is able to bypass permission checks for chown. + - name: DAC_OVERRIDE + description: Roundcube is able to bypass permission checks. +hostMounts: [] diff --git a/library/ix-dev/community/roundcube/questions.yaml b/library/ix-dev/community/roundcube/questions.yaml new file mode 100644 index 0000000000..67c3bb9a64 --- /dev/null +++ b/library/ix-dev/community/roundcube/questions.yaml @@ -0,0 +1,743 @@ +groups: + - name: Roundcube Configuration + description: Configure Roundcube + - name: Network Configuration + description: Configure Network for Roundcube + - name: Storage Configuration + description: Configure Storage for Roundcube + - name: Resources Configuration + description: Configure Resources for Roundcube + +portals: + web_portal: + protocols: + - "$kubernetes-resource_configmap_portal_protocol" + host: + - "$kubernetes-resource_configmap_portal_host" + ports: + - "$kubernetes-resource_configmap_portal_port" + path: "$kubernetes-resource_configmap_portal_path" + +questions: + + - variable: roundcubeConfig + label: "" + group: Roundcube Configuration + schema: + type: dict + attrs: + - variable: defaultHost + label: Default Host (IMAP) + description: The default host to connect to. + schema: + type: string + default: "" + required: true + - variable: defaultPort + label: Default Port (IMAP) + description: The default port to connect to. + schema: + type: int + default: 143 + min: 1 + max: 65535 + required: true + - variable: smtpServer + label: SMTP Server + description: The SMTP server to use. + schema: + type: string + default: "" + required: true + - variable: smtpPort + label: SMTP Port + description: The SMTP port to use. + schema: + type: int + default: 587 + min: 1 + max: 65535 + required: true + - variable: skin + label: Skin + description: | + Configures the default theme
+ If you don't have the theme installed, + it will show an error on all pages. + schema: + type: string + default: elastic + required: true + - variable: uploadMaxSize + label: Upload Max Size + description: The maximum size of an upload in MB.
+ schema: + type: int + default: 5 + min: 1 + required: true + - variable: aspellDicts + label: Aspell Dictionaries + description: A list of aspell dictionaries to install. + schema: + type: list + default: [] + items: + - variable: aspellDict + label: Aspell Dictionary + schema: + type: string + required: true + - variable: plugins + label: Plugins + description: A list of plugins to enable. + schema: + type: list + default: + - archive + - zipdownload + items: + - variable: plugin + label: Plugin + schema: + type: string + required: true + + - variable: additionalEnvs + label: Additional Environment Variables + description: Configure additional environment variables for Roundcube. + schema: + type: list + default: [] + items: + - variable: env + label: Environment Variable + schema: + type: dict + attrs: + - variable: name + label: Name + schema: + type: string + required: true + - variable: value + label: Value + schema: + type: string + required: true + + - variable: roundcubeNetwork + label: "" + group: Network Configuration + schema: + type: dict + attrs: + - variable: webPort + label: Web Port + description: The port for the Roundcube WebUI. + schema: + type: int + default: 31007 + min: 9000 + max: 65535 + required: true + + - variable: roundcubeStorage + label: "" + group: Storage Configuration + schema: + type: dict + attrs: + - variable: html + label: Roundcube HTML Storage + description: The path to store Roundcube HTML. + schema: + type: dict + attrs: + - variable: type + label: Type + description: | + ixVolume: Is dataset created automatically by the system.
+ Host Path: Is a path that already exists on the system. + schema: + type: string + required: true + immutable: true + default: ixVolume + enum: + - value: hostPath + description: Host Path (Path that already exists on the system) + - value: ixVolume + description: ixVolume (Dataset created automatically by the system) + - variable: ixVolumeConfig + label: ixVolume Configuration + description: The configuration for the ixVolume dataset. + schema: + type: dict + show_if: [["type", "=", "ixVolume"]] + $ref: + - "normalize/ixVolume" + attrs: + - variable: aclEnable + label: Enable ACL + description: Enable ACL for the dataset. + schema: + type: boolean + default: false + - variable: datasetName + label: Dataset Name + description: The name of the dataset to use for storage. + schema: + type: string + required: true + immutable: true + hidden: true + default: "html" + - variable: aclEntries + label: ACL Configuration + schema: + type: dict + show_if: [["aclEnable", "=", true]] + attrs: [] + - variable: hostPathConfig + label: Host Path Configuration + schema: + type: dict + show_if: [["type", "=", "hostPath"]] + attrs: + - variable: aclEnable + label: Enable ACL + description: Enable ACL for the dataset. + schema: + type: boolean + default: false + - variable: acl + label: ACL Configuration + schema: + type: dict + show_if: [["aclEnable", "=", true]] + attrs: [] + $ref: + - "normalize/acl" + - variable: hostPath + label: Host Path + description: The host path to use for storage. + schema: + type: hostpath + show_if: [["aclEnable", "=", false]] + required: true + - variable: config + label: Roundcube Config Storage + description: The path to store Roundcube Config. + schema: + type: dict + attrs: + - variable: type + label: Type + description: | + ixVolume: Is dataset created automatically by the system.
+ Host Path: Is a path that already exists on the system. + schema: + type: string + required: true + immutable: true + default: ixVolume + enum: + - value: hostPath + description: Host Path (Path that already exists on the system) + - value: ixVolume + description: ixVolume (Dataset created automatically by the system) + - variable: ixVolumeConfig + label: ixVolume Configuration + description: The configuration for the ixVolume dataset. + schema: + type: dict + show_if: [["type", "=", "ixVolume"]] + $ref: + - "normalize/ixVolume" + attrs: + - variable: aclEnable + label: Enable ACL + description: Enable ACL for the dataset. + schema: + type: boolean + default: false + - variable: datasetName + label: Dataset Name + description: The name of the dataset to use for storage. + schema: + type: string + required: true + immutable: true + hidden: true + default: "config" + - variable: aclEntries + label: ACL Configuration + schema: + type: dict + show_if: [["aclEnable", "=", true]] + attrs: [] + - variable: hostPathConfig + label: Host Path Configuration + schema: + type: dict + show_if: [["type", "=", "hostPath"]] + attrs: + - variable: aclEnable + label: Enable ACL + description: Enable ACL for the dataset. + schema: + type: boolean + default: false + - variable: acl + label: ACL Configuration + schema: + type: dict + show_if: [["aclEnable", "=", true]] + attrs: [] + $ref: + - "normalize/acl" + - variable: hostPath + label: Host Path + description: The host path to use for storage. + schema: + type: hostpath + show_if: [["aclEnable", "=", false]] + required: true + - variable: temps + label: Roundcube Temp Storage + description: The path to store Roundcube Temp. + schema: + type: dict + attrs: + - variable: type + label: Type + description: | + ixVolume: Is dataset created automatically by the system.
+ Host Path: Is a path that already exists on the system. + schema: + type: string + required: true + immutable: true + default: ixVolume + enum: + - value: hostPath + description: Host Path (Path that already exists on the system) + - value: ixVolume + description: ixVolume (Dataset created automatically by the system) + - variable: ixVolumeConfig + label: ixVolume Configuration + description: The configuration for the ixVolume dataset. + schema: + type: dict + show_if: [["type", "=", "ixVolume"]] + $ref: + - "normalize/ixVolume" + attrs: + - variable: aclEnable + label: Enable ACL + description: Enable ACL for the dataset. + schema: + type: boolean + default: false + - variable: datasetName + label: Dataset Name + description: The name of the dataset to use for storage. + schema: + type: string + required: true + immutable: true + hidden: true + default: "temps" + - variable: aclEntries + label: ACL Configuration + schema: + type: dict + show_if: [["aclEnable", "=", true]] + attrs: [] + - variable: hostPathConfig + label: Host Path Configuration + schema: + type: dict + show_if: [["type", "=", "hostPath"]] + attrs: + - variable: aclEnable + label: Enable ACL + description: Enable ACL for the dataset. + schema: + type: boolean + default: false + - variable: acl + label: ACL Configuration + schema: + type: dict + show_if: [["aclEnable", "=", true]] + attrs: [] + $ref: + - "normalize/acl" + - variable: hostPath + label: Host Path + description: The host path to use for storage. + schema: + type: hostpath + show_if: [["aclEnable", "=", false]] + required: true + + - variable: pgData + label: Roundcube Postgres Data Storage + description: The path to store Roundcube Postgres Data. + schema: + type: dict + attrs: + - variable: type + label: Type + description: | + ixVolume: Is dataset created automatically by the system.
+ Host Path: Is a path that already exists on the system. + schema: + type: string + required: true + immutable: true + default: ixVolume + enum: + - value: hostPath + description: Host Path (Path that already exists on the system) + - value: ixVolume + description: ixVolume (Dataset created automatically by the system) + - variable: ixVolumeConfig + label: ixVolume Configuration + description: The configuration for the ixVolume dataset. + schema: + type: dict + # Nothing to show for the user + hidden: true + show_if: [["type", "=", "ixVolume"]] + $ref: + - "normalize/ixVolume" + attrs: + - variable: aclEnable + label: Enable ACL + description: Enable ACL for the dataset. + schema: + type: boolean + # Postgres does a CHMOD at startup + # Which fails with ACL + hidden: true + default: false + - variable: datasetName + label: Dataset Name + description: The name of the dataset to use for storage. + schema: + type: string + required: true + immutable: true + hidden: true + default: "pgData" + - variable: aclEntries + label: ACL Configuration + schema: + type: dict + show_if: [["aclEnable", "=", true]] + attrs: [] + - variable: hostPathConfig + label: Host Path Configuration + schema: + type: dict + show_if: [["type", "=", "hostPath"]] + attrs: + - variable: aclEnable + label: Enable ACL + description: Enable ACL for the dataset. + schema: + type: boolean + # Postgres does a CHMOD at startup + # Which fails with ACL + hidden: true + default: false + - variable: acl + label: ACL Configuration + schema: + type: dict + show_if: [["aclEnable", "=", true]] + attrs: [] + $ref: + - "normalize/acl" + - variable: hostPath + label: Host Path + description: The host path to use for storage. + schema: + type: hostpath + show_if: [["aclEnable", "=", false]] + required: true + + - variable: pgBackup + label: Roundcube Postgres Backup Storage + description: The path to store Roundcube Postgres Backup. + schema: + type: dict + attrs: + - variable: type + label: Type + description: | + ixVolume: Is dataset created automatically by the system.
+ Host Path: Is a path that already exists on the system. + schema: + type: string + required: true + immutable: true + default: ixVolume + enum: + - value: hostPath + description: Host Path (Path that already exists on the system) + - value: ixVolume + description: ixVolume (Dataset created automatically by the system) + - variable: ixVolumeConfig + label: ixVolume Configuration + description: The configuration for the ixVolume dataset. + schema: + type: dict + # Nothing to show for the user + hidden: true + show_if: [["type", "=", "ixVolume"]] + $ref: + - "normalize/ixVolume" + attrs: + - variable: aclEnable + label: Enable ACL + description: Enable ACL for the dataset. + schema: + type: boolean + # Postgres does a CHMOD at startup + # Which fails with ACL + hidden: true + default: false + - variable: datasetName + label: Dataset Name + description: The name of the dataset to use for storage. + schema: + type: string + required: true + immutable: true + hidden: true + default: "pgBackup" + - variable: aclEntries + label: ACL Configuration + schema: + type: dict + show_if: [["aclEnable", "=", true]] + attrs: [] + - variable: hostPathConfig + label: Host Path Configuration + schema: + type: dict + show_if: [["type", "=", "hostPath"]] + attrs: + - variable: aclEnable + label: Enable ACL + description: Enable ACL for the dataset. + schema: + type: boolean + # Postgres does a CHMOD at startup + # Which fails with ACL + hidden: true + default: false + - variable: acl + label: ACL Configuration + schema: + type: dict + show_if: [["aclEnable", "=", true]] + attrs: [] + $ref: + - "normalize/acl" + - variable: hostPath + label: Host Path + description: The host path to use for storage. + schema: + type: hostpath + show_if: [["aclEnable", "=", false]] + required: true + + - variable: additionalStorages + label: Additional Storage + description: Additional storage for Roundcube. + schema: + type: list + default: [] + items: + - variable: storageEntry + label: Storage Entry + schema: + type: dict + attrs: + - variable: type + label: Type + description: | + ixVolume: Is dataset created automatically by the system.
+ Host Path: Is a path that already exists on the system.
+ SMB Share: Is a SMB share that is mounted to a persistent volume claim. + schema: + type: string + required: true + default: "ixVolume" + immutable: true + enum: + - value: "hostPath" + description: Host Path (Path that already exists on the system) + - value: "ixVolume" + description: ixVolume (Dataset created automatically by the system) + - value: "smb-pv-pvc" + description: SMB Share (Mounts a persistent volume claim to a SMB share) + - variable: readOnly + label: Read Only + description: Mount the volume as read only. + schema: + type: boolean + default: false + - variable: mountPath + label: Mount Path + description: The path inside the container to mount the storage. + schema: + type: path + required: true + - variable: hostPathConfig + label: Host Path Configuration + schema: + type: dict + show_if: [["type", "=", "hostPath"]] + attrs: + - variable: aclEnable + label: Enable ACL + description: Enable ACL for the dataset. + schema: + type: boolean + default: false + - variable: acl + label: ACL Configuration + schema: + type: dict + show_if: [["aclEnable", "=", true]] + attrs: [] + $ref: + - "normalize/acl" + - variable: hostPath + label: Host Path + description: The host path to use for storage. + schema: + type: hostpath + show_if: [["aclEnable", "=", false]] + required: true + - variable: ixVolumeConfig + label: ixVolume Configuration + description: The configuration for the ixVolume dataset. + schema: + type: dict + show_if: [["type", "=", "ixVolume"]] + $ref: + - "normalize/ixVolume" + attrs: + - variable: aclEnable + label: Enable ACL + description: Enable ACL for the dataset. + schema: + type: boolean + default: false + - variable: datasetName + label: Dataset Name + description: The name of the dataset to use for storage. + schema: + type: string + required: true + immutable: true + default: "storage_entry" + - variable: aclEntries + label: ACL Configuration + schema: + type: dict + show_if: [["aclEnable", "=", true]] + attrs: [] + - variable: smbConfig + label: SMB Share Configuration + description: The configuration for the SMB Share. + schema: + type: dict + show_if: [["type", "=", "smb-pv-pvc"]] + attrs: + - variable: server + label: Server + description: The server for the SMB share. + schema: + type: string + required: true + - variable: share + label: Share + description: The share name for the SMB share. + schema: + type: string + required: true + - variable: domain + label: Domain (Optional) + description: The domain for the SMB share. + schema: + type: string + - variable: username + label: Username + description: The username for the SMB share. + schema: + type: string + required: true + - variable: password + label: Password + description: The password for the SMB share. + schema: + type: string + required: true + private: true + - variable: size + label: Size (in Gi) + description: The size of the volume quota. + schema: + type: int + required: true + min: 1 + default: 1 + + - variable: resources + label: "" + group: Resources Configuration + schema: + type: dict + attrs: + - variable: limits + label: Limits + schema: + type: dict + attrs: + - variable: cpu + label: CPU + description: CPU limit for Roundcube. + schema: + type: string + max_length: 6 + valid_chars: '^(0\.[1-9]|[1-9][0-9]*)(\.[0-9]|m?)$' + valid_chars_error: | + Valid CPU limit formats are
+ - Plain Integer - eg. 1
+ - Float - eg. 0.5
+ - Milicpu - eg. 500m + default: "4000m" + required: true + - variable: memory + label: Memory + description: Memory limit for Roundcube. + schema: + type: string + max_length: 12 + valid_chars: '^[1-9][0-9]*([EPTGMK]i?|e[0-9]+)?$' + valid_chars_error: | + Valid Memory limit formats are
+ - Suffixed with E/P/T/G/M/K - eg. 1G
+ - Suffixed with Ei/Pi/Ti/Gi/Mi/Ki - eg. 1Gi
+ - Plain Integer in bytes - eg. 1024
+ - Exponent - eg. 134e6 + default: "8Gi" + required: true diff --git a/library/ix-dev/community/roundcube/templates/NOTES.txt b/library/ix-dev/community/roundcube/templates/NOTES.txt new file mode 100644 index 0000000000..ba4e01146c --- /dev/null +++ b/library/ix-dev/community/roundcube/templates/NOTES.txt @@ -0,0 +1 @@ +{{ include "ix.v1.common.lib.chart.notes" $ }} diff --git a/library/ix-dev/community/roundcube/templates/_configuration.tpl b/library/ix-dev/community/roundcube/templates/_configuration.tpl new file mode 100644 index 0000000000..dd610e1888 --- /dev/null +++ b/library/ix-dev/community/roundcube/templates/_configuration.tpl @@ -0,0 +1,54 @@ +{{- define "roundcube.configuration" -}} + + {{- $fullname := (include "ix.v1.common.lib.chart.names.fullname" $) -}} + + {{- $dbHost := (printf "%s-postgres" $fullname) -}} + {{- $dbUser := "roundcube" -}} + {{- $dbName := "roundcube" -}} + + {{- $dbPass := (randAlphaNum 32) -}} + {{- with (lookup "v1" "Secret" .Release.Namespace (printf "%s-postgres-creds" $fullname)) -}} + {{- $dbPass = ((index .data "POSTGRES_PASSWORD") | b64dec) -}} + {{- end -}} + + {{/* Temporary set dynamic db details on values, + so we can print them on the notes */}} + {{- $_ := set .Values "roundcubeDbPass" $dbPass -}} + {{- $_ := set .Values "roundcubeDbHost" $dbHost -}} + + {{- $dbURL := (printf "postgres://%s:%s@%s:5432/%s?sslmode=disable" $dbUser $dbPass $dbHost $dbName) }} +secret: + postgres-creds: + enabled: true + data: + POSTGRES_USER: {{ $dbUser }} + POSTGRES_DB: {{ $dbName }} + POSTGRES_PASSWORD: {{ $dbPass }} + POSTGRES_HOST: {{ $dbHost }} + POSTGRES_URL: {{ $dbURL }} + + roundcube-creds: + enabled: true + data: + ROUNDCUBEMAIL_DB_TYPE: pgsql + ROUNDCUBEMAIL_DB_HOST: {{ $dbHost }} + ROUNDCUBEMAIL_DB_PORT: "5432" + ROUNDCUBEMAIL_DB_USER: {{ $dbUser }} + ROUNDCUBEMAIL_DB_PASSWORD: {{ $dbPass }} + ROUNDCUBEMAIL_DB_NAME: {{ $dbName }} + +configmap: + roundcube-config: + enabled: true + data: + ROUNDCUBEMAIL_SKIN: {{ .Values.roundcubeConfig.skin }} + {{/* IMAP */}} + ROUNDCUBEMAIL_DEFAULT_HOST: {{ .Values.roundcubeConfig.defaultHost | quote }} + ROUNDCUBEMAIL_DEFAULT_PORT: {{ .Values.roundcubeConfig.defaultPort | quote }} + {{/* SMTP */}} + ROUNDCUBEMAIL_SMTP_SERVER: {{ .Values.roundcubeConfig.smtpServer | quote }} + ROUNDCUBEMAIL_SMTP_PORT: {{ .Values.roundcubeConfig.smtpPort | quote }} + ROUNDCUBEMAIL_PLUGINS: {{ join "," .Values.roundcubeConfig.plugins | quote }} + ROUNDCUBEMAIL_ASPELL_PACKAGES: {{ join "," .Values.roundcubeConfig.aspellDicts | quote }} + ROUNDCUBEMAIL_UPLOAD_MAX_FILESIZE: {{ printf "%vM" .Values.roundcubeConfig.uploadMaxSize | quote }} +{{- end -}} diff --git a/library/ix-dev/community/roundcube/templates/_persistence.tpl b/library/ix-dev/community/roundcube/templates/_persistence.tpl new file mode 100644 index 0000000000..934691e65d --- /dev/null +++ b/library/ix-dev/community/roundcube/templates/_persistence.tpl @@ -0,0 +1,47 @@ +{{- define "roundcube.persistence" -}} +persistence: + html: + enabled: true + {{- include "ix.v1.common.app.storageOptions" (dict "storage" .Values.roundcubeStorage.html) | nindent 4 }} + targetSelector: + roundcube: + roundcube: + mountPath: /var/www/html + config: + enabled: true + {{- include "ix.v1.common.app.storageOptions" (dict "storage" .Values.roundcubeStorage.config) | nindent 4 }} + targetSelector: + roundcube: + roundcube: + mountPath: /var/roundcube/config + temps: + enabled: true + {{- include "ix.v1.common.app.storageOptions" (dict "storage" .Values.roundcubeStorage.temps) | nindent 4 }} + targetSelector: + roundcube: + roundcube: + mountPath: /tmp/roundcube-temp + tmp: + enabled: true + type: emptyDir + targetSelector: + roundcube: + roundcube: + mountPath: /tmp + + {{- range $idx, $storage := .Values.roundcubeStorage.additionalStorages }} + {{ printf "roundcube-%v:" (int $idx) }} + enabled: true + {{- include "ix.v1.common.app.storageOptions" (dict "storage" $storage) | nindent 4 }} + targetSelector: + roundcube: + roundcube: + mountPath: {{ $storage.mountPath }} + {{- end }} + + {{- include "ix.v1.common.app.postgresPersistence" + (dict "pgData" .Values.roundcubeStorage.pgData + "pgBackup" .Values.roundcubeStorage.pgBackup + ) | nindent 2 }} + +{{- end -}} diff --git a/library/ix-dev/community/roundcube/templates/_portal.tpl b/library/ix-dev/community/roundcube/templates/_portal.tpl new file mode 100644 index 0000000000..b7eb68bdfb --- /dev/null +++ b/library/ix-dev/community/roundcube/templates/_portal.tpl @@ -0,0 +1,12 @@ +{{- define "roundcube.portal" -}} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: portal +data: + port: {{ .Values.roundcubeNetwork.webPort | quote }} + path: "/" + protocol: http + host: $node_ip +{{- end -}} diff --git a/library/ix-dev/community/roundcube/templates/_postgres.tpl b/library/ix-dev/community/roundcube/templates/_postgres.tpl new file mode 100644 index 0000000000..0c050b6ca0 --- /dev/null +++ b/library/ix-dev/community/roundcube/templates/_postgres.tpl @@ -0,0 +1,6 @@ +{{- define "postgres.workload" -}} +workload: +{{- include "ix.v1.common.app.postgres" (dict "secretName" "postgres-creds" + "resources" .Values.resources + "ixChartContext" .Values.ixChartContext) | nindent 2 }} +{{- end -}} diff --git a/library/ix-dev/community/roundcube/templates/_roundcube.tpl b/library/ix-dev/community/roundcube/templates/_roundcube.tpl new file mode 100644 index 0000000000..39c82fd52b --- /dev/null +++ b/library/ix-dev/community/roundcube/templates/_roundcube.tpl @@ -0,0 +1,57 @@ +{{- define "roundcube.workload" -}} +workload: + roundcube: + enabled: true + primary: true + type: Deployment + podSpec: + hostNetwork: false + containers: + roundcube: + enabled: true + primary: true + imageSelector: image + securityContext: + runAsUser: 0 + runAsGroup: 0 + runAsNonRoot: false + readOnlyRootFilesystem: false + capabilities: + add: + - CHOWN + - DAC_OVERRIDE + - FOWNER + - SETGID + - SETUID + envFrom: + - secretRef: + name: roundcube-creds + - configMapRef: + name: roundcube-config + {{ with .Values.roundcubeConfig.additionalEnvs }} + envList: + {{ range $env := . }} + - name: {{ $env.name }} + value: {{ $env.value }} + {{ end }} + {{ end }} + probes: + liveness: + enabled: true + type: http + path: /?ping=ping + port: 80 + readiness: + enabled: true + type: http + path: /?ping=ping + port: 80 + startup: + enabled: true + type: http + path: /?ping=ping + port: 80 + initContainers: + {{- include "ix.v1.common.app.postgresWait" (dict "name" "01-postgres-wait" + "secretName" "postgres-creds") | nindent 8 }} +{{- end -}} diff --git a/library/ix-dev/community/roundcube/templates/_service.tpl b/library/ix-dev/community/roundcube/templates/_service.tpl new file mode 100644 index 0000000000..5f7607ae73 --- /dev/null +++ b/library/ix-dev/community/roundcube/templates/_service.tpl @@ -0,0 +1,18 @@ +{{- define "roundcube.service" -}} +service: + roundcube: + enabled: true + primary: true + type: NodePort + targetSelector: roundcube + ports: + webui: + enabled: true + primary: true + port: {{ .Values.roundcubeNetwork.webPort }} + nodePort: {{ .Values.roundcubeNetwork.webPort }} + targetPort: 80 + targetSelector: roundcube + {{- include "ix.v1.common.app.postgresService" $ | nindent 2 }} + +{{- end -}} diff --git a/library/ix-dev/community/roundcube/templates/common.yaml b/library/ix-dev/community/roundcube/templates/common.yaml new file mode 100644 index 0000000000..82e0c46c4c --- /dev/null +++ b/library/ix-dev/community/roundcube/templates/common.yaml @@ -0,0 +1,13 @@ +{{- include "ix.v1.common.loader.init" . -}} + +{{/* Merge the templates with Values */}} +{{- $_ := mustMergeOverwrite .Values (include "roundcube.configuration" $ | fromYaml) -}} +{{- $_ := mustMergeOverwrite .Values (include "roundcube.service" $ | fromYaml) -}} +{{- $_ := mustMergeOverwrite .Values (include "roundcube.persistence" $ | fromYaml) -}} +{{- $_ := mustMergeOverwrite .Values (include "roundcube.workload" $ | fromYaml) -}} +{{- $_ := mustMergeOverwrite .Values (include "postgres.workload" $ | fromYaml) -}} + +{{/* Create the configmap for portal manually*/}} +{{- include "roundcube.portal" $ -}} + +{{- include "ix.v1.common.loader.apply" . -}} diff --git a/library/ix-dev/community/roundcube/upgrade_info.json b/library/ix-dev/community/roundcube/upgrade_info.json new file mode 100644 index 0000000000..767388094a --- /dev/null +++ b/library/ix-dev/community/roundcube/upgrade_info.json @@ -0,0 +1 @@ +{"filename": "values.yaml", "keys": ["image"]} diff --git a/library/ix-dev/community/roundcube/upgrade_strategy b/library/ix-dev/community/roundcube/upgrade_strategy new file mode 100755 index 0000000000..29ea824441 --- /dev/null +++ b/library/ix-dev/community/roundcube/upgrade_strategy @@ -0,0 +1,31 @@ +#!/usr/bin/python3 +import json +import re +import sys + +from catalog_update.upgrade_strategy import semantic_versioning + + +RE_STABLE_VERSION = re.compile(r'\d+\.\d+\.\d+-apache') + + +def newer_mapping(image_tags): + key = list(image_tags.keys())[0] + tags = {t.strip("-apache"): t for t in image_tags[key] if RE_STABLE_VERSION.fullmatch(t)} + version = semantic_versioning(list(tags)) + if not version: + return {} + + return { + 'tags': {key: tags[version]}, + 'app_version': version, + } + + +if __name__ == '__main__': + try: + versions_json = json.loads(sys.stdin.read()) + except ValueError: + raise ValueError('Invalid json specified') + + print(json.dumps(newer_mapping(versions_json))) diff --git a/library/ix-dev/community/roundcube/values.yaml b/library/ix-dev/community/roundcube/values.yaml new file mode 100644 index 0000000000..88977236b5 --- /dev/null +++ b/library/ix-dev/community/roundcube/values.yaml @@ -0,0 +1,66 @@ +image: + repository: roundcube/roundcubemail + pullPolicy: IfNotPresent + tag: 1.6.5-apache + +resources: + limits: + cpu: 4000m + memory: 8Gi + +roundcubeConfig: + defaultHost: '' + defaultPort: 143 + smtpServer: '' + smtpPort: 587 + skin: elastic + plugins: + - archive + - zipdownload + aspellDicts: [] + uploadMaxSize: 5 + additionalEnvs: [] + +roundcubeNetwork: + webPort: 31007 + +roundcubeStorage: + html: + type: ixVolume + ixVolumeConfig: + datasetName: html + config: + type: ixVolume + ixVolumeConfig: + datasetName: config + temps: + type: ixVolume + ixVolumeConfig: + datasetName: temps + pgData: + type: ixVolume + ixVolumeConfig: + datasetName: pgData + pgBackup: + type: ixVolume + ixVolumeConfig: + datasetName: pgBackup + additionalStorages: [] + +notes: + custom: | + ## Database + You can connect to the database using the pgAdmin App from the catalog + +
+ Database Details + + - Database: `roundcube` + - Username: `roundcube` + - Password: `{{ .Values.roundcubeDbPass }}` + - Host: `{{ .Values.roundcubeDbHost }}.{{ .Release.Namespace }}.svc.cluster.local` + - Port: `5432` + +
+ {{- $_ := unset .Values "roundcubeDbPass" }} + {{- $_ := unset .Values "roundcubeDbHost" }}