installer: create individual soft-serve instances for each env
diff --git a/core/installer/bootstrapper.go b/core/installer/bootstrapper.go
index dcf7ea1..4ad44d7 100644
--- a/core/installer/bootstrapper.go
+++ b/core/installer/bootstrapper.go
@@ -7,9 +7,9 @@
"log"
"net/netip"
"path/filepath"
+ "strings"
"time"
- "github.com/cenkalti/backoff/v4"
"helm.sh/helm/v3/pkg/action"
"helm.sh/helm/v3/pkg/chart"
"helm.sh/helm/v3/pkg/chart/loader"
@@ -41,7 +41,6 @@
if err := b.installLonghorn(env.Name, env.StorageDir, env.VolumeDefaultReplicaCount); err != nil {
return err
}
- time.Sleep(1 * time.Minute) // TODO(giolekva): implement proper wait
bootstrapJobKeys, err := NewSSHKeyPair("bootstrapper")
if err != nil {
return err
@@ -49,22 +48,25 @@
if err := b.installSoftServe(bootstrapJobKeys.AuthorizedKey(), env.Name, env.ServiceIPs.ConfigRepo); err != nil {
return err
}
- var ss *soft.Client
- err = backoff.Retry(func() error {
- var err error
- ss, err = soft.NewClient(netip.AddrPortFrom(env.ServiceIPs.ConfigRepo, 22), bootstrapJobKeys.RawPrivateKey(), log.Default())
- return err
- }, backoff.NewConstantBackOff(5*time.Second))
+ ss, err := soft.WaitForClient(
+ netip.AddrPortFrom(env.ServiceIPs.ConfigRepo, 22).String(),
+ bootstrapJobKeys.RawPrivateKey(),
+ log.Default())
if err != nil {
return err
}
+ defer func() {
+ if ss.RemovePublicKey("admin", bootstrapJobKeys.AuthorizedKey()); err != nil {
+ fmt.Printf("Failed to remove admin public key: %s\n", err.Error())
+ }
+ }()
if ss.AddPublicKey("admin", string(env.AdminPublicKey)); err != nil {
return err
}
if err := b.installFluxcd(ss, env.Name); err != nil {
return err
}
- repo, err := ss.GetRepo(env.Name)
+ repo, err := ss.GetRepo("config")
if err != nil {
return err
}
@@ -79,9 +81,6 @@
if err := b.installEnvManager(ss, repoIO, nsGen, b.ns, env); err != nil {
return err
}
- if ss.RemovePublicKey("admin", bootstrapJobKeys.AuthorizedKey()); err != nil {
- return err
- }
return nil
}
@@ -243,13 +242,13 @@
return nil
}
-func (b Bootstrapper) installSoftServe(adminPublicKey string, envName string, repoIP netip.Addr) error {
+func (b Bootstrapper) installSoftServe(adminPublicKey string, namespace string, repoIP netip.Addr) error {
fmt.Println("Installing SoftServe")
keys, err := NewSSHKeyPair("soft-serve")
if err != nil {
return err
}
- config, err := b.ha.New(envName)
+ config, err := b.ha.New(namespace)
if err != nil {
return err
}
@@ -263,13 +262,14 @@
"tag": "v0.7.1",
"pullPolicy": "IfNotPresent",
},
- "privateKey": string(keys.RawPrivateKey()),
- "publicKey": string(keys.RawAuthorizedKey()),
- "adminKey": adminPublicKey,
- "reservedIP": repoIP.String(),
+ "privateKey": string(keys.RawPrivateKey()),
+ "publicKey": string(keys.RawAuthorizedKey()),
+ "adminKey": adminPublicKey,
+ "reservedIP": repoIP.String(),
+ "serviceType": "LoadBalancer",
}
installer := action.NewInstall(config)
- installer.Namespace = envName
+ installer.Namespace = namespace
installer.CreateNamespace = true
installer.ReleaseName = "soft-serve"
installer.Wait = true
@@ -292,8 +292,15 @@
if err := ss.MakeUserAdmin("flux"); err != nil {
return err
}
- fmt.Printf("Creating /%s repo", envName)
- if err := ss.AddRepository(envName, "# dodo Systems"); err != nil {
+ if err := ss.AddRepository("config"); err != nil {
+ return err
+ }
+ repo, err := ss.GetRepo("config")
+ if err != nil {
+ return err
+ }
+ repoIO := NewRepoIO(repo, ss.Signer)
+ if err := repoIO.WriteCommitAndPush("README.md", fmt.Sprintf("# %s systems", envName), "readme"); err != nil {
return err
}
fmt.Println("Installing Flux")
@@ -301,9 +308,10 @@
if err != nil {
return err
}
+ host := strings.Split(ss.Addr, ":")[0]
if err := b.installFluxBootstrap(
- ss.GetRepoAddress(envName),
- ss.Addr.Addr().String(),
+ ss.GetRepoAddress("config"),
+ host,
string(ssPublic),
string(keys.RawPrivateKey()),
envName,
@@ -481,7 +489,7 @@
Values: map[string]any{
"RepoIP": env.ServiceIPs.ConfigRepo,
"RepoPort": 22,
- "RepoName": env.Name,
+ "RepoName": "config",
"SSHPrivateKey": string(keys.RawPrivateKey()),
},
}
diff --git a/core/installer/cmd/env_manager.go b/core/installer/cmd/env_manager.go
index 66bfb85..e177c08 100644
--- a/core/installer/cmd/env_manager.go
+++ b/core/installer/cmd/env_manager.go
@@ -2,7 +2,6 @@
import (
"log"
- "net/netip"
"github.com/spf13/cobra"
@@ -55,11 +54,7 @@
if err != nil {
return err
}
- repoAddr, err := netip.ParseAddrPort(envManagerFlags.repoAddr)
- if err != nil {
- return err
- }
- ss, err := soft.NewClient(repoAddr, sshKey.RawPrivateKey(), log.Default())
+ ss, err := soft.WaitForClient(envManagerFlags.repoAddr, sshKey.RawPrivateKey(), log.Default())
if err != nil {
return err
}
diff --git a/core/installer/repoio.go b/core/installer/repoio.go
index 54d9a7d..204caec 100644
--- a/core/installer/repoio.go
+++ b/core/installer/repoio.go
@@ -7,7 +7,6 @@
"io/fs"
"io/ioutil"
"net"
- "net/netip"
"path"
"path/filepath"
"time"
@@ -23,7 +22,7 @@
)
type RepoIO interface {
- Addr() netip.AddrPort
+ Addr() string
Fetch() error
ReadConfig() (Config, error)
ReadAppConfig(path string) (AppConfig, error)
@@ -32,6 +31,7 @@
ReadYaml(path string) (any, error)
WriteYaml(path string, data any) error
CommitAndPush(message string) error
+ WriteCommitAndPush(path, contents, message string) error
Reader(path string) (io.ReadCloser, error)
Writer(path string) (io.WriteCloser, error)
CreateDir(path string) error
@@ -54,7 +54,7 @@
}
}
-func (r *repoIO) Addr() netip.AddrPort {
+func (r *repoIO) Addr() string {
return r.repo.Addr.Addr
}
@@ -161,6 +161,18 @@
return data, err
}
+func (r *repoIO) WriteCommitAndPush(path, contents, message string) error {
+ w, err := r.Writer(path)
+ if err != nil {
+ return err
+ }
+ defer w.Close()
+ if _, err := io.WriteString(w, contents); err != nil {
+ return err
+ }
+ return r.CommitAndPush(message)
+}
+
func (r *repoIO) CommitAndPush(message string) error {
wt, err := r.repo.Worktree()
if err != nil {
diff --git a/core/installer/soft/client.go b/core/installer/soft/client.go
index 4f0bf16..5686ba5 100644
--- a/core/installer/soft/client.go
+++ b/core/installer/soft/client.go
@@ -6,11 +6,12 @@
"golang.org/x/crypto/ssh"
"log"
"net"
- "net/netip"
"os"
"regexp"
"strings"
+ "time"
+ "github.com/cenkalti/backoff/v4"
"github.com/go-git/go-billy/v5/memfs"
"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/plumbing/transport"
@@ -19,13 +20,13 @@
)
type Client struct {
- Addr netip.AddrPort
+ Addr string
Signer ssh.Signer
log *log.Logger
pemBytes []byte
}
-func NewClient(addr netip.AddrPort, clientPrivateKey []byte, log *log.Logger) (*Client, error) {
+func NewClient(addr string, clientPrivateKey []byte, log *log.Logger) (*Client, error) {
signer, err := ssh.ParsePrivateKey(clientPrivateKey)
if err != nil {
return nil, err
@@ -40,6 +41,24 @@
}, nil
}
+func WaitForClient(addr string, clientPrivateKey []byte, log *log.Logger) (*Client, error) {
+ var client *Client
+ err := backoff.RetryNotify(func() error {
+ var err error
+ client, err = NewClient(addr, clientPrivateKey, log)
+ if err != nil {
+ return err
+ }
+ if _, err := client.GetPublicKey(); err != nil {
+ return err
+ }
+ return nil
+ }, backoff.NewConstantBackOff(5*time.Second), func(err error, _ time.Duration) {
+ log.Printf("Failed to create client: %s\n", err.Error())
+ })
+ return client, err
+}
+
func (ss *Client) AddUser(name, pubKey string) error {
log.Printf("Adding user %s", name)
if err := ss.RunCommand("user", "create", name); err != nil {
@@ -59,17 +78,18 @@
}
func (ss *Client) RemovePublicKey(user string, pubKey string) error {
- log.Printf("Adding public key: %s %s\n", user, pubKey)
+ log.Printf("Removing public key: %s %s\n", user, pubKey)
return ss.RunCommand("user", "remove-pubkey", user, pubKey)
}
func (ss *Client) RunCommand(args ...string) error {
cmd := strings.Join(args, " ")
log.Printf("Running command %s", cmd)
- client, err := ssh.Dial("tcp", ss.Addr.String(), ss.sshClientConfig())
+ client, err := ssh.Dial("tcp", ss.Addr, ss.sshClientConfig())
if err != nil {
return err
}
+ defer client.Close()
session, err := client.NewSession()
if err != nil {
return err
@@ -80,14 +100,19 @@
return session.Run(cmd)
}
-func (ss *Client) AddRepository(name, readme string) error {
+func (ss *Client) AddRepository(name string) error {
log.Printf("Adding repository %s", name)
- return ss.RunCommand("repo", "create", name, "-d", fmt.Sprintf("\"%s\"", readme))
+ return ss.RunCommand("repo", "create", name)
}
-func (ss *Client) AddCollaborator(repo, user string) error {
- log.Printf("Adding collaborator %s %s", repo, user)
- return ss.RunCommand("repo", "collab", "add", repo, user)
+func (ss *Client) AddReadWriteCollaborator(repo, user string) error {
+ log.Printf("Adding read-write collaborator %s %s", repo, user)
+ return ss.RunCommand("repo", "collab", "add", repo, user, "read-write")
+}
+
+func (ss *Client) AddReadOnlyCollaborator(repo, user string) error {
+ log.Printf("Adding read-only collaborator %s %s", repo, user)
+ return ss.RunCommand("repo", "collab", "add", repo, user, "read-only")
}
type Repository struct {
@@ -100,7 +125,7 @@
}
type RepositoryAddress struct {
- Addr netip.AddrPort
+ Addr string
Name string
}
@@ -109,11 +134,7 @@
if len(items) != 3 {
return RepositoryAddress{}, fmt.Errorf("Invalid address")
}
- ipPort, err := netip.ParseAddrPort(items[1])
- if err != nil {
- return RepositoryAddress{}, err
- }
- return RepositoryAddress{ipPort, items[2]}, nil
+ return RepositoryAddress{items[1], items[2]}, nil
}
func (r RepositoryAddress) FullAddress() string {
@@ -199,10 +220,11 @@
return nil
},
}
- _, err := ssh.Dial("tcp", ss.Addr.String(), config)
+ client, err := ssh.Dial("tcp", ss.Addr, config)
if err != nil {
return nil, err
}
+ defer client.Close()
return ret, nil
}
diff --git a/core/installer/values-tmpl/soft-serve.yaml b/core/installer/values-tmpl/soft-serve.yaml
index 529986b..1c6fa87 100644
--- a/core/installer/values-tmpl/soft-serve.yaml
+++ b/core/installer/values-tmpl/soft-serve.yaml
@@ -10,15 +10,23 @@
sourceRef:
kind: GitRepository
name: pcloud
- namespace: {{ .Global.Id }}
+ namespace: {{ or .Values.ChartRepositoryNamespace .Global.Id }}
interval: 1m0s
values:
+ {{- if .Values.ServiceType }}
+ serviceType: {{ .Values.ServiceType }}
+ {{- end }}
reservedIP: ""
addressPool: {{ .Global.Id }}
adminKey: {{ .Values.AdminKey }}
+ {{- if and .Values.PrivateKey .Values.PublicKey }}
+ privateKey: |
+{{ .Values.PrivateKey | indent 6 }}
+ publicKey: {{ .Values.PublicKey }}
+ {{- end }}
{{- if .Values.Network }}
ingress:
- enabled: true # TODO(giolekva): make it configurable
+ enabled: {{ .Values.Ingress.Enabled }}
ingressClassName: {{ .Values.Network.IngressClass }}
certificateIssuer: {{ .Values.Network.CertificateIssuer }}
domain: {{ .Values.Subdomain }}.{{ .Values.Network.Domain }}
diff --git a/core/installer/welcome/create-env.html b/core/installer/welcome/create-env.html
index abaa197..d9f62c5 100644
--- a/core/installer/welcome/create-env.html
+++ b/core/installer/welcome/create-env.html
@@ -23,6 +23,12 @@
placeholder="Contact Email"
required
/>
+ <input
+ type="string"
+ name="admin-public-key"
+ placeholder="Admin SSH Public Key"
+ required
+ /> <!-- TODO(gio): remove-->
<textarea
name="secret-token"
placeholder="Secret Token"
diff --git a/core/installer/welcome/env-tmpl/config-secret.yaml b/core/installer/welcome/env-tmpl/config-secret.yaml
index 3ea515b..bba3de0 100644
--- a/core/installer/welcome/env-tmpl/config-secret.yaml
+++ b/core/installer/welcome/env-tmpl/config-secret.yaml
@@ -1,10 +1,10 @@
apiVersion: v1
+kind: Secret
+type: Opaque
+metadata:
+ name: {{ .Name }}
+ namespace: {{ .Name }}
data:
identity: {{ .PrivateKey }}
identity.pub: {{ .PublicKey }}
known_hosts: {{ .KnownHosts }}
-kind: Secret
-metadata:
- name: {{ .Name }}
- namespace: {{ .Name }}
-type: Opaque
diff --git a/core/installer/welcome/env-tmpl/config-source.yaml b/core/installer/welcome/env-tmpl/config-source.yaml
index 895c5e4..d22ab03 100644
--- a/core/installer/welcome/env-tmpl/config-source.yaml
+++ b/core/installer/welcome/env-tmpl/config-source.yaml
@@ -10,4 +10,4 @@
secretRef:
name: {{ .Name }}
timeout: 60s
- url: ssh://{{ .GitHost }}/{{ .Name }}
+ url: ssh://{{ .RepoHost }}/{{ .RepoName }}
diff --git a/core/installer/welcome/env-tmpl/kustomization.yaml b/core/installer/welcome/env-tmpl/kustomization.yaml
index 70db25f..070ae80 100644
--- a/core/installer/welcome/env-tmpl/kustomization.yaml
+++ b/core/installer/welcome/env-tmpl/kustomization.yaml
@@ -1,7 +1,7 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
-- namespace.yaml
+- config-repo
- config-secret.yaml
- config-source.yaml
- config-kustomization.yaml
diff --git a/core/installer/welcome/env-tmpl/namespace.yaml b/core/installer/welcome/env-tmpl/namespace.yaml
deleted file mode 100644
index 0c14654..0000000
--- a/core/installer/welcome/env-tmpl/namespace.yaml
+++ /dev/null
@@ -1,8 +0,0 @@
-apiVersion: v1
-kind: Namespace
-metadata:
- name: {{ .Name }}
- labels:
- pcloud-instance-id: {{ .Name }}
- annotations:
- helm.sh/resource-policy: keep
diff --git a/core/installer/welcome/env.go b/core/installer/welcome/env.go
index 029f6df..aa3e061 100644
--- a/core/installer/welcome/env.go
+++ b/core/installer/welcome/env.go
@@ -4,12 +4,16 @@
"embed"
"encoding/base64"
"encoding/json"
+ "errors"
"fmt"
htemplate "html/template"
"io"
+ "io/fs"
"log"
"net/http"
"path"
+ "path/filepath"
+ "strings"
"text/template"
"github.com/charmbracelet/keygen"
@@ -99,15 +103,19 @@
}
type createEnvReq struct {
- Name string
- ContactEmail string `json:"contactEmail"`
- Domain string `json:"domain"`
- SecretToken string `json:"secretToken"`
+ Name string
+ ContactEmail string `json:"contactEmail"`
+ Domain string `json:"domain"`
+ AdminPublicKey string `json:"adminPublicKey"`
+ SecretToken string `json:"secretToken"`
}
func (s *EnvServer) readInvitations() ([]invitation, error) {
r, err := s.repo.Reader("invitations")
if err != nil {
+ if errors.Is(err, fs.ErrNotExist) {
+ return make([]invitation, 0), nil
+ }
return nil, err
}
defer r.Close()
@@ -138,7 +146,7 @@
return s.repo.CommitAndPush("Generated new invitation")
}
-func (s *EnvServer) createEnv(w http.ResponseWriter, r *http.Request) {
+func extractRequest(r *http.Request) (createEnvReq, error) {
var req createEnvReq
if err := func() error {
var err error
@@ -154,31 +162,55 @@
if req.ContactEmail, err = getFormValue(r.PostForm, "contact-email"); err != nil {
return err
}
+ if req.AdminPublicKey, err = getFormValue(r.PostForm, "admin-public-key"); err != nil {
+ return err
+ }
return nil
}(); err != nil {
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
+ return createEnvReq{}, err
}
}
+ return req, nil
+}
+
+func (s *EnvServer) acceptInvitation(token string) error {
invitations, err := s.readInvitations()
if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
+ return err
}
found := false
- for _, i := range invitations {
- if i.Token == req.SecretToken && i.Status == StatusActive {
- i.Status = StatusAccepted
+ for i := range invitations {
+ if invitations[i].Token == token && invitations[i].Status == StatusActive {
+ invitations[i].Status = StatusAccepted
found = true
break
}
}
if !found {
- http.Error(w, "Invalid invitation", http.StatusNotFound)
+ return fmt.Errorf("Invitation not found")
+ }
+ return s.writeInvitations(invitations)
+}
+
+func (s *EnvServer) createEnv(w http.ResponseWriter, r *http.Request) {
+ req, err := extractRequest(r)
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
- if err := s.writeInvitations(invitations); err != nil {
+ var env installer.EnvConfig
+ cr, err := s.repo.Reader("config.yaml")
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ defer cr.Close()
+ if err := installer.ReadYaml(cr, &env); err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ if err := s.acceptInvitation(req.SecretToken); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
@@ -188,6 +220,74 @@
} else {
req.Name = name
}
+ appsRepo := installer.NewInMemoryAppRepository(installer.CreateAllApps())
+ ssApp, err := appsRepo.Find("soft-serve")
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ ssAdminKeys, err := installer.NewSSHKeyPair(fmt.Sprintf("%s-config-repo-admin-keys", req.Name))
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ ssKeys, err := installer.NewSSHKeyPair(fmt.Sprintf("%s-config-repo-keys", req.Name))
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ ssValues := map[string]any{
+ "ChartRepositoryNamespace": env.Name,
+ "ServiceType": "ClusterIP",
+ "PrivateKey": string(ssKeys.RawPrivateKey()),
+ "PublicKey": string(ssKeys.RawAuthorizedKey()),
+ "AdminKey": string(ssAdminKeys.RawAuthorizedKey()),
+ "Ingress": map[string]any{
+ "Enabled": false,
+ },
+ }
+ derived := installer.Derived{
+ Global: installer.Values{
+ Id: req.Name,
+ PCloudEnvName: env.Name,
+ },
+ Release: installer.Release{
+ Namespace: req.Name,
+ },
+ Values: ssValues,
+ }
+ if err := s.nsCreator.Create(req.Name); err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ if err := s.repo.InstallApp(*ssApp, filepath.Join("/environments", req.Name, "config-repo"), ssValues, derived); err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ k := installer.NewKustomization()
+ k.AddResources("config-repo")
+ if err := s.repo.WriteKustomization(filepath.Join("/environments", req.Name, "kustomization.yaml"), k); err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ ssClient, err := soft.WaitForClient(
+ fmt.Sprintf("soft-serve.%s.svc.cluster.local:%d", req.Name, 22),
+ ssAdminKeys.RawPrivateKey(),
+ log.Default())
+ if err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ if err := ssClient.AddPublicKey("admin", req.AdminPublicKey); err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ defer func() {
+ if err := ssClient.RemovePublicKey("admin", string(ssAdminKeys.RawAuthorizedKey())); err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ }()
fluxUserName := fmt.Sprintf("flux-%s", req.Name)
keys, err := installer.NewSSHKeyPair(fluxUserName)
if err != nil {
@@ -195,44 +295,42 @@
return
}
{
- readme := fmt.Sprintf("# %s PCloud environment", req.Name)
- if err := s.ss.AddRepository(req.Name, readme); err != nil {
+ if err := ssClient.AddRepository("config"); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
- if err := s.ss.AddUser(fluxUserName, keys.AuthorizedKey()); err != nil {
+ repo, err := ssClient.GetRepo("config")
+ if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
- if err := s.ss.AddCollaborator(req.Name, fluxUserName); err != nil {
+ repoIO := installer.NewRepoIO(repo, ssClient.Signer)
+ if err := repoIO.WriteCommitAndPush("README.md", fmt.Sprintf("# %s PCloud environment", req.Name), "readme"); err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ if err := ssClient.AddUser(fluxUserName, keys.AuthorizedKey()); err != nil {
+ http.Error(w, err.Error(), http.StatusInternalServerError)
+ return
+ }
+ if err := ssClient.AddReadOnlyCollaborator("config", fluxUserName); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
}
{
- repo, err := s.ss.GetRepo(req.Name)
+ repo, err := ssClient.GetRepo("config")
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
- var env installer.EnvConfig
- r, err := s.repo.Reader("config.yaml")
- if err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
- defer r.Close()
- if err := installer.ReadYaml(r, &env); err != nil {
- http.Error(w, err.Error(), http.StatusInternalServerError)
- return
- }
- if err := initNewEnv(s.ss, installer.NewRepoIO(repo, s.ss.Signer), s.nsCreator, req, env); err != nil {
+ if err := initNewEnv(ssClient, installer.NewRepoIO(repo, ssClient.Signer), s.nsCreator, req, env.Name, env.PublicIP); err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
}
}
{
- ssPubKey, err := s.ss.GetPublicKey()
+ ssPubKey, err := ssClient.GetPublicKey()
if err != nil {
http.Error(w, err.Error(), http.StatusInternalServerError)
return
@@ -240,6 +338,7 @@
if err := addNewEnv(
s.repo,
req,
+ strings.Split(ssClient.Addr, ":")[0],
keys,
ssPubKey,
); err != nil {
@@ -265,7 +364,8 @@
r installer.RepoIO,
nsCreator installer.NamespaceCreator,
req createEnvReq,
- env installer.EnvConfig,
+ pcloudEnvName string,
+ pcloudPublicIP string,
) error {
appManager, err := installer.NewAppManager(r, nsCreator)
if err != nil {
@@ -275,12 +375,12 @@
// TODO(giolekva): private domain can be configurable as well
config := installer.Config{
Values: installer.Values{
- PCloudEnvName: env.Name,
+ PCloudEnvName: pcloudEnvName,
Id: req.Name,
ContactEmail: req.ContactEmail,
Domain: req.Domain,
PrivateDomain: fmt.Sprintf("p.%s", req.Domain),
- PublicIP: env.PublicIP,
+ PublicIP: pcloudPublicIP,
NamespacePrefix: fmt.Sprintf("%s-", req.Name),
},
}
@@ -344,15 +444,6 @@
}); err != nil {
return err
}
- if err := appManager.Install(*app, nsGen, installer.NewSuffixGenerator("-soft-serve"), map[string]any{
- "Name": fmt.Sprintf("%s-soft-serve", req.Name), // TODO(giolekva): rename to config repo
- "From": "10.1.0.3",
- "To": "10.1.0.3",
- "AutoAssign": false,
- "Namespace": "metallb-system",
- }); err != nil {
- return err
- }
if err := appManager.Install(*app, nsGen, emptySuffixGen, map[string]any{
"Name": req.Name,
"From": "10.1.0.100",
@@ -412,7 +503,7 @@
if err := ss.AddUser(user, keys.AuthorizedKey()); err != nil {
return err
}
- if err := ss.AddCollaborator(req.Name, user); err != nil {
+ if err := ss.AddReadWriteCollaborator("config", user); err != nil {
return err
}
app, err := appsRepo.Find("welcome")
@@ -420,7 +511,7 @@
return err
}
if err := appManager.Install(*app, nsGen, emptySuffixGen, map[string]any{
- "RepoAddr": ss.GetRepoAddress(req.Name),
+ "RepoAddr": ss.GetRepoAddress("config"),
"SSHPrivateKey": string(keys.RawPrivateKey()),
}); err != nil {
return err
@@ -435,7 +526,7 @@
if err := ss.AddUser(user, keys.AuthorizedKey()); err != nil {
return err
}
- if err := ss.AddCollaborator(req.Name, user); err != nil {
+ if err := ss.AddReadWriteCollaborator("config", user); err != nil {
return err
}
app, err := appsRepo.Find("app-manager") // TODO(giolekva): configure
@@ -443,7 +534,7 @@
return err
}
if err := appManager.Install(*app, nsGen, emptySuffixGen, map[string]any{
- "RepoAddr": ss.GetRepoAddress(req.Name),
+ "RepoAddr": ss.GetRepoAddress("config"),
"SSHPrivateKey": string(keys.RawPrivateKey()),
}); err != nil {
return err
@@ -455,6 +546,7 @@
func addNewEnv(
repoIO installer.RepoIO,
req createEnvReq,
+ repoHost string,
keys *keygen.KeyPair,
pcloudRepoPublicKey []byte,
) error {
@@ -467,7 +559,6 @@
if err != nil {
return err
}
- repoIP := repoIO.Addr().Addr().String()
for _, tmpl := range tmpls.Templates() {
dstPath := path.Join("environments", req.Name, tmpl.Name())
dst, err := repoIO.Writer(dstPath)
@@ -479,8 +570,9 @@
"Name": req.Name,
"PrivateKey": base64.StdEncoding.EncodeToString(keys.RawPrivateKey()),
"PublicKey": base64.StdEncoding.EncodeToString(keys.RawAuthorizedKey()),
- "GitHost": repoIP,
- "KnownHosts": base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s %s", repoIP, pcloudRepoPublicKey))),
+ "RepoHost": repoHost,
+ "RepoName": "config",
+ "KnownHosts": base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s %s", repoHost, pcloudRepoPublicKey))),
}); err != nil {
return err
}