From 88e575a8ba35b97dcd90ce8cbe7598c034f66bb2 Mon Sep 17 00:00:00 2001 From: Stavros Kois <47820033+stavros-k@users.noreply.github.com> Date: Tue, 28 Nov 2023 17:10:21 +0200 Subject: [PATCH] NAS-123206 / 23.10 / migrate `wg-easy` to the new common library (#1403) * migrate `wg-easy` to the new common library * rename * do the helm migration * default to true as it was * fix typo * fix typo * fix ci case * hmm * remove one fail * hmm * add 2. * update migration script * update migration * testupgrades * meta * cleanup * reset * untouch * bump common * fix migration entrypoint * untouch * bump common * bump common * update migrations * fix values * fix dnsOpts * migration changes * clean up * bump common * naming * Add reasoning for keeping a version around * update migration script * untouch catalog.json --- charts/wg-easy/item.yaml | 3 +- library/ix-dev/charts/wg-easy/Chart.lock | 8 +- library/ix-dev/charts/wg-easy/Chart.yaml | 6 +- .../charts/wg-easy/charts/common-1.2.3.tgz | Bin 0 -> 63004 bytes .../charts/wg-easy/charts/common-2304.0.1.tgz | Bin 4995 -> 0 bytes .../ix-dev/charts/wg-easy/ci/test-values.yaml | 26 +- library/ix-dev/charts/wg-easy/metadata.yaml | 26 - .../ix-dev/charts/wg-easy/migrations/migrate | 94 ++++ library/ix-dev/charts/wg-easy/questions.yaml | 512 ++++++++++++------ .../charts/wg-easy/templates/_migration.tpl | 25 + .../charts/wg-easy/templates/_persistence.tpl | 26 + .../charts/wg-easy/templates/_portal.tpl | 12 + .../charts/wg-easy/templates/_service.tpl | 21 + .../charts/wg-easy/templates/_wgeasy.tpl | 84 +++ .../charts/wg-easy/templates/common.yaml | 14 + .../charts/wg-easy/templates/deployment.yaml | 136 ----- .../charts/wg-easy/templates/service.yaml | 19 - .../ix-dev/charts/wg-easy/to_keep_versions.md | 4 + .../charts/wg-easy/to_keep_versions.yaml | 1 + library/ix-dev/charts/wg-easy/values.yaml | 31 ++ 20 files changed, 676 insertions(+), 372 deletions(-) create mode 100644 library/ix-dev/charts/wg-easy/charts/common-1.2.3.tgz delete mode 100644 library/ix-dev/charts/wg-easy/charts/common-2304.0.1.tgz create mode 100755 library/ix-dev/charts/wg-easy/migrations/migrate create mode 100644 library/ix-dev/charts/wg-easy/templates/_migration.tpl create mode 100644 library/ix-dev/charts/wg-easy/templates/_persistence.tpl create mode 100644 library/ix-dev/charts/wg-easy/templates/_portal.tpl create mode 100644 library/ix-dev/charts/wg-easy/templates/_service.tpl create mode 100644 library/ix-dev/charts/wg-easy/templates/_wgeasy.tpl create mode 100644 library/ix-dev/charts/wg-easy/templates/common.yaml delete mode 100644 library/ix-dev/charts/wg-easy/templates/deployment.yaml delete mode 100644 library/ix-dev/charts/wg-easy/templates/service.yaml create mode 100644 library/ix-dev/charts/wg-easy/to_keep_versions.md create mode 100644 library/ix-dev/charts/wg-easy/to_keep_versions.yaml diff --git a/charts/wg-easy/item.yaml b/charts/wg-easy/item.yaml index c3ea148f5e..cd6a0cf5cc 100644 --- a/charts/wg-easy/item.yaml +++ b/charts/wg-easy/item.yaml @@ -4,5 +4,6 @@ categories: screenshots: - https://media.sys.truenas.net/apps/wg-easy/screenshots/screenshot1.png tags: - - vpn - wireguard + - network + - vpn diff --git a/library/ix-dev/charts/wg-easy/Chart.lock b/library/ix-dev/charts/wg-easy/Chart.lock index 48e620603c..12f832f4ec 100644 --- a/library/ix-dev/charts/wg-easy/Chart.lock +++ b/library/ix-dev/charts/wg-easy/Chart.lock @@ -1,6 +1,6 @@ dependencies: - name: common - repository: file://../../../common/2304.0.1 - version: 2304.0.1 -digest: sha256:1ed155c6760e1166e2cb75b52bc5e81c6bdf0252c16ff5ede001157077c41670 -generated: "2023-04-24T13:41:50.229362574+03:00" + repository: file://../../../common + version: 1.2.3 +digest: sha256:e6ff49b06bf5d4d159e505ae6d153f36cd46170bb519caf90462cd5caebfd0fb +generated: "2023-11-08T20:13:57.295656002+02:00" diff --git a/library/ix-dev/charts/wg-easy/Chart.yaml b/library/ix-dev/charts/wg-easy/Chart.yaml index 7e96b9b7bc..37e441d7a9 100644 --- a/library/ix-dev/charts/wg-easy/Chart.yaml +++ b/library/ix-dev/charts/wg-easy/Chart.yaml @@ -3,7 +3,7 @@ description: WG-Easy is the easiest way to install & manage WireGuard! annotations: title: WG Easy type: application -version: 1.0.12 +version: 2.0.0 apiVersion: v2 appVersion: "7" kubeVersion: ">=1.16.0-0" @@ -13,8 +13,8 @@ maintainers: email: dev@ixsystems.com dependencies: - name: common - repository: file://../../../common/2304.0.1 - version: 2304.0.1 + repository: file://../../../common + version: 1.2.3 home: https://github.com/WeeJeWel/wg-easy icon: https://media.sys.truenas.net/apps/wg-easy/icons/icon.png sources: diff --git a/library/ix-dev/charts/wg-easy/charts/common-1.2.3.tgz b/library/ix-dev/charts/wg-easy/charts/common-1.2.3.tgz new file mode 100644 index 0000000000000000000000000000000000000000..cddb9b05fb2a9ae54ecf8a24f3d85df3358f2670 GIT binary patch literal 63004 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%0D3-}>0)IsAR}jOJ~9Kqw5F}g!TO6X|M7$k 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 literal 0 HcmV?d00001 diff --git a/library/ix-dev/charts/wg-easy/charts/common-2304.0.1.tgz b/library/ix-dev/charts/wg-easy/charts/common-2304.0.1.tgz deleted file mode 100644 index 10cd5d29b4046f728f3857ae933c9b1fb057dbb3..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4995 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 N|NpsFTyg-4005+-;Lrd7 diff --git a/library/ix-dev/charts/wg-easy/ci/test-values.yaml b/library/ix-dev/charts/wg-easy/ci/test-values.yaml index 3683884014..236726d9e0 100644 --- a/library/ix-dev/charts/wg-easy/ci/test-values.yaml +++ b/library/ix-dev/charts/wg-easy/ci/test-values.yaml @@ -1,22 +1,14 @@ -appVolumeMounts: +wgStorage: config: - emptyDir: true - mountPath: /etc/wireguard -dnsConfig: - options: [] -emptyDirVolumes: true -environmentVariables: [] -extraAppVolumeMounts: [] -hostNetwork: true -wgUDPPort: 30290 -webUIPort: 30921 -wgeasy: + type: pvc + +wgConfig: host: wg.domain.com password: secret - client_mtu: 1420 - keep_alive: 5 - client_address_range: 10.10.0.x - client_dns_server: "8.8.8.8" - allowed_ips: + clientMTU: 1420 + keepAlive: 5 + clientAddressRange: 10.10.0.x + clientDNSServer: "8.8.8.8" + allowedIPs: - 10.10.10.0/24 - 10.10.12.0/24 diff --git a/library/ix-dev/charts/wg-easy/metadata.yaml b/library/ix-dev/charts/wg-easy/metadata.yaml index dce85d8796..bd22d78e49 100644 --- a/library/ix-dev/charts/wg-easy/metadata.yaml +++ b/library/ix-dev/charts/wg-easy/metadata.yaml @@ -5,34 +5,8 @@ runAsContext: uid: 0 description: WG Easy runs as root user. capabilities: - - name: CHOWN - description: WG Easy is able to chown files. - - name: FOWNER - description: WG Easy is able to bypass permission checks for it's sub-processes. - - name: SYS_CHROOT - description: WG Easy is able to use chroot. - - name: MKNOD - description: WG Easy is able to create device nodes. - - name: DAC_OVERRIDE - description: WG Easy is able to bypass permission checks. - - name: FSETID - description: WG Easy is able to set file capabilities. - - name: KILL - description: WG Easy is able to kill processes. - - name: SETGID - description: WG Easy is able to set group ID for it's sub-processes. - - name: SETUID - description: WG Easy is able to set user ID for it's sub-processes. - - name: SETPCAP - description: WG Easy is able to set process capabilities. - - name: NET_BIND_SERVICE - description: WG Easy is able to bind to privileged ports. - - name: SETFCAP - description: WG Easy is able to set file capabilities. - name: NET_RAW description: WG Easy is able to use raw sockets. - - name: AUDIT_WRITE - description: WG Easy is able to write to audit log. - name: SYS_MODULE description: WG Easy is able to load kernel modules. - name: NET_ADMIN diff --git a/library/ix-dev/charts/wg-easy/migrations/migrate b/library/ix-dev/charts/wg-easy/migrations/migrate new file mode 100755 index 0000000000..1d9d1348a6 --- /dev/null +++ b/library/ix-dev/charts/wg-easy/migrations/migrate @@ -0,0 +1,94 @@ +#!/usr/bin/python3 +import json +import os +import sys + + +def migrate_common_lib(values): + delete_keys = [ + 'wgUDPPort', 'webUIPort', 'hostNetwork', 'cpuLimit', 'memLimit', + 'dnsConfig', 'environmentVariables', 'appVolumeMounts', + 'extraAppVolumeMounts', 'wgeasy', 'enableResourceLimits', + ] + + values.update({ + # Migrate Network + 'wgNetwork': { + 'udpPort': values['wgUDPPort'], + 'webPort': values['webUIPort'], + 'hostNetwork': values['hostNetwork'], + }, + # Migrate Resources + 'resources': { + 'limits': { + 'cpu': values.get('cpuLimit', '4000m'), + 'memory': values.get('memLimit', '8Gi'), + } + }, + # Migrate DNS + 'podOptions': { + 'dnsConfig': { + 'options': [ + {'name': opt['name'], 'value': opt['value']} + for opt in values.get('dnsConfig', {}).get('options', []) + ] + } + }, + # Migrate Config + 'wgConfig': { + 'host': values['wgeasy']['host'], + 'password': values['wgeasy'].get('password', ''), + 'keepAlive': values['wgeasy']['keep_alive'], + 'clientMTU': values['wgeasy']['client_mtu'], + 'clientAddressRange': values['wgeasy']['client_address_range'], + 'clientDNSServer': values['wgeasy']['client_dns_server'], + 'allowedIPs': values['wgeasy']['allowed_ips'], + 'additionalEnvs': values.get('environmentVariables', []), + }, + # Migrate Storage + 'wgStorage': { + 'config': { + 'type': 'hostPath', + 'hostPathConfig': { + 'hostPath': values['appVolumeMounts']['config']['hostPath'] + }, + } if values['appVolumeMounts']['config']['hostPathEnabled'] else { + 'type': 'ixVolume', + 'ixVolumeConfig': { + 'datasetName': values['appVolumeMounts']['config']['datasetName'], + }, + }, + 'additionalStorages': [ + { + 'type': 'hostPath', + 'hostPathConfig': {'hostPath': e['hostPath']}, + 'mountPath': e['mountPath'], + } + for e in values.get('extraAppVolumeMounts', []) + ], + }, + }) + + for k in delete_keys: + values.pop(k, None) + + return values + +def migrate(values): + if not 'wgeasy' in values.keys(): + return values + + + return migrate_common_lib(values) + + + +if __name__ == '__main__': + with open('in.json', 'r') as f: + print(json.dumps(migrate(json.loads(f.read())))) + if len(sys.argv) != 2: + exit(1) + + if os.path.exists(sys.argv[1]): + with open(sys.argv[1], 'r') as f: + print(json.dumps(migrate(json.loads(f.read())))) diff --git a/library/ix-dev/charts/wg-easy/questions.yaml b/library/ix-dev/charts/wg-easy/questions.yaml index 2dc6e6cb19..b76a3047e2 100644 --- a/library/ix-dev/charts/wg-easy/questions.yaml +++ b/library/ix-dev/charts/wg-easy/questions.yaml @@ -1,84 +1,93 @@ groups: - - name: Configuration - description: WG-Easy application configuration - - name: Storage - description: Configure storage for WG-Easy - - name: Networking - description: Networking Configuration for WG-Easy - - name: Advanced DNS Settings - description: Configure DNS settings - - name: Resource Limits - description: Set CPU/memory limits for Kubernetes Pod + - name: WG-Easy Configuration + description: Configure WG-Easy + - name: Advanced Pod Configuration + description: Configure Advanced Pod Options for WG-Easy + - name: Network Configuration + description: Configure Network for WG-Easy + - name: Storage Configuration + description: Configure Storage for WG-Easy + - name: Resources Configuration + description: Configure Resources for WG-Easy portals: web_portal: protocols: - - http + - "$kubernetes-resource_configmap_portal_protocol" host: - - $node_ip + - "$kubernetes-resource_configmap_portal_host" ports: - - $variable-webUIPort - path: / + - "$kubernetes-resource_configmap_portal_port" + path: "$kubernetes-resource_configmap_portal_path" questions: - - variable: wgUDPPort - label: WireGuard UDP Node Port for WG-Easy - group: Networking - schema: - type: int - min: 9000 - max: 65535 - default: 20920 - required: true - - variable: webUIPort - label: WebUI Node Port for WG-Easy - group: Networking - schema: - type: int - min: 9000 - max: 65535 - default: 20921 - required: true - - variable: hostNetwork - label: Host Network - group: Networking - schema: - type: boolean - default: true - - - variable: dnsConfig - label: DNS Configuration - group: Advanced DNS Settings + - variable: wgNetwork + label: "" + group: Network Configuration schema: type: dict attrs: - - variable: options - label: DNS Options + - variable: udpPort + label: Web Port + description: The port for the WG-Easy Wireguard service. schema: - type: list - items: - - variable: optionsEntry - label: Option Entry Configuration - schema: - type: dict - attrs: - - variable: name - label: Option Name - schema: - type: string - required: true - - variable: value - label: Option Value - schema: - type: string - required: true + type: int + default: 30057 + min: 9000 + max: 65535 + required: true + - variable: webPort + label: Web Port + description: The port for the WG-Easy Web UI. + schema: + type: int + default: 30058 + min: 9000 + max: 65535 + required: true + - variable: hostNetwork + label: Host Network + schema: + type: boolean + default: true - - variable: wgeasy - label: WG-Easy Configuration - group: Configuration + - variable: podOptions + label: "" + group: Advanced Pod Configuration + schema: + type: dict + attrs: + - variable: dnsConfig + label: Advanced DNS Configuration + schema: + type: dict + attrs: + - variable: options + label: DNS Options + schema: + type: list + items: + - variable: optionsEntry + label: DNS Option Entry + schema: + type: dict + attrs: + - variable: name + label: Option Name + schema: + type: string + required: true + - variable: value + label: Option Value + schema: + type: string + required: true + + - variable: wgConfig + label: "" + group: WG-Easy Configuration schema: type: dict - additional_attrs: true attrs: - variable: host label: Hostname or IP @@ -95,35 +104,35 @@ questions: type: string private: true default: "" - - variable: keep_alive + - variable: keepAlive label: Persistent Keep Alive description: Value in seconds to keep the "connection" open. If this value is 0, then connections won't be kept alive. schema: type: int required: true default: 0 - - variable: client_mtu + - variable: clientMTU label: Clients MTU description: The MTU the clients will use. schema: type: int required: true default: 1420 - - variable: client_address_range + - variable: clientAddressRange label: Clients IP Address Range description: Clients IP address range. schema: type: string required: true default: 10.8.0.x - - variable: client_dns_server + - variable: clientDNSServer label: Clients DNS Server description: Clients DNS Server. schema: type: string required: true default: "1.1.1.1" - - variable: allowed_ips + - variable: allowedIPs label: Allowed IPs description: Allowed IPs clients will use. If none provided, <0.0.0.0/0,::/0> will be used. schema: @@ -136,125 +145,296 @@ questions: type: string required: true default: "" - - - variable: environmentVariables - label: WG-Easy Environment - group: Configuration - schema: - type: list - default: [] - items: - - variable: environmentVariable - label: Environment Variable + - variable: additionalEnvs + label: Additional Environment Variables + description: Configure additional environment variables for WG-Easy. schema: - type: dict - attrs: - - variable: name - label: Name + type: list + default: [] + items: + - variable: env + label: Environment Variable schema: - type: string - required: true - default: "" - - variable: value - label: Value - schema: - type: string - default: "" - required: true + type: dict + attrs: + - variable: name + label: Name + schema: + type: string + required: true + - variable: value + label: Value + schema: + type: string + required: true - - variable: appVolumeMounts - label: WG-Easy Storage - group: Storage + - variable: wgStorage + label: "" + group: Storage Configuration schema: type: dict attrs: - variable: config - label: Configuration Volume + label: WG-Easy Config Storage + description: The path to store WG-Easy Configuration. schema: type: dict attrs: - - variable: datasetName - label: Configuration Volume Dataset Name + - 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 - hidden: true + 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 - show_if: [["hostPathEnabled", "=", false]] - default: ix-wg-easy_config - editable: false - - variable: mountPath - label: Configuration Mount Path - description: Path where the volume will be mounted inside the pod - schema: - type: path - hidden: true - editable: true - default: /etc/wireguard - - variable: hostPathEnabled - label: Enable Custom Host Path for WG-Easy Configuration Volume - schema: - type: boolean - default: false - show_subquestions_if: true - subquestions: - - variable: hostPath - label: Host Path for WG-Easy Configuration Volume + - "normalize/ixVolume" + attrs: + - variable: aclEnable + label: Enable ACL + description: Enable ACL for the dataset. schema: - type: hostpath + 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 Config + 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: - - validations/lockedHostPath + - "normalize/acl" + - variable: hostPath + label: Host Path + description: The host path to use for storage. + schema: + type: hostpath + show_if: [["aclEnable", "=", false]] + immutable: true + required: true + - variable: additionalStorages + label: Additional Storage + description: Additional storage for WG-Easy. + 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 Config + 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]] + immutable: true + 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: extraAppVolumeMounts - label: Extra Host Path Volumes - group: Storage + - variable: resources + group: Resources Configuration + label: "" schema: - type: list - items: - - variable: extraAppVolume - label: Host Path Volume - description: Add an extra host path volume for WG-Easy application + type: dict + attrs: + - variable: limits + label: Limits schema: type: dict attrs: - - variable: mountPath - label: Mount Path in Pod - description: Path where the volume will be mounted inside the pod + - variable: cpu + label: CPU + description: CPU limit for WG-Easy. schema: - type: path + 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: hostPath - label: Host Path - description: Host path + - variable: memory + label: Memory + description: Memory limit for WG-Easy. schema: - type: hostpath + 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 - $ref: - - validations/lockedHostPath - - - variable: enableResourceLimits - label: Enable Pod resource limits - group: Resource Limits - schema: - type: boolean - default: false - - variable: cpuLimit - label: CPU Limit resource limits - description: CPU resource limit allow plain integer values with suffix m(milli) e.g 1000m, 100. - group: Resource Limits - schema: - type: string - show_if: [["enableResourceLimits", "=", true]] - valid_chars: "^\\d+(?:\\.\\d+(?!.*m$)|m?$)" - default: 4000m - - variable: memLimit - label: Memory Limit - group: Resource Limits - description: Memory limits is specified by number of bytes. Followed by quantity suffix like E,P,T,G,M,k and Ei,Pi,Ti,Mi,Gi,Ki can also be used. e.g 129e6, 129M, 128974848000m, 123Mi - schema: - type: string - show_if: [["enableResourceLimits", "=", true]] - valid_chars: "^([+-]?[0-9.]+)([eEinumkKMGTP]*[-+]?[0-9]*)$" - default: 8Gi diff --git a/library/ix-dev/charts/wg-easy/templates/_migration.tpl b/library/ix-dev/charts/wg-easy/templates/_migration.tpl new file mode 100644 index 0000000000..9e147f7a1e --- /dev/null +++ b/library/ix-dev/charts/wg-easy/templates/_migration.tpl @@ -0,0 +1,25 @@ +{{- define "wgeasy.migration.checks" -}} + {{/* Safely access the context, so it wont block CI */}} + {{- if hasKey .Values.global "ixChartContext" -}} + {{- if not .Values.global.ixChartContext.upgradeMetadata -}} + {{- fail "Upgrade Metadata is missing. Cannot proceed" -}} + {{- end -}} + + {{- $oldChartVersion := .Values.global.ixChartContext.upgradeMetadata.oldChartVersion -}} + {{- $newChartVersion := .Values.global.ixChartContext.upgradeMetadata.newChartVersion -}} + + {{/* Explode versions */}} + {{- $oldV := semver $oldChartVersion -}} + {{- $newV := semver $newChartVersion -}} + + {{/* If new is v2.x.x */}} + {{- if eq ($newV.Major | int) 2 -}} + {{/* And old is v1.x.x, but lower than .11 */}} + {{- if and (eq $oldV.Major 1) (lt ($oldV.Patch | int) 11) -}} + {{/* Block the upgrade */}} + {{- fail "Migration to 2.x.x is only allowed from 1.0.11 or higher" -}} + {{- end -}} + {{- end -}} + + {{- end -}} +{{- end -}} diff --git a/library/ix-dev/charts/wg-easy/templates/_persistence.tpl b/library/ix-dev/charts/wg-easy/templates/_persistence.tpl new file mode 100644 index 0000000000..4f5d75ed6b --- /dev/null +++ b/library/ix-dev/charts/wg-easy/templates/_persistence.tpl @@ -0,0 +1,26 @@ +{{- define "wgeasy.persistence" -}} +persistence: + config: + enabled: true + {{- include "ix.v1.common.app.storageOptions" (dict "storage" .Values.wgStorage.config) | nindent 4 }} + targetSelector: + wgeasy: + wgeasy: + mountPath: /etc/wireguard + tmp: + enabled: true + type: emptyDir + targetSelector: + wgeasy: + wgeasy: + mountPath: /tmp + {{- range $idx, $storage := .Values.wgStorage.additionalStorages }} + {{ printf "wgeasy-%v:" (int $idx) }} + enabled: true + {{- include "ix.v1.common.app.storageOptions" (dict "storage" $storage) | nindent 4 }} + targetSelector: + wgeasy: + wgeasy: + mountPath: {{ $storage.mountPath }} + {{- end }} +{{- end -}} diff --git a/library/ix-dev/charts/wg-easy/templates/_portal.tpl b/library/ix-dev/charts/wg-easy/templates/_portal.tpl new file mode 100644 index 0000000000..d724f0098a --- /dev/null +++ b/library/ix-dev/charts/wg-easy/templates/_portal.tpl @@ -0,0 +1,12 @@ +{{- define "wgeasy.portal" -}} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: portal +data: + path: "/" + port: {{ .Values.wgNetwork.webPort | quote }} + protocol: http + host: $node_ip +{{- end -}} diff --git a/library/ix-dev/charts/wg-easy/templates/_service.tpl b/library/ix-dev/charts/wg-easy/templates/_service.tpl new file mode 100644 index 0000000000..4d35224bdf --- /dev/null +++ b/library/ix-dev/charts/wg-easy/templates/_service.tpl @@ -0,0 +1,21 @@ +{{- define "wgeasy.service" -}} +service: + wgeasy: + enabled: true + primary: true + type: NodePort + targetSelector: wgeasy + ports: + webui: + enabled: true + primary: true + port: {{ .Values.wgNetwork.webPort }} + nodePort: {{ .Values.wgNetwork.webPort }} + targetSelector: wgeasy + vpn: + enabled: true + port: {{ .Values.wgNetwork.udpPort }} + nodePort: {{ .Values.wgNetwork.udpPort }} + protocol: udp + targetSelector: wgeasy +{{- end -}} diff --git a/library/ix-dev/charts/wg-easy/templates/_wgeasy.tpl b/library/ix-dev/charts/wg-easy/templates/_wgeasy.tpl new file mode 100644 index 0000000000..70957a9a63 --- /dev/null +++ b/library/ix-dev/charts/wg-easy/templates/_wgeasy.tpl @@ -0,0 +1,84 @@ +{{- define "wgeasy.workload" -}} +workload: + wgeasy: + enabled: true + primary: true + type: Deployment + podSpec: + hostNetwork: {{ .Values.wgNetwork.hostNetwork }} + containers: + wgeasy: + enabled: true + primary: true + imageSelector: image + {{/* https://github.com/WeeJeWel/wg-easy/pull/394 */}} + securityContext: + runAsUser: 0 + runAsGroup: 0 + runAsNonRoot: false + readOnlyRootFilesystem: false + capabilities: + add: + - NET_ADMIN + - NET_RAW + - SYS_MODULE + env: + WG_PORT: {{ .Values.wgNetwork.udpPort }} + PORT: {{ .Values.wgNetwork.webPort }} + WG_HOST: {{ .Values.wgConfig.host | quote }} + PASSWORD: {{ .Values.wgConfig.password | quote }} + WG_PERSISTENT_KEEPALIVE: {{ .Values.wgConfig.keepAlive }} + WG_MTU: {{ .Values.wgConfig.clientMTU }} + WG_DEFAULT_ADDRESS: {{ .Values.wgConfig.clientAddressRange }} + WG_DEFAULT_DNS: {{ .Values.wgConfig.clientDNSServer }} + WG_ALLOWED_IPS: {{ join "," .Values.wgConfig.clientAllowedIPs | default "0.0.0.0/0,::/0" | quote }} + fixedEnv: + PUID: 0 + {{ with .Values.wgConfig.additionalEnvs }} + envList: + {{ range $env := . }} + - name: {{ $env.name }} + value: {{ $env.value }} + {{ end }} + {{ end }} + probes: + liveness: + enabled: true + type: http + port: {{ .Values.wgNetwork.webPort }} + path: / + readiness: + enabled: true + type: http + port: {{ .Values.wgNetwork.webPort }} + path: / + startup: + enabled: true + type: http + port: {{ .Values.wgNetwork.webPort }} + path: / + {{ $ip := .Values.wgConfig.clientAddressRange | replace "x" "0" }} + lifecycle: + preStop: + type: exec + command: + - /bin/bash + - -c + - | + echo "Deleting routes created by the app..." + netmask=$(ip route | grep {{ $ip }}) + netmask=$(echo $netmask | grep -o -E '/.\d*') + netmask=${netmask#/} + echo "Matched routes to delete... {{ $ip }}/$netmask" + # Don't try to delete routes if steps above didn't grep-ed anything + if [ ! "$netmask" == "" ]; then + ip route del {{ $ip }}/$netmask || echo "Route deletion failed..." + fi + echo "Routes deleted..." + interface=$(ip a | grep wg0) + if [ ! "$interface" == "" ]; then + echo "Removing wg0 interface..." + ip link delete wg0 + echo "Removed wg0 interface..." + fi +{{- end -}} diff --git a/library/ix-dev/charts/wg-easy/templates/common.yaml b/library/ix-dev/charts/wg-easy/templates/common.yaml new file mode 100644 index 0000000000..5cc27b1d61 --- /dev/null +++ b/library/ix-dev/charts/wg-easy/templates/common.yaml @@ -0,0 +1,14 @@ +{{/* Apply helm migrations */}} +{{- include "ix.v1.common.loader.init" . -}} + +{{- include "wgeasy.migration.checks" . -}} + +{{/* Merge the templates with Values */}} +{{- $_ := mustMergeOverwrite .Values (include "wgeasy.workload" $ | fromYaml) -}} +{{- $_ := mustMergeOverwrite .Values (include "wgeasy.service" $ | fromYaml) -}} +{{- $_ := mustMergeOverwrite .Values (include "wgeasy.persistence" $ | fromYaml) -}} + +{{/* Create the configmap for portal manually*/}} +{{- include "wgeasy.portal" $ -}} + +{{- include "ix.v1.common.loader.apply" . -}} diff --git a/library/ix-dev/charts/wg-easy/templates/deployment.yaml b/library/ix-dev/charts/wg-easy/templates/deployment.yaml deleted file mode 100644 index 65cd8bed93..0000000000 --- a/library/ix-dev/charts/wg-easy/templates/deployment.yaml +++ /dev/null @@ -1,136 +0,0 @@ -{{ include "common.storage.hostPathValidate" .Values }} -apiVersion: {{ template "common.capabilities.deployment.apiVersion" . }} -kind: Deployment -metadata: - name: {{ template "common.names.fullname" . }}-wg - labels: - app: {{ template "common.names.name" . }} - chart: {{ template "common.names.chart" . }} - release: {{ .Release.Name }} - heritage: {{ .Release.Service }} - annotations: - rollme: {{ randAlphaNum 5 | quote }} -spec: - replicas: {{ (default 1 .Values.replicas) }} - strategy: - type: "Recreate" - selector: - matchLabels: - app: {{ template "common.names.name" . }} - release: {{ .Release.Name }} - template: - metadata: - name: {{ template "common.names.fullname" . }} - labels: - {{- include "common.labels.selectorLabels" . | nindent 8 }} - annotations: {{ include "common.annotations" . | nindent 8 }} - spec: - hostNetwork: {{ .Values.hostNetwork }} - hostname: {{ .Release.Name }} - containers: - - name: {{ .Chart.Name }} - {{ include "common.resources.limitation" . | nindent 10 }} - {{ include "common.containers.imageConfig" .Values.image | nindent 10 }} - securityContext: - capabilities: - add: - - NET_ADMIN - - SYS_MODULE - {{/* https://github.com/WeeJeWel/wg-easy/pull/394 */}} - runAsUser: 0 - runAsGroup: 0 - readOnlyRootFilesystem: false - runAsNonRoot: false - volumeMounts: {{ include "common.storage.configureAppVolumeMountsInContainer" .Values | nindent 12 }} - {{ range $index, $hostPathConfiguration := .Values.extraAppVolumeMounts }} - - name: extrappvolume-{{ $index }} - mountPath: {{ $hostPathConfiguration.mountPath }} - {{ end }} - ports: - - name: udp - containerPort: {{ .Values.wgUDPPort }} - protocol: UDP - {{- if not .Values.hostNetwork }} - hostPort: null - {{- end }} - - name: web - containerPort: {{ .Values.webUIPort }} - {{- if not .Values.hostNetwork }} - hostPort: null - {{- end }} - env: - {{ $wgeasy := .Values.wgeasy }} - {{ $envList := (default list .Values.environmentVariables) }} - {{ $envList = mustAppend $envList (dict "name" "WG_HOST" "value" $wgeasy.host) }} - {{ $envList = mustAppend $envList (dict "name" "PASSWORD" "value" $wgeasy.password) }} - {{ $envList = mustAppend $envList (dict "name" "WG_PORT" "value" .Values.wgUDPPort) }} - {{ $envList = mustAppend $envList (dict "name" "PORT" "value" .Values.webUIPort) }} - {{ $envList = mustAppend $envList (dict "name" "WG_PERSISTENT_KEEPALIVE" "value" $wgeasy.keep_alive) }} - {{ $envList = mustAppend $envList (dict "name" "WG_MTU" "value" $wgeasy.client_mtu) }} - {{ $envList = mustAppend $envList (dict "name" "WG_DEFAULT_ADDRESS" "value" $wgeasy.client_address_range) }} - {{ $envList = mustAppend $envList (dict "name" "WG_DEFAULT_DNS" "value" $wgeasy.client_dns_server) }} - {{ if $wgeasy.allowed_ips }} - {{ $envList = mustAppend $envList (dict "name" "WG_ALLOWED_IPS" "value" (join "," $wgeasy.allowed_ips)) }} - {{ else }} - {{ $envList = mustAppend $envList (dict "name" "WG_ALLOWED_IPS" "value" ("0.0.0.0/0,::/0")) }} - {{ end }} - {{ include "common.containers.environmentVariables" (dict "environmentVariables" $envList) | nindent 12 }} - readinessProbe: - httpGet: - path: / - port: {{ .Values.webUIPort }} - initialDelaySeconds: 10 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 5 - successThreshold: 2 - livenessProbe: - httpGet: - path: / - port: {{ .Values.webUIPort }} - initialDelaySeconds: 10 - periodSeconds: 10 - timeoutSeconds: 5 - failureThreshold: 5 - successThreshold: 1 - startupProbe: - httpGet: - path: / - port: {{ .Values.webUIPort }} - initialDelaySeconds: 10 - periodSeconds: 5 - timeoutSeconds: 2 - failureThreshold: 60 - successThreshold: 1 - {{ $ip := .Values.wgeasy.client_address_range | replace "x" "0" }} - lifecycle: - preStop: - exec: - command: - - /bin/bash - - -c - - | - echo "Deleting routes created by the app..." - netmask=$(ip route | grep {{ $ip }}) - netmask=$(echo $netmask | grep -o -E '/.\d*') - netmask=${netmask#/} - echo "Matched routes to delete... {{ $ip }}/$netmask" - # Don't try to delete routes if steps above didn't grep-ed anything - if [ ! "$netmask" == "" ]; then - ip route del {{ $ip }}/$netmask || echo "Route deletion failed..." - fi - echo "Routes deleted..." - interface=$(ip a | grep wg0) - if [ ! "$interface" == "" ]; then - echo "Removing wg0 interface..." - ip link delete wg0 - echo "Removed wg0 interface..." - fi - -{{ include "common.networking.dnsConfiguration" .Values | nindent 6 }} - volumes: {{ include "common.storage.configureAppVolumes" .Values | nindent 8 }} - {{ range $index, $hostPathConfiguration := .Values.extraAppVolumeMounts }} - - name: extrappvolume-{{ $index }} - hostPath: - path: {{ $hostPathConfiguration.hostPath }} - {{ end }} diff --git a/library/ix-dev/charts/wg-easy/templates/service.yaml b/library/ix-dev/charts/wg-easy/templates/service.yaml deleted file mode 100644 index 42d960b193..0000000000 --- a/library/ix-dev/charts/wg-easy/templates/service.yaml +++ /dev/null @@ -1,19 +0,0 @@ -{{ $selectors := list }} -{{ $selectors = mustAppend $selectors (dict "key" "app" "value" (include "common.names.name" .) ) }} -{{ $selectors = mustAppend $selectors (dict "key" "release" "value" .Release.Name ) }} -{{ $ports := list }} -{{- if not .Values.hostNetwork }} -{{ $ports = mustAppend $ports (dict "name" "web" "port" .Values.webUIPort "nodePort" .Values.webUIPort "targetPort" .Values.webUIPort) }} -{{ $ports = mustAppend $ports (dict "name" "udp" "port" .Values.wgUDPPort "nodePort" .Values.wgUDPPort "targetPort" .Values.wgUDPPort "protocol" "UDP") }} -{{- else }} -{{ $ports = mustAppend $ports (dict "name" "web" "port" .Values.webUIPort "targetPort" .Values.webUIPort) }} -{{ $ports = mustAppend $ports (dict "name" "udp" "port" .Values.wgUDPPort "targetPort" .Values.wgUDPPort "protocol" "UDP") }} -{{- end }} -{{ $params := . }} -{{- if not .Values.hostNetwork }} -{{ $_ := set $params "commonService" (dict "type" "NodePort" "ports" $ports ) }} -{{- else }} -{{ $_ := set $params "commonService" (dict "type" "ClusterIP" "ports" $ports ) }} -{{- end }} -{{ $_1 := set .Values "extraSelectorLabels" $selectors }} -{{ include "common.classes.service" $params }} diff --git a/library/ix-dev/charts/wg-easy/to_keep_versions.md b/library/ix-dev/charts/wg-easy/to_keep_versions.md new file mode 100644 index 0000000000..11b0cc322b --- /dev/null +++ b/library/ix-dev/charts/wg-easy/to_keep_versions.md @@ -0,0 +1,4 @@ +# 1.0.12 + +This version is kept because it contains a fix that is needed for migration to v2.x.x +It should be safe to remove few months after v2.x.x is released. diff --git a/library/ix-dev/charts/wg-easy/to_keep_versions.yaml b/library/ix-dev/charts/wg-easy/to_keep_versions.yaml new file mode 100644 index 0000000000..fdc614bcae --- /dev/null +++ b/library/ix-dev/charts/wg-easy/to_keep_versions.yaml @@ -0,0 +1 @@ +- 1.0.12 diff --git a/library/ix-dev/charts/wg-easy/values.yaml b/library/ix-dev/charts/wg-easy/values.yaml index 9fa0a8f646..824b74b989 100644 --- a/library/ix-dev/charts/wg-easy/values.yaml +++ b/library/ix-dev/charts/wg-easy/values.yaml @@ -2,3 +2,34 @@ image: pullPolicy: IfNotPresent repository: weejewel/wg-easy tag: "7" + +resources: + limits: + cpu: 4000m + memory: 8Gi + +podOptions: + dnsConfig: + options: [] + +wgNetwork: + udpPort: 30057 + webPort: 30058 + hostNetwork: true + +wgConfig: + host: '' + password: '' + keepAlive: 0 + clientMTU: 1420 + clientAddressRange: 10.8.0.x + clientDNSServer: "1.1.1.1" + allowedIPs: [] + additionalEnvs: [] + +wgStorage: + config: + type: ixVolume + ixVolumeConfig: + datasetName: config + additionalStorages: []