DodoApp: Status page
Implements basic status page, listing all apps and their commit
statuses. Separates web and api endpoints. Unifies API addresses a bit.
Change-Id: I98f9f949a49b60e80e188f7b51ec0e967666e65b
diff --git a/apps/app-runner/main.go b/apps/app-runner/main.go
index dce8ffe..21be651 100644
--- a/apps/app-runner/main.go
+++ b/apps/app-runner/main.go
@@ -21,7 +21,7 @@
var sshKey = flag.String("ssh-key", "", "Private SSH key to access Git repository")
var appDir = flag.String("app-dir", "", "Path to store application repository locally")
var runCfg = flag.String("run-cfg", "", "Run configuration")
-var manager = flag.String("manager", "", "Address of the manager")
+var managerAddr = flag.String("manager-addr", "", "Address of the manager")
type Command struct {
Bin string `json:"bin"`
@@ -98,6 +98,6 @@
if err := json.NewDecoder(r).Decode(&cmds); err != nil {
panic(err)
}
- s := NewServer(*port, *appId, *repoAddr, signer, *appDir, cmds, self, *manager)
+ s := NewServer(*port, *appId, *repoAddr, signer, *appDir, cmds, self, *managerAddr)
s.Start()
}
diff --git a/apps/app-runner/server.go b/apps/app-runner/server.go
index 7985ac6..f3ee563 100644
--- a/apps/app-runner/server.go
+++ b/apps/app-runner/server.go
@@ -24,7 +24,7 @@
appDir string
runCommands []Command
self string
- manager string
+ managerAddr string
}
func NewServer(port int, appId string, repoAddr string, signer ssh.Signer, appDir string, runCommands []Command, self string, manager string) *Server {
@@ -38,7 +38,7 @@
appDir: appDir,
runCommands: runCommands,
self: self,
- manager: manager,
+ managerAddr: manager,
}
}
@@ -120,7 +120,6 @@
}
type pingReq struct {
- AppId string `json:"appId"`
Address string `json:"address"`
}
@@ -131,9 +130,12 @@
s.pingManager()
}()
}()
- buf, err := json.Marshal(pingReq{s.appId, s.self})
+ buf, err := json.Marshal(pingReq{
+ Address: fmt.Sprintf("%s:%d", s.self, s.port),
+ })
if err != nil {
return
}
- http.Post(s.manager, "application/json", bytes.NewReader(buf))
+ registerWorkerAddr := fmt.Sprintf("%s/api/apps/%s/workers", s.managerAddr, s.appId)
+ http.Post(registerWorkerAddr, "application/json", bytes.NewReader(buf))
}
diff --git a/charts/app-runner/templates/install.yaml b/charts/app-runner/templates/install.yaml
index 1c33df9..d05287d 100644
--- a/charts/app-runner/templates/install.yaml
+++ b/charts/app-runner/templates/install.yaml
@@ -97,7 +97,7 @@
- --repo-addr={{ .Values.repoAddr }}
- --ssh-key=/pcloud/ssh-key/private
- --run-cfg=/pcloud/config/run
- - --manager={{ .Values.manager }}
+ - --manager-addr={{ .Values.managerAddr }}
volumeMounts:
- name: ssh-key
readOnly: true
diff --git a/charts/app-runner/values.yaml b/charts/app-runner/values.yaml
index f0625e4..1d21e06 100644
--- a/charts/app-runner/values.yaml
+++ b/charts/app-runner/values.yaml
@@ -8,5 +8,5 @@
runCfg: ""
appDir: /dodo-app
appPort: 8080
-manager: ""
+managerAddr: ""
volumes: []
diff --git a/charts/dodo-app/templates/install.yaml b/charts/dodo-app/templates/install.yaml
index b8c1359..50ff7ab 100644
--- a/charts/dodo-app/templates/install.yaml
+++ b/charts/dodo-app/templates/install.yaml
@@ -46,7 +46,21 @@
apiVersion: v1
kind: Service
metadata:
- name: dodo-app
+ name: api
+spec:
+ type: ClusterIP
+ selector:
+ app: dodo-app
+ ports:
+ - name: http
+ port: 80
+ targetPort: api
+ protocol: TCP
+---
+apiVersion: v1
+kind: Service
+metadata:
+ name: web
spec:
type: ClusterIP
selector:
@@ -78,25 +92,40 @@
- name: env-config
secret:
secretName: env-config
+ - name: db
+ persistentVolumeClaim:
+ claimName: {{ .Values.persistentVolumeClaimName }}
+ initContainers:
+ - name: volume-permissions
+ image: busybox:latest
+ command: ["sh", "-c", "chmod -Rv 777 /dodo-app/db"]
+ volumeMounts:
+ - name: db
+ mountPath: /dodo-app/db
containers:
- name: dodo-app
image: {{ .Values.image.repository }}:{{ .Values.image.tag }}
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
- containerPort: 8080
+ containerPort: {{ .Values.port }}
+ protocol: TCP
+ - name: api
+ containerPort: {{ .Values.apiPort }}
protocol: TCP
command:
- pcloud-installer
- dodo-app
- --repo-addr={{ .Values.repoAddr }}
- --ssh-key=/pcloud/ssh-key/private
- - --port=8080
+ - --port={{ .Values.port }}
+ - --api-port={{ .Values.apiPort }}
- --self={{ .Values.self }}
- --namespace={{ .Values.namespace }} # TODO(gio): maybe use .Release.Namespace ?
- --env-config=/pcloud/env-config/config.json
- --app-admin-key={{ .Values.appAdminKey }}
- --git-repo-public-key={{ .Values.gitRepoPublicKey }}
+ - --db=/dodo-app/db/apps.db
volumeMounts:
- name: ssh-key
readOnly: true
@@ -104,6 +133,8 @@
- name: env-config
readOnly: true
mountPath: /pcloud/env-config
+ - name: db
+ mountPath: /dodo-app/db
---
apiVersion: v1
kind: Secret
diff --git a/charts/dodo-app/values.yaml b/charts/dodo-app/values.yaml
index 66588cf..50aae4d 100644
--- a/charts/dodo-app/values.yaml
+++ b/charts/dodo-app/values.yaml
@@ -2,6 +2,8 @@
repository: giolekva/pcloud-installer
tag: latest
pullPolicy: Always
+port: 8080
+apiPort: 8081
clusterRoleName: dodo-app-creator
repoAddr: 192.168.0.11
sshPrivateKey: key
@@ -10,3 +12,4 @@
envConfig: ""
appAdminKey: ""
gitRepoPublicKey: ""
+persistentVolumeClaimName: ""
diff --git a/core/installer/app_configs/dodo_app.cue b/core/installer/app_configs/dodo_app.cue
index 32e0c45..c5b0554 100644
--- a/core/installer/app_configs/dodo_app.cue
+++ b/core/installer/app_configs/dodo_app.cue
@@ -6,7 +6,7 @@
input: {
repoAddr: string
- registerWorkerAddr: string
+ managerAddr: string
appId: string
sshPrivateKey: string
}
@@ -159,7 +159,7 @@
repoAddr: input.repoAddr
sshPrivateKey: base64.Encode(null, input.sshPrivateKey)
runCfg: base64.Encode(null, json.Marshal(_app.runConfiguration))
- manager: input.registerWorkerAddr
+ managerAddr: input.managerAddr
volumes: [
for key, value in _app.volumes {
name: value.name
diff --git a/core/installer/app_test.go b/core/installer/app_test.go
index 44d2dbd..7935ec2 100644
--- a/core/installer/app_test.go
+++ b/core/installer/app_test.go
@@ -315,10 +315,10 @@
AppDir: "/foo/bar",
}
_, err = app.Render(release, env, map[string]any{
- "repoAddr": "",
- "registerWorkerAddr": "",
- "appId": "",
- "sshPrivateKey": "",
+ "repoAddr": "",
+ "managerAddr": "",
+ "appId": "",
+ "sshPrivateKey": "",
}, nil)
if err != nil {
t.Fatal(err)
diff --git a/core/installer/cmd/dodo_app.go b/core/installer/cmd/dodo_app.go
index 78c88d2..4b34f01 100644
--- a/core/installer/cmd/dodo_app.go
+++ b/core/installer/cmd/dodo_app.go
@@ -1,6 +1,7 @@
package main
import (
+ "database/sql"
"encoding/json"
"log"
"os"
@@ -9,11 +10,15 @@
"github.com/giolekva/pcloud/core/installer/soft"
"github.com/giolekva/pcloud/core/installer/welcome"
+ _ "github.com/ncruces/go-sqlite3"
+ _ "github.com/ncruces/go-sqlite3/driver"
+ _ "github.com/ncruces/go-sqlite3/embed"
"github.com/spf13/cobra"
)
var dodoAppFlags struct {
port int
+ apiPort int
sshKey string
repoAddr string
self string
@@ -21,6 +26,7 @@
envConfig string
appAdminKey string
gitRepoPublicKey string
+ db string
}
func dodoAppCmd() *cobra.Command {
@@ -34,6 +40,18 @@
8080,
"",
)
+ cmd.Flags().IntVar(
+ &dodoAppFlags.apiPort,
+ "api-port",
+ 8081,
+ "",
+ )
+ cmd.Flags().StringVar(
+ &dodoAppFlags.db,
+ "db",
+ "",
+ "",
+ )
cmd.Flags().StringVar(
&dodoAppFlags.repoAddr,
"repo-addr",
@@ -80,6 +98,10 @@
}
func dodoAppCmdRun(cmd *cobra.Command, args []string) error {
+ sshKey, err := os.ReadFile(dodoAppFlags.sshKey)
+ if err != nil {
+ return err
+ }
envConfig, err := os.Open(dodoAppFlags.envConfig)
if err != nil {
return err
@@ -89,10 +111,6 @@
if err := json.NewDecoder(envConfig).Decode(&env); err != nil {
return err
}
- sshKey, err := os.ReadFile(dodoAppFlags.sshKey)
- if err != nil {
- return err
- }
cg := soft.RealClientGetter{}
softClient, err := cg.Get(dodoAppFlags.repoAddr, sshKey, log.Default())
if err != nil {
@@ -106,8 +124,29 @@
if err != nil {
return err
}
+ if ok, err := softClient.RepoExists(welcome.ConfigRepoName); err != nil {
+ return err
+ } else if !ok {
+ if err := softClient.AddRepository(welcome.ConfigRepoName); err != nil {
+ return err
+ }
+ }
+ configRepo, err := softClient.GetRepo(welcome.ConfigRepoName)
+ if err != nil {
+ return err
+ }
+ db, err := sql.Open("sqlite3", dodoAppFlags.db)
+ if err != nil {
+ return err
+ }
+ st, err := welcome.NewStore(configRepo, db)
+ if err != nil {
+ return err
+ }
s, err := welcome.NewDodoAppServer(
+ st,
dodoAppFlags.port,
+ dodoAppFlags.apiPort,
dodoAppFlags.self,
string(sshKey),
dodoAppFlags.gitRepoPublicKey,
diff --git a/core/installer/go.mod b/core/installer/go.mod
index fffd1fa..0e389fa 100644
--- a/core/installer/go.mod
+++ b/core/installer/go.mod
@@ -17,8 +17,9 @@
github.com/libdns/gandi v1.0.3
github.com/libdns/libdns v0.2.2
github.com/miekg/dns v1.1.58
+ github.com/ncruces/go-sqlite3 v0.17.0
github.com/spf13/cobra v1.8.0
- golang.org/x/crypto v0.22.0
+ golang.org/x/crypto v0.24.0
golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8
helm.sh/helm/v3 v3.14.3
k8s.io/api v0.30.0
@@ -117,6 +118,7 @@
github.com/monochromegane/go-gitignore v0.0.0-20200626010858-205db1a8cc00 // indirect
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 // indirect
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f // indirect
+ github.com/ncruces/julianday v1.0.0 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.0 // indirect
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
@@ -138,6 +140,7 @@
github.com/skeema/knownhosts v1.2.2 // indirect
github.com/spf13/cast v1.6.0 // indirect
github.com/spf13/pflag v1.0.5 // indirect
+ github.com/tetratelabs/wazero v1.7.3 // indirect
github.com/xanzy/ssh-agent v0.3.3 // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20190905194746-02993c407bfb // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
@@ -148,15 +151,15 @@
go.opentelemetry.io/otel/metric v1.24.0 // indirect
go.opentelemetry.io/otel/trace v1.24.0 // indirect
go.starlark.net v0.0.0-20240329153429-e6e8e7ce1b7a // indirect
- golang.org/x/mod v0.16.0 // indirect
- golang.org/x/net v0.24.0 // indirect
+ golang.org/x/mod v0.17.0 // indirect
+ golang.org/x/net v0.25.0 // indirect
golang.org/x/oauth2 v0.18.0 // indirect
- golang.org/x/sync v0.6.0 // indirect
- golang.org/x/sys v0.19.0 // indirect
- golang.org/x/term v0.19.0 // indirect
- golang.org/x/text v0.14.0 // indirect
+ golang.org/x/sync v0.7.0 // indirect
+ golang.org/x/sys v0.22.0 // indirect
+ golang.org/x/term v0.21.0 // indirect
+ golang.org/x/text v0.16.0 // indirect
golang.org/x/time v0.5.0 // indirect
- golang.org/x/tools v0.19.0 // indirect
+ golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d // indirect
google.golang.org/appengine v1.6.8 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240401170217-c3f982113cda // indirect
google.golang.org/grpc v1.63.0 // indirect
diff --git a/core/installer/go.sum b/core/installer/go.sum
index e0033a2..8356115 100644
--- a/core/installer/go.sum
+++ b/core/installer/go.sum
@@ -316,6 +316,10 @@
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f h1:y5//uYreIhSUg3J1GEMiLbxo1LJaP8RfCpH6pymGZus=
github.com/mxk/go-flowrate v0.0.0-20140419014527-cca7078d478f/go.mod h1:ZdcZmHo+o7JKHSa8/e818NopupXU1YMK5fe1lsApnBw=
+github.com/ncruces/go-sqlite3 v0.17.0 h1:tbrmwAF9Iq6O6i8NX+pO7rQYIwIJ4cZ/nZFQyw7GB18=
+github.com/ncruces/go-sqlite3 v0.17.0/go.mod h1:Ik98tXgiGdF2HgHYZlEkh84RAC3U3eqgS7PYsmLwLxY=
+github.com/ncruces/julianday v1.0.0 h1:fH0OKwa7NWvniGQtxdJRxAgkBMolni2BjDHaWTxqt7M=
+github.com/ncruces/julianday v1.0.0/go.mod h1:Dusn2KvZrrovOMJuOt0TNXL6tB7U2E8kvza5fFc9G7g=
github.com/onsi/ginkgo/v2 v2.17.1 h1:V++EzdbhI4ZV4ev0UTIj0PzhzOcReJFyJaLjtSF55M8=
github.com/onsi/ginkgo/v2 v2.17.1/go.mod h1:llBI3WDLL9Z6taip6f33H76YcWtJv+7R3HigUjbIBOs=
github.com/onsi/gomega v1.32.0 h1:JRYU78fJ1LPxlckP6Txi/EYqJvjtMrDC04/MM5XRHPk=
@@ -397,6 +401,8 @@
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
+github.com/tetratelabs/wazero v1.7.3 h1:PBH5KVahrt3S2AHgEjKu4u+LlDbbk+nsGE3KLucy6Rw=
+github.com/tetratelabs/wazero v1.7.3/go.mod h1:ytl6Zuh20R/eROuyDaGPkp82O9C/DJfXAwJfQ3X6/7Y=
github.com/xanzy/ssh-agent v0.3.3 h1:+/15pJfg/RsTxqYcX6fHqOXZwwMP+2VyYWJeWM2qQFM=
github.com/xanzy/ssh-agent v0.3.3/go.mod h1:6dzNDKs0J9rVPHPhaGCukekBHKqfl+L3KghI1Bc68Uw=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
@@ -440,16 +446,16 @@
golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
golang.org/x/crypto v0.3.1-0.20221117191849-2c476679df9a/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4=
golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
-golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30=
-golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M=
+golang.org/x/crypto v0.24.0 h1:mnl8DM0o513X8fdIkmyFE/5hTYxbwYOjDS/+rK6qpRI=
+golang.org/x/crypto v0.24.0/go.mod h1:Z1PMYSOR5nyMcyAVAIQSKCDwalqy85Aqn1x3Ws4L5DM=
golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8 h1:aAcj0Da7eBAtrTp03QXWvm88pSyOt+UgdZw2BFZ+lEw=
golang.org/x/exp v0.0.0-20240325151524-a685a6edb6d8/go.mod h1:CQ1k9gNrJ50XIzaKCRR2hssIjF07kZFEiieALBM/ARQ=
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
-golang.org/x/mod v0.16.0 h1:QX4fJ0Rr5cPQCF7O9lh9Se4pmwfwskqZfq5moyldzic=
-golang.org/x/mod v0.16.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA=
+golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@@ -462,8 +468,8 @@
golang.org/x/net v0.2.0/go.mod h1:KqCZLdyyvdV855qA2rE3GC2aiw5xGR5TEjj8smXukLY=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
-golang.org/x/net v0.24.0 h1:1PcaxkF854Fu3+lvBIx5SYn9wRlBzzcnHZSiaFFAb0w=
-golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8=
+golang.org/x/net v0.25.0 h1:d/OCCoBEUq33pjydKrGQhw7IlUPI2Oylr+8qLx49kac=
+golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI=
golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8=
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
@@ -473,8 +479,8 @@
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
-golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sync v0.7.0 h1:YsImfSBoP9QPYL0xyKJPq0gcaJdG3rInoqxTWbfQu9M=
+golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -495,15 +501,15 @@
golang.org/x/sys v0.3.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.19.0 h1:q5f1RH2jigJ1MoAWp2KTp3gm5zAGFUTarQZ5U386+4o=
-golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.22.0 h1:RI27ohtqKCnwULzJLqkv897zojh5/DwS/ENaMzUOaWI=
+golang.org/x/sys v0.22.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
golang.org/x/term v0.2.0/go.mod h1:TVmDHMZPmdnySmBfhjOoOdhjzdE1h4u1VwSiw2l1Nuc=
golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
-golang.org/x/term v0.19.0 h1:+ThwsDv+tYfnJFhF4L8jITxu1tdTWRTZpdsWgEgjL6Q=
-golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk=
+golang.org/x/term v0.21.0 h1:WVXCp+/EBEHOj53Rvu+7KiT/iElMrO8ACK16SMZ3jaA=
+golang.org/x/term v0.21.0/go.mod h1:ooXLefLobQVslOqselCNF4SxFAaoS6KujMbsGzSDmX0=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
@@ -512,8 +518,8 @@
golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
-golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
-golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+golang.org/x/text v0.16.0 h1:a94ExnEXNtEwYLGJSIUxnWoxoRz/ZcCsV63ROupILh4=
+golang.org/x/text v0.16.0/go.mod h1:GhwF1Be+LQoKShO3cGOHzqOgRrGaYc9AvblQOmPVHnI=
golang.org/x/time v0.5.0 h1:o7cqy6amK/52YcAKIPlM3a+Fpj35zvRj2TP+e1xFSfk=
golang.org/x/time v0.5.0/go.mod h1:3BpzKBy/shNhVucY/MWOyx10tF3SFh9QdLuxbVysPQM=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
@@ -522,8 +528,8 @@
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
-golang.org/x/tools v0.19.0 h1:tfGCXNR1OsFG+sVdLAitlpjAvD/I6dHDKnYrpEZUHkw=
-golang.org/x/tools v0.19.0/go.mod h1:qoJWxmGSIBmAeriMx19ogtrEPrGtDbPK634QFIcLAhc=
+golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d h1:vU5i/LfpvrRCpgM/VPfJLg5KjxD3E+hfT1SH+d9zLwg=
+golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
diff --git a/core/installer/values-tmpl/dodo-app.cue b/core/installer/values-tmpl/dodo-app.cue
index abc09b2..ddd3b17 100644
--- a/core/installer/values-tmpl/dodo-app.cue
+++ b/core/installer/values-tmpl/dodo-app.cue
@@ -53,6 +53,20 @@
}
}
+volumes: db: size: "10Gi"
+
+ingress: {
+ "dodo-app": {
+ auth: enabled: false
+ network: input.network
+ subdomain: input.subdomain
+ service: {
+ name: "web"
+ port: name: "http"
+ }
+ }
+}
+
portForward: [#PortForward & {
allocator: input.network.allocatePortAddr
reservator: input.network.reservePortAddr
@@ -92,13 +106,16 @@
tag: images.dodoApp.tag
pullPolicy: images.dodoApp.pullPolicy
}
+ port: 8080
+ apiPort: 8081
repoAddr: "soft-serve.\(release.namespace).svc.cluster.local:22"
sshPrivateKey: base64.Encode(null, input.dAppKeys.private)
- self: "dodo-app.\(release.namespace).svc.cluster.local"
+ self: "api.\(release.namespace).svc.cluster.local"
namespace: release.namespace
envConfig: base64.Encode(null, json.Marshal(global))
appAdminKey: input.adminKey
gitRepoPublicKey: input.ssKeys.public
+ persistentVolumeClaimName: volumes.db.name
}
}
}
diff --git a/core/installer/welcome/dodo_app.go b/core/installer/welcome/dodo_app.go
index 8cfa72f..89b7ad2 100644
--- a/core/installer/welcome/dodo_app.go
+++ b/core/installer/welcome/dodo_app.go
@@ -9,7 +9,6 @@
"net/http"
"strings"
"sync"
- "time"
"github.com/giolekva/pcloud/core/installer"
"github.com/giolekva/pcloud/core/installer/soft"
@@ -18,13 +17,15 @@
)
const (
- configRepoName = "config"
+ ConfigRepoName = "config"
namespacesFile = "/namespaces.json"
)
type DodoAppServer struct {
l sync.Locker
+ st Store
port int
+ apiPort int
self string
sshKey string
gitRepoPublicKey string
@@ -39,7 +40,9 @@
// TODO(gio): Initialize appNs on startup
func NewDodoAppServer(
+ st Store,
port int,
+ apiPort int,
self string,
sshKey string,
gitRepoPublicKey string,
@@ -49,16 +52,11 @@
jc installer.JobCreator,
env installer.EnvConfig,
) (*DodoAppServer, error) {
- if ok, err := client.RepoExists(configRepoName); err != nil {
- return nil, err
- } else if !ok {
- if err := client.AddRepository(configRepoName); err != nil {
- return nil, err
- }
- }
s := &DodoAppServer{
&sync.Mutex{},
+ st,
port,
+ apiPort,
self,
sshKey,
gitRepoPublicKey,
@@ -70,7 +68,7 @@
map[string]map[string]struct{}{},
map[string]string{},
}
- config, err := client.GetRepo(configRepoName)
+ config, err := client.GetRepo(ConfigRepoName)
if err != nil {
return nil, err
}
@@ -87,12 +85,50 @@
}
func (s *DodoAppServer) Start() error {
- r := mux.NewRouter()
- r.HandleFunc("/update", s.handleUpdate)
- r.HandleFunc("/register-worker", s.handleRegisterWorker).Methods(http.MethodPost)
- r.HandleFunc("/api/apps", s.handleCreateApp).Methods(http.MethodPost)
- r.HandleFunc("/api/add-admin-key", s.handleAddAdminKey).Methods(http.MethodPost)
- return http.ListenAndServe(fmt.Sprintf(":%d", s.port), r)
+ e := make(chan error)
+ go func() {
+ r := mux.NewRouter()
+ r.HandleFunc("/status/{app-name}", s.handleAppStatus).Methods(http.MethodGet)
+ r.HandleFunc("/status", s.handleStatus).Methods(http.MethodGet)
+ e <- http.ListenAndServe(fmt.Sprintf(":%d", s.port), r)
+ }()
+ go func() {
+ r := mux.NewRouter()
+ r.HandleFunc("/update", s.handleUpdate)
+ r.HandleFunc("/api/apps/{app-name}/workers", s.handleRegisterWorker).Methods(http.MethodPost)
+ r.HandleFunc("/api/apps", s.handleCreateApp).Methods(http.MethodPost)
+ r.HandleFunc("/api/add-admin-key", s.handleAddAdminKey).Methods(http.MethodPost)
+ e <- http.ListenAndServe(fmt.Sprintf(":%d", s.apiPort), r)
+ }()
+ return <-e
+}
+
+func (s *DodoAppServer) handleStatus(w http.ResponseWriter, r *http.Request) {
+ apps, err := s.st.GetApps()
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ for _, a := range apps {
+ fmt.Fprintf(w, "%s\n", a)
+ }
+}
+
+func (s *DodoAppServer) handleAppStatus(w http.ResponseWriter, r *http.Request) {
+ vars := mux.Vars(r)
+ appName, ok := vars["app-name"]
+ if !ok || appName == "" {
+ http.Error(w, "missing app-name", http.StatusBadRequest)
+ return
+ }
+ commits, err := s.st.GetCommitHistory(appName)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ for _, c := range commits {
+ fmt.Fprintf(w, "%s %s\n", c.Hash, c.Message)
+ }
}
type updateReq struct {
@@ -100,6 +136,7 @@
Repository struct {
Name string `json:"name"`
} `json:"repository"`
+ After string `json:"after"`
}
func (s *DodoAppServer) handleUpdate(w http.ResponseWriter, r *http.Request) {
@@ -113,38 +150,49 @@
fmt.Println(err)
return
}
- if req.Ref != "refs/heads/master" || strings.HasPrefix(req.Repository.Name, configRepoName) {
+ if req.Ref != "refs/heads/master" || req.Repository.Name == ConfigRepoName {
return
}
+ // TODO(gio): Create commit record on app init as well
go func() {
- time.Sleep(20 * time.Second)
if err := s.updateDodoApp(req.Repository.Name, s.appNs[req.Repository.Name]); err != nil {
- fmt.Println(err)
+ if err := s.st.CreateCommit(req.Repository.Name, req.After, err.Error()); err != nil {
+ fmt.Printf("Error: %s\n", err.Error())
+ return
+ }
+ }
+ if err := s.st.CreateCommit(req.Repository.Name, req.After, "OK"); err != nil {
+ fmt.Printf("Error: %s\n", err.Error())
+ }
+ for addr, _ := range s.workers[req.Repository.Name] {
+ go func() {
+ // TODO(gio): make port configurable
+ http.Get(fmt.Sprintf("http://%s/update", addr))
+ }()
}
}()
- for addr, _ := range s.workers[req.Repository.Name] {
- go func() {
- // TODO(gio): make port configurable
- http.Get(fmt.Sprintf("http://%s:3000/update", addr))
- }()
- }
}
type registerWorkerReq struct {
- AppId string `json:"appId"`
Address string `json:"address"`
}
func (s *DodoAppServer) handleRegisterWorker(w http.ResponseWriter, r *http.Request) {
+ vars := mux.Vars(r)
+ appName, ok := vars["app-name"]
+ if !ok || appName == "" {
+ http.Error(w, "missing app-name", http.StatusBadRequest)
+ return
+ }
var req registerWorkerReq
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
- if _, ok := s.workers[req.AppId]; !ok {
- s.workers[req.AppId] = map[string]struct{}{}
+ if _, ok := s.workers[appName]; !ok {
+ s.workers[appName] = map[string]struct{}{}
}
- s.workers[req.AppId][req.Address] = struct{}{}
+ s.workers[appName][req.Address] = struct{}{}
}
type createAppReq struct {
@@ -187,6 +235,9 @@
} else if ok {
return nil
}
+ if err := s.st.CreateApp(appName); err != nil {
+ return err
+ }
if err := s.client.AddRepository(appName); err != nil {
return err
}
@@ -212,7 +263,7 @@
if err := s.updateDodoApp(appName, namespace); err != nil {
return err
}
- repo, err := s.client.GetRepo(configRepoName)
+ repo, err := s.client.GetRepo(ConfigRepoName)
if err != nil {
return err
}
@@ -337,10 +388,10 @@
"/.dodo/app",
namespace,
map[string]any{
- "repoAddr": repo.FullAddress(),
- "registerWorkerAddr": fmt.Sprintf("http://%s/register-worker", s.self),
- "appId": name,
- "sshPrivateKey": s.sshKey,
+ "repoAddr": repo.FullAddress(),
+ "managerAddr": fmt.Sprintf("http://%s", s.self),
+ "appId": name,
+ "sshPrivateKey": s.sshKey,
},
installer.WithConfig(&s.env),
installer.WithLocalChartGenerator(lg),
diff --git a/core/installer/welcome/store.go b/core/installer/welcome/store.go
new file mode 100644
index 0000000..0ae5f4e
--- /dev/null
+++ b/core/installer/welcome/store.go
@@ -0,0 +1,103 @@
+package welcome
+
+import (
+ "database/sql"
+
+ "github.com/giolekva/pcloud/core/installer/soft"
+)
+
+type Commit struct {
+ Hash string
+ Message string
+}
+
+type Store interface {
+ GetApps() ([]string, error)
+ CreateApp(name string) error
+ CreateCommit(name, hash, message string) error
+ GetCommitHistory(name string) ([]Commit, error)
+}
+
+func NewStore(cf soft.RepoIO, db *sql.DB) (Store, error) {
+ s := &storeImpl{cf, db}
+ if err := s.init(); err != nil {
+ return nil, err
+ }
+ return s, nil
+}
+
+type storeImpl struct {
+ cf soft.RepoIO
+ db *sql.DB
+}
+
+func (s *storeImpl) init() error {
+ _, err := s.db.Exec(`
+ CREATE TABLE IF NOT EXISTS apps (
+ name TEXT PRIMARY KEY
+ );
+ CREATE TABLE IF NOT EXISTS commits (
+ app_name TEXT,
+ hash TEXT,
+ message TEXT
+ );
+ `)
+ return err
+
+}
+
+func (s *storeImpl) CreateApp(name string) error {
+ query := `INSERT INTO apps (name) VALUES (?)`
+ _, err := s.db.Exec(query, name)
+ return err
+}
+
+func (s *storeImpl) GetApps() ([]string, error) {
+ query := `SELECT name FROM apps`
+ rows, err := s.db.Query(query)
+ if err != nil {
+ return nil, err
+ }
+ defer rows.Close()
+ ret := []string{}
+ for rows.Next() {
+ if err := rows.Err(); err != nil {
+ return nil, err
+ }
+ var name string
+ if err := rows.Scan(&name); err != nil {
+ return nil, err
+ }
+ ret = append(ret, name)
+
+ }
+ return ret, nil
+}
+
+func (s *storeImpl) CreateCommit(name, hash, message string) error {
+ query := `INSERT INTO commits (app_name, hash, message) VALUES (?, ?, ?)`
+ _, err := s.db.Exec(query, name, hash, message)
+ return err
+}
+
+func (s *storeImpl) GetCommitHistory(name string) ([]Commit, error) {
+ query := `SELECT hash, message FROM commits WHERE app_name = ?`
+ rows, err := s.db.Query(query, name)
+ if err != nil {
+ return nil, err
+ }
+ defer rows.Close()
+ ret := []Commit{}
+ for rows.Next() {
+ if err := rows.Err(); err != nil {
+ return nil, err
+ }
+ var c Commit
+ if err := rows.Scan(&c.Hash, &c.Message); err != nil {
+ return nil, err
+ }
+ ret = append(ret, c)
+
+ }
+ return ret, nil
+}