feat: Implement Element Chat Kubernetes installer

- Add Element Chat installer module
- Integrate Conduit and Element Web deployments
- Support TFGW integration for FQDNs and TLS
- Implement installation and destruction logic
- Generate Kubernetes YAML from templates

Co-authored-by: peternashaaat <peternashaaat@gmail.com>
This commit is contained in:
Mahmoud-Emad
2025-11-02 17:24:01 +02:00
parent 672ff886d4
commit 3ee0e5b29c
11 changed files with 917 additions and 0 deletions

View File

@@ -1 +1,2 @@
cryptpad
element_chat

View File

@@ -0,0 +1,42 @@
#!/usr/bin/env -S v -n -w -gc none -cc tcc -d use_openssl -enable-globals run
import incubaid.herolib.installers.k8s.element_chat
// This example demonstrates how to use the Element Chat installer.
// 1. Create a new installer instance with specific hostnames.
// Replace 'matrixchattest' and 'elementchattest' with your desired hostnames.
// Note: Use only alphanumeric characters (no underscores or dashes).
mut installer := element_chat.get(
name: 'myelementchat'
create: true
)!
element_chat.delete()!
// 2. Configure the installer (all settings are optional with sensible defaults)
// installer.matrix_hostname = 'matrixchattest'
// installer.element_hostname = 'elementchattest'
// installer.namespace = 'chat'
// // Conduit (Matrix homeserver) configuration
// installer.conduit_port = 6167 // Default: 6167
// installer.database_backend = 'rocksdb' // Default: 'rocksdb' (can be 'sqlite')
// installer.database_path = '/var/lib/matrix-conduit' // Default: '/var/lib/matrix-conduit'
// installer.allow_registration = true // Default: true
// installer.allow_federation = true // Default: true
// installer.log_level = 'info' // Default: 'info' (can be 'debug', 'warn', 'error')
// // Element web client configuration
// installer.element_brand = 'Element' // Default: 'Element'
// 3. Install Element Chat.
// This will generate the necessary Kubernetes YAML files and apply them to your cluster.
installer.install()!
// println('Element Chat installation started.')
// println('Matrix homeserver will be available at: https://${installer.matrix_hostname}.gent01.grid.tf')
// println('Element web client will be available at: https://${installer.element_hostname}.gent01.grid.tf')
// 4. To destroy the deployment, you can run the following:
// installer.destroy()!

View File

@@ -0,0 +1,12 @@
!!hero_code.generate_installer
name:''
classname:'ElementChat'
singleton:0
templates:1
default:0
title:''
supported_platforms:''
startupmanager:0
hasconfig:1
build:0

View File

@@ -0,0 +1,120 @@
# Element Chat Kubernetes Installer
A Kubernetes installer for Element Chat (Matrix Conduit + Element Web) with TFGrid Gateway integration.
## Overview
This installer deploys a complete Matrix chat solution consisting of:
- **Conduit**: A lightweight Matrix homeserver implementation
- **Element Web**: A modern web client for Matrix
- **TFGW (ThreeFold Gateway)**: Provides public FQDNs with TLS termination
## Quick Start
```v
import incubaid.herolib.installers.k8s.element_chat
// Create and install Element Chat with defaults
mut installer := element_chat.get(
name: 'myelementchat'
create: true
)!
installer.install()!
```
## Configuration Options
All configuration options are optional and have sensible defaults:
### Hostnames and Namespace
```v
installer.matrix_hostname = 'matrixchat' // Default: 'matrixchat'
installer.element_hostname = 'elementchat' // Default: 'elementchat'
installer.namespace = 'chat' // Default: 'chat'
```
**Note**: Use only alphanumeric characters in hostnames (no underscores or dashes).
### Conduit (Matrix Homeserver) Configuration
```v
// Server port
installer.conduit_port = 6167 // Default: 6167
// Database configuration
installer.database_backend = 'rocksdb' // Default: 'rocksdb' (options: 'rocksdb', 'sqlite')
installer.database_path = '/var/lib/matrix-conduit' // Default: '/var/lib/matrix-conduit'
// Federation and registration
installer.allow_registration = true // Default: true (allow new user registration)
installer.allow_federation = true // Default: true (federate with other Matrix servers)
// Logging
installer.log_level = 'info' // Default: 'info' (options: 'info', 'debug', 'warn', 'error')
```
### Element Web Client Configuration
```v
installer.element_brand = 'Element' // Default: 'Element' (customize the branding name)
```
## Full Example
```v
import incubaid.herolib.installers.k8s.element_chat
mut installer := element_chat.get(
name: 'myelementchat'
create: true
)!
// Configure hostnames
installer.matrix_hostname = 'mymatrix'
installer.element_hostname = 'mychat'
installer.namespace = 'chat'
// Configure Conduit
installer.conduit_port = 6167
installer.database_backend = 'rocksdb'
installer.allow_registration = false // Disable public registration
installer.allow_federation = true
installer.log_level = 'debug'
// Configure Element
installer.element_brand = 'My Chat'
// Install
installer.install()!
println('Matrix homeserver: https://${installer.matrix_hostname}.gent01.grid.tf')
println('Element web client: https://${installer.element_hostname}.gent01.grid.tf')
```
## Management
### Check Installation Status
```v
if installer.installed()! {
println('Element Chat is installed')
} else {
println('Element Chat is not installed')
}
```
### Destroy Deployment
```v
installer.destroy()!
```
This will delete the entire namespace and all resources within it.
## See Also
- [Matrix Conduit Documentation](https://gitlab.com/famedly/conduit)
- [Element Web Documentation](https://github.com/vector-im/element-web)
- [Matrix Protocol](https://matrix.org/)

View File

@@ -0,0 +1,195 @@
module element_chat
import incubaid.herolib.osal.core as osal
import incubaid.herolib.ui.console
import incubaid.herolib.installers.ulist
import time
const max_deployment_retries = 30
const deployment_check_interval_seconds = 2
//////////////////// following actions are not specific to instance of the object
// checks if a certain version or above is installed
pub fn installed() !bool {
installer := get()!
mut k8s := installer.kube_client
// Try to get the conduit deployment
deployments := k8s.get_deployments(installer.namespace) or {
// If we can't get deployments, it's not running
return false
}
// Check if conduit and element-web deployments exist
mut conduit_found := false
mut element_found := false
for deployment in deployments {
if deployment.name == 'conduit' {
conduit_found = true
}
if deployment.name == 'element-web' {
element_found = true
}
}
return conduit_found && element_found
}
// get the Upload List of the files
fn ulist_get() !ulist.UList {
// optionally build a UList which is all paths which are result of building, is then used e.g. in upload
return ulist.UList{}
}
// uploads to S3 server if configured
fn upload() ! {
// installers.upload(
// cmdname: 'element_chat'
// source: '${gitpath}/target/x86_64-unknown-linux-musl/release/element_chat'
// )!
}
fn install() ! {
console.print_header('Installing Element Chat...')
// Get installer config to access namespace
installer := get()!
mut k8s := installer.kube_client
configure()!
// 1. Check for dependencies.
console.print_info('Checking for kubectl...')
kubectl_installed()!
console.print_info('kubectl is installed and configured.')
// 4. Apply the YAML files using kubernetes client
console.print_info('Applying Gateway YAML file to the cluster...')
res1 := k8s.apply_yaml('/tmp/element_chat/tfgw-element.yaml')!
if !res1.success {
return error('Failed to apply tfgw-element.yaml: ${res1.stderr}')
}
console.print_info('Gateway YAML file applied successfully.')
// 5. Verify TFGW deployments
verify_tfgw_deployment(tfgw_name: 'matrix-gw', namespace: installer.namespace)!
verify_tfgw_deployment(tfgw_name: 'element-gw', namespace: installer.namespace)!
// 6. Apply Chat App YAML
console.print_info('Applying Chat App YAML file to the cluster...')
res2 := k8s.apply_yaml('/tmp/element_chat/chat-app.yaml')!
if !res2.success {
return error('Failed to apply chat-app.yaml: ${res2.stderr}')
}
console.print_info('Chat App YAML file applied successfully.')
// 7. Verify deployment status
console.print_info('Verifying deployment status...')
mut is_running := false
for i in 0 .. max_deployment_retries {
if installed()! {
is_running = true
break
}
console.print_info('Waiting for Element Chat deployment to be ready... (${i + 1}/${max_deployment_retries})')
time.sleep(deployment_check_interval_seconds * time.second)
}
if is_running {
console.print_header('Element Chat installation successful!')
console.print_header('You can access Element Chat at https://${installer.element_hostname}.gent01.grid.tf')
console.print_header('You can access Matrix at https://${installer.matrix_hostname}.gent01.grid.tf')
} else {
return error('Element Chat deployment failed to start.')
}
}
// params for verifying the generating of the FQDN using tfgw crd
@[params]
struct VerifyTfgwDeployment {
pub mut:
tfgw_name string // tfgw serivce generating the FQDN
namespace string // namespace name for element chat deployments/services
}
// Function for verifying the generating of of the FQDN using tfgw crd
fn verify_tfgw_deployment(args VerifyTfgwDeployment) ! {
console.print_info('Verifying TFGW deployment for ${args.tfgw_name}...')
installer := get()!
mut k8s := installer.kube_client
mut is_fqdn_generated := false
for i in 0 .. max_deployment_retries {
// Use kubectl_exec for custom resource (TFGW) with jsonpath
result := k8s.kubectl_exec(
command: 'get tfgw ${args.tfgw_name} -n ${args.namespace} -o jsonpath="{.status.fqdn}"'
) or {
console.print_info('Waiting for FQDN to be generated for ${args.tfgw_name}... (${i + 1}/${max_deployment_retries})')
time.sleep(deployment_check_interval_seconds * time.second)
continue
}
if result.success && result.stdout != '' {
is_fqdn_generated = true
break
}
console.print_info('Waiting for FQDN to be generated for ${args.tfgw_name}... (${i + 1}/${max_deployment_retries})')
time.sleep(deployment_check_interval_seconds * time.second)
}
if !is_fqdn_generated {
console.print_stderr('Failed to get FQDN for ${args.tfgw_name}.')
// Use describe_resource to get detailed information about the TFGW resource
result := k8s.describe_resource(
resource: 'tfgw'
resource_name: args.tfgw_name
namespace: args.namespace
) or { return error('TFGW deployment failed for ${args.tfgw_name}.') }
console.print_stderr(result.stdout)
return error('TFGW deployment failed for ${args.tfgw_name}.')
}
console.print_info('TFGW deployment for ${args.tfgw_name} verified successfully.')
}
fn destroy() ! {
console.print_header('Destroying Element Chat...')
installer := get()!
mut k8s := installer.kube_client
console.print_debug('Attempting to delete namespace: ${installer.namespace}')
// Delete the namespace using kubernetes client
result := k8s.delete_resource('namespace', installer.namespace, '') or {
console.print_stderr('Failed to delete namespace ${installer.namespace}: ${err}')
return error('Failed to delete namespace ${installer.namespace}: ${err}')
}
console.print_debug('Delete command completed. Exit code: ${result.exit_code}, Success: ${result.success}')
if !result.success {
// Namespace not found is OK - it means it's already deleted
if result.stderr.contains('NotFound') {
console.print_info('Namespace ${installer.namespace} does not exist (already deleted).')
} else {
console.print_stderr('Failed to delete namespace ${installer.namespace}: ${result.stderr}')
return error('Failed to delete namespace ${installer.namespace}: ${result.stderr}')
}
} else {
console.print_info('Namespace ${installer.namespace} deleted successfully.')
}
}
fn kubectl_installed() ! {
// Check if kubectl command exists
if !osal.cmd_exists('kubectl') {
return error('kubectl is not installed. Please install it to continue.')
}
// Check if kubectl is configured to connect to a cluster
installer := get()!
mut k8s := installer.kube_client
if !k8s.test_connection()! {
return error('kubectl is not configured to connect to a Kubernetes cluster. Please check your kubeconfig.')
}
}

View File

@@ -0,0 +1,188 @@
module element_chat
import incubaid.herolib.core.base
import incubaid.herolib.core.playbook { PlayBook }
import incubaid.herolib.ui.console
import json
__global (
element_chat_global map[string]&ElementChat
element_chat_default string
)
/////////FACTORY
@[params]
pub struct ArgsGet {
pub mut:
name string = 'element_chat'
fromdb bool // will load from filesystem
create bool // default will not create if not exist
}
pub fn new(args ArgsGet) !&ElementChat {
mut obj := ElementChat{
name: args.name
}
set(obj)!
return get(name: args.name)!
}
pub fn get(args_ ArgsGet) !&ElementChat {
mut context := base.context()!
mut args := args_
if args.name == 'element_chat' && element_chat_default != '' {
args.name = element_chat_default
}
if args.fromdb || args.name !in element_chat_global {
mut r := context.redis()!
if r.hexists('context:element_chat', args.name)! {
data := r.hget('context:element_chat', args.name)!
if data.len == 0 {
print_backtrace()
return error('ElementChat with name: ${args.name} does not exist, prob bug.')
}
mut obj := json.decode(ElementChat, data)!
set_in_mem(obj)!
} else {
if args.create {
new(args)!
} else {
print_backtrace()
return error("ElementChat with name '${args.name}' does not exist")
}
}
return get(name: args.name)! // no longer from db nor create
}
return element_chat_global[args.name] or {
print_backtrace()
return error('could not get config for element_chat with name:${args.name}')
}
}
// register the config for the future
pub fn set(o ElementChat) ! {
mut o2 := set_in_mem(o)!
element_chat_default = o2.name
mut context := base.context()!
mut r := context.redis()!
r.hset('context:element_chat', o2.name, json.encode(o2))!
}
// does the config exists?
pub fn exists(args ArgsGet) !bool {
mut context := base.context()!
mut r := context.redis()!
return r.hexists('context:element_chat', args.name)!
}
pub fn delete(args ArgsGet) ! {
mut context := base.context()!
mut r := context.redis()!
r.hdel('context:element_chat', args.name)!
}
@[params]
pub struct ArgsList {
pub mut:
fromdb bool // will load from filesystem
}
// if fromdb set: load from filesystem, and not from mem, will also reset what is in mem
pub fn list(args ArgsList) ![]&ElementChat {
mut res := []&ElementChat{}
mut context := base.context()!
if args.fromdb {
// reset what is in mem
element_chat_global = map[string]&ElementChat{}
element_chat_default = ''
}
if args.fromdb {
mut r := context.redis()!
mut l := r.hkeys('context:element_chat')!
for name in l {
res << get(name: name, fromdb: true)!
}
return res
} else {
// load from memory
for _, client in element_chat_global {
res << client
}
}
return res
}
// only sets in mem, does not set as config
fn set_in_mem(o ElementChat) !ElementChat {
mut o2 := obj_init(o)!
element_chat_global[o2.name] = &o2
element_chat_default = o2.name
return o2
}
pub fn play(mut plbook PlayBook) ! {
if !plbook.exists(filter: 'element_chat.') {
return
}
mut install_actions := plbook.find(filter: 'element_chat.configure')!
if install_actions.len > 0 {
for mut install_action in install_actions {
heroscript := install_action.heroscript()
mut obj2 := heroscript_loads(heroscript)!
set(obj2)!
install_action.done = true
}
}
mut other_actions := plbook.find(filter: 'element_chat.')!
for mut other_action in other_actions {
if other_action.name in ['destroy', 'install', 'build'] {
mut p := other_action.params
reset := p.get_default_false('reset')
if other_action.name == 'destroy' || reset {
console.print_debug('install action element_chat.destroy')
destroy()!
}
if other_action.name == 'install' {
console.print_debug('install action element_chat.install')
install()!
}
}
other_action.done = true
}
}
////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////# LIVE CYCLE MANAGEMENT FOR INSTALLERS ///////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
// load from disk and make sure is properly intialized
pub fn (mut self ElementChat) reload() ! {
switch(self.name)
self = obj_init(self)!
}
@[params]
pub struct InstallArgs {
pub mut:
reset bool
}
pub fn (mut self ElementChat) install(args InstallArgs) ! {
switch(self.name)
if args.reset || (!installed()!) {
install()!
}
}
pub fn (mut self ElementChat) destroy() ! {
switch(self.name)
destroy()!
}
// switch instance to be used for element_chat
pub fn switch(name string) {
element_chat_default = name
}

View File

@@ -0,0 +1,177 @@
module element_chat
import incubaid.herolib.ui.console
import incubaid.herolib.data.encoderhero
import incubaid.herolib.virt.kubernetes
import incubaid.herolib.core.pathlib
import strings
pub const version = '0.0.0'
const singleton = false
const default = false
struct ConfigValues {
pub mut:
matrix_hostname string // The Matrix homeserver hostname
element_hostname string // The Element web hostname
backends string // The backends for the TFGW
namespace string // The namespace for the Element Chat deployment
conduit_port int // Conduit server port
database_backend string // Database backend (rocksdb, sqlite)
database_path string // Database path
allow_registration bool // Allow user registration
allow_federation bool // Allow federation with other Matrix servers
log_level string // Log level (info, debug, warn, error)
element_brand string // Element branding name
conduit_toml string // Generated conduit.toml content
element_json string // Generated element-config.json content
}
@[heap]
pub struct ElementChat {
pub mut:
name string = 'element_chat'
matrix_hostname string
element_hostname string
namespace string
// Conduit configuration
conduit_port int = 6167
database_backend string = 'rocksdb'
database_path string = '/var/lib/matrix-conduit'
allow_registration bool = true
allow_federation bool = true
log_level string = 'info'
// Element configuration
element_brand string = 'Element'
// Internal paths
chat_app_path string = '/tmp/element_chat/chat-app.yaml'
tfgw_path string = '/tmp/element_chat/tfgw-element.yaml'
conduit_cfg_path string = '/tmp/element_chat/conduit.toml'
element_cfg_path string = '/tmp/element_chat/element-config.json'
kube_client kubernetes.KubeClient @[skip]
}
// your checking & initialization code if needed
fn obj_init(mycfg_ ElementChat) !ElementChat {
mut mycfg := mycfg_
if mycfg.namespace == '' {
mycfg.namespace = 'chat'
}
if mycfg.matrix_hostname == '' {
mycfg.matrix_hostname = 'matrixchat'
}
if mycfg.element_hostname == '' {
mycfg.element_hostname = 'elementchat'
}
mycfg.kube_client = kubernetes.get(create: true)!
mycfg.kube_client.config.namespace = mycfg.namespace
return mycfg
}
// called before start if done
fn configure() ! {
mut installer := get()!
master_ips := get_master_node_ips()!
console.print_info('Master node IPs: ${master_ips}')
mut backends_str_builder := strings.new_builder(100)
for ip in master_ips {
backends_str_builder.writeln(' - "http://[${ip}]:80"')
}
console.print_info('Generating configuration files from templates...')
// Create config_values for template generation
mut config_values := ConfigValues{
matrix_hostname: installer.matrix_hostname
element_hostname: installer.element_hostname
backends: backends_str_builder.str()
namespace: installer.namespace
conduit_port: installer.conduit_port
database_backend: installer.database_backend
database_path: installer.database_path
allow_registration: installer.allow_registration
allow_federation: installer.allow_federation
log_level: installer.log_level
element_brand: installer.element_brand
conduit_toml: ''
element_json: ''
}
// Generate conduit.toml and element-config.json
conduit_toml_raw := $tmpl('./templates/conduit.toml.temp')
element_json_raw := $tmpl('./templates/element-config.json')
// Indent the configs for proper YAML formatting (4 spaces for ConfigMap data)
conduit_toml_lines := conduit_toml_raw.split('\n')
mut conduit_toml_indented := strings.new_builder(conduit_toml_raw.len + 100)
for line in conduit_toml_lines {
if line.len > 0 {
conduit_toml_indented.writeln(' ${line}')
}
}
element_json_lines := element_json_raw.split('\n')
mut element_json_indented := strings.new_builder(element_json_raw.len + 100)
for line in element_json_lines {
if line.len > 0 {
element_json_indented.writeln(' ${line}')
}
}
// Update config_values with the generated and indented configs
config_values.conduit_toml = conduit_toml_indented.str()
config_values.element_json = element_json_indented.str()
// Ensure the output directory exists
_ := pathlib.get_dir(path: '/tmp/element_chat', create: true)!
// Generate TFGW YAML
tfgw_yaml := $tmpl('./templates/tfgw.yaml')
mut tfgw_path := pathlib.get_file(
path: installer.tfgw_path
create: true
check: true
)!
tfgw_path.write(tfgw_yaml)!
// Generate chat-app YAML
chat_app_yaml := $tmpl('./templates/chat-app.yaml')
mut chat_app_path := pathlib.get_file(path: installer.chat_app_path, create: true)!
chat_app_path.write(chat_app_yaml)!
console.print_info('Configuration files generated successfully.')
}
// Get Kubernetes master node IPs
fn get_master_node_ips() ![]string {
mut master_ips := []string{}
installer := get()!
// Get all nodes using the kubernetes client
mut k8s := installer.kube_client
nodes := k8s.get_nodes()!
// Extract IPv6 internal IPs from all nodes (dual-stack support)
for node in nodes {
// Check all internal IPs (not just the first one) for IPv6 addresses
for ip in node.internal_ips {
if ip.len > 0 && ip.contains(':') {
master_ips << ip
}
}
}
return master_ips
}
/////////////NORMALLY NO NEED TO TOUCH
pub fn heroscript_loads(heroscript string) !ElementChat {
mut obj := encoderhero.decode[ElementChat](heroscript)!
return obj
}

View File

@@ -0,0 +1,139 @@
apiVersion: v1
kind: Namespace
metadata:
name: @{config_values.namespace}
---
apiVersion: v1
kind: ConfigMap
metadata:
name: conduit-config
namespace: @{config_values.namespace}
data:
conduit.toml: |
@{config_values.conduit_toml}
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: conduit
namespace: @{config_values.namespace}
spec:
replicas: 1
selector: { matchLabels: { app: conduit } }
template:
metadata: { labels: { app: conduit } }
spec:
enableServiceLinks: false
containers:
- name: conduit
image: matrixconduit/matrix-conduit:latest
env:
- name: CONDUIT_CONFIG
value: /etc/conduit/conduit.toml
ports: [{ name: http, containerPort: @{config_values.conduit_port} }]
volumeMounts:
- { name: cfg, mountPath: /etc/conduit, readOnly: true }
- { name: data, mountPath: /var/lib/matrix-conduit }
readinessProbe:
httpGet: { path: /_matrix/client/versions, port: @{config_values.conduit_port} }
initialDelaySeconds: 5
periodSeconds: 5
volumes:
- name: cfg
configMap: { name: conduit-config }
- name: data
emptyDir: {}
---
apiVersion: v1
kind: Service
metadata:
name: matrix-hs
namespace: @{config_values.namespace}
spec:
selector: { app: conduit }
ports:
- { name: http, port: @{config_values.conduit_port}, targetPort: @{config_values.conduit_port} }
---
apiVersion: v1
kind: ConfigMap
metadata:
name: element-config
namespace: @{config_values.namespace}
data:
config.json: |
@{config_values.element_json}
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: element-web
namespace: @{config_values.namespace}
spec:
replicas: 1
selector: { matchLabels: { app: element-web } }
template:
metadata: { labels: { app: element-web } }
spec:
enableServiceLinks: false
containers:
- name: element
image: vectorim/element-web:latest
env:
- { name: PORT, value: "80" }
ports: [{ name: http, containerPort: 80 }]
volumeMounts:
- name: element-config
mountPath: /app/config.json
subPath: config.json
readOnly: true
volumes:
- name: element-config
configMap: { name: element-config }
---
apiVersion: v1
kind: Service
metadata:
name: element-web
namespace: @{config_values.namespace}
spec:
selector: { app: element-web }
ports:
- { name: http, port: 80, targetPort: 80 }
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: matrix
namespace: @{config_values.namespace}
spec:
ingressClassName: traefik
rules:
- host: @{config_values.matrix_hostname}.gent01.grid.tf
http:
paths:
- path: /
pathType: Prefix
backend: { service: { name: matrix-hs, port: { number: @{config_values.conduit_port} } } }
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: element
namespace: @{config_values.namespace}
spec:
ingressClassName: traefik
rules:
- host: @{config_values.element_hostname}.gent01.grid.tf
http:
paths:
- path: /
pathType: Prefix
backend: { service: { name: element-web, port: { number: 80 } } }

View File

@@ -0,0 +1,9 @@
[global]
allow_registration = @{config_values.allow_registration}
allow_federation = @{config_values.allow_federation}
port = @{config_values.conduit_port}
server_name = "@{config_values.matrix_hostname}.gent01.grid.tf"
address = "0.0.0.0"
database_backend = "@{config_values.database_backend}"
database_path = "@{config_values.database_path}"
log = "@{config_values.log_level}"

View File

@@ -0,0 +1,10 @@
{
"disable_custom_urls": true,
"default_server_config": {
"m.homeserver": {
"base_url": "https://@{config_values.matrix_hostname}.gent01.grid.tf",
"server_name": "@{config_values.matrix_hostname}.gent01.grid.tf"
}
},
"brand": "@{config_values.element_brand}"
}

View File

@@ -0,0 +1,24 @@
apiVersion: v1
kind: Namespace
metadata:
name: @{config_values.namespace}
---
apiVersion: ingress.grid.tf/v1
kind: TFGW
metadata:
name: matrix-gw
namespace: @{config_values.namespace}
spec:
hostname: "@{config_values.matrix_hostname}"
backends:
@{config_values.backends}
---
apiVersion: ingress.grid.tf/v1
kind: TFGW
metadata:
name: element-gw
namespace: @{config_values.namespace}
spec:
hostname: "@{config_values.element_hostname}"
backends:
@{config_values.backends}