AppManager: Add API endpoint to install dodo app
Refactors cue definitions.
Next steps:
* Needs some cleanup, namespace is hard coded ...
* Maybe merge with regular install API
* Support exposing ports across clusters
Change-Id: Ibfc3c3f742b61f2c5874012fe6c77b958eae81d9
diff --git a/core/installer/Makefile b/core/installer/Makefile
index abdd656..0fc236c 100644
--- a/core/installer/Makefile
+++ b/core/installer/Makefile
@@ -1,4 +1,4 @@
-repo_name ?= dtabidze
+repo_name ?= giolekva
podman ?= docker
ifeq ($(podman), podman)
manifest_dest=docker://docker.io/$(repo_name)/pcloud-installer:latest
diff --git a/core/installer/app.go b/core/installer/app.go
index 612f2e5..948e17e 100644
--- a/core/installer/app.go
+++ b/core/installer/app.go
@@ -476,6 +476,31 @@
return AppTypeEnv
}
+func merge(d map[string]any, v map[string]any) map[string]any {
+ ret := map[string]any{}
+ for k, val := range d {
+ if vv, ok := v[k]; ok && vv != nil {
+ if mv, ok := val.(map[string]any); ok {
+ // TODO(gio): check that it is actually map
+ fmt.Println(vv)
+ ret[k] = merge(mv, vv.(map[string]any))
+ } else {
+ ret[k] = vv
+ }
+ } else {
+ ret[k] = val
+ }
+ }
+ for k, v := range v {
+ if v != nil {
+ if _, ok := d[k]; !ok {
+ d[k] = v
+ }
+ }
+ }
+ return ret
+}
+
func (a cueEnvApp) Render(
release Release,
env EnvConfig,
@@ -485,7 +510,12 @@
charts map[string]helmv2.HelmChartTemplateSpec,
vpnKeyGen VPNAPIClient,
) (EnvAppRendered, error) {
- derived, err := deriveValues(values, values, a.Schema(), networks, clusters, vpnKeyGen)
+ dv, err := ExtractDefaultValues(a.cueApp.cfg.LookupPath(cue.ParsePath("input")))
+ if err != nil {
+ return EnvAppRendered{}, err
+ }
+ mv := merge(dv.(map[string]any), values)
+ derived, err := deriveValues(mv, values, a.Schema(), networks, clusters, vpnKeyGen)
if err != nil {
return EnvAppRendered{}, err
}
diff --git a/core/installer/app_configs/app_base.cue b/core/installer/app_configs/app_base.cue
index 3ed300a..7698553 100644
--- a/core/installer/app_configs/app_base.cue
+++ b/core/installer/app_configs/app_base.cue
@@ -3,6 +3,7 @@
"encoding/yaml"
"list"
"net"
+ "strings"
)
input: {
@@ -62,15 +63,15 @@
fullNameWithTag: "\(fullName):\(tag)"
}
-#Volume: {
+#VolumeInput: {
cluster?: #Cluster
+ name: string
size: string
accessMode: "ReadWriteOnce" | "ReadOnlyMany" | "ReadWriteMany" | "ReadWriteOncePod" | *"ReadWriteOnce"
}
-#volume: {
- #Volume
- name: string
+#Volume: {
+ #VolumeInput
}
#Chart: #GitRepositoryRef | #HelmRepositoryRef
@@ -114,7 +115,7 @@
port: int
service: close({
name: string
- port: int & > 0
+ port: #PortValue
})
protocol: "TCP" | "UDP" | *"TCP"
@@ -237,19 +238,17 @@
name: "ssh"
value: 22
protocol: "TCP"
- }, {
- if codeServerEnabled {
- name: _codeServerPortName
- value: _codeServerPort
- protocol: "TCP"
- }
},
- for p in _ports {
- name: p.name
- value: p.value
- protocol: p.protocol
- }
- ]
+ if codeServerEnabled {
+ name: _codeServerPortName
+ value: _codeServerPort
+ protocol: "TCP"
+ }
+ for p in _ports {
+ name: p.name
+ value: p.value
+ protocol: p.protocol
+ }]
cloudInit: {
userData: base64.Encode(null, "#cloud-config\n\(yaml.Marshal(_cloudInitUserData))")
networkData: base64.Encode(null, yaml.Marshal({
@@ -319,17 +318,49 @@
}
}
-#MongoDB: #WithOut & {
+#Domain: {
+ network: string
+ subdomain: string
+}
+
+#PortDomain: {
+ #Domain
+ port: { name: string } | { value: #PortValue }
+}
+
+#MongoDBInput: {
cluster?: #Cluster
- _cluster: cluster
name: string
version: "8.0.1"
size: string | *"1Gi"
initdbScripts: {...}
- _initdbScripts: initdbScripts
+ expose: [...#Domain] | *[]
+ ...
+}
+#MongoDB: #WithOut & #MongoDBInput & {
+ cluster?: #Cluster
+ name: string
+ version: "8.0.1"
+ size: string | *"1Gi"
+ initdbScripts: {...}
+ expose: [...#Domain] | *[]
+
+ _cluster: cluster
+ _name: name
_size: size
_volumeClaimName: "\(name)-mongodb"
+ _initdbScripts: initdbScripts
+
+ openPort: [for i, e in expose {
+ network: networks[strings.ToLower(e.network)]
+ port: input["port_mongodb_\(_name)_\(i)"]
+ protocol: "TCP"
+ service: {
+ name: "mongodb-\(_name)"
+ port: 27017
+ }
+ }]
images: {
mongodb: {
@@ -348,7 +379,7 @@
path: "charts/mongodb"
}
}
- volumes: {
+ volume: {
"\(_volumeClaimName)": {
size: _size
if _cluster != _|_ {
@@ -357,7 +388,7 @@
}
}
helm: {
- mongodb: {
+ "mongodb-\(name)": {
chart: charts.mongodb
if _cluster != _|_ {
cluster: _cluster
@@ -422,6 +453,12 @@
}
...
}
+ openPortMap: {
+ for k, v in mongodb {
+ "mongodb-\(k)": v.openPort
+ }
+ ...
+ }
images: {
for k, v in mongodb {
for x, y in v.images {
@@ -447,16 +484,38 @@
...
}
-#PostgreSQL: #WithOut & {
+#PostgreSQLInput: {
cluster?: #Cluster
- _cluster: cluster
name: string
version: "15.3"
initSQL: string | *""
size: string | *"1Gi"
+ expose: [...#Domain] | *[]
+ ...
+}
+#PostgreSQL: #WithOut & #PostgreSQLInput & {
+ cluster?: #Cluster
+ name: string
+ version: "15.3"
+ initSQL: string | *""
+ size: string | *"1Gi"
+ expose: [...#Domain] | *[]
+
+ _cluster: cluster
_size: size
_volumeClaimName: "\(name)-postgresql"
+ _name: name
+
+ openPort: [for i, e in expose {
+ network: networks[strings.ToLower(e.network)]
+ port: input["port_postgresql_\(_name)_\(i)"]
+ protocol: "TCP"
+ service: {
+ name: "postgres-\(_name)"
+ port: 5432
+ }
+ }]
images: {
postgres: {
@@ -474,7 +533,7 @@
path: "charts/postgresql"
}
}
- volumes: {
+ volume: {
"\(_volumeClaimName)": {
size: _size
if _cluster != _|_ {
@@ -670,13 +729,12 @@
images: {...}
charts: {...}
helm: {...}
- openPort: [...#PortForward]
+ openPort: [...#PortForward] | *[]
openPortMap: {
"_self": openPort
...
}
clusterProxy: {...}
- openPort: [...#PortForward] | *[]
images: {
for k, v in images {
"\(k)": #Image & v
@@ -765,10 +823,10 @@
}
...
}
- volumes: {...}
- volumes: {
- for k, v in volumes {
- "\(k)": #volume & v & {
+ volume: {...}
+ volume: {
+ for k, v in volume {
+ "\(k)": #Volume & v & {
name: k
if _cluster != _|_ {
cluster: _cluster
@@ -777,7 +835,7 @@
}
}
helm: {
- for k, v in volumes {
+ for k, v in volume {
"\(k)-volume": {
chart: charts.volume
info: "Creating disk for \(k)"
diff --git a/core/installer/app_configs/dodo_app.cue b/core/installer/app_configs/dodo_app.cue
index 13fd0d4..3770ff0 100644
--- a/core/installer/app_configs/dodo_app.cue
+++ b/core/installer/app_configs/dodo_app.cue
@@ -5,104 +5,79 @@
"strings"
)
+cluster?: string
+_cluster: cluster
+
input: {
- repoAddr: string
- repoPublicAddr: string
+ // VM uses this endpoint to load env variables from dodo-app server.
+ // app-runner registers itself as worker, which later is used by dodo-app server
+ // to ping runners on git push.
managerAddr: string
appId: string
- branch: string
sshPrivateKey: string
// TODO(gio): this should not be necessary as app.dev.username is autogenerated
username?: string
+ if _cluster != _|_ {
+ cluster: clusterMap[strings.ToLower(_cluster)]
+ }
+
+ for v in _postgresql {
+ for i, e in v.expose {
+ "port_postgresql_\(v.name)_\(i)": int @role(port)
+ }
+ }
+ for v in _mongodb {
+ for i, e in v.expose {
+ "port_mongodb_\(v.name)_\(i)": int @role(port)
+ }
+ }
+ for svc in service {
+ for i, e in svc.expose {
+ "port_service_\(svc.name)_\(i)": int @role(port)
+ }
+ }
+
+ if input.cluster != _|_ {
+ appVPNAuthKey: string @role(VPNAuthKey) @username(private-network-proxy)
+ }
+
+ for svc in service {
+ if svc.dev.enabled {
+ username: string | *svc.dev.username
+ vpnAuthKey: string @role(VPNAuthKey) @usernameField(username)
+ }
+ }
}
+_appIdSanitized: strings.Replace(input.appId, "/", "-", -1)
+
_devVM: {}
-#PSQL: {
- name: string
- size: string | *"1Gi"
- cluster?: string
- expose: [...string] | *[]
-}
+volume: [...#VolumeInput] | *[]
+postgresql: [...#PostgreSQLInput] | *[]
+mongodb: [...#MongoDBInput] | *[]
-postgresql: [...#PSQL] | *[]
+_volume: volume
_postgresql: postgresql
+_mongodb: mongodb
-input: {
- for psql in _postgresql {
- for i, e in psql.expose {
- "port_\(psql.name)_\(i)": int @role(port)
- }
+envVars: [
+ for v in _volume {
+ "DODO_VOLUME_\(strings.ToUpper(v.name))=/dodo/volume/\(v.name)"
}
-}
-
-out: {
- postgresql: {
- for psql in _postgresql {
- "\(psql.name)": #PostgreSQL & {
- name: psql.name
- size: psql.size
- if psql.cluster != _|_ {
- cluster: clusterMap[strings.ToLower(app.cluster)]
- }
- openPort: [for i, e in psql.expose {
- network: networks[strings.ToLower(e)]
- port: input["port_\(psql.name)_\(i)"]
- protocol: "TCP"
- service: {
- name: "postgres-\(psql.name)"
- port: 5432
- }
- }]
- }
- }
+ for p in _postgresql {
+ "DODO_POSTGRESQL_\(strings.ToUpper(p.name))_URL=postgresql://postgres:postgres@postgres-\(p.name).\(release.namespace).svc.cluster.local/postgres"
}
-}
-if app.dev.enabled {
- input: {
- username?: string | *app.dev.username
- vpnAuthKey: string @role(VPNAuthKey) @usernameField(username)
+ for m in _mongodb {
+ "DODO_MONGODB_\(strings.ToUpper(m.name))_URL=mongodb://mongo:mongo@mongodb-\(m.name).\(release.namespace).svc.cluster.local/mongo"
}
- _devVM: {
- username: app.dev.username
- domain: global.domain
- vpn: {
- enabled: true
- loginServer: "https://headscale.\(global.domain)"
- authKey: input.vpnAuthKey
- }
- codeServerEnabled: true
- cpuCores: 2
- memory: "3Gi"
- ports: app.ports
- cloudInit: {
- _loadEnvFile: "/home/\(username)/.dodo_env.sh"
- writeFiles: [{
- path: _loadEnvFile
- content: "source <(curl -fsSL \(input.managerAddr)/api/apps/\(input.appId)/branch/\(input.branch)/env-profile)"
- owner: "\(username):\(username)"
- permissions: "0700"
- },
- {
- path: "/home/\(username)/.bash_profile"
- content: "source \(_loadEnvFile)"
- owner: "\(username):\(username)"
- permissions: "0700"
- }]
- runCmd: list.Concat([[
- ["sh", "-c", "chown \(username):\(username) /home/\(username)/.cache"],
- ["sh", "-c", "GIT_SSH_COMMAND='ssh -i /home/\(username)/.ssh/id_ed25519 -o IdentitiesOnly=yes -o StrictHostKeyChecking=accept-new' git clone --branch \(input.branch) \(input.repoPublicAddr)/\(input.appId) /home/\(username)/code"],
- ["sh", "-c", "chown -R \(username):\(username) /home/\(username)/code"],
- ["sh", "-c", "chown -R \(username):\(username) /home/\(username)"],
- ], app.vm.cloudInit.runCmd])
- }
- }
-}
+]
#AppIngress: {
network: string
subdomain: string
auth: #Auth
+ port: { name: string } | { value: number } | *{ name: "web" }
_network: networks[strings.ToLower(network)]
baseURL: "https://\(subdomain).\(_network.domain)"
@@ -131,52 +106,46 @@
}
#AppTmpl: {
+ name: string | *"app"
type: string
- cluster?: string
- ingress: #AppIngress
- volumes: [...#volume]
- postgresql: [...#PostgreSQL]
- mongodb: [...#MongoDB]
+ ingress: #AppIngress // TODO(gio): make it a list
+ expose: [...#PortDomain] | *[]
rootDir: string
runConfiguration: [...#Command]
+ volume: [...string] | *[]
dev: #Dev | *{ enabled: false }
vm: #VMCustomization
// TODO(gio): check for duplicate values
apiPort: #PortValue | *3000
ports: [...#Port]
+ source: close({
+ repository: string
+ branch: string | *"master"
+ rootDir: string | *"/"
+ })
- lastCmdEnv: [
- for p in ports {
- "DODO_PORT_\(strings.ToUpper(p.name))=\(p.value)"
- }
- for v in volumes {
- "DODO_VOLUME_\(strings.ToUpper(v.name))=/dodo-volume/\(v.name)"
- }
- for p in postgresql {
- "DODO_POSTGRESQL_\(strings.ToUpper(p.name))_URL=postgresql://postgres:postgres@postgres-\(p.name).\(release.namespace).svc.cluster.local/postgres"
- }
- for m in mongodb {
- "DODO_MONGODB_\(strings.ToUpper(m.name))_URL=mongodb://mongo:mongo@mongodb-\(m.name).\(release.namespace).svc.cluster.local/mongo"
- }
- ]
+ lastCmdEnv: list.Concat([
+ envVars,
+ [
+ for p in ports {
+ "DODO_PORT_\(strings.ToUpper(p.name))=\(p.value)"
+ }
+ ]
+ ])
...
}
-envProfile: strings.Join(list.Concat([
- app.vm.env,
- [for e in app.lastCmdEnv { "export \(e)" }]
-]), "\n")
-
// Go app
-_goVer1220: "golang:1.22.0"
_goVer1200: "golang:1.20.0"
+_goVer1220: "golang:1.22.0"
+_goVer1240: "golang:1.24.0"
#GoAppTmpl: #AppTmpl & {
- type: _goVer1220 | _goVer1200
+ type: _goVer1200 | _goVer1220 | _goVer1240
run: string | *"main.go"
- ports: [{
+ ports: [...#Port] | *[{
name: "web"
value: 8080
}]
@@ -212,9 +181,33 @@
#GoApp1220: #GoAppTmpl & {
type: _goVer1220
+ vm: {
+ env: [
+ "export PATH=$PATH:/usr/local/go/bin"
+ ]
+ cloudInit: runCmd: [
+ ["sh", "-c", "wget https://go.dev/dl/go1.22.0.linux-amd64.tar.gz -O /tmp/go.tar.gz"],
+ ["sh", "-c", "rm -rf /usr/local/go && tar -C /usr/local -xzf /tmp/go.tar.gz"],
+ ["sh", "-c", "rm /tmp/go.tar.gz"],
+ ]
+ }
}
-#GoApp: #GoApp1200 | #GoApp1220
+#GoApp1240: #GoAppTmpl & {
+ type: _goVer1240
+ vm: {
+ env: [
+ "export PATH=$PATH:/usr/local/go/bin"
+ ]
+ cloudInit: runCmd: [
+ ["sh", "-c", "wget https://go.dev/dl/go1.24.0.linux-amd64.tar.gz -O /tmp/go.tar.gz"],
+ ["sh", "-c", "rm -rf /usr/local/go && tar -C /usr/local -xzf /tmp/go.tar.gz"],
+ ["sh", "-c", "rm /tmp/go.tar.gz"],
+ ]
+ }
+}
+
+#GoApp: #GoApp1200 | #GoApp1220 | #GoApp1240
// Hugo app
@@ -223,7 +216,7 @@
#HugoAppTmpl: #AppTmpl & {
type: _hugoLatest
ingress: #AppIngress
- ports: [{
+ ports: [...#Port] | *[{
name: "web"
value: 1313
}]
@@ -253,7 +246,7 @@
#PHPAppTmpl: #AppTmpl & {
type: "php:8.2-apache"
- ports: [{
+ ports: [...#Port] | *[{
name: "web"
value: 80
}]
@@ -274,7 +267,7 @@
#NextjsDeno2AppTmpl: #AppTmpl & {
type: "nextjs:deno-2.0.0"
apiPort: 2000
- ports: [{
+ ports: [...#Port] | *[{
name: "web"
value: 3000
}]
@@ -322,7 +315,7 @@
#NodeJSAppTmpl: #AppTmpl & {
buildPath: string | *"dist"
apiPort: 2000
- ports: [{
+ ports: [...#Port] | *[{
name: "web"
value: 3000
}]
@@ -371,177 +364,247 @@
#App: #GoApp | #HugoApp | #PHPApp | #NextjsApp | #NodeJSApp
-app: #App
-_app: app
+service: [...#App]
-if !_app.dev.enabled {
- {
- if _app.cluster != _|_ {
- input: {
- appVPNAuthKey: string @role(VPNAuthKey) @username(private-network-proxy)
- }
- }
- out: {
- ingress: {
- app: {
- label: "App"
- network: networks[strings.ToLower(_app.ingress.network)]
- subdomain: _app.ingress.subdomain
- auth: _app.ingress.auth
- service: {
- name: "app-app"
- port: name: "web"
- }
- }
- }
- images: {
- app: {
- repository: "giolekva"
- name: "app-runner"
- tag: strings.Replace(_app.type, ":", "-", -1)
- pullPolicy: "Always"
- }
- "tailscale-proxy": {
- repository: "tailscale"
- name: "tailscale"
- tag: "v1.42.0"
- pullPolicy: "IfNotPresent"
- }
- }
- charts: {
- "access-secrets": {
- kind: "GitRepository"
- address: "https://code.v1.dodo.cloud/helm-charts"
- branch: "main"
- path: "charts/access-secrets"
- }
- app: {
- kind: "GitRepository"
- address: "https://code.v1.dodo.cloud/helm-charts"
- branch: "main"
- path: "charts/app-runner"
- }
- }
- helm: {
- if _app.cluster != _|_ {
- {
- "access-secrets": {
- chart: charts["access-secrets"]
- values: {
- serviceAccountName: "default"
- }
- }
- }
- }
- app: {
- chart: charts.app
- values: {
- image: {
- repository: images.app.fullName
- tag: images.app.tag
- pullPolicy: images.app.pullPolicy
- }
- // TODO(gio): install gvisor runtime during new remote cluster init
- if _app.cluster == _|_ {
- runtimeClassName: "untrusted-external" // TODO(gio): make this part of the infra config
- }
- if _app.cluster != _|_ {
- extraContainers: [{
- name: "proxy"
- image: images["tailscale-proxy"].fullNameWithTag
- env: [{
- name: "TS_AUTHKEY"
- value: input.appVPNAuthKey
- }, {
- name: "TS_HOSTNAME"
- value: "dodo-app-\(input.appId)"
- }, {
- name: "TS_EXTRA_ARGS"
- value: "--login-server=https://headscale.\(global.domain)"
- }]
- }]
- }
- apiPort: _app.apiPort
- appPorts: [for p in _app.ports {
- name: p.name
- containerPort: p.value
- protocol: p.protocol
- }]
- appDir: _app.rootDir
- appId: input.appId
- repoAddr: "\(input.repoPublicAddr)/\(input.appId)"
- branch: input.branch
- sshPrivateKey: base64.Encode(null, input.sshPrivateKey)
- runCfg: base64.Encode(null, json.Marshal(_app.runConfiguration))
- managerAddr: input.managerAddr
- volumes: [
- for v in _app.volumes {
- name: v.name
- mountPath: "/dodo-volume/\(v.name)"
+outs: {
+ for svc in service {
+ "service_\(svc.name)": #WithOut & {
+ envProfile: strings.Join(list.Concat([
+ svc.vm.env,
+ [for e in svc.lastCmdEnv { "export \(e)" }]
+ ]), "\n")
+ if !svc.dev.enabled {
+ {
+ // TODO(gio): support vm open ports
+ openPort: list.Concat([
+ [for i, e in svc.expose if e.port.name != _|_ {
+ for p in svc.ports if e.port.name == p.name {
+ network: networks[strings.ToLower(e.network)]
+ port: input["port_service_app_\(i)"] // TODO(gio): app name
+ protocol: "TCP"
+ service: {
+ name: "app-app"
+ port: p.value
+ }
+ }
+ }],
+ [for i, e in svc.expose if e.port.value != _|_ {
+ for p in svc.ports if e.port.value == p.value {
+ network: networks[strings.ToLower(e.network)]
+ port: input["port_service_app_\(i)"] // TODO(gio): app name
+ protocol: "TCP"
+ service: {
+ name: "app-app"
+ port: p.value
+ }
+ }
+ }]
+ ])
+ ingress: {
+ "\(svc.name)": {
+ label: "App"
+ network: networks[strings.ToLower(svc.ingress.network)]
+ subdomain: svc.ingress.subdomain
+ auth: svc.ingress.auth
+ if input.cluster != _|_ {
+ cluster: input.cluster
+ }
+ service: {
+ name: "app-app"
+ if svc.ingress.port.name != _|_ {
+ port: name: svc.ingress.port.name
+ }
+ if svc.ingress.port.value != _|_ {
+ port: number: svc.ingress.port.value
+ }
+ }
}
- ]
+ }
+ images: {
+ app: {
+ repository: "giolekva"
+ name: "app-runner"
+ tag: strings.Replace(svc.type, ":", "-", -1)
+ pullPolicy: "Always"
+ }
+ "tailscale-proxy": {
+ repository: "tailscale"
+ name: "tailscale"
+ tag: "v1.42.0"
+ pullPolicy: "IfNotPresent"
+ }
+ }
+ charts: {
+ "access-secrets": {
+ kind: "GitRepository"
+ address: "https://code.v1.dodo.cloud/helm-charts"
+ branch: "main"
+ path: "charts/access-secrets"
+ }
+ app: {
+ kind: "GitRepository"
+ address: "https://code.v1.dodo.cloud/helm-charts"
+ branch: "main"
+ path: "charts/app-runner"
+ }
+ }
+ helm: {
+ if input.cluster != _|_ {
+ {
+ "access-secrets": {
+ chart: charts["access-secrets"]
+ values: {
+ serviceAccountName: "default"
+ }
+ }
+ }
+ }
+ "\(svc.name)": {
+ chart: charts.app
+ values: {
+ image: {
+ repository: images.app.fullName
+ tag: images.app.tag
+ pullPolicy: images.app.pullPolicy
+ }
+ // TODO(gio): install gvisor runtime during new remote cluster init
+ if input.cluster == _|_ {
+ runtimeClassName: "untrusted-external" // TODO(gio): make this part of the infra config
+ }
+ if input.cluster != _|_ {
+ extraContainers: [{
+ name: "proxy"
+ image: images["tailscale-proxy"].fullNameWithTag
+ env: [{
+ name: "TS_AUTHKEY"
+ value: input.appVPNAuthKey
+ }, {
+ name: "TS_HOSTNAME"
+ value: "dodo-app-\(_appIdSanitized)-\(svc.name)"
+ }, {
+ name: "TS_EXTRA_ARGS"
+ value: "--login-server=https://headscale.\(global.domain)"
+ }]
+ }]
+ }
+ name: svc.name
+ apiPort: svc.apiPort
+ appPorts: [for p in svc.ports {
+ name: p.name
+ containerPort: p.value
+ protocol: p.protocol
+ }]
+ appDir: svc.rootDir
+ appId: input.appId
+ repoAddr: svc.source.repository
+ branch: svc.source.branch
+ rootDir: svc.source.rootDir
+ if input.sshPrivateKey != "" {
+ sshPrivateKey: base64.Encode(null, input.sshPrivateKey)
+ }
+ runCfg: base64.Encode(null, json.Marshal(svc.runConfiguration))
+ managerAddr: input.managerAddr
+ volumes: [
+ for v in svc.volume {
+ name: v.name
+ mountPath: "/dodo/volume/\(v)"
+ }
+ ]
+ }
+ }
+ }
}
}
}
- }
- }
-}
-if _app.dev.enabled {
- {
- out: {
- ingress: {
- app: {
- label: "App"
- network: networks[strings.ToLower(_app.ingress.network)]
- subdomain: _app.ingress.subdomain
- auth: _app.ingress.auth
- service: {
- name: _vmName
- port: name: "web"
- }
- }
- code: {
- label: "VS Code"
- home: "/?folder=/home/\(_app.dev.username)/code"
- network: networks[strings.ToLower(_app.ingress.network)]
- subdomain: "code-\(_app.ingress.subdomain)"
- auth: enabled: false
- service: {
- name: _vmName
- port: name: _codeServerPortName
+ if svc.dev.enabled {
+ {
+ _vmName: "\(_appIdSanitized)-\(svc.name)-\(svc.source.branch)"
+ "\(svc.name)": #WithOut & {
+ ingress: {
+ "\(svc.name)": {
+ label: "App"
+ network: networks[strings.ToLower(svc.ingress.network)]
+ subdomain: svc.ingress.subdomain
+ auth: svc.ingress.auth
+ service: {
+ name: _vmName
+ port: name: "web"
+ }
+ }
+ code: {
+ label: "VS Code"
+ home: "/?folder=/home/\(svc.dev.username)/code"
+ network: networks[strings.ToLower(svc.ingress.network)]
+ subdomain: "code-\(svc.ingress.subdomain)"
+ auth: enabled: false
+ service: {
+ name: _vmName
+ port: name: _codeServerPortName
+ }
+ }
+ }
+ vm: {
+ "\(_vmName)": {
+ username: svc.dev.username
+ domain: global.domain
+ vpn: {
+ enabled: true
+ loginServer: "https://headscale.\(global.domain)"
+ authKey: input.vpnAuthKey
+ }
+ codeServerEnabled: true
+ cpuCores: 2
+ memory: "3Gi"
+ ports: svc.ports
+ cloudInit: {
+ _loadEnvFile: "/home/\(username)/.dodo_env.sh"
+ writeFiles: [{
+ path: _loadEnvFile
+ content: "source <(curl -fsSL \(input.managerAddr)/api/apps/\(input.appId)/branch/\(svc.source.branch)/env-profile)"
+ owner: "\(username):\(username)"
+ permissions: "0700"
+ },
+ {
+ path: "/home/\(username)/.bash_profile"
+ content: "source \(_loadEnvFile)"
+ owner: "\(username):\(username)"
+ permissions: "0700"
+ }]
+ runCmd: list.Concat([[
+ ["sh", "-c", "chown \(username):\(username) /home/\(username)/.cache"],
+ ["sh", "-c", "GIT_SSH_COMMAND='ssh -i /home/\(username)/.ssh/id_ed25519 -o IdentitiesOnly=yes -o StrictHostKeyChecking=accept-new' git clone --branch \(svc.source.branch) \(svc.source.repository) /home/\(username)/code"],
+ ["sh", "-c", "chown -R \(username):\(username) /home/\(username)/code"],
+ ["sh", "-c", "chown -R \(username):\(username) /home/\(username)"],
+ ], svc.vm.cloudInit.runCmd])
+ }
+ }
+ }
}
}
}
- }
}
}
-_vmName: "\(input.appId)-\(input.branch)"
-
out: {
- if app.cluster != _|_ {
- cluster: clusterMap[strings.ToLower(app.cluster)]
+ if input.cluster != _|_ {
+ cluster: input.cluster
}
- volumes: {
- for v in app.volumes {
+ volume: {
+ for v in _volume {
"\(v.name)": v
}
}
- // TODO(gio): remove
postgresql: {
- for v in app.postgresql {
+ for v in _postgresql {
"\(v.name)": v
}
}
mongodb: {
- for v in app.mongodb {
+ for v in _mongodb {
"\(v.name)": v
}
}
- vm: {
- "\(_vmName)": _devVM
- }
}
_appDir: "/dodo-app"
diff --git a/core/installer/app_test.go b/core/installer/app_test.go
index a59571d..f0fe537 100644
--- a/core/installer/app_test.go
+++ b/core/installer/app_test.go
@@ -401,7 +401,8 @@
}
var dodoAppRemoteClusterCue = `
-app: {
+service: [{
+ name: "app"
type: "golang:1.22.0"
run: "main.go"
ingress: {
@@ -413,7 +414,8 @@
enabled: false
}
cluster: "io"
-}`
+ source: repository: "ssh://foo.bar"
+}]`
func TestDodoAppRemoteCluster(t *testing.T) {
app, err := NewDodoApp([]byte(dodoAppRemoteClusterCue))
@@ -432,12 +434,9 @@
}
keyGen := testKeyGen{}
r, err := app.Render(release, env, networks, clusters, map[string]any{
- "repoAddr": "1",
- "repoPublicAddr": "2",
- "managerAddr": "3",
- "appId": "4",
- "branch": "5",
- "sshPrivateKey": "6",
+ "managerAddr": "3",
+ "appId": "4",
+ "sshPrivateKey": "6",
}, nil, keyGen)
if err != nil {
for _, e := range errors.Errors(err) {
@@ -453,7 +452,8 @@
}
var dodoAppDevDisabledCue = `
-app: {
+service: [{
+ name: "app"
type: "golang:1.22.0"
run: "main.go"
ingress: {
@@ -464,10 +464,12 @@
dev: {
enabled: false
}
-}`
+ source: repository: "ssh://foo.bar"
+}]`
var dodoAppDevEnabledCue = `
-app: {
+service: [{
+ name: "app"
type: "golang:1.20.0"
run: "main.go"
ingress: {
@@ -475,19 +477,24 @@
subdomain: "testapp"
auth: enabled: false
}
+ volume: ["data"]
dev: {
enabled: true
username: "gio"
}
- volumes: [{
- name: "data"
- size: "5Gi"
- }]
- mongodb: [{
- name: "db"
- size: "10Gi"
- }]
-}`
+ source: repository: "ssh://foo.bar"
+}]
+
+volume: [{
+ name: "data"
+ size: "5Gi"
+}]
+
+mongodb: [{
+ name: "db"
+ size: "10Gi"
+}]
+`
func TestDodoAppDevDisabled(t *testing.T) {
app, err := NewDodoApp([]byte(dodoAppDevDisabledCue))
@@ -506,12 +513,9 @@
}
keyGen := testKeyGen{}
r, err := app.Render(release, env, networks, nil, map[string]any{
- "repoAddr": "",
- "repoPublicAddr": "",
- "managerAddr": "",
- "appId": "",
- "branch": "",
- "sshPrivateKey": "",
+ "managerAddr": "",
+ "appId": "",
+ "sshPrivateKey": "",
}, nil, keyGen)
if err != nil {
for _, e := range errors.Errors(err) {
@@ -543,13 +547,10 @@
}
keyGen := testKeyGen{}
r, err := app.Render(release, env, networks, nil, map[string]any{
- "repoAddr": "",
- "repoPublicAddr": "",
- "managerAddr": "",
- "appId": "",
- "branch": "",
- "sshPrivateKey": "",
- "username": "",
+ "managerAddr": "",
+ "appId": "",
+ "sshPrivateKey": "",
+ "username": "",
}, nil, keyGen)
if err != nil {
for _, e := range errors.Errors(err) {
@@ -574,7 +575,6 @@
}
values := map[string]any{
"repoAddr": "",
- "repoPublicAddr": "",
"repoHost": "",
"branch": "",
"gitRepoPublicKey": "",
diff --git a/core/installer/canvas-app.cue b/core/installer/canvas-app.cue
new file mode 100644
index 0000000..a8be305
--- /dev/null
+++ b/core/installer/canvas-app.cue
@@ -0,0 +1,37 @@
+POST http://localhost:8080/api/dodo-app
+Content-Type: application/json
+
+{
+ "id": "canvas",
+ "sshPrivateKey": "",
+ "config": {
+ "service": [{
+ "name": "app",
+ "type": "golang:1.24.0",
+ "source": {
+ "repository": "https://code.v1.dodo.cloud/pcloud",
+ "branch": "test-canvas",
+ "rootDir": "apps/canvas/server"
+ },
+ "ingress": {
+ "network": "private",
+ "subdomain": "canvas",
+ "auth": {
+ "enabled": false
+ }
+ },
+ "dev": {
+ "enabled": false
+ }
+ }],
+ "mongodb": [{
+ "name": "pgg",
+ "size": "2Gi",
+ "expose": [{
+ "network": "private",
+ "subdomain": "mongoo"
+ }]
+ }],
+ "cluster": "ct"
+ }
+}
diff --git a/core/installer/dodo_app_test.go b/core/installer/dodo_app_test.go
index e9d7737..5b0f3b1 100644
--- a/core/installer/dodo_app_test.go
+++ b/core/installer/dodo_app_test.go
@@ -6,8 +6,9 @@
"cuelang.org/go/cue/errors"
)
-var exposedPostgreSQL = `
-app: {
+var exposed = `
+service: [{
+ name: "app"
type: "golang:1.20.0"
run: "main.go"
ingress: {
@@ -15,25 +16,93 @@
subdomain: "testapp"
auth: enabled: false
}
-}
+ source: repository: "ssh://foo.bar"
+ ports: [{
+ name: "a"
+ value: 100
+ }, {
+ name: "web"
+ value: 8080
+ }, {
+ name: "b"
+ value: 101
+ }]
+ expose: [{
+ network: "private"
+ subdomain: "1"
+ port: value: 100
+ }, {
+ network: "public"
+ subdomain:"2"
+ port: name: "web"
+ }, {
+ network: "private"
+ subdomain: "3"
+ port: value: 101
+ }]
+}]
postgresql: [{
name: "db_1"
- expose: ["private", "public", "private"]
+ expose: [{
+ network: "private"
+ subdomain: "1"
+ }, {
+ network: "public"
+ subdomain:"2"
+ }, {
+ network: "private"
+ subdomain: "3"
+ }]
}, {
name: "db_2"
- expose: ["public", "private", "public"]
-}]`
+ expose: [{
+ network: "public"
+ subdomain: "1"
+ }, {
+ network: "private"
+ subdomain:"2"
+ }, {
+ network: "public"
+ subdomain: "3"
+ }]
+}]
-func TestExposedPostgreSQL(t *testing.T) {
- app, err := NewDodoApp([]byte(exposedPostgreSQL))
+mongodb: [{
+ name: "mdb_1"
+ expose: [{
+ network: "public"
+ subdomain: "1"
+ }, {
+ network: "private"
+ subdomain:"2"
+ }, {
+ network: "public"
+ subdomain: "3"
+ }]
+}, {
+ name: "mdb_2"
+ expose: [{
+ network: "private"
+ subdomain: "1"
+ }, {
+ network: "public"
+ subdomain:"2"
+ }, {
+ network: "private"
+ subdomain: "3"
+ }]
+}]
+`
+
+func TestExposedPorts(t *testing.T) {
+ app, err := NewDodoApp([]byte(exposed))
if err != nil {
for _, e := range errors.Errors(err) {
t.Log(e)
}
t.Fatal(err)
}
-
release := Release{
Namespace: "foo",
AppInstanceId: "foo-bar",
@@ -42,28 +111,102 @@
}
keyGen := testKeyGen{}
r, err := app.Render(release, env, networks, nil, map[string]any{
- "repoAddr": "",
- "repoPublicAddr": "",
- "managerAddr": "",
- "appId": "",
- "branch": "",
- "sshPrivateKey": "",
- "port_db_1_0": 1,
- "port_db_1_1": 2,
- "port_db_1_2": 3,
- "port_db_2_0": 4,
- "port_db_2_1": 5,
- "port_db_2_2": 6,
+ "managerAddr": "",
+ "appId": "",
+ "sshPrivateKey": "",
+ "port_postgresql_db_1_0": 1,
+ "port_postgresql_db_1_1": 2,
+ "port_postgresql_db_1_2": 3,
+ "port_postgresql_db_2_0": 4,
+ "port_postgresql_db_2_1": 5,
+ "port_postgresql_db_2_2": 6,
+ "port_mongodb_mdb_1_0": 1,
+ "port_mongodb_mdb_1_1": 2,
+ "port_mongodb_mdb_1_2": 3,
+ "port_mongodb_mdb_2_0": 4,
+ "port_mongodb_mdb_2_1": 5,
+ "port_mongodb_mdb_2_2": 6,
+ "port_service_app_0": 7,
+ "port_service_app_1": 8,
+ "port_service_app_2": 9,
}, nil, keyGen)
if err != nil {
+ t.Fatal(err)
+ }
+ t.Log(string(r.Raw))
+}
+
+const canvas = `
+{
+ "service": [
+ {
+ "type": "nextjs:deno-2.0.0",
+ "name": "app",
+ "source": {
+ "repository": "ssh://d.p.v1.dodo.cloud:62533/myblog",
+ "branch": "master",
+ "rootDir": "/"
+ },
+ "ports": [
+ {
+ "name": "web",
+ "value": 3000,
+ "protocol": "TCP"
+ }
+ ],
+ "env": [
+ {
+ "name": "DODO_POSTGRESQL_DB_CONNECTION_URL"
+ }
+ ],
+ "ingress": {
+ "network": "Private",
+ "subdomain": "foo",
+ "port": {
+ "name": "web"
+ },
+ "auth": {
+ "enabled": false
+ }
+ },
+ "expose": [],
+ "dev": { "enabled": true, "username": "gio" }
+ }
+ ],
+ "volume": [],
+ "postgresql": [
+ {
+ "name": "db",
+ "size": "1Gi",
+ "expose": []
+ }
+ ],
+ "mongodb": []
+}
+`
+
+func TestCanvas(t *testing.T) {
+ app, err := NewDodoApp([]byte(canvas))
+ if err != nil {
for _, e := range errors.Errors(err) {
- for _, f := range errors.Errors(e) {
- for _, g := range errors.Errors(f) {
- t.Log(g)
- }
- }
+ t.Log(e)
}
t.Fatal(err)
}
+ release := Release{
+ Namespace: "foo",
+ AppInstanceId: "foo-bar",
+ RepoAddr: "ssh://192.168.100.210:22/config",
+ AppDir: "/foo/bar",
+ }
+ keyGen := testKeyGen{}
+ r, err := app.Render(release, env, networks, nil, map[string]any{
+ "managerAddr": "",
+ "appId": "",
+ "sshPrivateKey": "",
+ }, nil, keyGen)
+ if err != nil {
+ t.Fatal(err)
+ }
t.Log(string(r.Raw))
}
diff --git a/core/installer/reconcile.sh b/core/installer/reconcile.sh
new file mode 100755
index 0000000..f8b3295
--- /dev/null
+++ b/core/installer/reconcile.sh
@@ -0,0 +1,5 @@
+while true
+do
+ flux reconcile source git -n hgrz hgrz
+ flux reconcile kustomization -n hgrz hgrz
+done
diff --git a/core/installer/schema.go b/core/installer/schema.go
index 7f8410f..fb5d305 100644
--- a/core/installer/schema.go
+++ b/core/installer/schema.go
@@ -369,6 +369,56 @@
}
}
+func ExtractDefaultValues(v cue.Value) (any, error) {
+ switch v.IncompleteKind() {
+ case cue.StringKind:
+ if d, ok := v.Default(); ok {
+ return d.String()
+ }
+ case cue.BoolKind:
+ if d, ok := v.Default(); ok {
+ return d.Bool()
+ }
+ case cue.NumberKind:
+ // TODO(gio): handle numbers
+ return nil, fmt.Errorf("implement: %s", v)
+ case cue.IntKind:
+ if d, ok := v.Default(); ok {
+ return d.Int64()
+ }
+ case cue.ListKind:
+ // TODO(gio): handle lists
+ return nil, nil
+ case cue.StructKind:
+ // TODO(gio): Such fields might have default values as well?
+ if isNetwork(v) {
+ return nil, nil
+ } else if isAuth(v) {
+ return nil, nil
+ } else if isSSHKey(v) {
+ return nil, nil
+ } else if isCluster(v) {
+ return nil, nil
+ }
+ ret := map[string]any{}
+ f, err := v.Fields(cue.All())
+ if err != nil {
+ return nil, err
+ }
+ for f.Next() {
+ fv, err := ExtractDefaultValues(f.Value())
+ if err != nil {
+ return nil, err
+ }
+ ret[f.Selector().String()] = fv
+ }
+ return ret, nil
+ default:
+ return nil, fmt.Errorf("SHOULD NOT REACH! value: %s", v)
+ }
+ return nil, nil
+}
+
func cleanFieldName(name string) string {
return strings.ReplaceAll(strings.ReplaceAll(name, "?", ""), "!", "")
}
diff --git a/core/installer/schema_test.go b/core/installer/schema_test.go
index 32baa40..0dee8e8 100644
--- a/core/installer/schema_test.go
+++ b/core/installer/schema_test.go
@@ -101,3 +101,21 @@
t.Fatal("not really network")
}
}
+
+const inputIsCluster = `
+input: {
+ name: string
+ kubeconfig: string
+ ingressClassName: string
+}
+`
+
+func TestIsCluster(t *testing.T) {
+ v, err := ParseCueAppConfig(CueAppData{"/test.cue": []byte(inputIsCluster)})
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !isCluster(v.LookupPath(cue.ParsePath("input"))) {
+ t.Fatal("is cluster")
+ }
+}
diff --git a/core/installer/server/appmanager/server.go b/core/installer/server/appmanager/server.go
index 5e1e06b..b3a0883 100644
--- a/core/installer/server/appmanager/server.go
+++ b/core/installer/server/appmanager/server.go
@@ -1,6 +1,7 @@
package appmanager
import (
+ "bytes"
"context"
"embed"
"encoding/json"
@@ -9,6 +10,7 @@
"html/template"
"net"
"net/http"
+ "path/filepath"
"strconv"
"strings"
"sync"
@@ -138,6 +140,7 @@
r.HandleFunc("/api/instance/{slug}", s.handleInstance).Methods(http.MethodGet)
r.HandleFunc("/api/instance/{slug}/update", s.handleAppUpdate).Methods(http.MethodPost)
r.HandleFunc("/api/instance/{slug}/remove", s.handleAppRemove).Methods(http.MethodPost)
+ r.HandleFunc("/api/dodo-app", s.handleDodoAppInstall).Methods(http.MethodPost)
r.HandleFunc("/clusters/{cluster}/servers/{server}/remove", s.handleClusterRemoveServer).Methods(http.MethodPost)
r.HandleFunc("/clusters/{cluster}/servers", s.handleClusterAddServer).Methods(http.MethodPost)
r.HandleFunc("/clusters/{name}", s.handleCluster).Methods(http.MethodGet)
@@ -154,6 +157,47 @@
return http.ListenAndServe(fmt.Sprintf(":%d", s.port), r)
}
+type dodoAppInstallReq struct {
+ Id string `json:"id"`
+ SSHPrivateKey string `json:"sshPrivateKey"`
+ Config map[string]any `json:"config"`
+}
+
+func (s *Server) handleDodoAppInstall(w http.ResponseWriter, r *http.Request) {
+ var req dodoAppInstallReq
+ // TODO(gio): validate that no internal fields are overridden by request
+ if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ return
+ }
+ clusters, err := s.m.GetClusters()
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ req.Config["clusters"] = installer.ToAccessConfigs(clusters)
+ var cfg bytes.Buffer
+ if err := json.NewEncoder(&cfg).Encode(req.Config); err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ app, err := installer.NewDodoApp(cfg.Bytes())
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusBadRequest)
+ return
+ }
+ appDir := filepath.Join("/dodo-app", req.Id)
+ namespace := "dodo-app-test" // TODO(gio)
+ if _, err := s.m.Install(app, req.Id, appDir, namespace, map[string]any{
+ "managerAddr": "", // TODO(gio)
+ "appId": req.Id,
+ "sshPrivateKey": req.SSHPrivateKey,
+ }); err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+}
+
func (s *Server) handleNetworks(w http.ResponseWriter, r *http.Request) {
env, err := s.m.Config()
if err != nil {
diff --git a/core/installer/server/dodo-app/schemas/app.schema.json b/core/installer/server/dodo-app/schemas/app.schema.json
index 55b9941..f6f2171 100644
--- a/core/installer/server/dodo-app/schemas/app.schema.json
+++ b/core/installer/server/dodo-app/schemas/app.schema.json
@@ -22,7 +22,16 @@
"$ref": "#/definitions/nodejs"
}
]
- }
+ },
+ "volume": {
+ "$ref": "#/definitions/volumes"
+ },
+ "postgresql": {
+ "$ref": "#/definitions/postgresql"
+ },
+ "mongodb": {
+ "$ref": "#/definitions/mongodb"
+ }
},
"definitions": {
"golang": {
@@ -45,15 +54,6 @@
"ingress": {
"$ref": "#/definitions/ingress"
},
- "volumes": {
- "$ref": "#/definitions/volumes"
- },
- "postgresql": {
- "$ref": "#/definitions/postgresql"
- },
- "mongodb": {
- "$ref": "#/definitions/mongodb"
- },
"dev": {
"$ref": "#/definitions/dev"
}
@@ -100,15 +100,6 @@
"ingress": {
"$ref": "#/definitions/ingress"
},
- "volumes": {
- "$ref": "#/definitions/volumes"
- },
- "postgresql": {
- "$ref": "#/definitions/postgresql"
- },
- "mongodb": {
- "$ref": "#/definitions/mongodb"
- },
"dev": {
"$ref": "#/definitions/dev"
}
@@ -132,15 +123,6 @@
"ingress": {
"$ref": "#/definitions/ingress"
},
- "volumes": {
- "$ref": "#/definitions/volumes"
- },
- "postgresql": {
- "$ref": "#/definitions/postgresql"
- },
- "mongodb": {
- "$ref": "#/definitions/mongodb"
- },
"dev": {
"$ref": "#/definitions/dev"
},
@@ -167,15 +149,6 @@
"ingress": {
"$ref": "#/definitions/ingress"
},
- "volumes": {
- "$ref": "#/definitions/volumes"
- },
- "postgresql": {
- "$ref": "#/definitions/postgresql"
- },
- "mongodb": {
- "$ref": "#/definitions/mongodb"
- },
"dev": {
"$ref": "#/definitions/dev"
},
diff --git a/core/installer/server/dodo-app/server.go b/core/installer/server/dodo-app/server.go
index 7643168..2bbbb7c 100644
--- a/core/installer/server/dodo-app/server.go
+++ b/core/installer/server/dodo-app/server.go
@@ -1439,7 +1439,6 @@
"/.dodo/app",
namespace,
map[string]any{
- "repoAddr": repo.FullAddress(),
"repoPublicAddr": s.repoPublicAddr,
"managerAddr": fmt.Sprintf("http://%s", s.self),
"appId": name,
diff --git a/core/installer/values-tmpl/config-repo.cue b/core/installer/values-tmpl/config-repo.cue
index 4fdb20a..384ee3f 100644
--- a/core/installer/values-tmpl/config-repo.cue
+++ b/core/installer/values-tmpl/config-repo.cue
@@ -26,7 +26,7 @@
}
}
- volumes: data: size: "1Gi"
+ volume: data: size: "1Gi"
helm: {
softserve: {
@@ -43,7 +43,7 @@
tag: images.softserve.tag
pullPolicy: images.softserve.pullPolicy
}
- persistentVolumeClaimName: volumes.data.name
+ persistentVolumeClaimName: volume.data.name
}
}
}
diff --git a/core/installer/values-tmpl/dodo-app.cue b/core/installer/values-tmpl/dodo-app.cue
index 349f0d6..5ad606e 100644
--- a/core/installer/values-tmpl/dodo-app.cue
+++ b/core/installer/values-tmpl/dodo-app.cue
@@ -83,7 +83,7 @@
}
}
- volumes: {
+ volume: {
"config-repo": size: "10Gi"
db: size: "10Gi"
}
@@ -137,7 +137,7 @@
tag: images.softserve.tag
pullPolicy: images.softserve.pullPolicy
}
- persistentVolumeClaimName: volumes["config-repo"].name
+ persistentVolumeClaimName: volume["config-repo"].name
}
}
"dodo-app": {
@@ -161,7 +161,7 @@
envAppManagerAddr: "http://appmanager.\(global.namespacePrefix)appmanager.svc.cluster.local"
envConfig: base64.Encode(null, json.Marshal(global))
gitRepoPublicKey: input.ssKeys.public
- persistentVolumeClaimName: volumes.db.name
+ persistentVolumeClaimName: volume.db.name
allowedNetworks: strings.Join([for n in input.allowedNetworks { n.name }], ",")
external: input.external
fetchUsersAddr: "http://memberships-api.\(global.namespacePrefix)core-auth-memberships.svc.cluster.local/api/users"
diff --git a/core/installer/values-tmpl/env-dns.cue b/core/installer/values-tmpl/env-dns.cue
index 2b73ada..f5b8ac2 100644
--- a/core/installer/values-tmpl/env-dns.cue
+++ b/core/installer/values-tmpl/env-dns.cue
@@ -53,10 +53,11 @@
}
}
- volumes: data: {
+ volume: data: {
accessMode: "ReadWriteMany"
size: "5Gi"
}
+ _volume: volume
helm: {
coredns: {
@@ -116,11 +117,11 @@
}]
extraConfig: import: parameters: "\(_mountPath)/coredns.conf"
extraVolumes: [{
- name: volumes.data.name
- persistentVolumeClaim: claimName: volumes.data.name
+ name: volume.data.name
+ persistentVolumeClaim: claimName: volume.data.name
}]
extraVolumeMounts: [{
- name: volumes.data.name
+ name: volume.data.name
mountPath: _mountPath
}]
livenessProbe: {
@@ -161,7 +162,7 @@
nameserverIP: strings.Join(global.nameserverIP, ",")
service: type: "ClusterIP"
volume: {
- claimName: volumes.data.name
+ claimName: _volume.data.name
mountPath: _mountPath
}
}
diff --git a/core/installer/values-tmpl/etherpad.cue b/core/installer/values-tmpl/etherpad.cue
index 980c5eb..a70b7cd 100644
--- a/core/installer/values-tmpl/etherpad.cue
+++ b/core/installer/values-tmpl/etherpad.cue
@@ -46,7 +46,7 @@
}
}
- volumes: data: size: "1Gi"
+ volume: data: size: "1Gi"
postgresql: db: {
name: "db"
@@ -64,7 +64,7 @@
pullPolicy: images.etherpad.pullPolicy
}
portName: _httpPortName
- persistentVolumeClaimName: volumes.data.name
+ persistentVolumeClaimName: volume.data.name
db: {
type: "postgres"
host: "postgres-db.\(release.namespace).svc.cluster.local"
diff --git a/core/installer/values-tmpl/gerrit.cue b/core/installer/values-tmpl/gerrit.cue
index 2c57ed5..c783817 100644
--- a/core/installer/values-tmpl/gerrit.cue
+++ b/core/installer/values-tmpl/gerrit.cue
@@ -104,7 +104,7 @@
}
}
- volumes: {
+ volume: {
git: {
accessMode: "ReadWriteMany"
size: "50Gi"
@@ -246,14 +246,14 @@
gitRepositoryStorage: {
externalPVC: {
use: true
- name: volumes.git.name
+ name: volume.git.name
}
}
logStorage: {
enabled: true
externalPVC: {
use: true
- name: volumes.logs.name
+ name: volume.logs.name
}
}
ingress: enabled: false
diff --git a/core/installer/values-tmpl/jenkins.cue b/core/installer/values-tmpl/jenkins.cue
index 3169853..5d4110e 100644
--- a/core/installer/values-tmpl/jenkins.cue
+++ b/core/installer/values-tmpl/jenkins.cue
@@ -69,7 +69,7 @@
}
}
- volumes: jenkins: size: "10Gi"
+ volume: jenkins: size: "10Gi"
helm: {
"oauth2-client": {
@@ -140,7 +140,7 @@
}
persistence: {
enabled: true
- existingClaim: volumes.jenkins.name
+ existingClaim: volume.jenkins.name
}
}
}
diff --git a/core/installer/values-tmpl/memberships.cue b/core/installer/values-tmpl/memberships.cue
index 95a2b60..521c4d1 100644
--- a/core/installer/values-tmpl/memberships.cue
+++ b/core/installer/values-tmpl/memberships.cue
@@ -49,7 +49,7 @@
}
}
- volumes: data: size: "1Gi"
+ volume: data: size: "1Gi"
helm: {
memberships: {
@@ -61,7 +61,7 @@
pullPolicy: images.memberships.pullPolicy
}
portName: _httpPortName
- volumeClaimName: volumes.data.name
+ volumeClaimName: volume.data.name
}
}
}
diff --git a/core/installer/values-tmpl/open-project.cue b/core/installer/values-tmpl/open-project.cue
index 6598094..10234b4 100644
--- a/core/installer/values-tmpl/open-project.cue
+++ b/core/installer/values-tmpl/open-project.cue
@@ -63,7 +63,7 @@
}
}
- volumes: {
+ volume: {
openProject: {
name: "open-project"
accessMode: "ReadWriteMany"
@@ -99,7 +99,7 @@
}
persistence: {
enabled: true
- existingClaim: volumes.openProject.name
+ existingClaim: volume.openProject.name
}
postgresql: {
bundled: false
@@ -129,7 +129,7 @@
}
"open-project-volume": {
chart: charts.volume
- values: volumes.openProject
+ values: volume.openProject
}
postgres: {
chart: charts.postgres
diff --git a/core/installer/values-tmpl/pihole.cue b/core/installer/values-tmpl/pihole.cue
index 01a3ca1..6607409 100644
--- a/core/installer/values-tmpl/pihole.cue
+++ b/core/installer/values-tmpl/pihole.cue
@@ -65,7 +65,7 @@
}
}
- volumes: data: size: input.storageSize
+ volume: data: size: input.storageSize
helm: {
pihole: {
@@ -75,7 +75,7 @@
fullnameOverride: "pihole"
persistentVolumeClaim: {
enabled: true
- existingClaim: volumes.data.name
+ existingClaim: volume.data.name
}
admin: {
enabled: false
diff --git a/core/installer/values-tmpl/soft-serve.cue b/core/installer/values-tmpl/soft-serve.cue
index dae0515..23e07bb 100644
--- a/core/installer/values-tmpl/soft-serve.cue
+++ b/core/installer/values-tmpl/soft-serve.cue
@@ -77,7 +77,7 @@
}
}]
- volumes: data: size: "1Gi"
+ volume: data: size: "1Gi"
helm: {
softserve: {
@@ -88,7 +88,7 @@
adminKey: input.adminKey
host: _domain
sshPublicPort: input.sshPort
- persistentVolumeClaimName: volumes.data.name
+ persistentVolumeClaimName: volume.data.name
image: {
repository: images.softserve.fullName
tag: images.softserve.tag
diff --git a/core/installer/values-tmpl/url-shortener.cue b/core/installer/values-tmpl/url-shortener.cue
index 1fa70c4..9f401fb 100644
--- a/core/installer/values-tmpl/url-shortener.cue
+++ b/core/installer/values-tmpl/url-shortener.cue
@@ -69,7 +69,7 @@
}
}
- volumes: data: size: input.storageSize
+ volume: data: size: input.storageSize
helm: {
"url-shortener": {
@@ -82,7 +82,7 @@
pullPolicy: images.urlShortener.pullPolicy
}
portName: _httpPortName
- persistentVolumeClaimNama: volumes.data.name
+ persistentVolumeClaimNama: volume.data.name
requireAuth: input.auth.enabled
}
}
diff --git a/core/installer/values-tmpl/vaultwarden.cue b/core/installer/values-tmpl/vaultwarden.cue
index 69ac75f..7b68190 100644
--- a/core/installer/values-tmpl/vaultwarden.cue
+++ b/core/installer/values-tmpl/vaultwarden.cue
@@ -62,7 +62,7 @@
}
}
- volumes: data: size: input.storageSize
+ volume: data: size: input.storageSize
helm: {
vaultwarden: {
@@ -75,7 +75,7 @@
pullPolicy: images.vaultwarden.pullPolicy
}
domain: _domain
- persistentVolumeClaimName: volumes.data.name
+ persistentVolumeClaimName: volume.data.name
httpPortName: _httpPortName
}
}
diff --git a/core/installer/values-tmpl/zot.cue b/core/installer/values-tmpl/zot.cue
index c5cf631..4f98388 100644
--- a/core/installer/values-tmpl/zot.cue
+++ b/core/installer/values-tmpl/zot.cue
@@ -84,7 +84,7 @@
}
}
- volumes: zot: size: "100Gi"
+ volume: zot: size: "100Gi"
_httpPort: 80
_oauth2ClientSecretName: "oauth2-client"
@@ -176,7 +176,7 @@
persistence: true
pvc: {
create: false
- name: volumes.zot.name
+ name: volume.zot.name
}
extraVolumes: [{
name: "config"