installer: fully automate initial bootstrap and env creation
diff --git a/core/installer/Dockerfile b/core/installer/Dockerfile
new file mode 100644
index 0000000..0b3f04b
--- /dev/null
+++ b/core/installer/Dockerfile
@@ -0,0 +1,8 @@
+FROM alpine:latest
+
+ARG TARGETARCH
+
+COPY tmp/charts /charts
+
+COPY server_${TARGETARCH} /usr/bin/pcloud-installer
+RUN chmod +x /usr/bin/pcloud-installer
diff --git a/core/installer/Makefile b/core/installer/Makefile
index d80fa92..2a3ed5b 100644
--- a/core/installer/Makefile
+++ b/core/installer/Makefile
@@ -1,20 +1,41 @@
-image_arm64:
- docker build --file=Dockerfile.flux --tag=giolekva/flux:latest . --platform=linux/arm64
+clean:
+ rm -rf tmp
+ rm -f server_*
+ rm -f pcloud
-push_arm64: image_arm64
+push_fluxcd_arm64:
+ docker build --file=Dockerfile.flux --tag=giolekva/flux:latest . --platform=linux/arm64
docker push giolekva/flux:latest
-build:
+build: clean
go build -o pcloud cmd/*.go
bootstrap:
- ./pcloud bootstrap --kubeconfig=../../priv/kubeconfig --charts-dir=../../charts --admin-pub-key=/Users/lekva/.ssh/id_rsa.pub --admin-priv-key=/Users/lekva/.ssh/id_rsa --soft-serve-ip=192.168.0.211 --storage-dir=/pcloud-storage/longhorn
+ ./pcloud bootstrap --kubeconfig=../../priv/kubeconfig --charts-dir=../../charts --admin-pub-key=/Users/lekva/.ssh/id_rsa.pub --soft-serve-ip=192.168.0.211 --storage-dir=/pcloud-storage/longhorn
create_env:
- ./pcloud create-env --admin-priv-key=/Users/lekva/.ssh/id_rsa --name=lekva --ip=192.168.0.211
+ ./pcloud create-env --admin-priv-key=/Users/lekva/.ssh/id_rsa --name=lekva --ip=192.168.0.211 --admin-username=gio
rpuppy:
./pcloud install --ssh-key=/Users/lekva/.ssh/id_rsa --app=rpuppy --repo-addr=ssh://localhost:2222/lekva
appmanager:
- ./pcloud appmanager --ssh-key=/Users/lekva/.ssh/id_rsa --repo-addr=ssh://localhost:2222/lekva
+ ./pcloud appmanager --ssh-key=/Users/lekva/.ssh/id_rsa --repo-addr=ssh://192.168.0.211/lekva --port=9090
+
+
+
+
+## installer image
+build_arm64: export CGO_ENABLED=0
+build_arm64: export GO111MODULE=on
+build_arm64: export GOOS=linux
+build_arm64: export GOARCH=arm64
+build_arm64:
+ go build -o server_arm64 cmd/*.go
+
+push: clean build_arm64
+ mkdir tmp
+ cp -r ../../charts tmp/
+ podman build --tag=giolekva/pcloud-installer:latest .
+ rm -rf tmp
+ podman push giolekva/pcloud-installer:latest
diff --git a/core/installer/app.go b/core/installer/app.go
index fbbcd64..96caf68 100644
--- a/core/installer/app.go
+++ b/core/installer/app.go
@@ -5,6 +5,8 @@
"fmt"
"log"
"text/template"
+
+ "github.com/Masterminds/sprig/v3"
)
//go:embed values-tmpl
@@ -46,12 +48,11 @@
}
func CreateAllApps() []App {
- tmpls, err := template.ParseFS(valuesTmpls, "values-tmpl/*")
+ tmpls, err := template.New("root").Funcs(template.FuncMap(sprig.FuncMap())).ParseFS(valuesTmpls, "values-tmpl/*")
if err != nil {
log.Fatal(err)
}
return []App{
- // CreateAppIngressPublic(tmpls),
CreateAppIngressPrivate(valuesTmpls, tmpls),
CreateAppCoreAuth(valuesTmpls, tmpls),
CreateAppVaultwarden(valuesTmpls, tmpls),
@@ -62,21 +63,16 @@
CreateAppJellyfin(valuesTmpls, tmpls),
CreateAppRpuppy(valuesTmpls, tmpls),
CreateAppHeadscale(valuesTmpls, tmpls),
- }
-}
-
-func CreateAppIngressPublic(fs embed.FS, tmpls *template.Template) App {
- schema, err := fs.ReadFile("values-tmpl/ingress-public.jsonschema")
- if err != nil {
- panic(err)
- }
- return App{
- "ingress-public",
- []*template.Template{
- tmpls.Lookup("ingress-public.yaml"),
- },
- string(schema),
- nil,
+ CreateAppTailscaleProxy(valuesTmpls, tmpls),
+ CreateMetallbConfigEnv(valuesTmpls, tmpls),
+ CreateEnvManager(valuesTmpls, tmpls),
+ CreateIngressPublic(valuesTmpls, tmpls),
+ CreateCertManager(valuesTmpls, tmpls),
+ CreateCertManagerWebhookGandi(valuesTmpls, tmpls),
+ CreateCertManagerWebhookGandiRole(valuesTmpls, tmpls),
+ CreateCSIDriverSMB(valuesTmpls, tmpls),
+ CreateResourceRendererController(valuesTmpls, tmpls),
+ CreateHeadscaleController(valuesTmpls, tmpls),
}
}
@@ -98,6 +94,21 @@
}
}
+func CreateCertificateIssuerPrivate(fs embed.FS, tmpls *template.Template) App {
+ schema, err := fs.ReadFile("values-tmpl/certificate-issuer-private.jsonschema")
+ if err != nil {
+ panic(err)
+ }
+ return App{
+ "ingress-private",
+ []*template.Template{
+ tmpls.Lookup("certificate-issuer-private.yaml"),
+ },
+ string(schema),
+ tmpls.Lookup("certificate-issuer-private.md"),
+ }
+}
+
func CreateAppCoreAuth(fs embed.FS, tmpls *template.Template) App {
schema, err := fs.ReadFile("values-tmpl/core-auth.jsonschema")
if err != nil {
@@ -234,3 +245,153 @@
tmpls.Lookup("headscale.md"),
}
}
+
+func CreateAppTailscaleProxy(fs embed.FS, tmpls *template.Template) App {
+ schema, err := fs.ReadFile("values-tmpl/tailscale-proxy.jsonschema")
+ if err != nil {
+ panic(err)
+ }
+ return App{
+ "tailscale-proxy",
+ []*template.Template{
+ tmpls.Lookup("tailscale-proxy.yaml"),
+ },
+ string(schema),
+ tmpls.Lookup("tailscale-proxy.md"),
+ }
+}
+
+func CreateMetallbConfigEnv(fs embed.FS, tmpls *template.Template) App {
+ schema, err := fs.ReadFile("values-tmpl/metallb-config-env.jsonschema")
+ if err != nil {
+ panic(err)
+ }
+ return App{
+ "metallb-config-env",
+ []*template.Template{
+ tmpls.Lookup("metallb-config-env.yaml"),
+ },
+ string(schema),
+ tmpls.Lookup("metallb-config-env.md"),
+ }
+}
+
+func CreateEnvManager(fs embed.FS, tmpls *template.Template) App {
+ schema, err := fs.ReadFile("values-tmpl/env-manager.jsonschema")
+ if err != nil {
+ panic(err)
+ }
+ return App{
+ "env-manager",
+ []*template.Template{
+ tmpls.Lookup("env-manager.yaml"),
+ },
+ string(schema),
+ tmpls.Lookup("env-manager.md"),
+ }
+}
+
+func CreateIngressPublic(fs embed.FS, tmpls *template.Template) App {
+ schema, err := fs.ReadFile("values-tmpl/ingress-public.jsonschema")
+ if err != nil {
+ panic(err)
+ }
+ return App{
+ "ingress-public",
+ []*template.Template{
+ tmpls.Lookup("ingress-public.yaml"),
+ },
+ string(schema),
+ tmpls.Lookup("ingress-public.md"),
+ }
+}
+
+func CreateCertManager(fs embed.FS, tmpls *template.Template) App {
+ schema, err := fs.ReadFile("values-tmpl/cert-manager.jsonschema")
+ if err != nil {
+ panic(err)
+ }
+ return App{
+ "cert-manager",
+ []*template.Template{
+ tmpls.Lookup("cert-manager.yaml"),
+ },
+ string(schema),
+ tmpls.Lookup("cert-manager.md"),
+ }
+}
+
+func CreateCertManagerWebhookGandi(fs embed.FS, tmpls *template.Template) App {
+ schema, err := fs.ReadFile("values-tmpl/cert-manager-webhook-gandi.jsonschema")
+ if err != nil {
+ panic(err)
+ }
+ return App{
+ "cert-manager-webhook-gandi",
+ []*template.Template{
+ tmpls.Lookup("cert-manager-webhook-gandi.yaml"),
+ },
+ string(schema),
+ tmpls.Lookup("cert-manager-webhook-gandi.md"),
+ }
+}
+
+func CreateCertManagerWebhookGandiRole(fs embed.FS, tmpls *template.Template) App {
+ schema, err := fs.ReadFile("values-tmpl/cert-manager-webhook-gandi-role.jsonschema")
+ if err != nil {
+ panic(err)
+ }
+ return App{
+ "cert-manager-webhook-gandi-role",
+ []*template.Template{
+ tmpls.Lookup("cert-manager-webhook-gandi-role.yaml"),
+ },
+ string(schema),
+ tmpls.Lookup("cert-manager-webhook-gandi-role.md"),
+ }
+}
+
+func CreateCSIDriverSMB(fs embed.FS, tmpls *template.Template) App {
+ schema, err := fs.ReadFile("values-tmpl/csi-driver-smb.jsonschema")
+ if err != nil {
+ panic(err)
+ }
+ return App{
+ "csi-driver-smb",
+ []*template.Template{
+ tmpls.Lookup("csi-driver-smb.yaml"),
+ },
+ string(schema),
+ tmpls.Lookup("csi-driver-smb.md"),
+ }
+}
+
+func CreateResourceRendererController(fs embed.FS, tmpls *template.Template) App {
+ schema, err := fs.ReadFile("values-tmpl/resource-renderer-controller.jsonschema")
+ if err != nil {
+ panic(err)
+ }
+ return App{
+ "resource-renderer-controller",
+ []*template.Template{
+ tmpls.Lookup("resource-renderer-controller.yaml"),
+ },
+ string(schema),
+ tmpls.Lookup("resource-renderer-controller.md"),
+ }
+}
+
+func CreateHeadscaleController(fs embed.FS, tmpls *template.Template) App {
+ schema, err := fs.ReadFile("values-tmpl/headscale-controller.jsonschema")
+ if err != nil {
+ panic(err)
+ }
+ return App{
+ "headscale-controller",
+ []*template.Template{
+ tmpls.Lookup("headscale-controller.yaml"),
+ },
+ string(schema),
+ tmpls.Lookup("headscale-controller.md"),
+ }
+}
diff --git a/core/installer/app_manager.go b/core/installer/app_manager.go
index 6bf0161..5c1822a 100644
--- a/core/installer/app_manager.go
+++ b/core/installer/app_manager.go
@@ -2,18 +2,8 @@
import (
"fmt"
- "io/fs"
"io/ioutil"
- "net"
- "time"
- "golang.org/x/crypto/ssh"
- "golang.org/x/exp/slices"
-
- "github.com/go-git/go-billy/v5/util"
- "github.com/go-git/go-git/v5"
- "github.com/go-git/go-git/v5/plumbing/object"
- gitssh "github.com/go-git/go-git/v5/plumbing/transport/ssh"
"sigs.k8s.io/yaml"
)
@@ -22,23 +12,17 @@
const kustomizationFileName = "kustomization.yaml"
type AppManager struct {
- repo *git.Repository
- signer ssh.Signer
+ repoIO RepoIO
}
-func NewAppManager(repo *git.Repository, signer ssh.Signer) (*AppManager, error) {
+func NewAppManager(repoIO RepoIO) (*AppManager, error) {
return &AppManager{
- repo,
- signer,
+ repoIO,
}, nil
}
func (m *AppManager) Config() (Config, error) {
- wt, err := m.repo.Worktree()
- if err != nil {
- return Config{}, err
- }
- configF, err := wt.Filesystem.Open(configFileName)
+ configF, err := m.repoIO.Reader(configFileName)
if err != nil {
return Config{}, err
}
@@ -51,11 +35,7 @@
}
func (m *AppManager) AppConfig(name string) (map[string]any, error) {
- wt, err := m.repo.Worktree()
- if err != nil {
- return nil, err
- }
- configF, err := wt.Filesystem.Open(wt.Filesystem.Join(appDirName, name, configFileName))
+ configF, err := m.repoIO.Reader(fmt.Sprintf("%s/%s/%s", appDirName, name, configFileName))
if err != nil {
return nil, err
}
@@ -70,17 +50,9 @@
}
func (m *AppManager) Install(app App, config map[string]any) error {
- if err := m.repo.Fetch(&git.FetchOptions{
- RemoteName: "origin",
- Auth: auth(m.signer),
- Force: true,
- }); err != nil {
- return err
- }
- wt, err := m.repo.Worktree()
- if err != nil {
- return err
- }
+ // if err := m.repoIO.Fetch(); err != nil {
+ // return err
+ // }
globalConfig, err := m.Config()
if err != nil {
return err
@@ -89,101 +61,5 @@
"Global": globalConfig.Values,
"Values": config,
}
- appsRoot, err := wt.Filesystem.Chroot(appDirName)
- if err != nil {
- return err
- }
- rootKustF, err := appsRoot.Open(kustomizationFileName)
- if err != nil {
- return err
- }
- defer rootKustF.Close()
- rootKust, err := ReadKustomization(rootKustF)
- if err != nil {
- return err
- }
- appRoot, err := appsRoot.Chroot(app.Name)
- if err != nil {
- return err
- }
- if err := util.RemoveAll(appRoot, app.Name); err != nil {
- return err
- }
- if err := appRoot.MkdirAll(app.Name, fs.ModePerm); err != nil {
- return nil
- }
- appKust := NewKustomization()
- for _, t := range app.Templates {
- out, err := appRoot.Create(t.Name())
- if err != nil {
- return err
- }
- defer out.Close()
- if err := t.Execute(out, all); err != nil {
- return err
- }
- appKust.AddResources(t.Name())
- }
- {
- out, err := appRoot.Create(configFileName)
- if err != nil {
- return err
- }
- defer out.Close()
- configBytes, err := yaml.Marshal(config)
- if err != nil {
- return err
- }
- if _, err := out.Write(configBytes); err != nil {
- return err
- }
- }
- appKustF, err := appRoot.Create(kustomizationFileName)
- if err != nil {
- return err
- }
- defer appKustF.Close()
- if err := appKust.Write(appKustF); err != nil {
- return err
- }
- if !slices.Contains(rootKust.Resources, app.Name) {
- rootKust.AddResources(app.Name)
- rootKustFW, err := appsRoot.Create(kustomizationFileName)
- if err != nil {
- return err
- }
- defer rootKustFW.Close()
- if err := rootKust.Write(rootKustFW); err != nil {
- return err
- }
- }
- // Commit and push
- if err := wt.AddGlob("*"); err != nil {
- return err
- }
- if _, err := wt.Commit(fmt.Sprintf("install: %s", app.Name), &git.CommitOptions{
- Author: &object.Signature{
- Name: "pcloud-appmanager",
- When: time.Now(),
- },
- }); err != nil {
- return err
- }
- return m.repo.Push(&git.PushOptions{
- RemoteName: "origin",
- Auth: auth(m.signer),
- })
-}
-
-func auth(signer ssh.Signer) *gitssh.PublicKeys {
- return &gitssh.PublicKeys{
- Signer: signer,
- HostKeyCallbackHelper: gitssh.HostKeyCallbackHelper{
- HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error {
- // TODO(giolekva): verify server public key
- // fmt.Printf("## %s || %s -- \n", serverPubKey, ssh.MarshalAuthorizedKey(key))
- return nil
- },
- },
- }
+ return m.repoIO.InstallApp(app, "apps", all)
}
diff --git a/core/installer/cmd/app_manager.go b/core/installer/cmd/app_manager.go
index b1e8135..9fd2045 100644
--- a/core/installer/cmd/app_manager.go
+++ b/core/installer/cmd/app_manager.go
@@ -63,7 +63,7 @@
if err != nil {
return err
}
- m, err := installer.NewAppManager(repo, signer)
+ m, err := installer.NewAppManager(installer.NewRepoIO(repo, signer))
if err != nil {
return err
}
diff --git a/core/installer/cmd/apps.go b/core/installer/cmd/apps.go
index baab5bf..9cfe955 100644
--- a/core/installer/cmd/apps.go
+++ b/core/installer/cmd/apps.go
@@ -60,10 +60,10 @@
if err != nil {
return err
}
- m, err := installer.NewAppManager(
+ m, err := installer.NewAppManager(installer.NewRepoIO(
repo,
signer,
- )
+ ))
if err != nil {
return err
}
diff --git a/core/installer/cmd/bootstrap.go b/core/installer/cmd/bootstrap.go
index e5f3f2b..135b6b4 100644
--- a/core/installer/cmd/bootstrap.go
+++ b/core/installer/cmd/bootstrap.go
@@ -1,6 +1,3 @@
-// TODO
-// * ns pcloud not found
-
package main
import (
@@ -22,12 +19,12 @@
)
var bootstrapFlags struct {
+ pcloudEnvName string
chartsDir string
adminPubKey string
- adminPrivKey string
storageDir string
volumeDefaultReplicaCount int
- softServeIP string
+ softServeIP string // TODO(giolekva): reserve using metallb IPAddressPool
}
func bootstrapCmd() *cobra.Command {
@@ -36,6 +33,12 @@
RunE: bootstrapCmdRun,
}
cmd.Flags().StringVar(
+ &bootstrapFlags.pcloudEnvName,
+ "pcloud-env-name",
+ "pcloud",
+ "",
+ )
+ cmd.Flags().StringVar(
&bootstrapFlags.chartsDir,
"charts-dir",
"",
@@ -48,12 +51,6 @@
"",
)
cmd.Flags().StringVar(
- &bootstrapFlags.adminPrivKey,
- "admin-priv-key",
- "",
- "",
- )
- cmd.Flags().StringVar(
&bootstrapFlags.storageDir,
"storage-dir",
"",
@@ -75,73 +72,68 @@
}
func bootstrapCmdRun(cmd *cobra.Command, args []string) error {
- adminPubKey, adminPrivKey, err := readAdminKeys()
+ adminPubKey, err := os.ReadFile(bootstrapFlags.adminPubKey)
if err != nil {
return err
}
- softServePub, softServePriv, err := installer.GenerateSSHKeys()
+ bootstrapJobKeys, err := installer.NewSSHKeyPair()
if err != nil {
return err
}
- if err := installMetallbNamespace(); err != nil {
- return err
- }
if err := installMetallb(); err != nil {
return err
}
- time.Sleep(1 * time.Minute)
- if err := installMetallbConfig(); err != nil {
- return err
- }
if err := installLonghorn(); err != nil {
return err
}
- time.Sleep(2 * time.Minute)
- if err := installSoftServe(softServePub, softServePriv, string(adminPubKey)); err != nil {
+ time.Sleep(5 * time.Minute) // TODO(giolekva): implement proper wait
+ if err := installSoftServe(bootstrapJobKeys.Public); err != nil {
return err
}
- time.Sleep(2 * time.Minute)
- ss, err := soft.NewClient(bootstrapFlags.softServeIP, 22, adminPrivKey, log.Default())
+ time.Sleep(2 * time.Minute) // TODO(giolekva): implement proper wait
+ ss, err := soft.NewClient(bootstrapFlags.softServeIP, 22, []byte(bootstrapJobKeys.Private), log.Default())
if err != nil {
return err
}
- fluxPub, fluxPriv, err := installer.GenerateSSHKeys()
+ if ss.AddPublicKey("admin", string(adminPubKey)); err != nil {
+ return err
+ }
+ if err := installFluxcd(ss, bootstrapFlags.pcloudEnvName); err != nil {
+ return err
+ }
+ repo, err := ss.GetRepo(bootstrapFlags.pcloudEnvName)
if err != nil {
return err
}
- if err := ss.AddUser("flux", fluxPub); err != nil {
+ repoIO := installer.NewRepoIO(repo, ss.Signer)
+ if err := configurePCloudRepo(repoIO); err != nil {
return err
}
- if err := ss.MakeUserAdmin("flux"); err != nil {
+ // TODO(giolekva): commit this to the repo above
+ global := map[string]any{
+ "PCloudEnvName": bootstrapFlags.pcloudEnvName,
+ }
+ if err := installInfrastructureServices(repoIO, global); err != nil {
return err
}
- fmt.Println("Creating /pcloud repo")
- if err := ss.AddRepository("pcloud", "# PCloud Systems"); err != nil {
+ if err := installEnvManager(ss, repoIO, global); err != nil {
return err
}
- fmt.Println("Installing Flux")
- if err := installFlux("ssh://soft-serve.pcloud.svc.cluster.local:22/pcloud", "soft-serve.pcloud.svc.cluster.local", softServePub, fluxPriv); err != nil {
+ if ss.RemovePublicKey("admin", bootstrapJobKeys.Public); err != nil {
return err
}
- pcloudRepo, err := ss.GetRepo("pcloud") // TODO(giolekva): configurable
- if err != nil {
+
+ return nil
+}
+
+func installMetallb() error {
+ if err := installMetallbNamespace(); err != nil {
return err
}
- if err := configurePCloudRepo(installer.NewRepoIO(pcloudRepo, ss.Signer)); err != nil {
+ if err := installMetallbService(); err != nil {
return err
}
- // TODO(giolekva): everything below must be installed using Flux
- if err := installIngressPublic(); err != nil {
- return err
- }
- if err := installCertManager(); err != nil {
- return err
- }
- if err := installCertManagerWebhookGandi(); err != nil {
- return err
- }
- // TODO(giolekva): ideally should be installed automatically if any of the user installed apps requires it
- if err := installSmbDriver(); err != nil {
+ if err := installMetallbConfig(); err != nil {
return err
}
return nil
@@ -150,7 +142,7 @@
func installMetallbNamespace() error {
fmt.Println("Installing metallb namespace")
// config, err := createActionConfig("default")
- config, err := createActionConfig("pcloud")
+ config, err := createActionConfig(bootstrapFlags.pcloudEnvName)
if err != nil {
return err
}
@@ -168,7 +160,7 @@
},
}
installer := action.NewInstall(config)
- installer.Namespace = "pcloud"
+ installer.Namespace = bootstrapFlags.pcloudEnvName
installer.ReleaseName = "metallb-ns"
installer.Wait = true
installer.WaitForJobs = true
@@ -178,7 +170,7 @@
return nil
}
-func installMetallb() error {
+func installMetallbService() error {
fmt.Println("Installing metallb")
// config, err := createActionConfig("default")
config, err := createActionConfig("metallb-system")
@@ -251,7 +243,7 @@
func installLonghorn() error {
fmt.Println("Installing Longhorn")
- config, err := createActionConfig("pcloud")
+ config, err := createActionConfig(bootstrapFlags.pcloudEnvName)
if err != nil {
return err
}
@@ -288,9 +280,13 @@
return nil
}
-func installSoftServe(pubKey, privKey, adminKey string) error {
+func installSoftServe(adminPublicKey string) error {
fmt.Println("Installing SoftServe")
- config, err := createActionConfig("pcloud")
+ keys, err := installer.NewSSHKeyPair()
+ if err != nil {
+ return err
+ }
+ config, err := createActionConfig(bootstrapFlags.pcloudEnvName)
if err != nil {
return err
}
@@ -299,13 +295,13 @@
return err
}
values := map[string]interface{}{
- "privateKey": privKey,
- "publicKey": pubKey,
- "adminKey": adminKey,
+ "privateKey": keys.Private,
+ "publicKey": keys.Public,
+ "adminKey": adminPublicKey,
"reservedIP": bootstrapFlags.softServeIP,
}
installer := action.NewInstall(config)
- installer.Namespace = "pcloud"
+ installer.Namespace = bootstrapFlags.pcloudEnvName
installer.CreateNamespace = true
installer.ReleaseName = "soft-serve"
installer.Wait = true
@@ -317,8 +313,39 @@
return nil
}
-func installFlux(repoAddr, repoHost, repoHostPubKey, privateKey string) error {
- config, err := createActionConfig("pcloud")
+func installFluxcd(ss *soft.Client, pcloudEnvName string) error {
+ keys, err := installer.NewSSHKeyPair()
+ if err != nil {
+ return err
+ }
+ if err := ss.AddUser("flux", keys.Public); err != nil {
+ return err
+ }
+ if err := ss.MakeUserAdmin("flux"); err != nil {
+ return err
+ }
+ fmt.Printf("Creating /%s repo", pcloudEnvName)
+ if err := ss.AddRepository(pcloudEnvName, "# PCloud Systems"); err != nil {
+ return err
+ }
+ fmt.Println("Installing Flux")
+ ssPublic, err := ss.GetPublicKey()
+ if err != nil {
+ return err
+ }
+ if err := installFluxBootstrap(
+ ss.GetRepoAddress(pcloudEnvName),
+ ss.IP,
+ string(ssPublic),
+ keys.Private,
+ ); err != nil {
+ return err
+ }
+ return nil
+}
+
+func installFluxBootstrap(repoAddr, repoHost, repoHostPubKey, privateKey string) error {
+ config, err := createActionConfig(bootstrapFlags.pcloudEnvName)
if err != nil {
return err
}
@@ -333,7 +360,7 @@
"privateKey": privateKey,
}
installer := action.NewInstall(config)
- installer.Namespace = "pcloud"
+ installer.Namespace = bootstrapFlags.pcloudEnvName
installer.CreateNamespace = true
installer.ReleaseName = "flux"
installer.Wait = true
@@ -345,150 +372,103 @@
return nil
}
-func installIngressPublic() error {
- config, err := createActionConfig("pcloud")
- if err != nil {
- return err
+func installInfrastructureServices(repo installer.RepoIO, global map[string]any) error {
+ values := map[string]any{
+ "Global": global,
}
- chart, err := loader.Load(filepath.Join(bootstrapFlags.chartsDir, "ingress-nginx"))
- if err != nil {
- return err
+ appRepo := installer.NewInMemoryAppRepository(installer.CreateAllApps())
+ install := func(name string) error {
+ app, err := appRepo.Find(name)
+ if err != nil {
+ return err
+ }
+ return repo.InstallApp(*app, "infrastructure", values)
}
- values := map[string]interface{}{
- "fullnameOverride": "pcloud-ingress-public",
- "controller": map[string]interface{}{
- "service": map[string]interface{}{
- "type": "LoadBalancer",
- },
- "ingressClassByName": true,
- "ingressClassResource": map[string]interface{}{
- "name": "pcloud-ingress-public",
- "enabled": true,
- "default": false,
- "controllerValue": "k8s.io/pcloud-ingress-public",
- },
- "config": map[string]interface{}{
- "proxy-body-size": "100M",
- },
- },
- "udp": map[string]interface{}{
- "6881": "lekva-app-qbittorrent/torrent:6881",
- },
- "tcp": map[string]interface{}{
- "6881": "lekva-app-qbittorrent/torrent:6881",
- },
+ appsToInstall := []string{
+ "resource-renderer-controller",
+ "headscale-controller",
+ "csi-driver-smb",
+ "ingress-public",
+ "cert-manager",
+ "cert-manager-webhook-gandi",
+ "cert-manager-webhook-gandi-role",
}
- installer := action.NewInstall(config)
- installer.Namespace = "pcloud-ingress-public"
- installer.CreateNamespace = true
- installer.ReleaseName = "ingress-public"
- installer.Wait = true
- installer.WaitForJobs = true
- installer.Timeout = 20 * time.Minute
- if _, err := installer.RunWithContext(context.TODO(), chart, values); err != nil {
- return err
- }
- return nil
-}
-
-func installCertManager() error {
- config, err := createActionConfig("pcloud-cert-manager")
- if err != nil {
- return err
- }
- chart, err := loader.Load(filepath.Join(bootstrapFlags.chartsDir, "cert-manager"))
- if err != nil {
- return err
- }
- values := map[string]interface{}{
- "fullnameOverride": "pcloud-cert-manager",
- "installCRDs": true,
- "image": map[string]interface{}{
- "tag": "v1.11.1",
- "pullPolicy": "IfNotPresent",
- },
- }
- installer := action.NewInstall(config)
- installer.Namespace = "pcloud-cert-manager"
- installer.CreateNamespace = true
- installer.ReleaseName = "cert-manager"
- installer.Wait = true
- installer.WaitForJobs = true
- installer.Timeout = 20 * time.Minute
- if _, err := installer.RunWithContext(context.TODO(), chart, values); err != nil {
- return err
- }
- return nil
-}
-
-func installCertManagerWebhookGandi() error {
- config, err := createActionConfig("pcloud-cert-manager")
- if err != nil {
- return err
- }
- chart, err := loader.Load(filepath.Join(bootstrapFlags.chartsDir, "cert-manager-webhook-gandi"))
- if err != nil {
- return err
- }
- values := map[string]interface{}{
- "fullnameOverride": "pcloud-cert-manager-webhook-gandi",
- "certManager": map[string]interface{}{
- "namespace": "pcloud-cert-manager",
- "serviceAccountName": "pcloud-cert-manager",
- },
- "image": map[string]interface{}{
- "repository": "giolekva/cert-manager-webhook-gandi",
- "tag": "v0.2.0",
- "pullPolicy": "IfNotPresent",
- },
- "logLevel": 2,
- }
- installer := action.NewInstall(config)
- installer.Namespace = "pcloud-cert-manager"
- installer.CreateNamespace = false
- installer.ReleaseName = "cert-manager-webhook-gandi"
- installer.Wait = true
- installer.WaitForJobs = true
- installer.Timeout = 20 * time.Minute
- if _, err := installer.RunWithContext(context.TODO(), chart, values); err != nil {
- return err
- }
- return nil
-}
-
-func installSmbDriver() error {
- config, err := createActionConfig("pcloud-csi-driver-smb")
- if err != nil {
- return err
- }
- chart, err := loader.Load(filepath.Join(bootstrapFlags.chartsDir, "csi-driver-smb"))
- if err != nil {
- return err
- }
- values := map[string]interface{}{}
- installer := action.NewInstall(config)
- installer.Namespace = "pcloud-csi-driver-smb"
- installer.CreateNamespace = true
- installer.ReleaseName = "csi-driver-smb"
- installer.Wait = true
- installer.WaitForJobs = true
- installer.Timeout = 20 * time.Minute
- if _, err := installer.RunWithContext(context.TODO(), chart, values); err != nil {
- return err
+ for _, name := range appsToInstall {
+ if err := install(name); err != nil {
+ return err
+ }
}
return nil
}
func configurePCloudRepo(repo installer.RepoIO) error {
- kust := installer.NewKustomization()
- kust.AddResources("pcloud-flux", "environments")
- if err := repo.WriteKustomization("kustomization.yaml", kust); err != nil {
+ {
+ kust := installer.NewKustomization()
+ kust.AddResources("pcloud-flux", "infrastructure", "environments")
+ if err := repo.WriteKustomization("kustomization.yaml", kust); err != nil {
+ return err
+ }
+ {
+ out, err := repo.Writer("infrastructure/pcloud-charts.yaml")
+ if err != nil {
+ return err
+ }
+ defer out.Close()
+ _, err = out.Write([]byte(`
+apiVersion: source.toolkit.fluxcd.io/v1beta2
+kind: GitRepository
+metadata:
+ name: pcloud # TODO(giolekva): use more generic name
+ namespace: pcloud # TODO(giolekva): configurable
+spec:
+ interval: 1m0s
+ url: https://github.com/giolekva/pcloud
+ ref:
+ branch: main
+`))
+ if err != nil {
+ return err
+ }
+ }
+ infraKust := installer.NewKustomization()
+ infraKust.AddResources("pcloud-charts.yaml")
+ if err := repo.WriteKustomization("infrastructure/kustomization.yaml", infraKust); err != nil {
+ return err
+ }
+ if err := repo.WriteKustomization("environments/kustomization.yaml", installer.NewKustomization()); err != nil {
+ return err
+ }
+ if err := repo.CommitAndPush("initialize pcloud directory structure"); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func installEnvManager(ss *soft.Client, repo installer.RepoIO, global map[string]any) error {
+ keys, err := installer.NewSSHKeyPair()
+ if err != nil {
return err
}
- if err := repo.WriteKustomization("environments/kustomization.yaml", installer.NewKustomization()); err != nil {
+ user := fmt.Sprintf("%s-env-manager", bootstrapFlags.pcloudEnvName)
+ if err := ss.AddUser(user, keys.Public); err != nil {
return err
}
- return repo.CommitAndPush("initialize pcloud directory structure, environments with kustomization.yaml-s")
+ if err := ss.MakeUserAdmin(user); err != nil {
+ return err
+ }
+ appRepo := installer.NewInMemoryAppRepository(installer.CreateAllApps())
+ envManager, err := appRepo.Find("env-manager")
+ if err != nil {
+ return err
+ }
+ return repo.InstallApp(*envManager, "infrastructure", map[string]any{
+ "Global": global,
+ "Values": map[string]any{
+ "RepoIP": bootstrapFlags.softServeIP,
+ "SSHPrivateKey": keys.Private,
+ },
+ })
}
func createActionConfig(namespace string) (*action.Configuration, error) {
@@ -506,15 +486,3 @@
}
return config, nil
}
-
-func readAdminKeys() ([]byte, []byte, error) {
- pubKey, err := os.ReadFile(bootstrapFlags.adminPubKey)
- if err != nil {
- return nil, nil, err
- }
- privKey, err := os.ReadFile(bootstrapFlags.adminPrivKey)
- if err != nil {
- return nil, nil, err
- }
- return pubKey, privKey, nil
-}
diff --git a/core/installer/cmd/env.go b/core/installer/cmd/env.go
index 8b7dc1e..045b258 100644
--- a/core/installer/cmd/env.go
+++ b/core/installer/cmd/env.go
@@ -7,6 +7,7 @@
"embed"
"encoding/base64"
"fmt"
+ "github.com/spf13/cobra"
"log"
"os"
"path"
@@ -14,17 +15,17 @@
"github.com/giolekva/pcloud/core/installer"
"github.com/giolekva/pcloud/core/installer/soft"
- "github.com/spf13/cobra"
)
//go:embed env-tmpl
var filesTmpls embed.FS
var createEnvFlags struct {
- name string
- ip string
- port int
- adminPrivKey string
+ name string
+ ip string
+ port int
+ adminPrivKey string
+ adminUsername string
}
func createEnvCmd() *cobra.Command {
@@ -56,6 +57,12 @@
"",
"",
)
+ cmd.Flags().StringVar(
+ &createEnvFlags.adminUsername,
+ "admin-username",
+ "",
+ "",
+ )
return cmd
}
@@ -72,61 +79,190 @@
if err != nil {
return err
}
- fmt.Println(string(ssPubKey))
- pub, priv, err := installer.GenerateSSHKeys()
- {
- _ = priv
- }
+ keys, err := installer.NewSSHKeyPair()
if err != nil {
return err
}
- readme := fmt.Sprintf("# %s PCloud environment", createEnvFlags.name)
- if err := ss.AddRepository(createEnvFlags.name, readme); err != nil {
+ if 1 == 2 {
+ readme := fmt.Sprintf("# %s PCloud environment", createEnvFlags.name)
+ if err := ss.AddRepository(createEnvFlags.name, readme); err != nil {
+ return err
+ }
+ fluxUserName := fmt.Sprintf("flux-%s", createEnvFlags.name)
+ if err := ss.AddUser(fluxUserName, keys.Public); err != nil {
+ return err
+ }
+ if err := ss.AddCollaborator(createEnvFlags.name, fluxUserName); err != nil {
+ return err
+ }
+ }
+ envRepo, err := ss.GetRepo(createEnvFlags.name)
+ if envRepo == nil {
return err
}
- fluxUserName := fmt.Sprintf("flux-%s", createEnvFlags.name)
- if err := ss.AddUser(fluxUserName, pub); err != nil {
+ if err := initEnvRepo(installer.NewRepoIO(envRepo, ss.Signer)); err != nil {
return err
}
- if err := ss.AddCollaborator(createEnvFlags.name, fluxUserName); err != nil {
- return err
- }
- repo, err := ss.GetRepo("pcloud")
- if err != nil {
- return err
- }
- repoIO := installer.NewRepoIO(repo, ss.Signer)
- kust, err := repoIO.ReadKustomization("environments/kustomization.yaml")
- if err != nil {
- return err
- }
- kust.AddResources(createEnvFlags.name)
- tmpls, err := template.ParseFS(filesTmpls, "env-tmpl/*.yaml")
- if err != nil {
- return err
- }
- for _, tmpl := range tmpls.Templates() {
- dstPath := path.Join("environments", createEnvFlags.name, tmpl.Name())
- dst, err := repoIO.Writer(dstPath)
+ if 1 == 2 {
+ repo, err := ss.GetRepo("pcloud")
if err != nil {
return err
}
- defer dst.Close()
- if err := tmpl.Execute(dst, map[string]string{
- "Name": createEnvFlags.name,
- "PrivateKey": base64.StdEncoding.EncodeToString([]byte(priv)),
- "PublicKey": base64.StdEncoding.EncodeToString([]byte(pub)),
- "GitHost": createEnvFlags.ip,
- "KnownHosts": base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s %s", createEnvFlags.ip, ssPubKey))),
+ repoIO := installer.NewRepoIO(repo, ss.Signer)
+ kust, err := repoIO.ReadKustomization("environments/kustomization.yaml")
+ if err != nil {
+ return err
+ }
+ kust.AddResources(createEnvFlags.name)
+ tmpls, err := template.ParseFS(filesTmpls, "env-tmpl/*.yaml")
+ if err != nil {
+ return err
+ }
+ for _, tmpl := range tmpls.Templates() {
+ dstPath := path.Join("environments", createEnvFlags.name, tmpl.Name())
+ dst, err := repoIO.Writer(dstPath)
+ if err != nil {
+ return err
+ }
+ defer dst.Close()
+ if err := tmpl.Execute(dst, map[string]string{
+ "Name": createEnvFlags.name,
+ "PrivateKey": base64.StdEncoding.EncodeToString([]byte(keys.Private)),
+ "PublicKey": base64.StdEncoding.EncodeToString([]byte(keys.Public)),
+ "GitHost": createEnvFlags.ip,
+ "KnownHosts": base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s %s", createEnvFlags.ip, ssPubKey))),
+ }); err != nil {
+ return err
+ }
+ }
+ if err := repoIO.WriteKustomization("environments/kustomization.yaml", *kust); err != nil {
+ return err
+ }
+ if err := repoIO.CommitAndPush(fmt.Sprintf("%s: initialize environment", createEnvFlags.name)); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func initEnvRepo(r installer.RepoIO) error {
+ appManager, err := installer.NewAppManager(r)
+ if err != nil {
+ return err
+ }
+ appsRepo := installer.NewInMemoryAppRepository(installer.CreateAllApps())
+ if 1 == 2 {
+ config := installer.Config{ // TODO(gioleka): configurable
+ Values: installer.Values{
+ PCloudEnvName: "pcloud",
+ Id: "lekva",
+ ContactEmail: "giolekva@gmail.com",
+ Domain: "lekva.me",
+ PrivateDomain: "p.lekva.me",
+ PublicIP: "46.49.35.44",
+ NamespacePrefix: "lekva-",
+ },
+ }
+ if err := r.WriteYaml("config.yaml", config); err != nil {
+ return err
+ }
+ {
+ out, err := r.Writer("pcloud-charts.yaml")
+ if err != nil {
+ return err
+ }
+ defer out.Close()
+ _, err = out.Write([]byte(`
+apiVersion: source.toolkit.fluxcd.io/v1beta2
+kind: GitRepository
+metadata:
+ name: pcloud
+ namespace: lekva
+spec:
+ interval: 1m0s
+ url: https://github.com/giolekva/pcloud
+ ref:
+ branch: main
+`))
+ if err != nil {
+ return err
+ }
+ }
+ rootKust := installer.NewKustomization()
+ rootKust.AddResources("pcloud-charts.yaml", "apps")
+ if err := r.WriteKustomization("kustomization.yaml", rootKust); err != nil {
+ return err
+ }
+ appsKust := installer.NewKustomization()
+ if err := r.WriteKustomization("apps/kustomization.yaml", appsKust); err != nil {
+ return err
+ }
+ r.CommitAndPush("initialize config")
+ {
+ app, err := appsRepo.Find("metallb-config-env")
+ if err != nil {
+ return err
+ }
+ if err := appManager.Install(*app, map[string]any{
+ "IngressPrivate": "10.1.0.1",
+ "Headscale": "10.1.0.2",
+ "SoftServe": "10.1.0.3",
+ "Rest": map[string]any{
+ "From": "10.1.0.100",
+ "To": "10.1.0.255",
+ },
+ }); err != nil {
+ return err
+ }
+ }
+ {
+ app, err := appsRepo.Find("ingress-private")
+ if err != nil {
+ return err
+ }
+ if err := appManager.Install(*app, map[string]any{
+ "GandiAPIToken": "", // TODO(gioleka): configurable
+ }); err != nil {
+ return err
+ }
+ }
+ {
+ app, err := appsRepo.Find("core-auth")
+ if err != nil {
+ return err
+ }
+ if err := appManager.Install(*app, map[string]any{
+ "Subdomain": "test", // TODO(giolekva): make core-auth chart actually use this
+ }); err != nil {
+ return err
+ }
+ }
+ }
+ {
+ app, err := appsRepo.Find("headscale")
+ if err != nil {
+ return err
+ }
+ if err := appManager.Install(*app, map[string]any{
+ "Subdomain": "headscale",
}); err != nil {
return err
}
}
- if err := repoIO.WriteKustomization("environments/kustomization.yaml", *kust); err != nil {
- return err
- }
- if err := repoIO.CommitAndPush(fmt.Sprintf("%s: initialize environment", createEnvFlags.name)); err != nil {
- return err
+ if 1 == 2 {
+ {
+ app, err := appsRepo.Find("tailscale-proxy")
+ if err != nil {
+ return err
+ }
+ if err := appManager.Install(*app, map[string]any{
+ "Username": createEnvFlags.adminUsername,
+ "IPSubnet": "10.1.0.0/24",
+ }); err != nil {
+ return err
+ }
+ // TODO(giolekva): headscale accept routes
+ }
}
return nil
}
diff --git a/core/installer/cmd/env_manager.go b/core/installer/cmd/env_manager.go
new file mode 100644
index 0000000..4279445
--- /dev/null
+++ b/core/installer/cmd/env_manager.go
@@ -0,0 +1,323 @@
+package main
+
+import (
+ "encoding/base64"
+ "encoding/json"
+ "fmt"
+ "log"
+ "os"
+ "path"
+ "text/template"
+
+ "github.com/labstack/echo/v4"
+ "github.com/spf13/cobra"
+
+ "github.com/giolekva/pcloud/core/installer"
+ "github.com/giolekva/pcloud/core/installer/soft"
+)
+
+var envManagerFlags struct {
+ repoIP string
+ repoPort int
+ sshKey string
+ port int
+}
+
+func envManagerCmd() *cobra.Command {
+ cmd := &cobra.Command{
+ Use: "envmanager",
+ RunE: envManagerCmdRun,
+ }
+ cmd.Flags().StringVar(
+ &envManagerFlags.repoIP,
+ "repo-ip",
+ "",
+ "",
+ )
+ cmd.Flags().IntVar(
+ &envManagerFlags.repoPort,
+ "repo-port",
+ 22,
+ "",
+ )
+ cmd.Flags().StringVar(
+ &envManagerFlags.sshKey,
+ "ssh-key",
+ "",
+ "",
+ )
+ cmd.Flags().IntVar(
+ &envManagerFlags.port,
+ "port",
+ 8080,
+ "",
+ )
+ return cmd
+}
+
+func envManagerCmdRun(cmd *cobra.Command, args []string) error {
+ sshKey, err := os.ReadFile(envManagerFlags.sshKey)
+ if err != nil {
+ return err
+ }
+ fmt.Println(string(sshKey))
+ ss, err := soft.NewClient(envManagerFlags.repoIP, envManagerFlags.repoPort, sshKey, log.Default())
+ if err != nil {
+ return err
+ }
+ b, err := ss.GetPublicKey()
+ if err != nil {
+ return err
+ }
+ fmt.Println(string(b))
+ fmt.Println(111)
+ repo, err := ss.GetRepo("pcloud")
+ fmt.Println(222)
+ if err != nil {
+ return err
+ }
+ fmt.Println(333)
+ repoIO := installer.NewRepoIO(repo, ss.Signer)
+ s := &envServer{
+ port: envManagerFlags.port,
+ ss: ss,
+ repo: repoIO,
+ }
+ s.start()
+ return nil
+}
+
+type envServer struct {
+ port int
+ ss *soft.Client
+ repo installer.RepoIO
+}
+
+func (s *envServer) start() {
+ e := echo.New()
+ e.POST("/env", s.createEnv)
+ log.Fatal(e.Start(fmt.Sprintf(":%d", s.port)))
+}
+
+type createEnvReq struct {
+ Name string `json:"name"`
+ ContactEmail string `json:"contactEmail"`
+ Domain string `json:"domain"`
+ GandiAPIToken string `json:"gandiAPIToken"`
+ AdminUsername string `json:"adminUsername"`
+ // TODO(giolekva): take admin password as well
+}
+
+func (s *envServer) createEnv(c echo.Context) error {
+ var req createEnvReq
+ if err := json.NewDecoder(c.Request().Body).Decode(&req); err != nil {
+ return err
+ }
+ keys, err := installer.NewSSHKeyPair()
+ if err != nil {
+ return err
+ }
+ {
+ readme := fmt.Sprintf("# %s PCloud environment", req.Name)
+ if err := s.ss.AddRepository(req.Name, readme); err != nil {
+ return err
+ }
+ fluxUserName := fmt.Sprintf("flux-%s", req.Name)
+ if err := s.ss.AddUser(fluxUserName, keys.Public); err != nil {
+ return err
+ }
+ if err := s.ss.AddCollaborator(req.Name, fluxUserName); err != nil {
+ return err
+ }
+ }
+ {
+ repo, err := s.ss.GetRepo(req.Name)
+ if repo == nil {
+ return err
+ }
+ if err := initNewEnv(installer.NewRepoIO(repo, s.ss.Signer), req); err != nil {
+ return err
+ }
+ }
+ {
+ repo, err := s.ss.GetRepo("pcloud")
+ if err != nil {
+ return err
+ }
+ ssPubKey, err := s.ss.GetPublicKey()
+ if err != nil {
+ return err
+ }
+ if err := addNewEnv(
+ installer.NewRepoIO(repo, s.ss.Signer),
+ req,
+ keys,
+ ssPubKey,
+ ); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func initNewEnv(r installer.RepoIO, req createEnvReq) error {
+ appManager, err := installer.NewAppManager(r)
+ if err != nil {
+ return err
+ }
+ appsRepo := installer.NewInMemoryAppRepository(installer.CreateAllApps())
+ // TODO(giolekva): env name and ip should come from pcloud repo config.yaml
+ // TODO(giolekva): private domain can be configurable as well
+ config := installer.Config{
+ Values: installer.Values{
+ PCloudEnvName: "pcloud",
+ Id: req.Name,
+ ContactEmail: req.ContactEmail,
+ Domain: req.Domain,
+ PrivateDomain: fmt.Sprintf("p.%s", req.Domain),
+ PublicIP: "46.49.35.44",
+ NamespacePrefix: fmt.Sprintf("%s-", req.Name),
+ },
+ }
+ if err := r.WriteYaml("config.yaml", config); err != nil {
+ return err
+ }
+ {
+ out, err := r.Writer("pcloud-charts.yaml")
+ if err != nil {
+ return err
+ }
+ defer out.Close()
+ _, err = out.Write([]byte(`
+apiVersion: source.toolkit.fluxcd.io/v1beta2
+kind: GitRepository
+metadata:
+ name: pcloud
+ namespace: lekva
+spec:
+ interval: 1m0s
+ url: https://github.com/giolekva/pcloud
+ ref:
+ branch: main
+`))
+ if err != nil {
+ return err
+ }
+ }
+ rootKust := installer.NewKustomization()
+ rootKust.AddResources("pcloud-charts.yaml", "apps")
+ if err := r.WriteKustomization("kustomization.yaml", rootKust); err != nil {
+ return err
+ }
+ appsKust := installer.NewKustomization()
+ if err := r.WriteKustomization("apps/kustomization.yaml", appsKust); err != nil {
+ return err
+ }
+ r.CommitAndPush("initialize config")
+ {
+ app, err := appsRepo.Find("metallb-config-env")
+ if err != nil {
+ return err
+ }
+ if err := appManager.Install(*app, map[string]any{
+ "IngressPrivate": "10.1.0.1",
+ "Headscale": "10.1.0.2",
+ "SoftServe": "10.1.0.3",
+ "Rest": map[string]any{
+ "From": "10.1.0.100",
+ "To": "10.1.0.255",
+ },
+ }); err != nil {
+ return err
+ }
+ }
+ {
+ app, err := appsRepo.Find("ingress-private")
+ if err != nil {
+ return err
+ }
+ if err := appManager.Install(*app, map[string]any{
+ "GandiAPIToken": req.GandiAPIToken,
+ }); err != nil {
+ return err
+ }
+ }
+ {
+ app, err := appsRepo.Find("core-auth")
+ if err != nil {
+ return err
+ }
+ if err := appManager.Install(*app, map[string]any{
+ "Subdomain": "test", // TODO(giolekva): make core-auth chart actually use this
+ }); err != nil {
+ return err
+ }
+ }
+ {
+ app, err := appsRepo.Find("headscale")
+ if err != nil {
+ return err
+ }
+ if err := appManager.Install(*app, map[string]any{
+ "Subdomain": "headscale",
+ }); err != nil {
+ return err
+ }
+ }
+ {
+ app, err := appsRepo.Find("tailscale-proxy")
+ if err != nil {
+ return err
+ }
+ if err := appManager.Install(*app, map[string]any{
+ "Username": req.AdminUsername,
+ "IPSubnet": "10.1.0.0/24",
+ }); err != nil {
+ return err
+ }
+ // TODO(giolekva): headscale accept routes
+ }
+
+ return nil
+}
+
+func addNewEnv(
+ repoIO installer.RepoIO,
+ req createEnvReq,
+ keys installer.KeyPair,
+ pcloudRepoPublicKey []byte,
+) error {
+ kust, err := repoIO.ReadKustomization("environments/kustomization.yaml")
+ if err != nil {
+ return err
+ }
+ kust.AddResources(req.Name)
+ tmpls, err := template.ParseFS(filesTmpls, "env-tmpl/*.yaml")
+ if err != nil {
+ return err
+ }
+ for _, tmpl := range tmpls.Templates() {
+ dstPath := path.Join("environments", req.Name, tmpl.Name())
+ dst, err := repoIO.Writer(dstPath)
+ if err != nil {
+ return err
+ }
+ defer dst.Close()
+ if err := tmpl.Execute(dst, map[string]string{
+ "Name": req.Name,
+ "PrivateKey": base64.StdEncoding.EncodeToString([]byte(keys.Private)),
+ "PublicKey": base64.StdEncoding.EncodeToString([]byte(keys.Public)),
+ "GitHost": envManagerFlags.repoIP,
+ "KnownHosts": base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%s %s", envManagerFlags.repoIP, pcloudRepoPublicKey))),
+ }); err != nil {
+ return err
+ }
+ }
+ if err := repoIO.WriteKustomization("environments/kustomization.yaml", *kust); err != nil {
+ return err
+ }
+ if err := repoIO.CommitAndPush(fmt.Sprintf("%s: initialize environment", req.Name)); err != nil {
+ return err
+ }
+ return nil
+}
diff --git a/core/installer/cmd/main.go b/core/installer/cmd/main.go
index 7a71b90..e82b338 100644
--- a/core/installer/cmd/main.go
+++ b/core/installer/cmd/main.go
@@ -26,6 +26,7 @@
rootCmd.AddCommand(createEnvCmd())
rootCmd.AddCommand(installCmd())
rootCmd.AddCommand(appManagerCmd())
+ rootCmd.AddCommand(envManagerCmd())
}
func main() {
diff --git a/core/installer/config.go b/core/installer/config.go
index f234d04..6712894 100644
--- a/core/installer/config.go
+++ b/core/installer/config.go
@@ -12,23 +12,23 @@
}
type Values struct {
- PCloudEnvName string `json:"pcloudEnvName,omitempty"`
- Id string `json:"id,omitempty"`
- ContactEmail string `json:"contactEmail,omitempty"`
- Domain string `json:"domain,omitempty"`
- PrivateDomain string `json:"privateDomain,omitempty"`
- PublicIP string `json:"publicIP,omitempty"`
- GandiAPIToken string `json:"gandiAPIToken,omitempty"`
- NamespacePrefix string `json:"namespacePrefix,omitempty"`
- LighthouseAuthUIIP string `json:"lighthouseAuthUIIP,omitempty"`
- LighthouseMainIP string `json:"lighthouseMainIP,omitempty"`
- LighthouseMainPort string `json:"lighthouseMainPort,omitempty"`
- MXHostname string `json:"mxHostname,omitempty"`
- MailGatewayAddress string `json:"mailGatewayAddress,omitempty"`
- MatrixOAuth2ClientSecret string `json:"matrixOAuth2ClientSecret,omitempty"`
- MatrixStorageSize string `json:"matrixStorageSize,omitempty"`
- PiholeOAuth2ClientSecret string `json:"piholeOAuth2ClientSecret,omitempty"`
- PiholeOAuth2CookieSecret string `json:"piholeOAuth2CookieSecret,omitempty"`
+ PCloudEnvName string `json:"pcloudEnvName,omitempty"`
+ Id string `json:"id,omitempty"`
+ ContactEmail string `json:"contactEmail,omitempty"`
+ Domain string `json:"domain,omitempty"`
+ PrivateDomain string `json:"privateDomain,omitempty"`
+ PublicIP string `json:"publicIP,omitempty"`
+ NamespacePrefix string `json:"namespacePrefix,omitempty"`
+ // GandiAPIToken string `json:"gandiAPIToken,omitempty"`
+ // LighthouseAuthUIIP string `json:"lighthouseAuthUIIP,omitempty"`
+ // LighthouseMainIP string `json:"lighthouseMainIP,omitempty"`
+ // LighthouseMainPort string `json:"lighthouseMainPort,omitempty"`
+ // MXHostname string `json:"mxHostname,omitempty"`
+ // MailGatewayAddress string `json:"mailGatewayAddress,omitempty"`
+ // MatrixOAuth2ClientSecret string `json:"matrixOAuth2ClientSecret,omitempty"`
+ // MatrixStorageSize string `json:"matrixStorageSize,omitempty"`
+ // PiholeOAuth2ClientSecret string `json:"piholeOAuth2ClientSecret,omitempty"`
+ // PiholeOAuth2CookieSecret string `json:"piholeOAuth2CookieSecret,omitempty"`
}
func ReadConfig(r io.Reader) (Config, error) {
diff --git a/core/installer/go.mod b/core/installer/go.mod
index ac66c3a..f61dffd 100644
--- a/core/installer/go.mod
+++ b/core/installer/go.mod
@@ -3,12 +3,13 @@
go 1.18
require (
- github.com/go-git/go-billy/v5 v5.3.1
- github.com/go-git/go-git/v5 v5.4.2
+ github.com/Masterminds/sprig/v3 v3.2.2
+ github.com/go-git/go-billy/v5 v5.4.1
+ github.com/go-git/go-git/v5 v5.7.0
github.com/labstack/echo/v4 v4.10.2
github.com/spf13/cobra v1.4.0
- golang.org/x/crypto v0.6.0
- golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53
+ golang.org/x/crypto v0.9.0
+ golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1
helm.sh/helm/v3 v3.9.0
sigs.k8s.io/yaml v1.3.0
)
@@ -19,17 +20,17 @@
github.com/MakeNowJust/heredoc v0.0.0-20170808103936-bb23615498cd // indirect
github.com/Masterminds/goutils v1.1.1 // indirect
github.com/Masterminds/semver/v3 v3.1.1 // indirect
- github.com/Masterminds/sprig/v3 v3.2.2 // indirect
github.com/Masterminds/squirrel v1.5.2 // indirect
- github.com/Microsoft/go-winio v0.5.1 // indirect
- github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7 // indirect
+ github.com/Microsoft/go-winio v0.5.2 // indirect
+ github.com/ProtonMail/go-crypto v0.0.0-20230518184743-7afd39499903 // indirect
github.com/PuerkitoBio/purell v1.1.1 // indirect
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 // indirect
- github.com/acomagu/bufpipe v1.0.3 // indirect
+ github.com/acomagu/bufpipe v1.0.4 // indirect
github.com/asaskevich/govalidator v0.0.0-20200428143746-21a406dcc535 // indirect
github.com/beorn7/perks v1.0.1 // indirect
github.com/cespare/xxhash/v2 v2.1.2 // indirect
github.com/chai2010/gettext-go v0.0.0-20160711120539-c6fed771bfd5 // indirect
+ github.com/cloudflare/circl v1.3.3 // indirect
github.com/containerd/containerd v1.6.3 // indirect
github.com/cyphar/filepath-securejoin v0.2.3 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
@@ -41,12 +42,12 @@
github.com/docker/go-metrics v0.0.1 // indirect
github.com/docker/go-units v0.4.0 // indirect
github.com/emicklei/go-restful v2.9.5+incompatible // indirect
- github.com/emirpasic/gods v1.12.0 // indirect
+ github.com/emirpasic/gods v1.18.1 // indirect
github.com/evanphx/json-patch v4.12.0+incompatible // indirect
github.com/exponent-io/jsonpath v0.0.0-20151013193312-d6023ce2651d // indirect
github.com/fatih/color v1.13.0 // indirect
github.com/go-errors/errors v1.0.1 // indirect
- github.com/go-git/gcfg v1.5.0 // indirect
+ github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
github.com/go-gorp/gorp/v3 v3.0.2 // indirect
github.com/go-logr/logr v1.2.2 // indirect
github.com/go-openapi/jsonpointer v0.19.5 // indirect
@@ -54,10 +55,11 @@
github.com/go-openapi/swag v0.19.14 // indirect
github.com/gobwas/glob v0.2.3 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
+ github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
github.com/golang/protobuf v1.5.2 // indirect
github.com/google/btree v1.0.1 // indirect
github.com/google/gnostic v0.5.7-v3refs // indirect
- github.com/google/go-cmp v0.5.8 // indirect
+ github.com/google/go-cmp v0.5.9 // indirect
github.com/google/gofuzz v1.2.0 // indirect
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect
github.com/google/uuid v1.2.0 // indirect
@@ -65,13 +67,13 @@
github.com/gosuri/uitable v0.0.4 // indirect
github.com/gregjones/httpcache v0.0.0-20180305231024-9cad4c3443a7 // indirect
github.com/huandu/xstrings v1.3.2 // indirect
- github.com/imdario/mergo v0.3.12 // indirect
+ github.com/imdario/mergo v0.3.15 // indirect
github.com/inconshreveable/mousetrap v1.0.0 // indirect
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect
github.com/jmoiron/sqlx v1.3.4 // indirect
github.com/josharian/intern v1.0.0 // indirect
github.com/json-iterator/go v1.1.12 // indirect
- github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 // indirect
+ github.com/kevinburke/ssh_config v1.2.0 // indirect
github.com/klauspost/compress v1.13.6 // indirect
github.com/labstack/gommon v0.4.0 // indirect
github.com/lann/builder v0.0.0-20180802200727-47ae307949d0 // indirect
@@ -84,7 +86,6 @@
github.com/mattn/go-runewidth v0.0.9 // indirect
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369 // indirect
github.com/mitchellh/copystructure v1.2.0 // indirect
- github.com/mitchellh/go-homedir v1.1.0 // indirect
github.com/mitchellh/go-wordwrap v1.0.0 // indirect
github.com/mitchellh/reflectwalk v1.0.2 // indirect
github.com/moby/locker v1.0.1 // indirect
@@ -98,6 +99,7 @@
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.0.3-0.20211202183452-c5a74bcca799 // indirect
github.com/peterbourgon/diskv v2.0.1+incompatible // indirect
+ github.com/pjbgf/sha1cd v0.3.0 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/prometheus/client_golang v1.12.1 // indirect
@@ -109,23 +111,24 @@
github.com/sergi/go-diff v1.1.0 // indirect
github.com/shopspring/decimal v1.2.0 // indirect
github.com/sirupsen/logrus v1.8.1 // indirect
+ github.com/skeema/knownhosts v1.1.1 // indirect
github.com/spf13/cast v1.4.1 // indirect
github.com/spf13/pflag v1.0.5 // indirect
github.com/stretchr/testify v1.8.1 // indirect
github.com/valyala/bytebufferpool v1.0.0 // indirect
github.com/valyala/fasttemplate v1.2.2 // indirect
- github.com/xanzy/ssh-agent v0.3.0 // indirect
+ github.com/xanzy/ssh-agent v0.3.3 // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
github.com/xeipuuv/gojsonschema v1.2.0 // indirect
github.com/xlab/treeprint v0.0.0-20181112141820-a009c3971eca // indirect
go.starlark.net v0.0.0-20200306205701-8dd3e2ee1dd5 // indirect
- golang.org/x/net v0.7.0 // indirect
+ golang.org/x/net v0.10.0 // indirect
golang.org/x/oauth2 v0.0.0-20211104180415-d3ed0bb246c8 // indirect
- golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
- golang.org/x/sys v0.5.0 // indirect
- golang.org/x/term v0.5.0 // indirect
- golang.org/x/text v0.7.0 // indirect
+ golang.org/x/sync v0.1.0 // indirect
+ golang.org/x/sys v0.8.0 // indirect
+ golang.org/x/term v0.8.0 // indirect
+ golang.org/x/text v0.9.0 // indirect
golang.org/x/time v0.3.0 // indirect
google.golang.org/appengine v1.6.7 // indirect
google.golang.org/genproto v0.0.0-20220107163113-42d7afdf6368 // indirect
diff --git a/core/installer/go.sum b/core/installer/go.sum
index 7562e09..65ec121 100644
--- a/core/installer/go.sum
+++ b/core/installer/go.sum
@@ -64,30 +64,27 @@
github.com/Masterminds/sprig/v3 v3.2.2/go.mod h1:UoaO7Yp8KlPnJIYWTFkMaqPUYKTfGFPhxNuwnnxkKlk=
github.com/Masterminds/squirrel v1.5.2 h1:UiOEi2ZX4RCSkpiNDQN5kro/XIBpSRk9iTqdIRPzUXE=
github.com/Masterminds/squirrel v1.5.2/go.mod h1:NNaOrjSoIDfDA40n7sr2tPNZRfjzjA400rg+riTZj10=
-github.com/Microsoft/go-winio v0.4.14/go.mod h1:qXqCSQ3Xa7+6tgxaGTIe4Kpcdsi+P8jBhyzoq1bpyYA=
-github.com/Microsoft/go-winio v0.4.16/go.mod h1:XB6nPKklQyQ7GC9LdcBEcBl8PF76WugXOPRXwdLnMv0=
-github.com/Microsoft/go-winio v0.5.1 h1:aPJp2QD7OOrhO5tQXqQoGSJc+DjDtWTGLOmNyAm6FgY=
-github.com/Microsoft/go-winio v0.5.1/go.mod h1:JPGBdM1cNvN/6ISo+n8V5iA4v8pBzdOpzfwIujj1a84=
+github.com/Microsoft/go-winio v0.5.2 h1:a9IhgEQBCUEk6QCdml9CiJGhAws+YwffDHEMp1VMrpA=
+github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY=
github.com/Microsoft/hcsshim v0.9.2 h1:wB06W5aYFfUB3IvootYAY2WnOmIdgPGfqSI6tufQNnY=
github.com/NYTimes/gziphandler v0.0.0-20170623195520-56545f4a5d46/go.mod h1:3wb06e3pkSAbeQ52E9H9iFoQsEEwGN64994WTCIhntQ=
github.com/NYTimes/gziphandler v1.1.1/go.mod h1:n/CVRwUEOgIxrgPvAQhUUr9oeUtvrhMomdKFjzJNB0c=
github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU=
-github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7 h1:YoJbenK9C67SkzkDfmQuVln04ygHj3vjZfd9FL+GmQQ=
-github.com/ProtonMail/go-crypto v0.0.0-20210428141323-04723f9f07d7/go.mod h1:z4/9nQmJSSwwds7ejkxaJwO37dru3geImFUdJlaLzQo=
+github.com/ProtonMail/go-crypto v0.0.0-20230518184743-7afd39499903 h1:ZK3C5DtzV2nVAQTx5S5jQvMeDqWtD1By5mOoyY/xJek=
+github.com/ProtonMail/go-crypto v0.0.0-20230518184743-7afd39499903/go.mod h1:8TI4H3IbrackdNgv+92dI+rhpCaLqM0IfpgCgenFvRE=
github.com/PuerkitoBio/purell v1.1.1 h1:WEQqlqaGbrPkxLJWfBwQmfEAE1Z7ONdDLqrN38tNFfI=
github.com/PuerkitoBio/purell v1.1.1/go.mod h1:c11w/QuzBsJSee3cPx9rAFu61PvFxuPbtSwDGJws/X0=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578 h1:d+Bc7a5rLufV/sSk/8dngufqelfh6jnri85riMAaF/M=
github.com/PuerkitoBio/urlesc v0.0.0-20170810143723-de5bf2ad4578/go.mod h1:uGdkoq3SwY9Y+13GIhn11/XLaGBb4BfwItxLd5jeuXE=
github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d h1:UrqY+r/OJnIp5u0s1SbQ8dVfLCZJsnvazdBP5hS4iRs=
-github.com/acomagu/bufpipe v1.0.3 h1:fxAGrHZTgQ9w5QqVItgzwj235/uYZYgbXitB+dLupOk=
-github.com/acomagu/bufpipe v1.0.3/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4=
+github.com/acomagu/bufpipe v1.0.4 h1:e3H4WUzM3npvo5uv95QuJM3cQspFNtFBzvJ2oNjKIDQ=
+github.com/acomagu/bufpipe v1.0.4/go.mod h1:mxdxdup/WdsKVreO5GpW4+M/1CE2sMG4jeGJ2sYmHc4=
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/template v0.0.0-20190718012654-fb15b899a751/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0=
github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho=
-github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239 h1:kFOfPq6dUM1hTo4JG6LR5AXSUEsOjtdm0kw0FtQtMJA=
-github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c=
+github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8=
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
github.com/antlr/antlr4/runtime/Go/antlr v0.0.0-20210826220005-b48c857c3a0e/go.mod h1:F7bn7fEU90QkQ3tnmaTx3LTKLEDqnwWODIYppRQ5hnY=
github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hCbHZ8TKRvWD2dDTCfh9M9ya+I9JpbB7O8o=
@@ -112,6 +109,7 @@
github.com/bugsnag/bugsnag-go v0.0.0-20141110184014-b1d153021fcd h1:rFt+Y/IK1aEZkEHchZRSq9OQbsSzIT/OrI8YFFmRIng=
github.com/bugsnag/osext v0.0.0-20130617224835-0dd3f918b21b h1:otBG+dV+YK+Soembjv71DPz3uX/V/6MMlSyD9JBQ6kQ=
github.com/bugsnag/panicwrap v0.0.0-20151223152923-e2c28503fcd0 h1:nvj0OLI3YqYXer/kZD8Ri1aaunCxIEsOst1BVJswV0o=
+github.com/bwesterb/go-ristretto v1.2.0/go.mod h1:fUIoIZaG73pV5biE2Blr2xEzDoMj7NFEuV9ekS419A0=
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
github.com/certifi/gocertifi v0.0.0-20191021191039-0944d244cd40/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
@@ -125,6 +123,9 @@
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU=
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
+github.com/cloudflare/circl v1.1.0/go.mod h1:prBCrKB9DV4poKZY1l9zBXg2QJY7mvgRvtMxxK7fi4I=
+github.com/cloudflare/circl v1.3.3 h1:fE/Qz0QdIGqeWfnwq0RE0R7MI51s0M2E4Ga9kq5AEMs=
+github.com/cloudflare/circl v1.3.3/go.mod h1:5XYMA4rFBvNIrhs50XuiBJ15vF2pZn4nnUKZrLbUZFA=
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
@@ -180,13 +181,13 @@
github.com/docker/libtrust v0.0.0-20150114040149-fa567046d9b1 h1:ZClxb8laGDf5arXfYcAtECDFgAgHklGI8CxgjHnXKJ4=
github.com/docopt/docopt-go v0.0.0-20180111231733-ee0de3bc6815/go.mod h1:WwZ+bS3ebgob9U8Nd0kOddGdZWjyMGR8Wziv+TBNwSE=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
-github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153 h1:yUdfgN0XgIJw7foRItutHYUIhlcKzcSf5vDpdhQAKTc=
github.com/elazarl/goproxy v0.0.0-20180725130230-947c36da3153/go.mod h1:/Zj4wYkgs4iZTTu3o/KG3Itv/qCCa8VVMlb3i9OVuzc=
+github.com/elazarl/goproxy v0.0.0-20221015165544-a0805db90819 h1:RIB4cRk+lBqKK3Oy0r2gRX4ui7tuhiZq2SuTtTCi0/0=
github.com/emicklei/go-restful v0.0.0-20170410110728-ff4f55a20633/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
github.com/emicklei/go-restful v2.9.5+incompatible h1:spTtZBk5DYEvbxMVutUuTyh1Ao2r4iyvLdACqsl/Ljk=
github.com/emicklei/go-restful v2.9.5+incompatible/go.mod h1:otzb+WCGbkyDHkqmQmT5YD2WR4BBwUdeQoFo8l/7tVs=
-github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg=
-github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
+github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc=
+github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98=
@@ -207,7 +208,6 @@
github.com/fatih/color v1.13.0/go.mod h1:kLAiJbzzSOZDVNGyDpeOxJ47H46qBXwg5ILebYFFOfk=
github.com/felixge/httpsnoop v1.0.1 h1:lvB5Jl89CsZtGIWuTcDM1E/vkVs49/Ml7JJe07l8SPQ=
github.com/felixge/httpsnoop v1.0.1/go.mod h1:m8KPJKqk1gH5J9DgRY2ASl2lWCfGKXixSwevea8zH2U=
-github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc=
github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
@@ -217,19 +217,16 @@
github.com/getkin/kin-openapi v0.76.0/go.mod h1:660oXbgy5JFMKreazJaQTw7o+X00qeSyhcnluiMv+Xg=
github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ=
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
-github.com/gliderlabs/ssh v0.2.2 h1:6zsha5zo/TWhRhwqCD3+EarCAgZ2yN28ipRnGPnwkI0=
-github.com/gliderlabs/ssh v0.2.2/go.mod h1:U7qILu1NlMHj9FlMhZLlkCdDnU1DBEAqr0aevW3Awn0=
+github.com/gliderlabs/ssh v0.3.5 h1:OcaySEmAQJgyYcArR+gGGTHCyE7nvhEMTlYY+Dp8CpY=
github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w=
github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q=
-github.com/go-git/gcfg v1.5.0 h1:Q5ViNfGF8zFgyJWPqYwA7qGFoMTEiBmdlkcfRmpIMa4=
-github.com/go-git/gcfg v1.5.0/go.mod h1:5m20vg6GwYabIxaOonVkTdrILxQMpEShl1xiMF4ua+E=
-github.com/go-git/go-billy/v5 v5.2.0/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
-github.com/go-git/go-billy/v5 v5.3.1 h1:CPiOUAzKtMRvolEKw+bG1PLRpT7D3LIs3/3ey4Aiu34=
-github.com/go-git/go-billy/v5 v5.3.1/go.mod h1:pmpqyWchKfYfrkb/UVH4otLvyi/5gJlGI4Hb3ZqZ3W0=
-github.com/go-git/go-git-fixtures/v4 v4.2.1 h1:n9gGL1Ct/yIw+nfsfr8s4+sbhT+Ncu2SubfXjIWgci8=
-github.com/go-git/go-git-fixtures/v4 v4.2.1/go.mod h1:K8zd3kDUAykwTdDCr+I0per6Y6vMiRR/nnVTBtavnB0=
-github.com/go-git/go-git/v5 v5.4.2 h1:BXyZu9t0VkbiHtqrsvdq39UDhGJTl1h55VW6CSC4aY4=
-github.com/go-git/go-git/v5 v5.4.2/go.mod h1:gQ1kArt6d+n+BGd+/B/I74HwRTLhth2+zti4ihgckDc=
+github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI=
+github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic=
+github.com/go-git/go-billy/v5 v5.4.1 h1:Uwp5tDRkPr+l/TnbHOQzp+tmJfLceOlbVucgpTz8ix4=
+github.com/go-git/go-billy/v5 v5.4.1/go.mod h1:vjbugF6Fz7JIflbVpl1hJsGjSHNltrSw45YK/ukIvQg=
+github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20230305113008-0c11038e723f h1:Pz0DHeFij3XFhoBRGUDPzSJ+w2UcK5/0JvF8DRI58r8=
+github.com/go-git/go-git/v5 v5.7.0 h1:t9AudWVLmqzlo+4bqdf7GY+46SUuRsx59SboFxkq2aE=
+github.com/go-git/go-git/v5 v5.7.0/go.mod h1:coJHKEOk5kUClpsNlXrUvPrDxY3w3gjHvhcZd8Fodw8=
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8=
@@ -331,8 +328,8 @@
github.com/google/go-cmp v0.5.3/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.4/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
-github.com/google/go-cmp v0.5.8 h1:e6P7q2lk1O+qJJb4BtCQXlK8vWEO8V1ZeuEdJNOqZyg=
-github.com/google/go-cmp v0.5.8/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
+github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38=
+github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.1.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/gofuzz v1.2.0 h1:xRy4A+RhZaiKjJ1bPfwQ8sedCA+YS2YcCHW6ec7JMi0=
@@ -403,13 +400,12 @@
github.com/ianlancetaylor/demangle v0.0.0-20200824232613-28f6c0f3b639/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc=
github.com/imdario/mergo v0.3.5/go.mod h1:2EnlNZ0deacrJVfApfmtdGgDfMuh/nq6Ok1EcJh5FfA=
github.com/imdario/mergo v0.3.11/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
-github.com/imdario/mergo v0.3.12 h1:b6R2BslTbIEToALKP7LxUvijTsNI9TAe80pLWN2g/HU=
-github.com/imdario/mergo v0.3.12/go.mod h1:jmQim1M+e3UYxmgPu/WyfjB3N3VflVyUjjjwH0dnCYA=
+github.com/imdario/mergo v0.3.15 h1:M8XP7IuFNsqUx6VPK2P9OSmsYsI/YFaGil0uD21V3dM=
+github.com/imdario/mergo v0.3.15/go.mod h1:WBLT9ZmE3lPoWsEzCh9LPo3TiwVN+ZKEjmz+hD27ysY=
github.com/inconshreveable/mousetrap v1.0.0 h1:Z8tu5sraLXCXIcARxBp/8cbvlwVa7Z1NHg9XEKhtSvM=
github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A=
github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo=
-github.com/jessevdk/go-flags v1.5.0/go.mod h1:Fw0T6WPc1dYxT4mKEZRfG5kJhaTDP9pj1c2EWnYs/m4=
github.com/jmoiron/sqlx v1.3.4 h1:wv+0IJZfL5z0uZoUjlpKgHkgaFSYD+r9CfrXjEXsO7w=
github.com/jmoiron/sqlx v1.3.4/go.mod h1:2BljVx/86SuTyjE+aPYlHCTNvZrnJXghYGpNiXLBMCQ=
github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo=
@@ -430,8 +426,8 @@
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
github.com/karrick/godirwalk v1.16.1 h1:DynhcF+bztK8gooS0+NDJFrdNZjJ3gzVzC545UNA9iw=
github.com/karrick/godirwalk v1.16.1/go.mod h1:j4mkqPuvaLI8mp1DroR3P6ad7cyYd4c1qeJ3RV7ULlk=
-github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351 h1:DowS9hvgyYSX4TO5NpyC606/Z4SxnNYbT+WX27or6Ck=
-github.com/kevinburke/ssh_config v0.0.0-20201106050909-4977a11b4351/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
+github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4=
+github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM=
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
@@ -509,7 +505,6 @@
github.com/mitchellh/copystructure v1.2.0 h1:vpKXTN4ewci03Vljg/q9QvCGUDttBOGBIa15WveJJGw=
github.com/mitchellh/copystructure v1.2.0/go.mod h1:qLl+cE2AmVv+CoeAwDPye/v+N2HKCj9FbZEVFJRxO9s=
github.com/mitchellh/go-homedir v1.0.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
-github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y=
github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0=
github.com/mitchellh/go-testing-interface v1.0.0/go.mod h1:kRemZodwjscx+RGhAo8eIhFbs2+BFgRtFPeD/KE+zxI=
github.com/mitchellh/go-wordwrap v1.0.0 h1:6GlHJ/LTGMrIJbwgdqdl2eEH8o+Exx/0m8ir9Gns0u4=
@@ -572,6 +567,8 @@
github.com/peterbourgon/diskv v2.0.1+incompatible h1:UBdAOUP5p4RWqPBg048CAvpKN+vxiaj6gdUUzhl4XmI=
github.com/peterbourgon/diskv v2.0.1+incompatible/go.mod h1:uqqh8zWWbv1HBMNONnaR/tNboyR3/BZd58JJSHlUSCU=
github.com/phayes/freeport v0.0.0-20180830031419-95f893ade6f2 h1:JhzVVoYvbOACxoUmOs6V/G4D5nPVUW73rKvXxP4XUJc=
+github.com/pjbgf/sha1cd v0.3.0 h1:4D5XXmUUBUl/xQ6IjCkEAbqXskkq/4O7LmGn0AqMDs4=
+github.com/pjbgf/sha1cd v0.3.0/go.mod h1:nZ1rrWOcGJ5uZgEEVL1VUM9iRQiZvWdbZjkKyFzPPsI=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
@@ -632,12 +629,13 @@
github.com/shopspring/decimal v1.2.0/go.mod h1:DKyhrW/HYNuLGql+MJL6WCR6knT2jwCFRcu2hWCYk4o=
github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeVRXNmyL/1OwPU0+IJeTBvfc=
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
-github.com/sirupsen/logrus v1.4.1/go.mod h1:ni0Sbl8bgC9z8RoU9G6nDWqqs/fq4eDPysMBDgk/93Q=
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE=
github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
+github.com/skeema/knownhosts v1.1.1 h1:MTk78x9FPgDFVFkDLTrsnnfCJl7g1C/nnKvePgrIngE=
+github.com/skeema/knownhosts v1.1.1/go.mod h1:g4fPeYpque7P0xefxtGzV81ihjC8sX2IqpAoNkjxbMo=
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
@@ -687,8 +685,8 @@
github.com/valyala/fasttemplate v1.2.1/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
github.com/valyala/fasttemplate v1.2.2 h1:lxLXG0uE3Qnshl9QyaK6XJxMXlQZELvChBOCmQD0Loo=
github.com/valyala/fasttemplate v1.2.2/go.mod h1:KHLXt3tVN2HBp8eijSv/kGJopbvo7S+qRAEEKiv+SiQ=
-github.com/xanzy/ssh-agent v0.3.0 h1:wUMzuKtKilRgBAD1sUb8gOwwRr2FGoBVumcjoOACClI=
-github.com/xanzy/ssh-agent v0.3.0/go.mod h1:3s9xbODqPuuhK9JV1R321M/FlMZSBvE5aY6eAcqrDh0=
+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 h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f/go.mod h1:N2zxlSyiKSe5eX1tZViRH5QA0qijqEDrYZiPEAiq3wU=
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 h1:EzJWgHovont7NscjpAxXsDA8S8BMYve8Y5+7cuRE7R0=
@@ -705,6 +703,7 @@
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
github.com/yuin/goldmark v1.4.1/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
+github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
github.com/yvasiyarov/go-metrics v0.0.0-20140926110328-57bccd1ccd43 h1:+lm10QQTNSBd8DVTNGHx7o/IKu9HYDvLMffDhbyLccI=
github.com/yvasiyarov/gorelic v0.0.0-20141212073537-a9bba5b9ab50 h1:hlE8//ciYMztlGpl/VA+Zm1AcTPHYkHJPbHqE6WJUXE=
github.com/yvasiyarov/newrelic_platform_go v0.0.0-20140908184405-b21fdbd4370f h1:ERexzlUfuTvpE74urLSbIQW0Z/6hF9t8U4NsJLaioAY=
@@ -754,7 +753,6 @@
go.uber.org/zap v1.19.0/go.mod h1:xg/QME4nWcxGxrpdeYfq7UvYrLh66cuVKdrbD1XF/NI=
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20181029021203-45a5f77698d3/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
-golang.org/x/crypto v0.0.0-20190219172222-a4c6cb3142f2/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
@@ -765,12 +763,12 @@
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20200820211705-5c72a883971a/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
-golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
-golang.org/x/crypto v0.0.0-20210421170649-83a5a9bb288b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220214200702-86341886e292/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
-golang.org/x/crypto v0.6.0 h1:qfktjS5LUO+fFKeJXZ+ikTRijMmljikvG68fpMMruSc=
-golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
+golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
+golang.org/x/crypto v0.7.0/go.mod h1:pYwdfH91IfpZVANVyUOhSIPZaFoJGxTFbZhFTx+dXZU=
+golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g=
+golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8=
@@ -781,8 +779,8 @@
golang.org/x/exp v0.0.0-20200119233911-0405dc783f0a/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4=
golang.org/x/exp v0.0.0-20200207192155-f17229e696bd/go.mod h1:J/WKrq2StrnmMY6+EHIKF9dgMWnmCNThgcyBT1FY9mM=
golang.org/x/exp v0.0.0-20200224162631-6cc2880d07d6/go.mod h1:3jZMyOhIsHpP37uCMkUooju7aAi5cS1Q23tOzKc+0MU=
-golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53 h1:5llv2sWeaMSnA3w2kS57ouQQ4pudlXrR0dCgw51QK9o=
-golang.org/x/exp v0.0.0-20230425010034-47ecfdc1ba53/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
+golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1 h1:k/i9J1pBpvlfR+9QsetwPyERsqu1GIbi967PQMq3Ivc=
+golang.org/x/exp v0.0.0-20230522175609-2e198f4a06a1/go.mod h1:V1LtkGg67GoY2N1AnLN78QLrzxkLyJw7RJb1gzOOz9w=
golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js=
golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0=
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
@@ -809,6 +807,8 @@
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY=
+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/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
@@ -851,7 +851,6 @@
golang.org/x/net v0.0.0-20210119194325-5f4716e94777/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc=
-golang.org/x/net v0.0.0-20210326060303-6b1517762897/go.mod h1:uSPa2vr4CLtc/ILN5odXGNXS6mhrKVzTaCXzk9m6W3k=
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
@@ -859,8 +858,11 @@
golang.org/x/net v0.0.0-20211015210444-4f30a5c0130f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
-golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
-golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
+golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
+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.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
+golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
@@ -886,8 +888,10 @@
golang.org/x/sync v0.0.0-20200625203802-6e8e738ad208/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
-golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/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 h1:wsuoTGHzEhffawBOhz5CYhcrV4IdKZbEyZjBMuTp12o=
+golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
@@ -906,7 +910,6 @@
golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20190904154756-749cb33beabd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20190916202348-b4ddaad3f8a3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191001151750-bb3f8db39f24/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191002063906-3421d5a6bb1c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20191005200804-aed5e4c7ecf9/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
@@ -944,11 +947,9 @@
golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210320140829-1e4c9ba3b0c4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210324051608-47abb6519492/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
-golang.org/x/sys v0.0.0-20210502180810-71e4cd670f79/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -957,18 +958,27 @@
golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210831042530-f4d43177bf5e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220209214540-3681064d5158/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
+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.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
+golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
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.5.0 h1:n2a8QNdAb0sZNpU9R1ALUXBbY+w51fCQDN+7EdxNBsY=
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.8.0 h1:n5xxQn2i3PC0yLAbjTpNT85q/Kgzcr2gIoX9OrJUols=
+golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
@@ -978,8 +988,10 @@
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
-golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
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.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
+golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
golang.org/x/time v0.0.0-20191024005414-555d28b269f0/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
@@ -1046,6 +1058,8 @@
golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
golang.org/x/tools v0.1.10-0.20220218145154-897bd77cd717/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E=
+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/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/keys.go b/core/installer/keys.go
index bb39c4d..695176f 100644
--- a/core/installer/keys.go
+++ b/core/installer/keys.go
@@ -9,14 +9,19 @@
"golang.org/x/crypto/ssh"
)
-func GenerateSSHKeys() (string, string, error) {
+type KeyPair struct {
+ Public string
+ Private string
+}
+
+func NewSSHKeyPair() (KeyPair, error) {
pub, priv, err := ed25519.GenerateKey(rand.Reader)
if err != nil {
- return "", "", err
+ return KeyPair{}, err
}
privEnc, err := x509.MarshalPKCS8PrivateKey(priv)
if err != nil {
- return "", "", err
+ return KeyPair{}, err
}
privPem := pem.EncodeToMemory(
&pem.Block{
@@ -26,7 +31,10 @@
)
pubKey, err := ssh.NewPublicKey(pub)
if err != nil {
- return "", "", err
+ return KeyPair{}, err
}
- return string(ssh.MarshalAuthorizedKey(pubKey)), string(privPem), nil
+ return KeyPair{
+ Public: string(ssh.MarshalAuthorizedKey(pubKey)),
+ Private: string(privPem),
+ }, nil
}
diff --git a/core/installer/kustomization.go b/core/installer/kustomization.go
index f5f42e5..93f806a 100644
--- a/core/installer/kustomization.go
+++ b/core/installer/kustomization.go
@@ -2,6 +2,7 @@
import (
"bytes"
+ "golang.org/x/exp/slices"
"io"
"io/ioutil"
@@ -46,5 +47,9 @@
}
func (k *Kustomization) AddResources(names ...string) {
- k.Resources = append(k.Resources, names...)
+ for _, name := range names {
+ if !slices.Contains(k.Resources, name) {
+ k.Resources = append(k.Resources, name)
+ }
+ }
}
diff --git a/core/installer/manifest.yaml b/core/installer/manifest.yaml
new file mode 100644
index 0000000..61f8d80
--- /dev/null
+++ b/core/installer/manifest.yaml
@@ -0,0 +1,75 @@
+# TODO(giolekva): finish
+apiVersion: v1
+kind: Namespace
+metadata:
+ name: pcloud
+---
+apiVersion: v1
+kind: ServiceAccount
+metadata:
+ name: pcloud-bootstrap
+ namespace: pcloud
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRole
+metadata:
+ name: pcloud-bootstrap
+ namespace: pcloud
+rules:
+- apiGroups:
+ - *
+ resources:
+ - *
+ verbs:
+ - *
+---
+apiVersion: rbac.authorization.k8s.io/v1
+kind: ClusterRoleBinding
+metadata:
+ name: pcloud:pcloud-bootstrap
+roleRef:
+ apiGroup: rbac.authorization.k8s.io
+ kind: ClusterRole
+ name: pcloud:pcloud-bootstrap
+subjects:
+- kind: ServiceAccount
+ name: pcloud-bootstrap
+ namespace: pcloud
+---
+apiVersion: v1
+kind: ConfigMap
+metadata:
+ name: admin-pub-key
+ namespace: pcloud
+data: # TODO(giolekva): can it work without ssh-ed25519 prefix
+ key.pub: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIOa7FUrmXzdY3no8qNGUk7OPaRcIUi8G7MVbLlff9eB/
+---
+apiVersion: batch/v1
+kind: Job
+metadata:
+ name: pcloud-bootstrap
+ namespace: pcloud
+spec:
+ template:
+ spec:
+ serviceAccountName: pcloud-bootstrap
+ volumes:
+ - name: admin-pub-key
+ configMap:
+ name: admin-pub-key
+ containers:
+ - name: pcloud-bootstrap
+ image: giolekva/pcloud-installer:latest
+ imagePullPolicy: Always
+ volumeMounts:
+ - name: admin-pub-key
+ mountPath: /admin-pub-key
+ command:
+ - pcloud-installer
+ - bootstrap
+ - --pcloud-env-name=pcloud
+ - --admin-pub-key=/admin-pub-key/key.pub
+ - --soft-serve-ip=192.168.0.211
+ - --charts-dir=/charts
+ - --storage-dir=/pcloud-storage/longhorn
+ restartPolicy: Never
diff --git a/core/installer/repoio.go b/core/installer/repoio.go
index a1d86d2..97bf9b6 100644
--- a/core/installer/repoio.go
+++ b/core/installer/repoio.go
@@ -1,21 +1,34 @@
package installer
import (
+ "errors"
+ "fmt"
"io"
"io/fs"
+ "net"
+ "path"
"path/filepath"
"time"
+ "github.com/go-git/go-billy/v5/util"
"github.com/go-git/go-git/v5"
"github.com/go-git/go-git/v5/plumbing/object"
+ gitssh "github.com/go-git/go-git/v5/plumbing/transport/ssh"
"golang.org/x/crypto/ssh"
+ "sigs.k8s.io/yaml"
)
type RepoIO interface {
+ Fetch() error
ReadKustomization(path string) (*Kustomization, error)
WriteKustomization(path string, kust Kustomization) error
+ WriteYaml(path string, data any) error
CommitAndPush(message string) error
+ Reader(path string) (io.ReadCloser, error)
Writer(path string) (io.WriteCloser, error)
+ CreateDir(path string) error
+ RemoveDir(path string) error
+ InstallApp(app App, path string, values map[string]any) error
}
type repoIO struct {
@@ -30,12 +43,20 @@
}
}
-func (r *repoIO) ReadKustomization(path string) (*Kustomization, error) {
- wt, err := r.repo.Worktree()
- if err != nil {
- return nil, err
+func (r *repoIO) Fetch() error {
+ err := r.repo.Fetch(&git.FetchOptions{
+ RemoteName: "origin",
+ Auth: auth(r.signer),
+ Force: true,
+ })
+ if err == nil || err == git.NoErrAlreadyUpToDate {
+ return nil
}
- inp, err := wt.Filesystem.Open(path)
+ return err
+}
+
+func (r *repoIO) ReadKustomization(path string) (*Kustomization, error) {
+ inp, err := r.Reader(path)
if err != nil {
return nil, err
}
@@ -43,6 +64,14 @@
return ReadKustomization(inp)
}
+func (r *repoIO) Reader(path string) (io.ReadCloser, error) {
+ wt, err := r.repo.Worktree()
+ if err != nil {
+ return nil, err
+ }
+ return wt.Filesystem.Open(path)
+}
+
func (r *repoIO) Writer(path string) (io.WriteCloser, error) {
wt, err := r.repo.Worktree()
if err != nil {
@@ -62,6 +91,21 @@
return kust.Write(out)
}
+func (r *repoIO) WriteYaml(path string, data any) error {
+ out, err := r.Writer(path)
+ if err != nil {
+ return err
+ }
+ serialized, err := yaml.Marshal(data)
+ if err != nil {
+ return err
+ }
+ if _, err := out.Write(serialized); err != nil {
+ return err
+ }
+ return nil
+}
+
func (r *repoIO) CommitAndPush(message string) error {
wt, err := r.repo.Worktree()
if err != nil {
@@ -83,3 +127,80 @@
Auth: auth(r.signer),
})
}
+
+func (r *repoIO) CreateDir(path string) error {
+ wt, err := r.repo.Worktree()
+ if err != nil {
+ return err
+ }
+ return wt.Filesystem.MkdirAll(path, fs.ModePerm)
+}
+
+func (r *repoIO) RemoveDir(path string) error {
+ wt, err := r.repo.Worktree()
+ if err != nil {
+ return err
+ }
+ err = util.RemoveAll(wt.Filesystem, path)
+ if err == nil || errors.Is(err, fs.ErrNotExist) {
+ return nil
+ }
+ return err
+}
+
+func (r *repoIO) InstallApp(app App, root string, values map[string]any) error {
+ {
+ appsKustPath := path.Join(root, "kustomization.yaml")
+ appsKust, err := r.ReadKustomization(appsKustPath)
+ if err != nil {
+ return err
+ }
+ appsKust.AddResources(app.Name)
+ if err := r.WriteKustomization(appsKustPath, *appsKust); err != nil {
+ return err
+ }
+ }
+ appRootDir := path.Join(root, app.Name)
+ {
+ if err := r.RemoveDir(appRootDir); err != nil {
+ return err
+ }
+ if err := r.CreateDir(appRootDir); err != nil {
+ return err
+ }
+ if err := r.WriteYaml(path.Join(appRootDir, configFileName), values); err != nil {
+ return err
+ }
+ }
+ {
+ appKust := NewKustomization()
+ for _, t := range app.Templates {
+ appKust.AddResources(t.Name())
+ out, err := r.Writer(path.Join(appRootDir, t.Name()))
+ if err != nil {
+ return err
+ }
+ defer out.Close()
+ if err := t.Execute(out, values); err != nil {
+ return err
+ }
+ }
+ if err := r.WriteKustomization(path.Join(appRootDir, "kustomization.yaml"), appKust); err != nil {
+ return err
+ }
+ }
+ return r.CommitAndPush(fmt.Sprintf("install: %s", app.Name))
+}
+
+func auth(signer ssh.Signer) *gitssh.PublicKeys {
+ return &gitssh.PublicKeys{
+ Signer: signer,
+ HostKeyCallbackHelper: gitssh.HostKeyCallbackHelper{
+ HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error {
+ // TODO(giolekva): verify server public key
+ // fmt.Printf("## %s || %s -- \n", serverPubKey, ssh.MarshalAuthorizedKey(key))
+ return nil
+ },
+ },
+ }
+}
diff --git a/core/installer/soft/client.go b/core/installer/soft/client.go
index e07532e..59e94a8 100644
--- a/core/installer/soft/client.go
+++ b/core/installer/soft/client.go
@@ -1,28 +1,26 @@
package soft
import (
+ "encoding/base64"
"fmt"
- "io/ioutil"
+ "golang.org/x/crypto/ssh"
"log"
"net"
"os"
- "time"
+ "strings"
"github.com/go-git/go-billy/v5/memfs"
"github.com/go-git/go-git/v5"
- // "github.com/go-git/go-git/v5/config"
- "github.com/go-git/go-git/v5/plumbing/object"
gitssh "github.com/go-git/go-git/v5/plumbing/transport/ssh"
"github.com/go-git/go-git/v5/storage/memory"
- "golang.org/x/crypto/ssh"
- "sigs.k8s.io/yaml"
)
type Client struct {
- ip string
- port int
- Signer ssh.Signer
- log *log.Logger
+ IP string
+ port int
+ Signer ssh.Signer
+ log *log.Logger
+ pemBytes []byte
}
func NewClient(ip string, port int, clientPrivateKey []byte, log *log.Logger) (*Client, error) {
@@ -31,28 +29,45 @@
return nil, err
}
log.SetPrefix("SOFT-SERVE: ")
+ log.Printf("Created signer")
+ pub := signer.PublicKey().Marshal()
+ b := make([]byte, 100)
+ base64.StdEncoding.Encode(b, pub)
+ log.Printf("%s\n", string(b))
return &Client{
ip,
port,
signer,
log,
+ clientPrivateKey,
}, nil
}
func (ss *Client) AddUser(name, pubKey string) error {
log.Printf("Adding user %s", name)
- if err := ss.RunCommand(fmt.Sprintf("user create %s", name)); err != nil {
+ if err := ss.RunCommand("user", "create", name); err != nil {
return err
}
- return ss.RunCommand(fmt.Sprintf("user add-pubkey %s %s", name, pubKey))
+ return ss.AddPublicKey(name, pubKey)
}
func (ss *Client) MakeUserAdmin(name string) error {
log.Printf("Making user %s admin", name)
- return ss.RunCommand(fmt.Sprintf("user set-admin %s true", name))
+ return ss.RunCommand("user", "set-admin", name, "true")
}
-func (ss *Client) RunCommand(cmd string) error {
+func (ss *Client) AddPublicKey(user string, pubKey string) error {
+ log.Printf("Adding public key: %s %s\n", user, pubKey)
+ return ss.RunCommand("user", "add-pubkey", user, pubKey)
+}
+
+func (ss *Client) RemovePublicKey(user string, pubKey string) error {
+ log.Printf("Adding 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.addressSSH(), ss.sshClientConfig())
if err != nil {
@@ -63,84 +78,25 @@
return err
}
defer session.Close()
+ session.Stdout = os.Stdout
+ session.Stderr = os.Stderr
return session.Run(cmd)
}
func (ss *Client) AddRepository(name, readme string) error {
log.Printf("Adding repository %s", name)
- return ss.RunCommand(fmt.Sprintf("repo create %s -d \"%s\"", name, readme))
+ return ss.RunCommand("repo", "create", name, "-d", fmt.Sprintf("\"%s\"", readme))
}
func (ss *Client) AddCollaborator(repo, user string) error {
log.Printf("Adding collaborator %s %s", repo, user)
- return ss.RunCommand(fmt.Sprintf("repo collab add %s %s", repo, user))
-}
-
-func (ss *Client) CreateRepository(name string) error {
- log.Printf("Creating repository %s", name)
- configRepo, err := ss.getConfigRepo()
- if err != nil {
- return err
- }
- wt, err := configRepo.Worktree()
- if err != nil {
- return err
- }
- if err = wt.Checkout(&git.CheckoutOptions{
- Branch: "refs/heads/master",
- }); err != nil {
- return err
- }
- f, err := wt.Filesystem.Open("config.yaml")
- if err != nil {
- return err
- }
- defer f.Close()
- configBytes, err := ioutil.ReadAll(f)
- if err != nil {
- return err
- }
- config := make(map[string]interface{})
- if err := yaml.Unmarshal(configBytes, &config); err != nil {
- return err
- }
- repos := config["repos"].([]interface{})
- repos = append(repos, map[string]interface{}{
- "name": name,
- "repo": name,
- "private": true,
- "note": fmt.Sprintf("PCloud env for %s", name),
- })
- config["repos"] = repos
- configBytes, err = yaml.Marshal(config)
- if err != nil {
- return err
- }
- if err := ss.writeFile(wt, "config.yaml", string(configBytes)); err != nil {
- return err
- }
- if err := ss.Commit(wt, fmt.Sprintf("add-repo: %s", name)); err != nil {
- return err
- }
- return ss.Push(configRepo)
-}
-
-func (ss *Client) getConfigRepo() (*git.Repository, error) {
- return git.Clone(memory.NewStorage(), memfs.New(), &git.CloneOptions{
- URL: ss.addressGit(),
- Auth: ss.authGit(),
- RemoteName: "origin",
- ReferenceName: "refs/heads/master",
- Depth: 1,
- InsecureSkipTLS: true,
- Progress: os.Stdout,
- })
+ return ss.RunCommand("repo", "collab", "add", repo, user)
}
func (ss *Client) GetRepo(name string) (*git.Repository, error) {
return git.Clone(memory.NewStorage(), memfs.New(), &git.CloneOptions{
- URL: fmt.Sprintf("%s/%s", ss.addressGit(), name),
- Auth: ss.authGit(),
+ URL: ss.GetRepoAddress(name),
+ Auth: ss.authSSH(),
RemoteName: "origin",
ReferenceName: "refs/heads/master",
Depth: 1,
@@ -149,57 +105,38 @@
})
}
-func (ss *Client) repoPathByName(name string) string {
- return fmt.Sprintf("%s/%s", ss.addressGit(), name)
-}
-
-func (ss *Client) Commit(wt *git.Worktree, message string) error {
- _, err := wt.Commit(message, &git.CommitOptions{
- Author: &object.Signature{
- Name: "pcloud",
- Email: "pcloud@installer",
- When: time.Now(),
- },
- })
- return err
-}
-
-func (ss *Client) Push(repo *git.Repository) error {
- return repo.Push(&git.PushOptions{
- RemoteName: "origin",
- Auth: ss.authGit(),
- })
-}
-
-func (ss *Client) writeFile(wt *git.Worktree, path, contents string) error {
- f, err := wt.Filesystem.Create(path)
+func (ss *Client) authSSH() gitssh.AuthMethod {
+ a, err := gitssh.NewPublicKeys("git", ss.pemBytes, "")
if err != nil {
- return err
+ panic(err)
}
- defer f.Close()
- if _, err = f.Write([]byte(contents)); err != nil {
- return err
+ a.HostKeyCallback = func(hostname string, remote net.Addr, key ssh.PublicKey) error {
+ // TODO(giolekva): verify server public key
+ ss.log.Printf("--- %+v\n", ssh.MarshalAuthorizedKey(key))
+ return nil
}
- _, err = wt.Add(path)
- return err
-}
-
-func (ss *Client) CloneRepository(name string) (*git.Repository, error) {
- return git.Clone(memory.NewStorage(), memfs.New(), &git.CloneOptions{
- URL: ss.repoPathByName(name),
- Auth: ss.authGit(),
- RemoteName: "origin",
- InsecureSkipTLS: true,
- })
+ return a
+ // return &gitssh.PublicKeys{
+ // User: "git",
+ // Signer: ss.Signer,
+ // HostKeyCallbackHelper: gitssh.HostKeyCallbackHelper{
+ // HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error {
+ // // TODO(giolekva): verify server public key
+ // ss.log.Printf("--- %+v\n", ssh.MarshalAuthorizedKey(key))
+ // return nil
+ // },
+ // },
+ // }
}
func (ss *Client) authGit() *gitssh.PublicKeys {
return &gitssh.PublicKeys{
+ User: "git",
Signer: ss.Signer,
HostKeyCallbackHelper: gitssh.HostKeyCallbackHelper{
HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error {
// TODO(giolekva): verify server public key
- // fmt.Printf("## %s || %s -- \n", serverPubKey, ssh.MarshalAuthorizedKey(key))
+ ss.log.Printf("--- %+v\n", ssh.MarshalAuthorizedKey(key))
return nil
},
},
@@ -238,10 +175,14 @@
}
}
+func (ss *Client) GetRepoAddress(name string) string {
+ return fmt.Sprintf("%s/%s", ss.addressGit(), name)
+}
+
func (ss *Client) addressGit() string {
- return fmt.Sprintf("ssh://%s:%d", ss.ip, ss.port)
+ return fmt.Sprintf("ssh://%s", ss.addressSSH())
}
func (ss *Client) addressSSH() string {
- return fmt.Sprintf("%s:%d", ss.ip, ss.port)
+ return fmt.Sprintf("%s:%d", ss.IP, ss.port)
}
diff --git a/core/installer/values-tmpl/cert-manager-webhook-gandi-role.jsonschema b/core/installer/values-tmpl/cert-manager-webhook-gandi-role.jsonschema
new file mode 100644
index 0000000..f42d895
--- /dev/null
+++ b/core/installer/values-tmpl/cert-manager-webhook-gandi-role.jsonschema
@@ -0,0 +1,6 @@
+{
+ "type": "object",
+ "properties": {
+ },
+ "additionalProperties": false
+}
diff --git a/core/installer/values-tmpl/cert-manager-webhook-gandi-role.md b/core/installer/values-tmpl/cert-manager-webhook-gandi-role.md
new file mode 100644
index 0000000..e6f01a3
--- /dev/null
+++ b/core/installer/values-tmpl/cert-manager-webhook-gandi-role.md
@@ -0,0 +1 @@
+Installs rbacs to let cert-manager create gandi resource
diff --git a/core/installer/values-tmpl/cert-manager-webhook-gandi-role.yaml b/core/installer/values-tmpl/cert-manager-webhook-gandi-role.yaml
new file mode 100644
index 0000000..f0f9b93
--- /dev/null
+++ b/core/installer/values-tmpl/cert-manager-webhook-gandi-role.yaml
@@ -0,0 +1,23 @@
+apiVersion: helm.toolkit.fluxcd.io/v2beta1
+kind: HelmRelease
+metadata:
+ name: cert-manager-webhook-gandi-role
+ namespace: {{ .Global.PCloudEnvName }}
+spec:
+ targetNamespace: {{ .Global.PCloudEnvName }}-cert-manager
+ dependsOn:
+ - name: cert-manager
+ namespace: {{ .Global.PCloudEnvName }}
+ chart:
+ spec:
+ chart: charts/cert-manager-webhook-gandi-role
+ sourceRef:
+ kind: GitRepository
+ name: pcloud
+ namespace: {{ .Global.PCloudEnvName }}
+ interval: 1m0s
+ timeout: 20m0s
+ values:
+ certManager:
+ namespace: {{ .Global.PCloudEnvName }}-cert-manager
+ name: {{ .Global.PCloudEnvName }}-cert-manager
diff --git a/core/installer/values-tmpl/cert-manager-webhook-gandi.jsonschema b/core/installer/values-tmpl/cert-manager-webhook-gandi.jsonschema
new file mode 100644
index 0000000..f42d895
--- /dev/null
+++ b/core/installer/values-tmpl/cert-manager-webhook-gandi.jsonschema
@@ -0,0 +1,6 @@
+{
+ "type": "object",
+ "properties": {
+ },
+ "additionalProperties": false
+}
diff --git a/core/installer/values-tmpl/cert-manager-webhook-gandi.md b/core/installer/values-tmpl/cert-manager-webhook-gandi.md
new file mode 100644
index 0000000..6590062
--- /dev/null
+++ b/core/installer/values-tmpl/cert-manager-webhook-gandi.md
@@ -0,0 +1 @@
+Installs cert-manager DNS01 resolver for Gandi.net domain registrar
diff --git a/core/installer/values-tmpl/cert-manager-webhook-gandi.yaml b/core/installer/values-tmpl/cert-manager-webhook-gandi.yaml
new file mode 100644
index 0000000..fdcc030
--- /dev/null
+++ b/core/installer/values-tmpl/cert-manager-webhook-gandi.yaml
@@ -0,0 +1,29 @@
+apiVersion: helm.toolkit.fluxcd.io/v2beta1
+kind: HelmRelease
+metadata:
+ name: cert-manager-webhook-gandi
+ namespace: {{ .Global.PCloudEnvName }}
+spec:
+ targetNamespace: {{ .Global.PCloudEnvName }}-cert-manager
+ dependsOn:
+ - name: cert-manager
+ namespace: {{ .Global.PCloudEnvName }}
+ chart:
+ spec:
+ chart: charts/cert-manager-webhook-gandi
+ sourceRef:
+ kind: GitRepository
+ name: pcloud
+ namespace: {{ .Global.PCloudEnvName }}
+ interval: 1m0s
+ timeout: 20m0s
+ values:
+ fullnameOverride: {{ .Global.PCloudEnvName }}-cert-manager-webhook-gandi
+ certManager:
+ namespace: {{ .Global.PCloudEnvName }}-cert-manager
+ name: {{ .Global.PCloudEnvName }}-cert-manager
+ image:
+ repository: giolekva/cert-manager-webhook-gandi
+ tag: v0.2.0
+ pullPolicy: IfNotPresent
+ logLevel: 2
diff --git a/core/installer/values-tmpl/cert-manager.jsonschema b/core/installer/values-tmpl/cert-manager.jsonschema
new file mode 100644
index 0000000..f42d895
--- /dev/null
+++ b/core/installer/values-tmpl/cert-manager.jsonschema
@@ -0,0 +1,6 @@
+{
+ "type": "object",
+ "properties": {
+ },
+ "additionalProperties": false
+}
diff --git a/core/installer/values-tmpl/cert-manager.md b/core/installer/values-tmpl/cert-manager.md
new file mode 100644
index 0000000..aba785a
--- /dev/null
+++ b/core/installer/values-tmpl/cert-manager.md
@@ -0,0 +1 @@
+Installs cert-manager
diff --git a/core/installer/values-tmpl/cert-manager.yaml b/core/installer/values-tmpl/cert-manager.yaml
new file mode 100644
index 0000000..db00d34
--- /dev/null
+++ b/core/installer/values-tmpl/cert-manager.yaml
@@ -0,0 +1,47 @@
+apiVersion: helm.toolkit.fluxcd.io/v2beta1
+kind: HelmRelease
+metadata:
+ name: namespaces-cert-manager
+ namespace: {{ .Global.PCloudEnvName }}
+spec:
+ chart:
+ spec:
+ chart: charts/namespaces
+ sourceRef:
+ kind: GitRepository
+ name: {{ .Global.PCloudEnvName }}
+ namespace: {{ .Global.PCloudEnvName }}
+ interval: 1m0s
+ values:
+ pcloudInstanceId: ""
+ namespacePrefix: {{ .Global.PCloudEnvName }}-
+ namespaces:
+ - cert-manager
+---
+apiVersion: helm.toolkit.fluxcd.io/v2beta1
+kind: HelmRelease
+metadata:
+ name: cert-manager
+ namespace: {{ .Global.PCloudEnvName }}
+spec:
+ targetNamespace: {{ .Global.PCloudEnvName }}-cert-manager
+ dependsOn:
+ - name: namespaces-cert-manager
+ namespace: {{ .Global.PCloudEnvName }}
+ - name: ingress-public
+ namespace: {{ .Global.PCloudEnvName }}
+ chart:
+ spec:
+ chart: charts/cert-manager
+ sourceRef:
+ kind: GitRepository
+ name: pcloud
+ namespace: {{ .Global.PCloudEnvName }}
+ interval: 1m0s
+ timeout: 20m0s
+ values:
+ fullnameOverride: {{ .Global.PCloudEnvName }}-cert-manager
+ installCRDs: true
+ image:
+ tag: v1.11.1
+ pullPolicy: IfNotPresent
diff --git a/core/installer/values-tmpl/certificate-issuer-private.jsonschema b/core/installer/values-tmpl/certificate-issuer-private.jsonschema
new file mode 100644
index 0000000..46ae9c3
--- /dev/null
+++ b/core/installer/values-tmpl/certificate-issuer-private.jsonschema
@@ -0,0 +1,7 @@
+{
+ "type": "object",
+ "properties": {
+ "GandiAPIToken": { "type": "string" },
+ },
+ "additionalProperties": false
+}
diff --git a/core/installer/values-tmpl/certificate-issuer-private.md b/core/installer/values-tmpl/certificate-issuer-private.md
new file mode 100644
index 0000000..9ee84cc
--- /dev/null
+++ b/core/installer/values-tmpl/certificate-issuer-private.md
@@ -0,0 +1 @@
+Installs certificate issuer for private domain
diff --git a/core/installer/values-tmpl/certificate-issuer-private.yaml b/core/installer/values-tmpl/certificate-issuer-private.yaml
new file mode 100644
index 0000000..23004a0
--- /dev/null
+++ b/core/installer/values-tmpl/certificate-issuer-private.yaml
@@ -0,0 +1,30 @@
+apiVersion: helm.toolkit.fluxcd.io/v2beta1
+kind: HelmRelease
+metadata:
+ name: certificate-issuer
+ namespace: {{ .Global.Id }}
+spec:
+ targetNamespace: {{ .Global.NamespacePrefix }}ingress-private
+ dependsOn:
+ - name: ingress-private
+ namespace: {{ .Global.Id }}
+ chart:
+ spec:
+ chart: charts/certificate-issuer-private
+ sourceRef:
+ kind: GitRepository
+ name: pcloud
+ namespace: {{ .Global.Id }}
+ interval: 1m0s
+ values:
+ certManager:
+ namespace: {{ .Global.PCloudEnvName }}-cert-manager
+ gandiWebhookSecretReader: {{ .Global.PCloudEnvName }}-cert-manager-webhook-gandi
+ issuer:
+ name: {{ .Global.Id }}-private
+ # server: https://acme-v02.api.letsencrypt.org/directory
+ server: https://acme-staging-v02.api.letsencrypt.org/directory
+ domain: {{ .Global.PrivateDomain }}
+ contactEmail: {{ .Global.ContactEmail }}
+ ingressClassName: {{ .Global.Id }}-ingress-private
+ gandiAPIToken: {{ .Values.GandiAPIToken }}
diff --git a/core/installer/values-tmpl/core-auth.yaml b/core/installer/values-tmpl/core-auth.yaml
index 13e9c9c..856fb4c 100644
--- a/core/installer/values-tmpl/core-auth.yaml
+++ b/core/installer/values-tmpl/core-auth.yaml
@@ -8,6 +8,8 @@
dependsOn:
- name: core-auth-storage
namespace: {{ .Global.Id }}
+ - name: ingress-private
+ namespace: {{ .Global.Id }}
chart:
spec:
chart: charts/auth
diff --git a/core/installer/values-tmpl/csi-driver-smb.jsonschema b/core/installer/values-tmpl/csi-driver-smb.jsonschema
new file mode 100644
index 0000000..f42d895
--- /dev/null
+++ b/core/installer/values-tmpl/csi-driver-smb.jsonschema
@@ -0,0 +1,6 @@
+{
+ "type": "object",
+ "properties": {
+ },
+ "additionalProperties": false
+}
diff --git a/core/installer/values-tmpl/csi-driver-smb.md b/core/installer/values-tmpl/csi-driver-smb.md
new file mode 100644
index 0000000..171a000
--- /dev/null
+++ b/core/installer/values-tmpl/csi-driver-smb.md
@@ -0,0 +1 @@
+Installs iCSI SMB driver
diff --git a/core/installer/values-tmpl/csi-driver-smb.yaml b/core/installer/values-tmpl/csi-driver-smb.yaml
new file mode 100644
index 0000000..9a2cf36
--- /dev/null
+++ b/core/installer/values-tmpl/csi-driver-smb.yaml
@@ -0,0 +1,40 @@
+apiVersion: helm.toolkit.fluxcd.io/v2beta1
+kind: HelmRelease
+metadata:
+ name: namespaces-csi-driver-smb
+ namespace: {{ .Global.PCloudEnvName }}
+spec:
+ chart:
+ spec:
+ chart: charts/namespaces
+ sourceRef:
+ kind: GitRepository
+ name: {{ .Global.PCloudEnvName }}
+ namespace: {{ .Global.PCloudEnvName }}
+ interval: 1m0s
+ values:
+ pcloudInstanceId: ""
+ namespacePrefix: {{ .Global.PCloudEnvName }}-
+ namespaces:
+ - csi-driver-smb
+---
+apiVersion: helm.toolkit.fluxcd.io/v2beta1
+kind: HelmRelease
+metadata:
+ name: csi-driver-smb
+ namespace: {{ .Global.PCloudEnvName }}
+spec:
+ targetNamespace: {{ .Global.PCloudEnvName }}-csi-driver-smb
+ dependsOn:
+ - name: namespaces-csi-driver-smb
+ namespace: {{ .Global.PCloudEnvName }}
+ chart:
+ spec:
+ chart: charts/csi-driver-smb
+ sourceRef:
+ kind: GitRepository
+ name: pcloud
+ namespace: {{ .Global.PCloudEnvName }}
+ interval: 1m0s
+ timeout: 20m0s
+ values:
diff --git a/core/installer/values-tmpl/env-manager.jsonschema b/core/installer/values-tmpl/env-manager.jsonschema
new file mode 100644
index 0000000..aa2f01d
--- /dev/null
+++ b/core/installer/values-tmpl/env-manager.jsonschema
@@ -0,0 +1,8 @@
+{
+ "type": "object",
+ "properties": {
+ "RepoIP": { "type": "string", "default": "192.168.0.11" },
+ "SSHPrivateKey": { "type": "string", "default": "foo bar" }
+ },
+ "additionalProperties": false
+}
diff --git a/core/installer/values-tmpl/env-manager.md b/core/installer/values-tmpl/env-manager.md
new file mode 100644
index 0000000..ec69eba
--- /dev/null
+++ b/core/installer/values-tmpl/env-manager.md
@@ -0,0 +1 @@
+PCloud environment manager
diff --git a/core/installer/values-tmpl/env-manager.yaml b/core/installer/values-tmpl/env-manager.yaml
new file mode 100644
index 0000000..691693b
--- /dev/null
+++ b/core/installer/values-tmpl/env-manager.yaml
@@ -0,0 +1,17 @@
+apiVersion: helm.toolkit.fluxcd.io/v2beta1
+kind: HelmRelease
+metadata:
+ name: env-manager
+ namespace: {{ .Global.PCloudEnvName }}
+spec:
+ chart:
+ spec:
+ chart: charts/env-manager
+ sourceRef:
+ kind: GitRepository
+ name: pcloud
+ namespace: {{ .Global.PCloudEnvName }}
+ interval: 1m0s
+ values:
+ repoIP: {{ .Values.RepoIP }}
+ sshPrivateKey: {{ .Values.SSHPrivateKey | b64enc }}
diff --git a/core/installer/values-tmpl/headscale-controller.jsonschema b/core/installer/values-tmpl/headscale-controller.jsonschema
new file mode 100644
index 0000000..f42d895
--- /dev/null
+++ b/core/installer/values-tmpl/headscale-controller.jsonschema
@@ -0,0 +1,6 @@
+{
+ "type": "object",
+ "properties": {
+ },
+ "additionalProperties": false
+}
diff --git a/core/installer/values-tmpl/headscale-controller.md b/core/installer/values-tmpl/headscale-controller.md
new file mode 100644
index 0000000..99d2190
--- /dev/null
+++ b/core/installer/values-tmpl/headscale-controller.md
@@ -0,0 +1 @@
+Installs headscale controller
diff --git a/core/installer/values-tmpl/headscale-controller.yaml b/core/installer/values-tmpl/headscale-controller.yaml
new file mode 100644
index 0000000..3285f58
--- /dev/null
+++ b/core/installer/values-tmpl/headscale-controller.yaml
@@ -0,0 +1,38 @@
+apiVersion: helm.toolkit.fluxcd.io/v2beta1
+kind: HelmRelease
+metadata:
+ name: namespaces-headscale-controller
+ namespace: {{ .Global.PCloudEnvName }}
+spec:
+ chart:
+ spec:
+ chart: charts/namespaces
+ sourceRef:
+ kind: GitRepository
+ name: pcloud
+ namespace: {{ .Global.PCloudEnvName }}
+ interval: 1m0s
+ values:
+ namespacePrefix: {{ .Global.PCloudEnvName }}-
+ namespaces:
+ - headscale-controller
+---
+apiVersion: helm.toolkit.fluxcd.io/v2beta1
+kind: HelmRelease
+metadata:
+ name: headscale-controller
+ namespace: {{ .Global.PCloudEnvName }}
+spec:
+ targetNamespace: {{ .Global.PCloudEnvName }}-headscale-controller
+ dependsOn:
+ - name: namespaces-headscale-controller
+ namespace: {{ .Global.PCloudEnvName }}
+ chart:
+ spec:
+ chart: charts/headscale-controller
+ sourceRef:
+ kind: GitRepository
+ name: pcloud
+ namespace: {{ .Global.PCloudEnvName }}
+ interval: 1m0s
+ values:
diff --git a/core/installer/values-tmpl/headscale.yaml b/core/installer/values-tmpl/headscale.yaml
index 79e457e..8c16b86 100644
--- a/core/installer/values-tmpl/headscale.yaml
+++ b/core/installer/values-tmpl/headscale.yaml
@@ -28,6 +28,8 @@
dependsOn:
- name: namespaces-headscale
namespace: {{ .Global.Id }}
+ - name: core-auth
+ namespace: {{ .Global.Id }}
chart:
spec:
chart: charts/headscale
@@ -46,7 +48,7 @@
ingressClassName: pcloud-ingress-public
certificateIssuer: {{ .Global.Id }}-public
domain: {{ .Values.Subdomain }}.{{ .Global.Domain }}
- internalBaseDomain: {{ .Global.PrivateDomain }}
+ publicBaseDomain: {{ .Global.Domain }}
oauth2:
hydraAdmin: http://hydra-admin.{{ .Global.NamespacePrefix }}core-auth.svc.cluster.local
hydraPublic: https://hydra.{{ .Global.Domain }}
diff --git a/core/installer/values-tmpl/ingress-private.yaml b/core/installer/values-tmpl/ingress-private.yaml
index f33e179..0874b72 100644
--- a/core/installer/values-tmpl/ingress-private.yaml
+++ b/core/installer/values-tmpl/ingress-private.yaml
@@ -21,34 +21,12 @@
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
- name: volumes-ingress-private
- namespace: {{ .Global.Id }}
-spec:
- targetNamespace: {{ .Global.NamespacePrefix }}ingress-private
- dependsOn:
- - name: namespaces-ingress-private
- namespace: {{ .Global.Id }}
- chart:
- spec:
- chart: charts/volumes
- sourceRef:
- kind: GitRepository
- name: pcloud
- namespace: {{ .Global.Id }}
- interval: 1m0s
- values:
- name: tailscale
- size: 1Gi
----
-apiVersion: helm.toolkit.fluxcd.io/v2beta1
-kind: HelmRelease
-metadata:
name: ingress-private
namespace: {{ .Global.Id }}
spec:
targetNamespace: {{ .Global.NamespacePrefix }}ingress-private
dependsOn:
- - name: volumes-ingress-private
+ - name: namespaces-ingress-private
namespace: {{ .Global.Id }}
chart:
spec:
diff --git a/core/installer/values-tmpl/ingress-public.jsonschema b/core/installer/values-tmpl/ingress-public.jsonschema
index ec6a2c5..f42d895 100644
--- a/core/installer/values-tmpl/ingress-public.jsonschema
+++ b/core/installer/values-tmpl/ingress-public.jsonschema
@@ -1,15 +1,6 @@
{
"type": "object",
"properties": {
- "Values": {
- "type": "object",
- "properties": {
- "NamespacePrefix": { "type": "string" },
- "Id": { "type": "string" },
- "Domain": { "type": "string" }
- },
- "additionalProperties": false
- }
},
"additionalProperties": false
}
diff --git a/core/installer/values-tmpl/ingress-public.md b/core/installer/values-tmpl/ingress-public.md
new file mode 100644
index 0000000..227c2d4
--- /dev/null
+++ b/core/installer/values-tmpl/ingress-public.md
@@ -0,0 +1 @@
+Sets up ingress for publicly accessible services
diff --git a/core/installer/values-tmpl/ingress-public.yaml b/core/installer/values-tmpl/ingress-public.yaml
index 43ae8bc..80a5efd 100644
--- a/core/installer/values-tmpl/ingress-public.yaml
+++ b/core/installer/values-tmpl/ingress-public.yaml
@@ -2,51 +2,52 @@
kind: HelmRelease
metadata:
name: namespaces-ingress-public
- namespace: {{ .Global.Id }}
+ namespace: {{ .Global.PCloudEnvName }}
spec:
chart:
spec:
chart: charts/namespaces
sourceRef:
kind: GitRepository
- name: pcloud
- namespace: {{ .Global.Id }}
+ name: {{ .Global.PCloudEnvName }}
+ namespace: {{ .Global.PCloudEnvName }}
interval: 1m0s
values:
- pcloudInstanceId: {{ .Global.Id }}
- namespacePrefix: {{ .Global.NamespacePrefix }}
+ pcloudInstanceId: ""
+ namespacePrefix: {{ .Global.PCloudEnvName }}-
namespaces:
- - app-ingress-public
+ - ingress-public
---
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
name: ingress-public
- namespace: {{ .Global.Id }}
+ namespace: {{ .Global.PCloudEnvName }}
spec:
- targetNamespace: {{ .Values.NamespacePrefix }}ingress-public
+ targetNamespace: {{ .Global.PCloudEnvName }}-ingress-public
dependsOn:
- name: namespaces-ingress-public
- namespace: {{ .Global.Id }}
+ namespace: {{ .Global.PCloudEnvName }}
chart:
spec:
- chart: ingress-nginx
- version: 4.0.3
+ chart: charts/ingress-nginx
sourceRef:
- kind: HelmRepository
- name: ingress-nginx
- namespace: {{ .Values.Id }}
+ kind: GitRepository
+ name: pcloud
+ namespace: {{ .Global.PCloudEnvName }}
interval: 1m0s
values:
- fullnameOverride: {{ .Values.Id }}-ingress-public
+ fullnameOverride: {{ .Global.PCloudEnvName }}-ingress-public
controller:
service:
type: LoadBalancer
+ annotations:
+ metallb.universe.tf/loadBalancerIPs: 192.168.0.213 # TODO(giolekva): configurable
ingressClassByName: true
ingressClassResource:
- name: {{ .Values.Id }}-ingress-public
+ name: {{ .Global.PCloudEnvName }}-ingress-public
enabled: true
default: false
- controllerValue: k8s.io/{{ .Values.Id }}-ingress-public
+ controllerValue: k8s.io/{{ .Global.PCloudEnvName }}-ingress-public
config:
- proxy-body-size: 100M
+ proxy-body-size: 100M # TODO(giolekva): configurable
diff --git a/core/installer/values-tmpl/metallb-config-env.yaml b/core/installer/values-tmpl/metallb-config-env.yaml
index 6ea2ac9..39907e4 100644
--- a/core/installer/values-tmpl/metallb-config-env.yaml
+++ b/core/installer/values-tmpl/metallb-config-env.yaml
@@ -1,7 +1,7 @@
apiVersion: helm.toolkit.fluxcd.io/v2beta1
kind: HelmRelease
metadata:
- name: meteallb-config-env
+ name: meteallb-config-env # TODO(giolekva): typo metea
namespace: {{ .Global.Id }}
spec:
chart:
diff --git a/core/installer/values-tmpl/resource-renderer-controller.jsonschema b/core/installer/values-tmpl/resource-renderer-controller.jsonschema
new file mode 100644
index 0000000..f42d895
--- /dev/null
+++ b/core/installer/values-tmpl/resource-renderer-controller.jsonschema
@@ -0,0 +1,6 @@
+{
+ "type": "object",
+ "properties": {
+ },
+ "additionalProperties": false
+}
diff --git a/core/installer/values-tmpl/resource-renderer-controller.md b/core/installer/values-tmpl/resource-renderer-controller.md
new file mode 100644
index 0000000..81231e0
--- /dev/null
+++ b/core/installer/values-tmpl/resource-renderer-controller.md
@@ -0,0 +1 @@
+Installs resource-renderer controller
diff --git a/core/installer/values-tmpl/resource-renderer-controller.yaml b/core/installer/values-tmpl/resource-renderer-controller.yaml
new file mode 100644
index 0000000..72cf68b
--- /dev/null
+++ b/core/installer/values-tmpl/resource-renderer-controller.yaml
@@ -0,0 +1,38 @@
+apiVersion: helm.toolkit.fluxcd.io/v2beta1
+kind: HelmRelease
+metadata:
+ name: namespaces-rr-controller
+ namespace: {{ .Global.PCloudEnvName }}
+spec:
+ chart:
+ spec:
+ chart: charts/namespaces
+ sourceRef:
+ kind: GitRepository
+ name: pcloud
+ namespace: {{ .Global.PCloudEnvName }}
+ interval: 1m0s
+ values:
+ namespacePrefix: {{ .Global.PCloudEnvName }}-
+ namespaces:
+ - rr-controller
+---
+apiVersion: helm.toolkit.fluxcd.io/v2beta1
+kind: HelmRelease
+metadata:
+ name: rr-controller
+ namespace: {{ .Global.PCloudEnvName }}
+spec:
+ targetNamespace: {{ .Global.PCloudEnvName }}-rr-controller
+ dependsOn:
+ - name: namespaces-rr-controller
+ namespace: {{ .Global.PCloudEnvName }}
+ chart:
+ spec:
+ chart: charts/resource-renderer-controller
+ sourceRef:
+ kind: GitRepository
+ name: pcloud
+ namespace: {{ .Global.PCloudEnvName }}
+ interval: 1m0s
+ values:
diff --git a/core/installer/values-tmpl/tailscale-proxy.yaml b/core/installer/values-tmpl/tailscale-proxy.yaml
index 56dec5e..9664e51 100644
--- a/core/installer/values-tmpl/tailscale-proxy.yaml
+++ b/core/installer/values-tmpl/tailscale-proxy.yaml
@@ -28,6 +28,8 @@
dependsOn:
- name: namespaces-tailscale-proxy
namespace: {{ .Global.Id }}
+ - name: headscale
+ namespace: {{ .Global.Id }}
chart:
spec:
chart: charts/tailscale
@@ -38,6 +40,7 @@
interval: 1m0s
values:
hostname: {{ .Global.PCloudEnvName }}-{{ .Global.Id }}-internal-proxy
+ apiServer: http://headscale-api.{{ .Global.Id }}-app-headscale.svc.cluster.local
loginServer: https://headscale.{{ .Global.Domain }} # TODO(gio): take headscale subdomain from configuration
ipSubnet: {{ .Values.IPSubnet }}
username: {{ .Values.Username }}