DodoApp: Filter domains
Change-Id: I475f6b6c9d00ccc0214c54f22c6c8fd428cd996d
diff --git a/charts/dodo-app/templates/install.yaml b/charts/dodo-app/templates/install.yaml
index d63326d..f94202b 100644
--- a/charts/dodo-app/templates/install.yaml
+++ b/charts/dodo-app/templates/install.yaml
@@ -127,6 +127,7 @@
- --app-admin-key={{ .Values.appAdminKey }}
- --git-repo-public-key={{ .Values.gitRepoPublicKey }}
- --db=/dodo-app/db/apps.db
+ - --networks={{ .Values.allowedNetworks }}
volumeMounts:
- name: ssh-key
readOnly: true
diff --git a/charts/dodo-app/values.yaml b/charts/dodo-app/values.yaml
index 4c0b788..abb976a 100644
--- a/charts/dodo-app/values.yaml
+++ b/charts/dodo-app/values.yaml
@@ -14,3 +14,4 @@
appAdminKey: ""
gitRepoPublicKey: ""
persistentVolumeClaimName: ""
+allowedNetworks: ""
diff --git a/core/installer/app_configs/app_global_env.cue b/core/installer/app_configs/app_global_env.cue
index ca7e099..47af9a0 100644
--- a/core/installer/app_configs/app_global_env.cue
+++ b/core/installer/app_configs/app_global_env.cue
@@ -11,21 +11,7 @@
network: #EnvNetwork
}
-networks: {
- public: #Network & {
- name: "Public"
- ingressClass: "\(global.pcloudEnvName)-ingress-public"
- certificateIssuer: "\(global.id)-public"
- domain: global.domain
- allocatePortAddr: "http://port-allocator.\(global.pcloudEnvName)-ingress-public.svc.cluster.local/api/allocate"
- }
- private: #Network & {
- name: "Private"
- ingressClass: "\(global.id)-ingress-private"
- domain: global.privateDomain
- allocatePortAddr: "http://port-allocator.\(global.id)-ingress-private.svc.cluster.local/api/allocate"
- }
-}
+networks: {}
// TODO(gio): remove
ingressPrivate: "\(global.id)-ingress-private"
diff --git a/core/installer/app_manager.go b/core/installer/app_manager.go
index 4fc0b1f..2cc29ed 100644
--- a/core/installer/app_manager.go
+++ b/core/installer/app_manager.go
@@ -649,6 +649,10 @@
}
}
+func WithNoNetworks() InstallOption {
+ return WithNetworks([]Network{})
+}
+
func WithBranch(branch string) InstallOption {
return func(o *installOptions) {
o.Branch = branch
diff --git a/core/installer/cmd/dodo_app.go b/core/installer/cmd/dodo_app.go
index 2eb5b8f..ea5e7fd 100644
--- a/core/installer/cmd/dodo_app.go
+++ b/core/installer/cmd/dodo_app.go
@@ -28,6 +28,7 @@
appAdminKey string
gitRepoPublicKey string
db string
+ networks []string
}
func dodoAppCmd() *cobra.Command {
@@ -101,6 +102,12 @@
"",
"",
)
+ cmd.Flags().StringSliceVar(
+ &dodoAppFlags.networks,
+ "networks",
+ []string{},
+ "",
+ )
return cmd
}
@@ -160,6 +167,7 @@
softClient,
dodoAppFlags.namespace,
dodoAppFlags.envAppManagerAddr,
+ dodoAppFlags.networks,
nsc,
jc,
env,
@@ -168,7 +176,7 @@
return err
}
if dodoAppFlags.appAdminKey != "" {
- if _, err := s.CreateApp("app", dodoAppFlags.appAdminKey); err != nil {
+ if _, err := s.CreateApp("app", dodoAppFlags.appAdminKey, "Private"); err != nil {
return err
}
}
diff --git a/core/installer/values-tmpl/dodo-app-instance.cue b/core/installer/values-tmpl/dodo-app-instance.cue
index e22f177..e0d6906 100644
--- a/core/installer/values-tmpl/dodo-app-instance.cue
+++ b/core/installer/values-tmpl/dodo-app-instance.cue
@@ -15,7 +15,6 @@
readme: "Deploy app by pushing to Git repository"
description: "Deploy app by pushing to Git repository"
icon: ""
-_domain: "\(input.subdomain).\(input.network.domain)"
resources: {
"config-kustomization": {
diff --git a/core/installer/values-tmpl/dodo-app.cue b/core/installer/values-tmpl/dodo-app.cue
index 99d4418..974225f 100644
--- a/core/installer/values-tmpl/dodo-app.cue
+++ b/core/installer/values-tmpl/dodo-app.cue
@@ -8,7 +8,8 @@
network: #Network @name(Network)
subdomain: string @name(Subdomain)
sshPort: int @name(SSH Port) @role(port)
- adminKey: string @name(Admin SSH Public Key)
+ adminKey: string | *"" @name(Admin SSH Public Key)
+ allowedNetworks: string | *"" @name(Allowed Networks)
// TODO(gio): auto generate
ssKeys: #SSHKey
@@ -117,6 +118,7 @@
appAdminKey: input.adminKey
gitRepoPublicKey: input.ssKeys.public
persistentVolumeClaimName: volumes.db.name
+ allowedNetworks: input.allowedNetworks
}
}
}
diff --git a/core/installer/welcome/dodo-app-tmpl/index.html b/core/installer/welcome/dodo-app-tmpl/index.html
new file mode 100644
index 0000000..e9a9b11
--- /dev/null
+++ b/core/installer/welcome/dodo-app-tmpl/index.html
@@ -0,0 +1,12 @@
+<!DOCTYPE html>
+<html lang='en'>
+ <head>
+ <title>dodo: app</title>
+ <meta charset='utf-8'>
+ </head>
+ <body>
+ {{ range .Apps }}
+ <a href="/{{ . }}">{{ . }}</a>
+ {{ end }}
+ </body>
+</html>
diff --git a/core/installer/welcome/dodo_app.go b/core/installer/welcome/dodo_app.go
index 20e881d..1c91cbc 100644
--- a/core/installer/welcome/dodo_app.go
+++ b/core/installer/welcome/dodo_app.go
@@ -2,13 +2,16 @@
import (
"context"
+ "embed"
"encoding/json"
"errors"
"fmt"
"golang.org/x/crypto/bcrypt"
+ "html/template"
"io"
"io/fs"
"net/http"
+ "slices"
"strings"
"sync"
@@ -19,6 +22,9 @@
"github.com/gorilla/securecookie"
)
+//go:embed dodo-app-tmpl/*
+var dodoAppTmplFS embed.FS
+
const (
ConfigRepoName = "config"
namespacesFile = "/namespaces.json"
@@ -28,6 +34,18 @@
userCtx = "user"
)
+type dodoAppTmplts struct {
+ index *template.Template
+}
+
+func parseTemplatesDodoApp(fs embed.FS) (dodoAppTmplts, error) {
+ index, err := template.New("index.html").ParseFS(fs, "dodo-app-tmpl/index.html")
+ if err != nil {
+ return dodoAppTmplts{}, err
+ }
+ return dodoAppTmplts{index}, nil
+}
+
type DodoAppServer struct {
l sync.Locker
st Store
@@ -39,12 +57,14 @@
client soft.Client
namespace string
envAppManagerAddr string
+ networks []string
env installer.EnvConfig
nsc installer.NamespaceCreator
jc installer.JobCreator
workers map[string]map[string]struct{}
appNs map[string]string
sc *securecookie.SecureCookie
+ tmplts dodoAppTmplts
}
// TODO(gio): Initialize appNs on startup
@@ -58,10 +78,15 @@
client soft.Client,
namespace string,
envAppManagerAddr string,
+ networks []string,
nsc installer.NamespaceCreator,
jc installer.JobCreator,
env installer.EnvConfig,
) (*DodoAppServer, error) {
+ tmplts, err := parseTemplatesDodoApp(dodoAppTmplFS)
+ if err != nil {
+ return nil, err
+ }
sc := securecookie.New(
securecookie.GenerateRandomKey(64),
securecookie.GenerateRandomKey(32),
@@ -77,12 +102,14 @@
client,
namespace,
envAppManagerAddr,
+ networks,
env,
nsc,
jc,
map[string]map[string]struct{}{},
map[string]string{},
sc,
+ tmplts,
}
config, err := client.GetRepo(ConfigRepoName)
if err != nil {
@@ -223,6 +250,10 @@
http.Redirect(w, r, fmt.Sprintf("/%s", appName), http.StatusSeeOther)
}
+type statusData struct {
+ Apps []string
+}
+
func (s *DodoAppServer) handleStatus(w http.ResponseWriter, r *http.Request) {
user := r.Context().Value(userCtx)
if user == nil {
@@ -234,8 +265,10 @@
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
- for _, a := range apps {
- fmt.Fprintf(w, "%s\n", a)
+ data := statusData{apps}
+ if err := s.tmplts.index.Execute(w, data); err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
}
}
@@ -272,7 +305,7 @@
c := contents.String()
fmt.Println(c)
if err := json.NewDecoder(strings.NewReader(c)).Decode(&req); err != nil {
- fmt.Println(err)
+ http.Error(w, err.Error(), http.StatusBadRequest)
return
}
if req.Ref != "refs/heads/master" || req.Repository.Name == ConfigRepoName {
@@ -280,7 +313,7 @@
}
// TODO(gio): Create commit record on app init as well
go func() {
- networks, err := getNetworks(fmt.Sprintf("%s/api/networks", s.envAppManagerAddr))
+ networks, err := s.getNetworks()
if err != nil {
return
}
@@ -326,6 +359,7 @@
type apiCreateAppReq struct {
AdminPublicKey string `json:"adminPublicKey"`
+ NetworkName string `json:"networkName"`
}
type apiCreateAppResp struct {
@@ -345,7 +379,7 @@
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
- password, err := s.CreateApp(appName, req.AdminPublicKey)
+ password, err := s.CreateApp(appName, req.AdminPublicKey, req.NetworkName)
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
@@ -360,7 +394,7 @@
}
}
-func (s *DodoAppServer) CreateApp(appName, adminPublicKey string) (string, error) {
+func (s *DodoAppServer) CreateApp(appName, adminPublicKey, networkName string) (string, error) {
s.l.Lock()
defer s.l.Unlock()
fmt.Printf("Creating app: %s\n", appName)
@@ -373,11 +407,7 @@
if err != nil {
return "", err
}
- if user != "" {
- if err := s.client.AddPublicKey(user, adminPublicKey); err != nil {
- return "", err
- }
- } else {
+ if user == "" {
user = appName
if err := s.client.AddUser(user, adminPublicKey); err != nil {
return "", err
@@ -409,7 +439,7 @@
if err != nil {
return "", err
}
- if err := InitRepo(appRepo); err != nil {
+ if err := InitRepo(appRepo, networkName); err != nil {
return "", err
}
apps := installer.NewInMemoryAppRepository(installer.CreateAllApps())
@@ -424,7 +454,7 @@
}
namespace := fmt.Sprintf("%s%s%s", s.env.NamespacePrefix, app.Namespace(), suffix)
s.appNs[appName] = namespace
- networks, err := getNetworks(fmt.Sprintf("%s/api/networks", s.envAppManagerAddr))
+ networks, err := s.getNetworks()
if err != nil {
return "", err
}
@@ -460,7 +490,7 @@
"gitRepoPublicKey": s.gitRepoPublicKey,
},
installer.WithConfig(&s.env),
- installer.WithNetworks(networks),
+ installer.WithNoNetworks(),
installer.WithNoPublish(),
installer.WithNoLock(),
); err != nil {
@@ -593,14 +623,14 @@
type: "golang:1.22.0"
run: "main.go"
ingress: {
- network: "Private" // or Public
+ network: "%s"
subdomain: "testapp"
auth: enabled: false
}
}
`
-func InitRepo(repo soft.RepoIO) error {
+func InitRepo(repo soft.RepoIO, networkName string) error {
return repo.Do(func(fs soft.RepoFS) (string, error) {
{
w, err := fs.Writer("go.mod")
@@ -624,7 +654,7 @@
return "", err
}
defer w.Close()
- fmt.Fprint(w, appCue)
+ fmt.Fprintf(w, appCue, networkName)
}
return "go web app template", nil
})
@@ -634,14 +664,24 @@
return "foo"
}
-func getNetworks(addr string) ([]installer.Network, error) {
+func (s *DodoAppServer) getNetworks() ([]installer.Network, error) {
+ addr := fmt.Sprintf("%s/api/networks", s.envAppManagerAddr)
resp, err := http.Get(addr)
if err != nil {
return nil, err
}
- ret := []installer.Network{}
- if json.NewDecoder(resp.Body).Decode(&ret); err != nil {
+ networks := []installer.Network{}
+ if json.NewDecoder(resp.Body).Decode(&networks); err != nil {
return nil, err
}
+ if len(s.networks) == 0 {
+ return networks, nil
+ }
+ ret := []installer.Network{}
+ for _, n := range networks {
+ if slices.Contains(s.networks, n.Name) {
+ ret = append(ret, n)
+ }
+ }
return ret, nil
}