From d7606c484194e256267304a9ec3d638dd809bd31 Mon Sep 17 00:00:00 2001 From: Stavros Kois <47820033+stavros-k@users.noreply.github.com> Date: Mon, 27 Dec 2021 14:40:31 +0200 Subject: [PATCH] feat(shlink): Add shlink (#1616) * feat(shlink): Add shlink * try this * Update charts/incubator/shlink/values.yaml * remove unwated `v` * deal with redis later * Update charts/incubator/shlink/values.yaml * set default redisUsername * Update charts/incubator/shlink/values.yaml * re-enable redis and give rootfs access * try this * run as root * update questions * add icon Co-authored-by: Kjeld Schouten-Lebbing --- charts/incubator/shlink/Chart.yaml | 36 +++ charts/incubator/shlink/questions.yaml | 288 ++++++++++++++++++ charts/incubator/shlink/templates/common.yaml | 1 + charts/incubator/shlink/values.yaml | 54 ++++ docs/_static/img/appicons/shlink-icon.png | Bin 0 -> 19106 bytes docs/manual/default-ports.md | 1 + 6 files changed, 380 insertions(+) create mode 100644 charts/incubator/shlink/Chart.yaml create mode 100644 charts/incubator/shlink/questions.yaml create mode 100644 charts/incubator/shlink/templates/common.yaml create mode 100644 charts/incubator/shlink/values.yaml create mode 100644 docs/_static/img/appicons/shlink-icon.png diff --git a/charts/incubator/shlink/Chart.yaml b/charts/incubator/shlink/Chart.yaml new file mode 100644 index 00000000000..7fcc2d3fba0 --- /dev/null +++ b/charts/incubator/shlink/Chart.yaml @@ -0,0 +1,36 @@ +apiVersion: v2 +appVersion: "2.10.1" +dependencies: +- name: common + repository: https://truecharts.org + version: 8.9.25 +- condition: postgresql.enabled + name: postgresql + repository: https://truecharts.org/ + version: 6.0.37 +- condition: redis.enabled + name: redis + repository: https://truecharts.org/ + version: 1.0.42 +deprecated: false +description: A PHP-based self-hosted URL shortener that can be used to serve shortened URLs under your own custom domain. +home: https://github.com/truecharts/apps/tree/master/charts/stable/shlink +icon: https://truecharts.org/_static/img/appicons/shlink-icon.png +keywords: +- url +- shortener +kubeVersion: '>=1.16.0-0' +maintainers: +- email: info@truecharts.org + name: TrueCharts + url: https://truecharts.org +name: shlink +sources: +- https://github.com/shlinkio/shlink +type: application +version: 0.0.1 +annotations: + truecharts.org/catagories: | + - utilities + truecharts.org/SCALE-support: "true" + truecharts.org/grade: U diff --git a/charts/incubator/shlink/questions.yaml b/charts/incubator/shlink/questions.yaml new file mode 100644 index 00000000000..69bf93a0e32 --- /dev/null +++ b/charts/incubator/shlink/questions.yaml @@ -0,0 +1,288 @@ +# Include{groups} +portals: + web_portal: + protocols: + - "$kubernetes-resource_configmap_portal_protocol" + host: + - "$kubernetes-resource_configmap_portal_host" + ports: + - "$kubernetes-resource_configmap_portal_port" +questions: + - variable: portal + group: "Container Image" + label: "Configure Portal Button" + schema: + type: dict + hidden: true + attrs: + - variable: enabled + label: "Enable" + description: "enable the portal button" + schema: + hidden: true + editable: false + type: boolean + default: true +# Include{global} + + - variable: controller + group: "Controller" + label: "" + schema: + type: dict + attrs: + - variable: advanced + label: "Show Advanced Controller Settings" + schema: + type: boolean + default: false + show_subquestions_if: true + subquestions: + - variable: type + description: "Please specify type of workload to deploy" + label: "(Advanced) Controller Type" + schema: + type: string + default: "deployment" + required: true + enum: + - value: "deployment" + description: "Deployment" + - value: "statefulset" + description: "Statefulset" + - value: "daemonset" + description: "Daemonset" + - variable: replicas + description: "Number of desired pod replicas" + label: "Desired Replicas" + schema: + type: int + default: 1 + required: true + - variable: strategy + description: "Please specify type of workload to deploy" + label: "(Advanced) Update Strategy" + schema: + type: string + default: "Recreate" + required: true + enum: + - value: "Recreate" + description: "Recreate: Kill existing pods before creating new ones" + - value: "RollingUpdate" + description: "RollingUpdate: Create new pods and then kill old ones" + - value: "OnDelete" + description: "(Legacy) OnDelete: ignore .spec.template changes" +# Include{controllerExpert} + + - variable: env + group: "Container Configuration" + label: "Image Environment" + schema: + type: dict + attrs: +# Include{fixedEnv} + - variable: DEFAULT_DOMAIN + label: "Default Domain" + description: "The default short domain used for this shlink instance. For example doma.in." + schema: + type: string + default: "" + - variable: GEOLITE_LICENSE_KEY + label: "GeoLite2 License Key" + description: "The license key used to download new GeoLite2 database files." + schema: + type: string + default: "" +# Include{containerConfig} + - variable: service + group: "Networking and Services" + label: "Configure Service(s)" + schema: + type: dict + attrs: + - variable: main + label: "Main Service" + description: "The Primary service on which the healthcheck runs, often the webUI" + schema: + type: dict + attrs: +# Include{serviceSelector} + - variable: main + label: "Main Service Port Configuration" + schema: + type: dict + attrs: + - variable: advanced + label: "Show Advanced settings" + schema: + type: boolean + default: false + show_subquestions_if: true + subquestions: + - variable: enabled + label: "Enable the port" + schema: + type: boolean + default: true + - variable: protocol + label: "Port Type" + schema: + type: string + default: "HTTPS" + enum: + - value: HTTP + description: "HTTP" + - value: "HTTPS" + description: "HTTPS" + - value: TCP + description: "TCP" + - value: "UDP" + description: "UDP" + - variable: nodePort + label: "Node Port (Optional)" + description: "This port gets exposed to the node. Only considered when service type is NodePort, Simple or LoadBalancer" + schema: + type: int + min: 9000 + max: 65535 + - variable: targetPort + label: "Target Port" + description: "The internal(!) port on the container the Application runs on" + schema: + type: int + default: 10153 + - variable: port + label: "Port" + description: "This port exposes the container port on the service" + schema: + type: int + default: 10153 + required: true + + - variable: serviceexpert + group: "Networking and Services" + label: "Show Expert Config" + schema: + type: boolean + default: false + show_subquestions_if: true + subquestions: + - variable: hostNetwork + group: "Networking and Services" + label: "Host-Networking (Complicated)" + schema: + type: boolean + default: false + +# Include{serviceExpert} + +# Include{serviceList} + +# Include{persistenceList} + + - variable: ingress + label: "" + group: "Ingress" + schema: + type: dict + attrs: + - variable: main + label: "Main Ingress" + schema: + type: dict + attrs: +# Include{ingressDefault} + +# Include{ingressTLS} + +# Include{ingressTraefik} + +# Include{ingressExpert} + +# Include{ingressList} + + - variable: advancedSecurity + label: "Show Advanced Security Settings" + group: "Security and Permissions" + schema: + type: boolean + default: false + show_subquestions_if: true + subquestions: + - variable: securityContext + label: "Security Context" + schema: + type: dict + attrs: + - variable: privileged + label: "Privileged mode" + schema: + type: boolean + default: false + - variable: readOnlyRootFilesystem + label: "ReadOnly Root Filesystem" + schema: + type: boolean + default: false + - variable: allowPrivilegeEscalation + label: "Allow Privilege Escalation" + schema: + type: boolean + default: false + - variable: runAsNonRoot + label: "runAsNonRoot" + schema: + type: boolean + default: false + + - variable: podSecurityContext + group: "Security and Permissions" + label: "Pod Security Context" + schema: + type: dict + attrs: + - variable: runAsUser + label: "runAsUser" + description: "The UserID of the user running the application" + schema: + type: int + default: 0 + - variable: runAsGroup + label: "runAsGroup" + description: The groupID this App of the user running the application" + schema: + type: int + default: 0 + - variable: fsGroup + label: "fsGroup" + description: "The group that should own ALL storage." + schema: + type: int + default: 568 + - variable: supplementalGroups + label: "supplemental Groups" + schema: + type: list + default: [] + items: + - variable: supplementalGroupsEntry + label: "supplemental Group" + schema: + type: int + - variable: fsGroupChangePolicy + label: "When should we take ownership?" + schema: + type: string + default: "OnRootMismatch" + enum: + - value: "OnRootMismatch" + description: "OnRootMismatch" + - value: "Always" + description: "Always" + +# Include{resources} + +# Include{advanced} + +# Include{addons} diff --git a/charts/incubator/shlink/templates/common.yaml b/charts/incubator/shlink/templates/common.yaml new file mode 100644 index 00000000000..a6613c2ce21 --- /dev/null +++ b/charts/incubator/shlink/templates/common.yaml @@ -0,0 +1 @@ +{{ include "common.all" . }} diff --git a/charts/incubator/shlink/values.yaml b/charts/incubator/shlink/values.yaml new file mode 100644 index 00000000000..245a307f7b7 --- /dev/null +++ b/charts/incubator/shlink/values.yaml @@ -0,0 +1,54 @@ +image: + repository: tccr.io/truecharts/shlink + pullPolicy: IfNotPresent + tag: v2.10.1@sha256:2abccbd1a150da840849f01789e4f824e35ee1136da7f5e56abaa86a290794ae + +securityContext: + runAsNonRoot: false + readOnlyRootFilesystem: false + +podSecurityContext: + runAsUser: 0 + runAsGroup: 0 + +service: + main: + protocol: HTTPS + ports: + main: + targetPort: 10153 + port: 10153 + +env: + DEFAULT_DOMAIN: "" + GEOLITE_LICENSE_KEY: "" + PORT: 10153 + IS_HTTPS_ENABLED: true + DB_DRIVER: "postgres" + DB_USER: "{{ .Values.postgresql.postgresqlUsername }}" + DB_NAME: "{{ .Values.postgresql.postgresqlDatabase }}" + +envValueFrom: + DB_PASSWORD: + secretKeyRef: + name: dbcreds + key: postgresql-password + DB_HOST: + secretKeyRef: + name: dbcreds + key: plainhost + REDIS_SERVERS: + secretKeyRef: + name: rediscreds + key: url + +postgresql: + enabled: true + existingSecret: "dbcreds" + postgresqlUsername: shlink + postgresqlDatabase: shlink + +redis: + enabled: true + existingSecret: "rediscreds" + redisUsername: "default" diff --git a/docs/_static/img/appicons/shlink-icon.png b/docs/_static/img/appicons/shlink-icon.png new file mode 100644 index 0000000000000000000000000000000000000000..47521550a40278048a3858b693a738f66cb9e6e9 GIT binary patch literal 19106 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