diff --git a/helm/.helmignore b/helm/.helmignore new file mode 100644 index 0000000..0e8a0eb --- /dev/null +++ b/helm/.helmignore @@ -0,0 +1,23 @@ +# Patterns to ignore when building packages. +# This supports shell glob matching, relative path matching, and +# negation (prefixed with !). Only one pattern per line. +.DS_Store +# Common VCS dirs +.git/ +.gitignore +.bzr/ +.bzrignore +.hg/ +.hgignore +.svn/ +# Common backup files +*.swp +*.bak +*.tmp +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/helm/Chart.yaml b/helm/Chart.yaml new file mode 100644 index 0000000..694edf1 --- /dev/null +++ b/helm/Chart.yaml @@ -0,0 +1,24 @@ +apiVersion: v2 +name: maubot +description: A Helm chart for Kubernetes + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +# Versions are expected to follow Semantic Versioning (https://semver.org/) +version: 0.1.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. Versions are not expected to +# follow Semantic Versioning. They should reflect the version the application is using. +# It is recommended to use it with quotes. +appVersion: "1.16.0" diff --git a/helm/ReadMe.md b/helm/ReadMe.md new file mode 100644 index 0000000..8e0c258 --- /dev/null +++ b/helm/ReadMe.md @@ -0,0 +1,40 @@ +# Standalone or Normal Mode? + +According to [docs.mau.fi](https://docs.mau.fi/maubot/usage/standalone.html) + +> The normal mode in maubot is very dynamic: the config file doesn't really contain any runtime details other than a general web server, database, etc. Everything else is set up at runtime using the web management interface or the management API directly. This dynamicness is very useful for developing bots and works fine for deploying it on personal servers, but it's not optimal for larger production deployments. +The solution is standalone mode: a separate entrypoint that runs a single maubot plugin with a predefined Matrix account. +Additionally, standalone mode supports using appservice transactions to receive events instead of /sync, which is often useful for huge production instances with lots of traffic. + +--- + +> [!NOTE] +> unlike Normal Mode, the Standalone Mode will not create an SQlite db for you (if no postgres is specified) . You'll have to create one yourself + +# Normal Mode Steps + +## After Deployment + +After deploying the Bot Framework you can navigate to the web interface and login with a User you specified in your Values's `admin` block. + +To use the maubot framework however you need to: + +1. register a user that the bot should use on your specified homeserver +> [!NOTE] +> you can skip the first step if you have a sharedSecret of your homeserver configured + +2. connect to the container with +```bash + kubectl exec -it deployments/maubot -- sh +``` + 3. run `mbc auth` with the user you want your bot to use. Note down the Access Token and device_id as you will need to enter these in the UI or in your config for future deployments. + + You may use the `--register` and `--update-client` flags to register a new user for your bot and make the pod store the access token. + +## Plugins + +You can find available "plugins", other bots that use the maubot framework at https://plugins.mau.bot + +## add Plugins + +see https://docs.mau.fi/maubot/usage/basic.html#uploading-plugins \ No newline at end of file diff --git a/helm/configs/config.yaml b/helm/configs/config.yaml new file mode 100644 index 0000000..4236a7d --- /dev/null +++ b/helm/configs/config.yaml @@ -0,0 +1,207 @@ +{{ if .Values.standaloneMode.enabled }} +# Bot account details +user: + credentials: + id: "{{- .Values.configSA.user.id }}" + homeserver: {{ .Values.configSA.user.homeserver }} + access_token: {{ .Values.configSA.user.access_token }} + # If you want to enable encryption, set the device ID corresponding to the access token here. + # When using an appservice, you should use appservice login manually to generate a device ID and access token. + device_id: {{ default "null" .Values.configSA.user.device_id }} + # Enable /sync? This is not needed for purely unencrypted webhook-based bots, but is necessary in most other cases. + sync: {{ .Values.configSA.user.sync }} + # Receive appservice transactions? This will add a /_matrix/app/v1/transactions endpoint on + # the HTTP server configured below. The base_path will not be applied for the /transactions path. + appservice: {{ .Values.configSA.user.appservice }} + # When appservice mode is enabled, the hs_token for the appservice. + hs_token: {{ default "null" .Values.configSA.user.hs_token }} + # Automatically accept invites? + autojoin: {{ .Values.configSA.user.autojoin }} + # The displayname and avatar URL to set for the bot on startup. + # Set to "disable" to not change the the current displayname/avatar. + displayname: {{ .Values.configSA.user.displayname }} + avatar_url: {{ .Values.configSA.user.avatar_url }} + # Should events from the initial sync be ignored? This should usually always be true. + ignore_initial_sync: {{ .Values.configSA.user.ignore_initial_sync }} + # Should events from the first sync after starting be ignored? This can be set to false + # if you want the bot to handle messages that were sent while the bot was down. + ignore_first_sync: {{ .Values.configSA.user.ignore_first_sync }} + +# Web server settings. These will only take effect if the plugin requests it using `webapp: true` in the meta file, +# or if user -> appservice is set to true. +server: + # The IP and port to listen to. + hostname: {{ .Values.configSA.server.hostname }} + port: {{ .Values.configSA.server.port }} + # The base path where the plugin's web resources will be served. Unlike the normal mode, + # the webserver is dedicated for a single bot in standalone mode, so the default path + # is just /. If you want to emulate normal mode, set this to /_matrix/maubot/plugin/something + base_path: {{ .Values.configSA.server.base_path }} + # The public URL where the resources are available. The base path is automatically appended to this. + public_url: {{ .Values.configSA.server.public_url }} + +# The database for the plugin. Used for plugin data, the sync token and e2ee data (if enabled). +# SQLite and Postgres are supported. +database: {{ .Values.configSA.database.type }} + +# Additional arguments for asyncpg.create_pool() or sqlite3.connect() +# https://magicstack.github.io/asyncpg/current/api/index.html#asyncpg.pool.create_pool +# https://docs.python.org/3/library/sqlite3.html#sqlite3.connect +# For sqlite, min_size is used as the connection thread pool size and max_size is ignored. +database_opts: + min_size: {{ .Values.configSA.database.opts.min }} + max_size: {{ .Values.configSA.database.opts.max }} + +{{ if .Values.configSA.plugin_config.has_config }} +# Config for the plugin. Refer to the plugin's base-config.yaml to find what (if anything) to put here. +plugin_config: + whitelist: {{ range .Values.configSA.plugin_config.whitelist }} + - "{{ . }}" + {{- end }} + command_prefix: {{ .Values.configSA.plugin_config.command_prefix }} +{{- end }} + +# Standard Python logging configuration +logging: + version: 1 + formatters: + colored: + (): maubot.lib.color_log.ColorFormatter + format: "{{ .Values.configSA.logging.format }}" + handlers: + console: + class: logging.StreamHandler + formatter: colored + loggers: + maubot: + level: {{ .Values.configSA.logging.loggers.maubot }} + mau: + level: {{ .Values.configSA.logging.loggers.mau }} + aiohttp: + level: {{ .Values.configSA.logging.loggers.aiohttp }} + root: + level: {{ .Values.configSA.logging.root.level }} + handlers: [{{ .Values.configSA.logging.root.handlers }}] +{{- end }} +{{- if .Values.normalMode.enabled }} + +database: {{ .Values.configN.database.type }} + +crypto_database: {{ .Values.configN.crypto_database }} + +database_opts: + min_size: {{ .Values.configN.database.opts.min }} + max_size: {{ .Values.configN.database.opts.max }} + +# Configuration for storing plugin .mbp files +plugin_directories: + # The directory where uploaded new plugins should be stored. + upload: {{ .Values.configN.plugin_directories.upload }} + # The directories from which plugins should be loaded. + # Duplicate plugin IDs will be moved to the trash. + load: {{ range .Values.configN.plugin_directories.load }} + - {{ . }} + {{- end }} + # The directory where old plugin versions and conflicting plugins should be moved. + # Set to "delete" to delete files immediately. + trash: {{ .Values.configN.plugin_directories.trash }} + +# Configuration for storing plugin databases +plugin_databases: + # The directory where SQLite plugin databases should be stored. + sqlite: {{ .Values.configN.plugin_databases.sqlite }} + # The connection URL for plugin databases. If null, all plugins will get SQLite databases. + # If set, plugins using the new asyncpg interface will get a Postgres connection instead. + # Plugins using the legacy SQLAlchemy interface will always get a SQLite connection. + # + # To use the same connection pool as the default database, set to "default" + # (the default database above must be postgres to do this). + # + # When enabled, maubot will create separate Postgres schemas in the database for each plugin. + # To view schemas in psql, use `\dn`. To view enter and interact with a specific schema, + # use `SET search_path = name` (where `name` is the name found with `\dn`) and then use normal + # SQL queries/psql commands. + postgres: {{ default "null" .Values.configN.plugin_databases.postgres }} + # Maximum number of connections per plugin instance. + postgres_max_conns_per_plugin: {{ .Values.configN.plugin_databases.max_conn_per_plugin }} + # Overrides for the default database_opts when using a non-"default" postgres connection string. + postgres_opts: {{ .Values.configN.plugin_databases.postgres_opts | toYaml }} + +server: + # The IP and port to listen to. + hostname: {{ .Values.configN.server.hostname }} + port: {{ .Values.configN.server.port }} + # Public base URL where the server is visible. + public_url: {{ .Values.configN.server.public_url }} + # The base path for the UI. + ui_base_path: {{ .Values.configN.server.ui_base_path }} + # The base path for plugin endpoints. The instance ID will be appended directly. + plugin_base_path: {{ .Values.configN.server.plugin_base_path }} + # Override path from where to load UI resources. + # Set to false to using pkg_resources to find the path. + override_resource_path: {{ .Values.configN.server.override_resource_path }} + # The shared secret to sign API access tokens. + # Set to "generate" to generate and save a new token at startup. + unshared_secret: {{ .Values.configN.server.unshared_secret }} + +# Known homeservers. This is required for the `mbc auth` command and also allows +# more convenient access from the management UI. This is not required to create +# clients in the management UI, since you can also just type the homeserver URL +# into the box there. +homeservers: + {{ .Values.configN.homeservers.server_name }}: + url: {{ .Values.configN.homeservers.url}} + secret: {{ .Values.configN.homeservers.secret }} + +# List of administrator users. Plaintext passwords will be bcrypted on startup. Set empty password +# to prevent normal login. Root is a special user that can't have a password and will always exist. +admins: {{ .Values.configN.admins | toYaml | nindent 2 }} + root: "" + +# API feature switches. +api_features: + login: {{ .Values.configN.api_feature.login }} + plugin: {{ .Values.configN.api_feature.plugin }} + plugin_upload: {{ .Values.configN.api_feature.plugin_upload }} + instance: {{ .Values.configN.api_feature.instance }} + instance_database: {{ .Values.configN.api_feature.instance_database }} + client: {{ .Values.configN.api_feature.client }} + client_proxy: {{ .Values.configN.api_feature.client_proxy }} + client_auth: {{ .Values.configN.api_feature.client_auth }} + dev_open: {{ .Values.configN.api_feature.dev_open }} + log: {{ .Values.configN.api_feature.log }} + +# Python logging configuration. +# +# See section 16.7.2 of the Python documentation for more info: +# https://docs.python.org/3.6/library/logging.config.html#configuration-dictionary-schema +logging: + version: 1 + formatters: + colored: + (): maubot.lib.color_log.ColorFormatter + format: "{{ .Values.configN.logging.c_format }}" + normal: + format: "{{ .Values.configN.logging.n_format }}" + handlers: + file: + class: logging.handlers.RotatingFileHandler + formatter: normal + filename: /data/maubot.log + maxBytes: 10485760 + backupCount: 10 + console: + class: logging.StreamHandler + formatter: colored + stream: ext://sys.stdout + loggers: + maubot: + level: {{ .Values.configN.logging.loggers.maubot }} + mau: + level: {{ .Values.configN.logging.loggers.mau }} + aiohttp: + level: {{ .Values.configN.logging.loggers.aiohttp }} + root: + level: {{ .Values.configN.logging.root.level }} + handlers: [{{ .Values.configN.logging.root.handlers }}] +{{- end -}} \ No newline at end of file diff --git a/helm/templates/NOTES.txt b/helm/templates/NOTES.txt new file mode 100644 index 0000000..caec349 --- /dev/null +++ b/helm/templates/NOTES.txt @@ -0,0 +1,22 @@ +1. Get the application URL by running these commands: +{{- if .Values.ingress.enabled }} +{{- range $host := .Values.ingress.hosts }} + {{- range .paths }} + http{{ if $.Values.ingress.tls }}s{{ end }}://{{ $host.host }}{{ .path }} + {{- end }} +{{- end }} +{{- else if contains "NodePort" .Values.service.type }} + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "maubot.fullname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo http://$NODE_IP:$NODE_PORT +{{- else if contains "LoadBalancer" .Values.service.type }} + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "maubot.fullname" . }}' + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "maubot.fullname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") + echo http://$SERVICE_IP:{{ .Values.service.port }} +{{- else if contains "ClusterIP" .Values.service.type }} + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "maubot.name" . }},app.kubernetes.io/instance={{ .Release.Name }}" -o jsonpath="{.items[0].metadata.name}") + export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") + echo "Visit http://127.0.0.1:8080 to use your application" + kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT +{{- end }} diff --git a/helm/templates/_helpers.tpl b/helm/templates/_helpers.tpl new file mode 100644 index 0000000..bcacad3 --- /dev/null +++ b/helm/templates/_helpers.tpl @@ -0,0 +1,62 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "maubot.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "maubot.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "maubot.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "maubot.labels" -}} +helm.sh/chart: {{ include "maubot.chart" . }} +{{ include "maubot.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "maubot.selectorLabels" -}} +app.kubernetes.io/name: {{ include "maubot.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "maubot.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "maubot.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} diff --git a/helm/templates/configmap.yaml b/helm/templates/configmap.yaml new file mode 100644 index 0000000..e5c074d --- /dev/null +++ b/helm/templates/configmap.yaml @@ -0,0 +1,8 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: maubot-config + labels: +{{ include "maubot.labels" . | indent 4 }} +data: + config.yaml: | {{ tpl (.Files.Get "configs/config.yaml") . | nindent 4 }} \ No newline at end of file diff --git a/helm/templates/deployment.yaml b/helm/templates/deployment.yaml new file mode 100644 index 0000000..8b6578b --- /dev/null +++ b/helm/templates/deployment.yaml @@ -0,0 +1,80 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "maubot.fullname" . }} + labels: + {{- include "maubot.labels" . | nindent 4 }} +spec: + {{- if not .Values.autoscaling.enabled }} + replicas: {{ .Values.replicaCount }} + {{- end }} + selector: + matchLabels: + {{- include "maubot.selectorLabels" . | nindent 6 }} + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "maubot.labels" . | nindent 8 }} + {{- with .Values.podLabels }} + {{- toYaml . | nindent 8 }} + {{- end }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "maubot.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + initContainers: + - name: copy + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + image: "alpine:latest" + imagePullPolicy: {{ .Values.image.pullPolicy }} + command: ["cp", "/config.yaml", "/data/config.yaml"] + {{- with .Values.volumeMounts }} + volumeMounts: + {{- toYaml . | nindent 12 }} + {{- end }} + containers: + - name: {{ .Chart.Name }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + #command: ["/bin/sleep", "30000"] + ports: + - name: http + containerPort: {{ .Values.service.port }} + protocol: TCP + livenessProbe: + {{- toYaml .Values.livenessProbe | nindent 12 }} + readinessProbe: + {{- toYaml .Values.readinessProbe | nindent 12 }} + resources: + {{- toYaml .Values.resources | nindent 12 }} + {{- with .Values.volumeMounts }} + volumeMounts: + {{- toYaml . | nindent 12 }} + {{- end }} + {{- with .Values.volumes }} + volumes: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/helm/templates/hpa.yaml b/helm/templates/hpa.yaml new file mode 100644 index 0000000..85dc5d3 --- /dev/null +++ b/helm/templates/hpa.yaml @@ -0,0 +1,32 @@ +{{- if .Values.autoscaling.enabled }} +apiVersion: autoscaling/v2 +kind: HorizontalPodAutoscaler +metadata: + name: {{ include "maubot.fullname" . }} + labels: + {{- include "maubot.labels" . | nindent 4 }} +spec: + scaleTargetRef: + apiVersion: apps/v1 + kind: Deployment + name: {{ include "maubot.fullname" . }} + minReplicas: {{ .Values.autoscaling.minReplicas }} + maxReplicas: {{ .Values.autoscaling.maxReplicas }} + metrics: + {{- if .Values.autoscaling.targetCPUUtilizationPercentage }} + - type: Resource + resource: + name: cpu + target: + type: Utilization + averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }} + {{- end }} + {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }} + - type: Resource + resource: + name: memory + target: + type: Utilization + averageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }} + {{- end }} +{{- end }} diff --git a/helm/templates/ingress.yaml b/helm/templates/ingress.yaml new file mode 100644 index 0000000..a6ea623 --- /dev/null +++ b/helm/templates/ingress.yaml @@ -0,0 +1,61 @@ +{{- if .Values.ingress.enabled -}} +{{- $fullName := include "maubot.fullname" . -}} +{{- $svcPort := .Values.service.port -}} +{{- if and .Values.ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }} + {{- if not (hasKey .Values.ingress.annotations "kubernetes.io/ingress.class") }} + {{- $_ := set .Values.ingress.annotations "kubernetes.io/ingress.class" .Values.ingress.className}} + {{- end }} +{{- end }} +{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1 +{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1beta1 +{{- else -}} +apiVersion: extensions/v1beta1 +{{- end }} +kind: Ingress +metadata: + name: {{ $fullName }} + labels: + {{- include "maubot.labels" . | nindent 4 }} + {{- with .Values.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if and .Values.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }} + ingressClassName: {{ .Values.ingress.className }} + {{- end }} + {{- if .Values.ingress.tls }} + tls: + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} + {{- end }} + rules: + {{- range .Values.ingress.hosts }} + - host: {{ .host | quote }} + http: + paths: + {{- range .paths }} + - path: {{ .path }} + {{- if and .pathType (semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion) }} + pathType: {{ .pathType }} + {{- end }} + backend: + {{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }} + service: + name: {{ $fullName }} + port: + number: {{ $svcPort }} + {{- else }} + serviceName: {{ $fullName }} + servicePort: {{ $svcPort }} + {{- end }} + {{- end }} + {{- end }} +{{- end }} diff --git a/helm/templates/pvc.yaml b/helm/templates/pvc.yaml new file mode 100644 index 0000000..3a823d6 --- /dev/null +++ b/helm/templates/pvc.yaml @@ -0,0 +1,18 @@ +{{- if .Values.persistence.enabled }} +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: maubot-data + labels: +{{ include "maubot.labels" . | indent 4 }} + annotations: +spec: + accessModes: + {{- range .Values.persistence.accessModes }} + - {{ . | quote }} + {{- end }} + resources: + requests: + storage: {{ .Values.persistence.size | quote }} + storageClassName: {{ default "longhorn" .Values.persistence.storageClassName }} +{{- end }} \ No newline at end of file diff --git a/helm/templates/service.yaml b/helm/templates/service.yaml new file mode 100644 index 0000000..78acbf7 --- /dev/null +++ b/helm/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "maubot.fullname" . }} + labels: + {{- include "maubot.labels" . | nindent 4 }} +spec: + type: {{ .Values.service.type }} + ports: + - port: {{ .Values.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + {{- include "maubot.selectorLabels" . | nindent 4 }} diff --git a/helm/templates/serviceaccount.yaml b/helm/templates/serviceaccount.yaml new file mode 100644 index 0000000..a1490e2 --- /dev/null +++ b/helm/templates/serviceaccount.yaml @@ -0,0 +1,13 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "maubot.serviceAccountName" . }} + labels: + {{- include "maubot.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +automountServiceAccountToken: {{ .Values.serviceAccount.automount }} +{{- end }} diff --git a/helm/templates/tests/test-connection.yaml b/helm/templates/tests/test-connection.yaml new file mode 100644 index 0000000..51465ed --- /dev/null +++ b/helm/templates/tests/test-connection.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Pod +metadata: + name: "{{ include "maubot.fullname" . }}-test-connection" + labels: + {{- include "maubot.labels" . | nindent 4 }} + annotations: + "helm.sh/hook": test +spec: + containers: + - name: wget + image: busybox + command: ['wget'] + args: ['{{ include "maubot.fullname" . }}:{{ .Values.service.port }}'] + restartPolicy: Never diff --git a/helm/values.yaml b/helm/values.yaml new file mode 100644 index 0000000..5d510bc --- /dev/null +++ b/helm/values.yaml @@ -0,0 +1,289 @@ +# Default values for maubot. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +replicaCount: 1 + +image: + repository: dock.mau.dev/maubot/maubot + pullPolicy: IfNotPresent + # Overrides the image tag whose default is the chart appVersion. + tag: "latest" + +imagePullSecrets: [] +nameOverride: "" +fullnameOverride: "" + +serviceAccount: + # Specifies whether a service account should be created + create: true + # Automatically mount a ServiceAccount's API credentials? + automount: true + # Annotations to add to the service account + annotations: {} + # The name of the service account to use. + # If not set and create is true, a name is generated using the fullname template + name: "" + +podAnnotations: {} +podLabels: {} + +podSecurityContext: {} + #fsGroup: 2000 + + +securityContext: {} + #runAsGroup: 2000 + #runAsUser: 2000 + # capabilities: + # drop: + # - ALL + # readOnlyRootFilesystem: true + # runAsNonRoot: true + +# standaloneMode port: 8080 +# normalMode port: 29316 +service: + type: ClusterIP + port: 29316 + +ingress: + enabled: false + className: "nginx" + annotations: + # standalone mode does not need 'app-root' redirect + nginx.ingress.kubernetes.io/app-root: /_matrix/maubot + #cert-manager.io/cluster-issuer: "letsencrypt-prod" + hosts: + - host: chart-example.local + paths: + - path: / + pathType: ImplementationSpecific + tls: [] + #- secretName: maubot-tls + # hosts: + # - chart-example.local + +resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +livenessProbe: + httpGet: + path: /_matrix/maubot + port: http +readinessProbe: + httpGet: + path: /_matrix/maubot + port: http + +autoscaling: + enabled: false + minReplicas: 1 + maxReplicas: 2 + targetCPUUtilizationPercentage: 80 + # targetMemoryUtilizationPercentage: 80 + +# you want to persist a volume as plugins and their configs are stored there +# this Chart uses longhorn as default storageClass +persistence: + enabled: enabled + accessModes: + - ReadWriteMany + size: 10Gi + storageClassName: + +# Additional volumes on the output Deployment definition. +volumes: + - name: maubot-data + persistentVolumeClaim: + claimName: maubot-data + - name: maubot-config + configMap: + name: "maubot-config" + defaultMode: 0660 + +# - name: foo +# secret: +# secretName: mysecret +# optional: false + +# Additional volumeMounts on the output Deployment definition. +volumeMounts: + - name: maubot-data + mountPath: "/data" + - name: maubot-config + mountPath: "/config.yaml" + subPath: config.yaml + +# - name: foo +# mountPath: "/etc/foo" +# readOnly: true + +nodeSelector: {} + +tolerations: [] + +affinity: {} + +# configure either Standalone or Normal mode values + +######## Standalone mode config values ######## +standaloneMode: + enabled: false +configSA: + user: + # full bot mxid + id: "@bot:example.com" + # homeserver you're registering this bot at + # this is the `server_name` from your homeserver.yaml + homeserver: https://example.com + # you need to use maubot-cli to get an access token *and* device_id + # getting these from element is NOT possible as they will be bootstrapped to a client + # which makes it unusable for maubot + access_token: + device_id: + # needs to be true for almost any use case + sync: true + # Receive appservice transactions? This will add a /_matrix/app/v1/transactions endpoint on + # the HTTP server configured below. The base_path will not be applied for the /transactions path. + appservice: false + # hs_token is needed when `appservice` is true + hs_token: + autojoin: true + displayname: 'Mau Bot' + # needs to be an `mxc://` url to an existing image on a matrix server + avatar_url: mxc://maunium.net/AKwRzQkTbggfVZGEqexbYLIO + ignore_initial_sync: true + ignore_first_sync: false + + server: + hostname: 0.0.0.0 + port: 8080 + # The public URL where the resources are available + public_url: https://example.com + # where the plugin's web resources will be served + # Unlike the normal mode,the webserver is dedicated for a single bot in standalone mode, so the default path + # is just /. If you want to emulate normal mode, set this to /_matrix/maubot/plugin/something + base_path: / + + database: + # SQLite: sqlite:filename.db + # Postgres: postgresql://username:password@hostname/dbname + type: 'sqlite:bot.db' + # For sqlite, min_size is used as the connection thread pool size and max_size is ignored. + opts: + min: 10 + max: 20 + + # for additional "plugins" aka other bots within the maubot framework + plugin_config: + has_config: false + # Who is allowed to use the bot? + whitelist: + - "@user:example.com" + # The prefix for the main command without the ! + command_prefix: myBotCommand + + # python logging configuration + logging: + format: "[%(asctime)s] [%(levelname)s@%(name)s] %(message)s" + loggers: + # DEBUG | INFO | WARN | ERROR | CRITICAL + maubot: DEBUG + mau: DEBUG + aiohttp: INFO + root: + level: DEBUG + handlers: console + +######## Normal mode config values ######## + +normalMode: + enabled: true +configN: + # SQLite: sqlite:filename.db + # Postgres: postgresql://username:password@hostname/dbname + # + # IF SQLite is used enter plugin_database path for sqlite + database: + type: sqlite:/data/maubot.db + # For sqlite, min_size is used as the connection thread pool size and max_size is ignored. + opts: + min: 10 + max: 20 + # Separate database URL for the crypto database. "default" means use the same database as above. + crypto_database: default + + plugin_directories: + upload: /data/plugins + load: + - /data/plugins + # set to "delete" to delete immediately + trash: /data/trash + plugin_databases: + # possible values: './plugins' OR null (default in template), but must use postgres + sqlite: /data/dbs + # possible values: 'default' (default in template) OR null + postgres: + max_conn_per_plugin: 3 + # Overrides for the default database_opts when using a non-"default" postgres connection string. + postgres_opts: {} + + server: + hostname: 0.0.0.0 + port: 29316 + public_url: https://example.com + ui_base_path: /_matrix/maubot + plugin_base_path: /_matrix/maubot/plugin/ + override_resource_path: false + # The shared secret to sign API access tokens. + # Set to "generate" to generate and save a new token at startup. + unshared_secret: generate + + homeservers: + server_name: matrix.org + # Client-server API URL + url: https://matrix-client.matrix.org + # registration_shared_secret from synapse config + # You can leave this empty if you don't have access to the homeserver. + # When this is empty, `mbc auth --register` won't work, but `mbc auth` (login) will. + secret: null + + admins: + # leave password empty to prevent normal login + # passwords need to be bcrypt'ed https://bcrypt-generator.com + #username: "password" + + api_feature: + login: true + plugin: true + plugin_upload: true + instance: true + instance_database: true + client: true + client_proxy: true + client_auth: true + dev_open: false + log: true + + # python logging configuration + logging: + c_format: "[%(asctime)s] [%(levelname)s@%(name)s] %(message)s" + n_format: "[%(asctime)s] [%(levelname)s@%(name)s] %(message)s" + loggers: + # DEBUG | INFO | WARN | ERROR | CRITICAL + maubot: DEBUG + mau: DEBUG + aiohttp: INFO + root: + level: DEBUG + handlers: file,console \ No newline at end of file