installer: orginize bootstrapper, improve service IP handling
diff --git a/core/installer/Makefile b/core/installer/Makefile
index 9c14dd1..4d76e6b 100644
--- a/core/installer/Makefile
+++ b/core/installer/Makefile
@@ -11,7 +11,7 @@
go build -o pcloud cmd/*.go
bootstrap:
- ./pcloud --kubeconfig=../../priv/kubeconfig bootstrap --charts-dir=../../charts --admin-pub-key=/Users/lekva/.ssh/id_rsa.pub --soft-serve-ip=192.168.0.211 --storage-dir=/pcloud-storage/longhorn
+ ./pcloud --kubeconfig=../../scripts/hetzner/kubeconfig bootstrap --env-name=dodo --charts-dir=../../charts --admin-pub-key=/Users/lekva/.ssh/id_rsa.pub --from-ip=192.168.100.210 --to-ip=192.168.100.240 --storage-dir=/pcloud-storage/longhorn
create_env:
./pcloud --kubeconfig=../../priv/kubeconfig create-env --admin-priv-key=/Users/lekva/.ssh/id_rsa --name=lekva --ip=192.168.0.211 --admin-username=gio
@@ -36,9 +36,28 @@
build_arm64:
go build -o server_arm64 cmd/*.go
-push: clean build_arm64
+build_amd64: export CGO_ENABLED=0
+build_amd64: export GO111MODULE=on
+build_amd64: export GOOS=linux
+build_amd64: export GOARCH=amd64
+build_amd64:
+ go build -o server_amd64 cmd/*.go
+
+push_arm64: clean build_arm64
mkdir tmp
cp -r ../../charts tmp/
- podman build --tag=giolekva/pcloud-installer:latest .
+ podman build --platform linux/arm64 --tag=giolekva/pcloud-installer:arm64 .
rm -rf tmp
- podman push giolekva/pcloud-installer:latest
+ podman push giolekva/pcloud-installer:arm64
+
+push_amd64: clean build_amd64
+ mkdir tmp
+ cp -r ../../charts tmp/
+ podman build --platform linux/amd64 --tag=giolekva/pcloud-installer:amd64 .
+ rm -rf tmp
+ podman push giolekva/pcloud-installer:amd64
+
+push: push_arm64 push_amd64
+ podman manifest create giolekva/pcloud-installer:latest giolekva/pcloud-installer:arm64 giolekva/pcloud-installer:amd64
+ podman manifest push giolekva/pcloud-installer:latest docker://docker.io/giolekva/pcloud-installer:latest
+ podman manifest rm giolekva/pcloud-installer:latest
diff --git a/core/installer/bootstrapper.go b/core/installer/bootstrapper.go
new file mode 100644
index 0000000..957f1ab
--- /dev/null
+++ b/core/installer/bootstrapper.go
@@ -0,0 +1,509 @@
+package installer
+
+import (
+ "context"
+ _ "embed"
+ "fmt"
+ "log"
+ "net/netip"
+ "path/filepath"
+ "time"
+
+ "github.com/cenkalti/backoff/v4"
+ "helm.sh/helm/v3/pkg/action"
+ "helm.sh/helm/v3/pkg/chart"
+ "helm.sh/helm/v3/pkg/chart/loader"
+
+ "github.com/giolekva/pcloud/core/installer/soft"
+)
+
+const IPAddressPoolLocal = "local"
+const IPAddressPoolConfigRepo = "config-repo"
+const IPAddressPoolIngressPublic = "ingress-public"
+
+type Bootstrapper struct {
+ cl ChartLoader
+ ns NamespaceCreator
+ ha HelmActionConfigFactory
+}
+
+func NewBootstrapper(cl ChartLoader, ns NamespaceCreator, ha HelmActionConfigFactory) Bootstrapper {
+ return Bootstrapper{cl, ns, ha}
+}
+
+func (b Bootstrapper) Run(env EnvConfig) error {
+ bootstrapJobKeys, err := NewSSHKeyPair()
+ if err != nil {
+ return err
+ }
+ if err := b.installMetallb(env); err != nil {
+ return err
+ }
+ if err := b.installLonghorn(env.Name, env.StorageDir, env.VolumeDefaultReplicaCount); err != nil {
+ return err
+ }
+ time.Sleep(1 * time.Minute) // TODO(giolekva): implement proper wait
+ if err := b.installSoftServe(bootstrapJobKeys.Public, env.Name, env.ServiceIPs.ConfigRepo); err != nil {
+ return err
+ }
+ var ss *soft.Client
+ err = backoff.Retry(func() error {
+ var err error
+ ss, err = soft.NewClient(netip.AddrPortFrom(env.ServiceIPs.ConfigRepo, 22), []byte(bootstrapJobKeys.Private), log.Default())
+ return err
+ }, backoff.NewConstantBackOff(5*time.Second))
+ if err != nil {
+ return err
+ }
+ if ss.AddPublicKey("admin", string(env.AdminPublicKey)); err != nil {
+ return err
+ }
+ if err := b.installFluxcd(ss, env.Name); err != nil {
+ return err
+ }
+ repo, err := ss.GetRepo(env.Name)
+ if err != nil {
+ return err
+ }
+ repoIO := NewRepoIO(repo, ss.Signer)
+ if err := configureMainRepo(repoIO, env); err != nil {
+ return err
+ }
+ nsGen := NewPrefixGenerator(env.NamespacePrefix)
+ if err := b.installInfrastructureServices(repoIO, nsGen, b.ns, env); err != nil {
+ return err
+ }
+ if err := b.installEnvManager(ss, repoIO, nsGen, b.ns, env); err != nil {
+ return err
+ }
+ if ss.RemovePublicKey("admin", bootstrapJobKeys.Public); err != nil {
+ return err
+ }
+ return nil
+}
+
+func (b Bootstrapper) installMetallb(env EnvConfig) error {
+ if err := b.installMetallbNamespace(env); err != nil {
+ return err
+ }
+ if err := b.installMetallbService(); err != nil {
+ return err
+ }
+ if err := b.installMetallbIPAddressPool(IPAddressPoolLocal, true, env.ServiceIPs.From, env.ServiceIPs.To); err != nil {
+ return err
+ }
+ if err := b.installMetallbIPAddressPool(IPAddressPoolConfigRepo, false, env.ServiceIPs.ConfigRepo, env.ServiceIPs.ConfigRepo); err != nil {
+ return err
+ }
+ if err := b.installMetallbIPAddressPool(IPAddressPoolIngressPublic, false, env.ServiceIPs.IngressPublic, env.ServiceIPs.IngressPublic); err != nil {
+ return err
+ }
+ return nil
+}
+
+func (b Bootstrapper) installMetallbNamespace(env EnvConfig) error {
+ fmt.Println("Installing metallb namespace")
+ config, err := b.ha.New(env.Name)
+ if err != nil {
+ return err
+ }
+ chart, err := b.cl.Load("namespace")
+ if err != nil {
+ return err
+ }
+ values := map[string]any{
+ "namespace": "metallb-system",
+ "labels": []string{
+ "pod-security.kubernetes.io/audit: privileged",
+ "pod-security.kubernetes.io/enforce: privileged",
+ "pod-security.kubernetes.io/warn: privileged",
+ },
+ }
+ installer := action.NewInstall(config)
+ installer.Namespace = env.Name
+ installer.ReleaseName = "metallb-ns"
+ installer.Wait = true
+ installer.WaitForJobs = true
+ if _, err := installer.RunWithContext(context.TODO(), chart, values); err != nil {
+ return err
+ }
+ return nil
+}
+
+func (b Bootstrapper) installMetallbService() error {
+ fmt.Println("Installing metallb")
+ config, err := b.ha.New("metallb-system")
+ if err != nil {
+ return err
+ }
+ chart, err := b.cl.Load("metallb")
+ if err != nil {
+ return err
+ }
+ values := map[string]any{ // TODO(giolekva): add loadBalancerClass?
+ "controller": map[string]any{
+ "image": map[string]any{
+ "repository": "quay.io/metallb/controller",
+ "tag": "v0.13.9",
+ "pullPolicy": "IfNotPresent",
+ },
+ "logLevel": "info",
+ },
+ "speaker": map[string]any{
+ "image": map[string]any{
+ "repository": "quay.io/metallb/speaker",
+ "tag": "v0.13.9",
+ "pullPolicy": "IfNotPresent",
+ },
+ "logLevel": "info",
+ },
+ }
+ installer := action.NewInstall(config)
+ installer.Namespace = "metallb-system"
+ installer.CreateNamespace = true
+ installer.ReleaseName = "metallb"
+ installer.IncludeCRDs = true
+ 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 (b Bootstrapper) installMetallbIPAddressPool(name string, autoAssign bool, from, to netip.Addr) error {
+ fmt.Printf("Installing metallb-ipaddresspool: %s\n", name)
+ config, err := b.ha.New("metallb-system")
+ if err != nil {
+ return err
+ }
+ chart, err := b.cl.Load("metallb-ipaddresspool")
+ if err != nil {
+ return err
+ }
+ values := map[string]any{
+ "name": name,
+ "autoAssign": autoAssign,
+ "from": from.String(),
+ "to": to.String(),
+ }
+ installer := action.NewInstall(config)
+ installer.Namespace = "metallb-system"
+ installer.CreateNamespace = true
+ installer.ReleaseName = name
+ 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 (b Bootstrapper) installLonghorn(envName string, storageDir string, volumeDefaultReplicaCount int) error {
+ fmt.Println("Installing Longhorn")
+ config, err := b.ha.New(envName)
+ if err != nil {
+ return err
+ }
+ chart, err := b.cl.Load("longhorn")
+ if err != nil {
+ return err
+ }
+ values := map[string]any{
+ "defaultSettings": map[string]any{
+ "defaultDataPath": storageDir,
+ },
+ "persistence": map[string]any{
+ "defaultClassReplicaCount": volumeDefaultReplicaCount,
+ },
+ "service": map[string]any{
+ "ui": map[string]any{
+ "type": "LoadBalancer",
+ },
+ },
+ "ingress": map[string]any{
+ "enabled": false,
+ },
+ }
+ installer := action.NewInstall(config)
+ installer.Namespace = "longhorn-system"
+ installer.CreateNamespace = true
+ installer.ReleaseName = "longhorn"
+ 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 (b Bootstrapper) installSoftServe(adminPublicKey string, envName string, repoIP netip.Addr) error {
+ fmt.Println("Installing SoftServe")
+ keys, err := NewSSHKeyPair()
+ if err != nil {
+ return err
+ }
+ config, err := b.ha.New(envName)
+ if err != nil {
+ return err
+ }
+ chart, err := b.cl.Load("soft-serve")
+ if err != nil {
+ return err
+ }
+ values := map[string]any{
+ "image": map[string]any{
+ "repository": "charmcli/soft-serve",
+ "tag": "v0.5.4",
+ "pullPolicy": "IfNotPresent",
+ },
+ "privateKey": keys.Private,
+ "publicKey": keys.Public,
+ "adminKey": adminPublicKey,
+ "reservedIP": repoIP.String(),
+ }
+ installer := action.NewInstall(config)
+ installer.Namespace = envName
+ installer.CreateNamespace = true
+ installer.ReleaseName = "soft-serve"
+ 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 (b Bootstrapper) installFluxcd(ss *soft.Client, envName string) error {
+ keys, err := 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", envName)
+ if err := ss.AddRepository(envName, "# dodo Systems"); err != nil {
+ return err
+ }
+ fmt.Println("Installing Flux")
+ ssPublic, err := ss.GetPublicKey()
+ if err != nil {
+ return err
+ }
+ if err := b.installFluxBootstrap(
+ ss.GetRepoAddress(envName),
+ ss.Addr.Addr().String(),
+ string(ssPublic),
+ keys.Private,
+ envName,
+ ); err != nil {
+ return err
+ }
+ return nil
+}
+
+func (b Bootstrapper) installFluxBootstrap(repoAddr, repoHost, repoHostPubKey, privateKey, envName string) error {
+ config, err := b.ha.New(envName)
+ if err != nil {
+ return err
+ }
+ chart, err := b.cl.Load("flux-bootstrap")
+ if err != nil {
+ return err
+ }
+ values := map[string]any{
+ "image": map[string]any{
+ "repository": "fluxcd/flux-cli", // "giolekva/flux",
+ "tag": "v2.0.0",
+ "pullPolicy": "IfNotPresent",
+ },
+ "repositoryAddress": repoAddr,
+ "repositoryHost": repoHost,
+ "repositoryHostPublicKey": repoHostPubKey,
+ "privateKey": privateKey,
+ "installationNamespace": fmt.Sprintf("%s-flux", envName),
+ }
+ installer := action.NewInstall(config)
+ installer.Namespace = envName
+ installer.CreateNamespace = true
+ installer.ReleaseName = "flux"
+ 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 (b Bootstrapper) installInfrastructureServices(repo RepoIO, nsGen NamespaceGenerator, nsCreator NamespaceCreator, env EnvConfig) error {
+ appRepo := NewInMemoryAppRepository(CreateAllApps())
+ install := func(name string) error {
+ app, err := appRepo.Find(name)
+ if err != nil {
+ return err
+ }
+ namespaces := make([]string, len(app.Namespaces))
+ for i, n := range app.Namespaces {
+ namespaces[i], err = nsGen.Generate(n)
+ if err != nil {
+ return err
+ }
+ }
+ for _, n := range namespaces {
+ if err := nsCreator.Create(n); err != nil {
+ return err
+ }
+ }
+ derived := Derived{
+ Global: Values{
+ PCloudEnvName: env.Name,
+ },
+ }
+ if len(namespaces) > 0 {
+ derived.Release.Namespace = namespaces[0]
+ }
+ values := map[string]any{
+ "IngressPublicIP": env.ServiceIPs.IngressPublic.String(),
+ }
+ return repo.InstallApp(*app, filepath.Join("/infrastructure", app.Name), values, derived)
+ }
+ appsToInstall := []string{
+ "resource-renderer-controller",
+ "headscale-controller",
+ "csi-driver-smb",
+ "ingress-public",
+ "cert-manager",
+ "cert-manager-webhook-gandi",
+ "cert-manager-webhook-gandi-role",
+ }
+ for _, name := range appsToInstall {
+ if err := install(name); err != nil {
+ return err
+ }
+ }
+ return nil
+}
+
+func configureMainRepo(repo RepoIO, env EnvConfig) error {
+ if err := repo.WriteYaml("config.yaml", env); err != nil {
+ return err
+ }
+ kust := NewKustomization()
+ kust.AddResources(
+ fmt.Sprintf("%s-flux", env.Name),
+ "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(fmt.Sprintf(`
+apiVersion: source.toolkit.fluxcd.io/v1
+kind: GitRepository
+metadata:
+ name: pcloud # TODO(giolekva): use more generic name
+ namespace: %s
+spec:
+ interval: 1m0s
+ url: https://github.com/giolekva/pcloud
+ ref:
+ branch: main
+`, env.Name)))
+ if err != nil {
+ return err
+ }
+ }
+ infraKust := 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", NewKustomization()); err != nil {
+ return err
+ }
+ if err := repo.CommitAndPush("initialize pcloud directory structure"); err != nil {
+ return err
+ }
+ return nil
+}
+
+func (b Bootstrapper) installEnvManager(ss *soft.Client, repo RepoIO, nsGen NamespaceGenerator, nsCreator NamespaceCreator, env EnvConfig) error {
+ keys, err := NewSSHKeyPair()
+ if err != nil {
+ return err
+ }
+ user := fmt.Sprintf("%s-env-manager", env.Name)
+ if err := ss.AddUser(user, keys.Public); err != nil {
+ return err
+ }
+ if err := ss.MakeUserAdmin(user); err != nil {
+ return err
+ }
+ appRepo := NewInMemoryAppRepository(CreateAllApps())
+ app, err := appRepo.Find("env-manager")
+ if err != nil {
+ return err
+ }
+ namespaces := make([]string, len(app.Namespaces))
+ for i, n := range app.Namespaces {
+ namespaces[i], err = nsGen.Generate(n)
+ if err != nil {
+ return err
+ }
+ }
+ for _, n := range namespaces {
+ if err := nsCreator.Create(n); err != nil {
+ return err
+ }
+ }
+ derived := Derived{
+ Global: Values{
+ PCloudEnvName: env.Name,
+ },
+ Values: map[string]any{
+ "RepoIP": env.ServiceIPs.ConfigRepo,
+ "RepoPort": 22,
+ "RepoName": env.Name,
+ "SSHPrivateKey": keys.Private,
+ },
+ }
+ if len(namespaces) > 0 {
+ derived.Release.Namespace = namespaces[0]
+ }
+ return repo.InstallApp(*app, filepath.Join("/infrastructure", app.Name), derived.Values, derived)
+}
+
+type HelmActionConfigFactory interface {
+ New(namespace string) (*action.Configuration, error)
+}
+
+type ChartLoader interface {
+ Load(name string) (*chart.Chart, error)
+}
+
+type fsChartLoader struct {
+ baseDir string
+}
+
+func NewFSChartLoader(baseDir string) ChartLoader {
+ return &fsChartLoader{baseDir}
+}
+
+func (l *fsChartLoader) Load(name string) (*chart.Chart, error) {
+ return loader.Load(filepath.Join(l.baseDir, name))
+}
diff --git a/core/installer/cmd/app_manager.go b/core/installer/cmd/app_manager.go
index 6027204..a19a9fc 100644
--- a/core/installer/cmd/app_manager.go
+++ b/core/installer/cmd/app_manager.go
@@ -1,17 +1,13 @@
package main
import (
- "net"
"os"
- "github.com/go-git/go-billy/v5/memfs"
- "github.com/go-git/go-git/v5"
- gitssh "github.com/go-git/go-git/v5/plumbing/transport/ssh"
- "github.com/go-git/go-git/v5/storage/memory"
"github.com/spf13/cobra"
"golang.org/x/crypto/ssh"
"github.com/giolekva/pcloud/core/installer"
+ "github.com/giolekva/pcloud/core/installer/soft"
"github.com/giolekva/pcloud/core/installer/welcome"
)
@@ -63,7 +59,11 @@
if err != nil {
return err
}
- repo, err := cloneRepo(appManagerFlags.repoAddr, signer)
+ addr, err := soft.ParseRepositoryAddress(appManagerFlags.repoAddr)
+ if err != nil {
+ return err
+ }
+ repo, err := soft.CloneRepo(addr, signer)
if err != nil {
return err
}
@@ -88,25 +88,3 @@
s.Start()
return nil
}
-
-func cloneRepo(address string, signer ssh.Signer) (*git.Repository, error) {
- return git.Clone(memory.NewStorage(), memfs.New(), &git.CloneOptions{
- URL: address,
- Auth: auth(signer),
- RemoteName: "origin",
- InsecureSkipTLS: true,
- })
-}
-
-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/cmd/bootstrap.go b/core/installer/cmd/bootstrap.go
index 19ec6c9..d177ff5 100644
--- a/core/installer/cmd/bootstrap.go
+++ b/core/installer/cmd/bootstrap.go
@@ -1,31 +1,27 @@
package main
import (
- "context"
_ "embed"
"fmt"
- "log"
+ "net/netip"
"os"
- "path/filepath"
- "time"
- "github.com/cenkalti/backoff/v4"
"github.com/spf13/cobra"
"helm.sh/helm/v3/pkg/action"
- "helm.sh/helm/v3/pkg/chart/loader"
"helm.sh/helm/v3/pkg/kube"
"github.com/giolekva/pcloud/core/installer"
- "github.com/giolekva/pcloud/core/installer/soft"
)
var bootstrapFlags struct {
- pcloudEnvName string
+ envName string
+ publicIP string
chartsDir string
adminPubKey string
storageDir string
volumeDefaultReplicaCount int
- softServeIP string // TODO(giolekva): reserve using metallb IPAddressPool
+ fromIP string
+ toIP string
}
func bootstrapCmd() *cobra.Command {
@@ -34,12 +30,18 @@
RunE: bootstrapCmdRun,
}
cmd.Flags().StringVar(
- &bootstrapFlags.pcloudEnvName,
- "pcloud-env-name",
+ &bootstrapFlags.envName,
+ "env-name",
"pcloud",
"",
)
cmd.Flags().StringVar(
+ &bootstrapFlags.envName,
+ "public-ip",
+ "",
+ "",
+ )
+ cmd.Flags().StringVar(
&bootstrapFlags.chartsDir,
"charts-dir",
"",
@@ -64,8 +66,14 @@
"",
)
cmd.Flags().StringVar(
- &bootstrapFlags.softServeIP,
- "soft-serve-ip",
+ &bootstrapFlags.fromIP,
+ "from-ip",
+ "",
+ "",
+ )
+ cmd.Flags().StringVar(
+ &bootstrapFlags.toIP,
+ "to-ip",
"",
"",
)
@@ -77,457 +85,42 @@
if err != nil {
return err
}
- bootstrapJobKeys, err := installer.NewSSHKeyPair()
- if err != nil {
- return err
- }
- if err := installMetallb(); err != nil {
- return err
- }
- if err := installLonghorn(); err != nil {
- return err
- }
- time.Sleep(2 * time.Minute) // TODO(giolekva): implement proper wait
- if err := installSoftServe(bootstrapJobKeys.Public); err != nil {
- return err
- }
- var ss *soft.Client
- err = backoff.Retry(func() error {
- var err error
- ss, err = soft.NewClient(bootstrapFlags.softServeIP, 22, []byte(bootstrapJobKeys.Private), log.Default())
- return err
- }, backoff.NewConstantBackOff(5*time.Second))
- if err != nil {
- return err
- }
- 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
- }
- repoIO := installer.NewRepoIO(repo, ss.Signer)
- if err := configurePCloudRepo(repoIO); err != nil {
- return err
- }
- // TODO(giolekva): commit this to the repo above
- global := installer.Values{
- PCloudEnvName: bootstrapFlags.pcloudEnvName,
- }
nsCreator, err := newNSCreator()
if err != nil {
return err
}
- nsGen := installer.NewPrefixGenerator("pcloud-")
- if err := installInfrastructureServices(repoIO, nsGen, nsCreator, global); err != nil {
+ serviceIPs, err := newServiceIPs(bootstrapFlags.fromIP, bootstrapFlags.toIP)
+ if err != nil {
return err
}
- if err := installEnvManager(ss, repoIO, nsGen, nsCreator, global); err != nil {
- return err
+ envConfig := installer.EnvConfig{
+ Name: bootstrapFlags.envName,
+ PublicIP: bootstrapFlags.publicIP,
+ NamespacePrefix: fmt.Sprintf("%s-", bootstrapFlags.envName),
+ StorageDir: bootstrapFlags.storageDir,
+ VolumeDefaultReplicaCount: bootstrapFlags.volumeDefaultReplicaCount,
+ AdminPublicKey: adminPubKey,
+ ServiceIPs: serviceIPs,
}
- if ss.RemovePublicKey("admin", bootstrapJobKeys.Public); err != nil {
- return err
- }
- return nil
+ b := installer.NewBootstrapper(
+ installer.NewFSChartLoader(bootstrapFlags.chartsDir),
+ nsCreator,
+ actionConfigFactory{rootFlags.kubeConfig},
+ )
+ return b.Run(envConfig)
}
-func installMetallb() error {
- if err := installMetallbNamespace(); err != nil {
- return err
- }
- if err := installMetallbService(); err != nil {
- return err
- }
- if err := installMetallbConfig(); err != nil {
- return err
- }
- return nil
+type actionConfigFactory struct {
+ kubeConfigPath string
}
-func installMetallbNamespace() error {
- fmt.Println("Installing metallb namespace")
- // config, err := createActionConfig("default")
- config, err := createActionConfig(bootstrapFlags.pcloudEnvName)
- if err != nil {
- return err
- }
- chart, err := loader.Load(filepath.Join(bootstrapFlags.chartsDir, "namespace"))
- if err != nil {
- return err
- }
- values := map[string]interface{}{
- // "namespace": "pcloud-metallb",
- "namespace": "metallb-system",
- "labels": []string{
- "pod-security.kubernetes.io/audit: privileged",
- "pod-security.kubernetes.io/enforce: privileged",
- "pod-security.kubernetes.io/warn: privileged",
- },
- }
- installer := action.NewInstall(config)
- installer.Namespace = bootstrapFlags.pcloudEnvName
- installer.ReleaseName = "metallb-ns"
- installer.Wait = true
- installer.WaitForJobs = true
- if _, err := installer.RunWithContext(context.TODO(), chart, values); err != nil {
- return err
- }
- return nil
-}
-
-func installMetallbService() error {
- fmt.Println("Installing metallb")
- // config, err := createActionConfig("default")
- config, err := createActionConfig("metallb-system")
- if err != nil {
- return err
- }
- chart, err := loader.Load(filepath.Join(bootstrapFlags.chartsDir, "metallb"))
- if err != nil {
- return err
- }
- values := map[string]interface{}{ // TODO(giolekva): add loadBalancerClass?
- "controller": map[string]interface{}{
- "image": map[string]interface{}{
- "repository": "quay.io/metallb/controller",
- "tag": "v0.13.9",
- "pullPolicy": "IfNotPresent",
- },
- "logLevel": "info",
- },
- "speaker": map[string]interface{}{
- "image": map[string]interface{}{
- "repository": "quay.io/metallb/speaker",
- "tag": "v0.13.9",
- "pullPolicy": "IfNotPresent",
- },
- "logLevel": "info",
- },
- }
- installer := action.NewInstall(config)
- installer.Namespace = "metallb-system" // "pcloud-metallb"
- installer.CreateNamespace = true
- installer.ReleaseName = "metallb"
- installer.IncludeCRDs = true
- 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 installMetallbConfig() error {
- fmt.Println("Installing metallb-config")
- // config, err := createActionConfig("default")
- config, err := createActionConfig("metallb-system")
- if err != nil {
- return err
- }
- chart, err := loader.Load(filepath.Join(bootstrapFlags.chartsDir, "metallb-config"))
- if err != nil {
- return err
- }
- values := map[string]interface{}{
- "from": "192.168.0.210",
- "to": "192.168.0.240",
- }
- installer := action.NewInstall(config)
- installer.Namespace = "metallb-system" // "pcloud-metallb"
- installer.CreateNamespace = true
- installer.ReleaseName = "metallb-cfg"
- 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 installLonghorn() error {
- fmt.Println("Installing Longhorn")
- config, err := createActionConfig(bootstrapFlags.pcloudEnvName)
- if err != nil {
- return err
- }
- chart, err := loader.Load(filepath.Join(bootstrapFlags.chartsDir, "longhorn"))
- if err != nil {
- return err
- }
- values := map[string]interface{}{
- "defaultSettings": map[string]interface{}{
- "defaultDataPath": bootstrapFlags.storageDir,
- },
- "persistence": map[string]interface{}{
- "defaultClassReplicaCount": bootstrapFlags.volumeDefaultReplicaCount,
- },
- "service": map[string]interface{}{
- "ui": map[string]interface{}{
- "type": "LoadBalancer",
- },
- },
- "ingress": map[string]interface{}{
- "enabled": false,
- },
- }
- installer := action.NewInstall(config)
- installer.Namespace = "longhorn-system"
- installer.CreateNamespace = true
- installer.ReleaseName = "longhorn"
- 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 installSoftServe(adminPublicKey string) error {
- fmt.Println("Installing SoftServe")
- keys, err := installer.NewSSHKeyPair()
- if err != nil {
- return err
- }
- config, err := createActionConfig(bootstrapFlags.pcloudEnvName)
- if err != nil {
- return err
- }
- chart, err := loader.Load(filepath.Join(bootstrapFlags.chartsDir, "soft-serve"))
- if err != nil {
- return err
- }
- values := map[string]any{
- "image": map[string]any{
- "repository": "charmcli/soft-serve",
- "tag": "v0.5.4",
- "pullPolicy": "IfNotPresent",
- },
- "privateKey": keys.Private,
- "publicKey": keys.Public,
- "adminKey": adminPublicKey,
- "reservedIP": bootstrapFlags.softServeIP,
- }
- installer := action.NewInstall(config)
- installer.Namespace = bootstrapFlags.pcloudEnvName
- installer.CreateNamespace = true
- installer.ReleaseName = "soft-serve"
- 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 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
- }
- chart, err := loader.Load(filepath.Join(bootstrapFlags.chartsDir, "flux-bootstrap"))
- if err != nil {
- return err
- }
- values := map[string]any{
- "image": map[string]any{
- "repository": "giolekva/flux",
- "tag": "2.0.0",
- "pullPolicy": "IfNotPresent",
- },
- "repositoryAddress": repoAddr,
- "repositoryHost": repoHost,
- "repositoryHostPublicKey": repoHostPubKey,
- "privateKey": privateKey,
- }
- installer := action.NewInstall(config)
- installer.Namespace = bootstrapFlags.pcloudEnvName
- installer.CreateNamespace = true
- installer.ReleaseName = "flux"
- 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 installInfrastructureServices(repo installer.RepoIO, nsGen installer.NamespaceGenerator, nsCreator installer.NamespaceCreator, global installer.Values) error {
- appRepo := installer.NewInMemoryAppRepository(installer.CreateAllApps())
- install := func(name string) error {
- app, err := appRepo.Find(name)
- if err != nil {
- return err
- }
- namespaces := make([]string, len(app.Namespaces))
- for i, n := range app.Namespaces {
- namespaces[i], err = nsGen.Generate(n)
- if err != nil {
- return err
- }
- }
- for _, n := range namespaces {
- if err := nsCreator.Create(n); err != nil {
- return err
- }
- }
- derived := installer.Derived{
- Global: global,
- }
- if len(namespaces) > 0 {
- derived.Release.Namespace = namespaces[0]
- }
- return repo.InstallApp(*app, filepath.Join("/infrastructure", app.Name), map[string]any{}, derived)
- }
- appsToInstall := []string{
- "resource-renderer-controller",
- "headscale-controller",
- "csi-driver-smb",
- "ingress-public",
- "cert-manager",
- "cert-manager-webhook-gandi",
- "cert-manager-webhook-gandi-role",
- }
- 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", "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/v1
-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, nsGen installer.NamespaceGenerator, nsCreator installer.NamespaceCreator, global installer.Values) error {
- keys, err := installer.NewSSHKeyPair()
- if err != nil {
- return err
- }
- user := fmt.Sprintf("%s-env-manager", bootstrapFlags.pcloudEnvName)
- if err := ss.AddUser(user, keys.Public); err != nil {
- return err
- }
- if err := ss.MakeUserAdmin(user); err != nil {
- return err
- }
- appRepo := installer.NewInMemoryAppRepository(installer.CreateAllApps())
- app, err := appRepo.Find("env-manager")
- if err != nil {
- return err
- }
- namespaces := make([]string, len(app.Namespaces))
- for i, n := range app.Namespaces {
- namespaces[i], err = nsGen.Generate(n)
- if err != nil {
- return err
- }
- }
- for _, n := range namespaces {
- if err := nsCreator.Create(n); err != nil {
- return err
- }
- }
- derived := installer.Derived{
- Global: global,
- Values: map[string]any{
- "RepoIP": bootstrapFlags.softServeIP,
- "SSHPrivateKey": keys.Private,
- },
- }
- if len(namespaces) > 0 {
- derived.Release.Namespace = namespaces[0]
- }
- return repo.InstallApp(*app, filepath.Join("/infrastructure", app.Name), derived.Values, derived)
-}
-
-func createActionConfig(namespace string) (*action.Configuration, error) {
+func (f actionConfigFactory) New(namespace string) (*action.Configuration, error) {
config := new(action.Configuration)
if err := config.Init(
- kube.GetConfig(rootFlags.kubeConfig, "", namespace),
+ kube.GetConfig(f.kubeConfigPath, "", namespace),
namespace,
"",
- func(fmtString string, args ...interface{}) {
+ func(fmtString string, args ...any) {
fmt.Printf(fmtString, args...)
fmt.Println()
},
@@ -536,3 +129,23 @@
}
return config, nil
}
+
+func newServiceIPs(from, to string) (installer.EnvServiceIPs, error) {
+ f, err := netip.ParseAddr(from)
+ if err != nil {
+ return installer.EnvServiceIPs{}, err
+ }
+ t, err := netip.ParseAddr(to)
+ if err != nil {
+ return installer.EnvServiceIPs{}, err
+ }
+ configRepo := f
+ ingressPublic := configRepo.Next()
+ restFrom := ingressPublic.Next()
+ return installer.EnvServiceIPs{
+ ConfigRepo: configRepo,
+ IngressPublic: ingressPublic,
+ From: restFrom,
+ To: t,
+ }, nil
+}
diff --git a/core/installer/cmd/env_manager.go b/core/installer/cmd/env_manager.go
index a74369d..a77061a 100644
--- a/core/installer/cmd/env_manager.go
+++ b/core/installer/cmd/env_manager.go
@@ -2,6 +2,7 @@
import (
"log"
+ "net/netip"
"os"
"github.com/spf13/cobra"
@@ -12,8 +13,8 @@
)
var envManagerFlags struct {
- repoIP string
- repoPort int
+ repoAddr string
+ repoName string
sshKey string
port int
}
@@ -24,15 +25,15 @@
RunE: envManagerCmdRun,
}
cmd.Flags().StringVar(
- &envManagerFlags.repoIP,
- "repo-ip",
+ &envManagerFlags.repoAddr,
+ "repo-addr",
"",
"",
)
- cmd.Flags().IntVar(
- &envManagerFlags.repoPort,
- "repo-port",
- 22,
+ cmd.Flags().StringVar(
+ &envManagerFlags.repoName,
+ "repo-name",
+ "",
"",
)
cmd.Flags().StringVar(
@@ -55,11 +56,15 @@
if err != nil {
return err
}
- ss, err := soft.NewClient(envManagerFlags.repoIP, envManagerFlags.repoPort, sshKey, log.Default())
+ repoAddr, err := netip.ParseAddrPort(envManagerFlags.repoAddr)
if err != nil {
return err
}
- repo, err := ss.GetRepo("pcloud")
+ ss, err := soft.NewClient(repoAddr, sshKey, log.Default())
+ if err != nil {
+ return err
+ }
+ repo, err := ss.GetRepo(envManagerFlags.repoName)
if err != nil {
return err
}
diff --git a/core/installer/cmd/welcome.go b/core/installer/cmd/welcome.go
index 6d2d7e0..0a38d13 100644
--- a/core/installer/cmd/welcome.go
+++ b/core/installer/cmd/welcome.go
@@ -1,18 +1,13 @@
package main
import (
- "fmt"
"golang.org/x/crypto/ssh"
- "net"
"os"
- "github.com/go-git/go-billy/v5/memfs"
- "github.com/go-git/go-git/v5"
- gitssh "github.com/go-git/go-git/v5/plumbing/transport/ssh"
- "github.com/go-git/go-git/v5/storage/memory"
"github.com/spf13/cobra"
"github.com/giolekva/pcloud/core/installer"
+ "github.com/giolekva/pcloud/core/installer/soft"
"github.com/giolekva/pcloud/core/installer/welcome"
)
@@ -53,38 +48,27 @@
if err != nil {
return err
}
- auth := authSSH(sshKey)
- repo, err := git.Clone(memory.NewStorage(), memfs.New(), &git.CloneOptions{
- URL: welcomeFlags.repo,
- Auth: auth,
- RemoteName: "origin",
- ReferenceName: "refs/heads/master",
- Depth: 1,
- InsecureSkipTLS: true,
- Progress: os.Stdout,
- })
+ signer, err := ssh.ParsePrivateKey(sshKey)
+ if err != nil {
+ return err
+ }
+ addr, err := soft.ParseRepositoryAddress(welcomeFlags.repo)
+ if err != nil {
+ return err
+ }
+ repo, err := soft.CloneRepo(addr, signer)
+ if err != nil {
+ return err
+ }
nsCreator, err := newNSCreator()
if err != nil {
return err
}
s := welcome.NewServer(
welcomeFlags.port,
- installer.NewRepoIO(repo, auth.Signer),
+ installer.NewRepoIO(repo, signer),
nsCreator,
)
s.Start()
return nil
}
-
-func authSSH(pemBytes []byte) *gitssh.PublicKeys {
- a, err := gitssh.NewPublicKeys("git", pemBytes, "")
- if err != nil {
- panic(err)
- }
- a.HostKeyCallback = func(hostname string, remote net.Addr, key ssh.PublicKey) error {
- // TODO(giolekva): verify server public key
- fmt.Printf("--- %+v\n", ssh.MarshalAuthorizedKey(key))
- return nil
- }
- return a
-}
diff --git a/core/installer/config.go b/core/installer/config.go
index 9f547ff..f800aff 100644
--- a/core/installer/config.go
+++ b/core/installer/config.go
@@ -1,5 +1,26 @@
package installer
+import (
+ "net/netip"
+)
+
+type EnvServiceIPs struct {
+ ConfigRepo netip.Addr `json:"configRepo"`
+ IngressPublic netip.Addr `json:"ingressPublic"`
+ From netip.Addr `json:"from"`
+ To netip.Addr `json:"to"`
+}
+
+type EnvConfig struct {
+ Name string `json:"name"`
+ PublicIP string `json:"publicIP"`
+ NamespacePrefix string `json:"namespacePrefix"`
+ StorageDir string `json:"storageDir"`
+ VolumeDefaultReplicaCount int `json:"volumeDefaultReplicaCount"`
+ AdminPublicKey []byte `json:"adminPublicKey"`
+ ServiceIPs EnvServiceIPs `json:"serviceIPs"`
+}
+
type Config struct {
Values Values `json:"values"`
}
diff --git a/core/installer/repoio.go b/core/installer/repoio.go
index ec7981c..41c479f 100644
--- a/core/installer/repoio.go
+++ b/core/installer/repoio.go
@@ -7,6 +7,7 @@
"io/fs"
"io/ioutil"
"net"
+ "net/netip"
"path"
"path/filepath"
"time"
@@ -17,9 +18,12 @@
gitssh "github.com/go-git/go-git/v5/plumbing/transport/ssh"
"golang.org/x/crypto/ssh"
"sigs.k8s.io/yaml"
+
+ "github.com/giolekva/pcloud/core/installer/soft"
)
type RepoIO interface {
+ Addr() netip.AddrPort
Fetch() error
ReadConfig() (Config, error)
ReadAppConfig(path string) (AppConfig, error)
@@ -39,17 +43,21 @@
}
type repoIO struct {
- repo *git.Repository
+ repo *soft.Repository
signer ssh.Signer
}
-func NewRepoIO(repo *git.Repository, signer ssh.Signer) RepoIO {
+func NewRepoIO(repo *soft.Repository, signer ssh.Signer) RepoIO {
return &repoIO{
repo,
signer,
}
}
+func (r *repoIO) Addr() netip.AddrPort {
+ return r.repo.Addr.Addr
+}
+
func (r *repoIO) Fetch() error {
err := r.repo.Fetch(&git.FetchOptions{
RemoteName: "origin",
diff --git a/core/installer/soft/client.go b/core/installer/soft/client.go
index 2a820a0..635ee0e 100644
--- a/core/installer/soft/client.go
+++ b/core/installer/soft/client.go
@@ -5,7 +5,9 @@
"golang.org/x/crypto/ssh"
"log"
"net"
+ "net/netip"
"os"
+ "regexp"
"strings"
"github.com/go-git/go-billy/v5/memfs"
@@ -15,14 +17,13 @@
)
type Client struct {
- IP string
- port int
+ Addr netip.AddrPort
Signer ssh.Signer
log *log.Logger
pemBytes []byte
}
-func NewClient(ip string, port int, clientPrivateKey []byte, log *log.Logger) (*Client, error) {
+func NewClient(addr netip.AddrPort, clientPrivateKey []byte, log *log.Logger) (*Client, error) {
signer, err := ssh.ParsePrivateKey(clientPrivateKey)
if err != nil {
return nil, err
@@ -30,8 +31,7 @@
log.SetPrefix("SOFT-SERVE: ")
log.Printf("Created signer")
return &Client{
- ip,
- port,
+ addr,
signer,
log,
clientPrivateKey,
@@ -64,7 +64,7 @@
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())
+ client, err := ssh.Dial("tcp", ss.Addr.String(), ss.sshClientConfig())
if err != nil {
return err
}
@@ -88,18 +88,66 @@
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: ss.GetRepoAddress(name),
- Auth: ss.authSSH(),
+type Repository struct {
+ *git.Repository
+ Addr RepositoryAddress
+}
+
+func (ss *Client) GetRepo(name string) (*Repository, error) {
+ return CloneRepo(RepositoryAddress{ss.Addr, name}, ss.Signer)
+}
+
+type RepositoryAddress struct {
+ Addr netip.AddrPort
+ Name string
+}
+
+func ParseRepositoryAddress(addr string) (RepositoryAddress, error) {
+ items := regexp.MustCompile(`ssh://.*)/(.*)`).FindStringSubmatch(addr)
+ if len(items) != 2 {
+ return RepositoryAddress{}, fmt.Errorf("Invalid address")
+ }
+ ipPort, err := netip.ParseAddrPort(items[1])
+ if err != nil {
+ return RepositoryAddress{}, err
+ }
+ return RepositoryAddress{ipPort, items[2]}, nil
+}
+
+func (r RepositoryAddress) FullAddress() string {
+ return fmt.Sprintf("ssh://%s/%s", r.Addr, r.Name)
+}
+
+func CloneRepo(addr RepositoryAddress, signer ssh.Signer) (*Repository, error) {
+ c, err := git.Clone(memory.NewStorage(), memfs.New(), &git.CloneOptions{
+ URL: addr.FullAddress(),
+ Auth: &gitssh.PublicKeys{
+ User: "git",
+ Signer: signer,
+ HostKeyCallbackHelper: gitssh.HostKeyCallbackHelper{
+ HostKeyCallback: func(hostname string, remote net.Addr, key ssh.PublicKey) error {
+ // TODO(giolekva): verify server public key
+ fmt.Printf("--- %+v\n", ssh.MarshalAuthorizedKey(key))
+ return nil
+ },
+ },
+ },
RemoteName: "origin",
ReferenceName: "refs/heads/master",
Depth: 1,
InsecureSkipTLS: true,
Progress: os.Stdout,
})
+ if err != nil {
+ return nil, err
+ }
+ return &Repository{
+ Repository: c,
+ Addr: addr,
+ }, nil
}
+// TODO(giolekva): dead code
func (ss *Client) authSSH() gitssh.AuthMethod {
a, err := gitssh.NewPublicKeys("git", ss.pemBytes, "")
if err != nil {
@@ -149,7 +197,7 @@
return nil
},
}
- _, err := ssh.Dial("tcp", ss.addressSSH(), config)
+ _, err := ssh.Dial("tcp", ss.Addr.String(), config)
if err != nil {
return nil, err
}
@@ -175,9 +223,5 @@
}
func (ss *Client) addressGit() string {
- return fmt.Sprintf("ssh://%s", ss.addressSSH())
-}
-
-func (ss *Client) addressSSH() string {
- return fmt.Sprintf("%s:%d", ss.IP, ss.port)
+ return fmt.Sprintf("ssh://%s", ss.Addr)
}
diff --git a/core/installer/soft/config.go b/core/installer/soft/config.go
deleted file mode 100644
index b674377..0000000
--- a/core/installer/soft/config.go
+++ /dev/null
@@ -1,49 +0,0 @@
-package soft
-
-type Repository struct {
- Name string `json:"name"`
- Repository string `json:"repo"`
- Private bool `json:"private"`
- Note string `json:"note"`
-}
-
-type User struct {
- Name string `json:"name"`
- Admin bool `json:"admin"`
- PublicKeys []string `json:"public-keys"`
-}
-
-type Config struct {
- Name string `json:"name"`
- Host string `json:"host"`
- Port int `json:"port"`
- AnonAccess string `json:"anon-access"`
- AllowKeyless bool `json:"allow-keyless"`
- Repositories []Repository `json:"repos"`
- Users []User `json:"users"`
-}
-
-func DefaultConfig(adminKeys []string) Config {
- return Config{
- Name: "PCloud",
- Host: "localhost",
- Port: 22,
- AnonAccess: "no-access",
- AllowKeyless: false,
- Repositories: []Repository{
- {
- Name: "Home",
- Repository: "config",
- Private: true,
- Note: "Configuration for PCloud SoftServe deployment",
- },
- },
- Users: []User{
- {
- Name: "Admin",
- Admin: true,
- PublicKeys: adminKeys,
- },
- },
- }
-}
diff --git a/core/installer/values-tmpl/env-manager.yaml b/core/installer/values-tmpl/env-manager.yaml
index a2ba684..7271dff 100644
--- a/core/installer/values-tmpl/env-manager.yaml
+++ b/core/installer/values-tmpl/env-manager.yaml
@@ -14,5 +14,7 @@
interval: 1m0s
values:
repoIP: {{ .Values.RepoIP }}
+ repoPort: {{ .Values.RepoPort }}
+ repoName: {{ .Values.RepoName }}
sshPrivateKey: {{ .Values.SSHPrivateKey | b64enc }}
clusterRoleName: {{ .Global.PCloudEnvName }}-env-manager
diff --git a/core/installer/values-tmpl/ingress-public.yaml b/core/installer/values-tmpl/ingress-public.yaml
index 67ac1b2..94773e8 100644
--- a/core/installer/values-tmpl/ingress-public.yaml
+++ b/core/installer/values-tmpl/ingress-public.yaml
@@ -18,7 +18,7 @@
service:
type: LoadBalancer
annotations:
- metallb.universe.tf/loadBalancerIPs: 192.168.0.213 # TODO(giolekva): configurable
+ metallb.universe.tf/loadBalancerIPs: {{ .Values.IngressPublicIP }}
ingressClassByName: true
ingressClassResource:
name: {{ .Global.PCloudEnvName }}-ingress-public
diff --git a/core/installer/welcome/env.go b/core/installer/welcome/env.go
index 22713f9..6fc03dc 100644
--- a/core/installer/welcome/env.go
+++ b/core/installer/welcome/env.go
@@ -303,7 +303,7 @@
if err != nil {
return err
}
- repoIP := "192.168.0.211" // TODO(giolekva): configure
+ repoIP := repoIO.Addr().Addr().String()
for _, tmpl := range tmpls.Templates() {
dstPath := path.Join("environments", req.Name, tmpl.Name())
dst, err := repoIO.Writer(dstPath)