DodoApp: Persist app namespaces in the config repository
Change-Id: I6bb6231ff63a4cfa8b66aa75c3d4cc1d9985d389
diff --git a/core/installer/app_manager.go b/core/installer/app_manager.go
index d3b64ab..0930356 100644
--- a/core/installer/app_manager.go
+++ b/core/installer/app_manager.go
@@ -310,6 +310,9 @@
if o.Force {
dopts = append(dopts, soft.WithForce())
}
+ if o.NoLock {
+ dopts = append(dopts, soft.WithNoLock())
+ }
return ReleaseResources{}, repo.Do(func(r soft.RepoFS) (string, error) {
if err := r.RemoveDir(appDir); err != nil {
return "", err
@@ -596,6 +599,7 @@
LG LocalChartGenerator
FetchContainerImages bool
Force bool
+ NoLock bool
}
type InstallOption func(*installOptions)
@@ -636,6 +640,12 @@
}
}
+func WithNoLock() InstallOption {
+ return func(o *installOptions) {
+ o.NoLock = true
+ }
+}
+
// InfraAppmanager
type InfraAppManager struct {
diff --git a/core/installer/cmd/dodo_app.go b/core/installer/cmd/dodo_app.go
index 5d54147..78c88d2 100644
--- a/core/installer/cmd/dodo_app.go
+++ b/core/installer/cmd/dodo_app.go
@@ -106,7 +106,7 @@
if err != nil {
return err
}
- s := welcome.NewDodoAppServer(
+ s, err := welcome.NewDodoAppServer(
dodoAppFlags.port,
dodoAppFlags.self,
string(sshKey),
@@ -117,6 +117,9 @@
jc,
env,
)
+ if err != nil {
+ return err
+ }
if dodoAppFlags.appAdminKey != "" {
if err := s.CreateApp("app", dodoAppFlags.appAdminKey); err != nil {
return err
diff --git a/core/installer/soft/repoio.go b/core/installer/soft/repoio.go
index dcf897d..872a5cf 100644
--- a/core/installer/soft/repoio.go
+++ b/core/installer/soft/repoio.go
@@ -40,10 +40,17 @@
NoCommit bool
Force bool
ToBranch string
+ NoLock bool
}
type DoOption func(*doOptions)
+func WithNoLock() DoOption {
+ return func(o *doOptions) {
+ o.NoLock = true
+ }
+}
+
func WithNoPull() DoOption {
return func(o *doOptions) {
o.NoPull = true
@@ -108,7 +115,7 @@
}
func (r *repoFS) Writer(path string) (io.WriteCloser, error) {
- if err := r.fs.MkdirAll(filepath.Dir(path), fs.ModePerm); err != nil {
+ if err := r.CreateDir(filepath.Dir(path)); err != nil {
return nil, err
}
return r.fs.Create(path)
@@ -224,32 +231,34 @@
}
func (r *repoIO) Do(op DoFn, opts ...DoOption) error {
- r.l.Lock()
- defer r.l.Unlock()
o := &doOptions{}
for _, i := range opts {
i(o)
}
+ if o.NoLock {
+ r.l.Lock()
+ defer r.l.Unlock()
+ }
if !o.NoPull {
if err := r.pullWithoutLock(); err != nil {
return err
}
}
- if msg, err := op(r); err != nil {
+ msg, err := op(r)
+ if err != nil {
return err
- } else {
- if !o.NoCommit {
- popts := []PushOption{}
- if o.Force {
- popts = append(popts, PushWithForce())
- }
- if o.ToBranch != "" {
- popts = append(popts, WithToBranch(o.ToBranch))
- }
- return r.CommitAndPush(msg, popts...)
- }
}
- return nil
+ if o.NoCommit {
+ return nil
+ }
+ popts := []PushOption{}
+ if o.Force {
+ popts = append(popts, PushWithForce())
+ }
+ if o.ToBranch != "" {
+ popts = append(popts, WithToBranch(o.ToBranch))
+ }
+ return r.CommitAndPush(msg, popts...)
}
func auth(signer ssh.Signer) *gitssh.PublicKeys {
diff --git a/core/installer/welcome/dodo_app.go b/core/installer/welcome/dodo_app.go
index f903d9b..8cfa72f 100644
--- a/core/installer/welcome/dodo_app.go
+++ b/core/installer/welcome/dodo_app.go
@@ -2,10 +2,13 @@
import (
"encoding/json"
+ "errors"
"fmt"
"io"
+ "io/fs"
"net/http"
"strings"
+ "sync"
"time"
"github.com/giolekva/pcloud/core/installer"
@@ -14,7 +17,13 @@
"github.com/gorilla/mux"
)
+const (
+ configRepoName = "config"
+ namespacesFile = "/namespaces.json"
+)
+
type DodoAppServer struct {
+ l sync.Locker
port int
self string
sshKey string
@@ -39,8 +48,16 @@
nsc installer.NamespaceCreator,
jc installer.JobCreator,
env installer.EnvConfig,
-) *DodoAppServer {
- return &DodoAppServer{
+) (*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{},
port,
self,
sshKey,
@@ -53,6 +70,20 @@
map[string]map[string]struct{}{},
map[string]string{},
}
+ config, err := client.GetRepo(configRepoName)
+ if err != nil {
+ return nil, err
+ }
+ r, err := config.Reader(namespacesFile)
+ if err == nil {
+ defer r.Close()
+ if err := json.NewDecoder(r).Decode(&s.appNs); err != nil {
+ return nil, err
+ }
+ } else if !errors.Is(err, fs.ErrNotExist) {
+ return nil, err
+ }
+ return s, nil
}
func (s *DodoAppServer) Start() error {
@@ -82,7 +113,7 @@
fmt.Println(err)
return
}
- if req.Ref != "refs/heads/master" || strings.HasPrefix(req.Repository.Name, "config") {
+ if req.Ref != "refs/heads/master" || strings.HasPrefix(req.Repository.Name, configRepoName) {
return
}
go func() {
@@ -148,6 +179,8 @@
}
func (s *DodoAppServer) CreateApp(appName, adminPublicKey string) error {
+ s.l.Lock()
+ defer s.l.Unlock()
fmt.Printf("Creating app: %s\n", appName)
if ok, err := s.client.RepoExists(appName); err != nil {
return err
@@ -179,14 +212,7 @@
if err := s.updateDodoApp(appName, namespace); err != nil {
return err
}
- if ok, err := s.client.RepoExists("config"); err != nil {
- return err
- } else if !ok {
- if err := s.client.AddRepository("config"); err != nil {
- return err
- }
- }
- repo, err := s.client.GetRepo("config")
+ repo, err := s.client.GetRepo(configRepoName)
if err != nil {
return err
}
@@ -195,11 +221,33 @@
if err != nil {
return err
}
- if _, err := m.Install(app, appName, "/"+appName, namespace, map[string]any{
- "repoAddr": s.client.GetRepoAddress(appName),
- "repoHost": strings.Split(s.client.Address(), ":")[0],
- "gitRepoPublicKey": s.gitRepoPublicKey,
- }, installer.WithConfig(&s.env)); err != nil {
+ if err := repo.Do(func(fs soft.RepoFS) (string, error) {
+ w, err := fs.Writer(namespacesFile)
+ if err != nil {
+ return "", err
+ }
+ defer w.Close()
+ if err := json.NewEncoder(w).Encode(s.appNs); err != nil {
+ return "", err
+ }
+ if _, err := m.Install(
+ app,
+ appName,
+ "/"+appName,
+ namespace,
+ map[string]any{
+ "repoAddr": s.client.GetRepoAddress(appName),
+ "repoHost": strings.Split(s.client.Address(), ":")[0],
+ "gitRepoPublicKey": s.gitRepoPublicKey,
+ },
+ installer.WithConfig(&s.env),
+ installer.WithNoPublish(),
+ installer.WithNoLock(),
+ ); err != nil {
+ return "", err
+ }
+ return fmt.Sprintf("Installed app: %s", appName), nil
+ }); err != nil {
return err
}
cfg, err := m.FindInstance(appName)