installer: env and app manager
diff --git a/core/installer/cmd/apps.go b/core/installer/cmd/apps.go
index eb49736..b96ac6f 100644
--- a/core/installer/cmd/apps.go
+++ b/core/installer/cmd/apps.go
@@ -1,19 +1,30 @@
package main
import (
+ "fmt"
"io/ioutil"
+ "net"
"os"
- "path/filepath"
+ "time"
"github.com/giolekva/pcloud/core/installer"
+ "github.com/go-git/go-billy/v5/memfs"
+ "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"
+ "github.com/go-git/go-git/v5/storage/memory"
"github.com/spf13/cobra"
+ "golang.org/x/crypto/ssh"
"sigs.k8s.io/yaml"
)
+const appDirName = "apps"
+
var installFlags struct {
- config string
- appName string
- outputDir string
+ sshKey string
+ config string
+ appName string
+ repoAddr string
}
func installCmd() *cobra.Command {
@@ -22,6 +33,12 @@
RunE: installCmdRun,
}
cmd.Flags().StringVar(
+ &installFlags.sshKey,
+ "ssh-key",
+ "",
+ "",
+ )
+ cmd.Flags().StringVar(
&installFlags.config,
"config",
"",
@@ -34,36 +51,92 @@
"",
)
cmd.Flags().StringVar(
- &installFlags.outputDir,
- "output-dir",
+ &installFlags.repoAddr,
+ "repo-addr",
"",
"",
)
return cmd
}
+type inMemoryAppRepository struct {
+ apps []installer.App
+}
+
+func NewInMemoryAppRepository(apps []installer.App) installer.AppRepository {
+ return &inMemoryAppRepository{
+ apps,
+ }
+}
+
+func (r inMemoryAppRepository) Find(name string) (*installer.App, error) {
+ for _, a := range r.apps {
+ if a.Name == name {
+ return &a, nil
+ }
+ }
+ return nil, fmt.Errorf("Application not found: %s", name)
+}
+
func installCmdRun(cmd *cobra.Command, args []string) error {
cfg, err := readConfig(installFlags.config)
if err != nil {
return err
}
- apps := installer.CreateAllApps()
- for _, a := range apps {
- if a.Name == installFlags.appName {
- for _, t := range a.Templates {
- out, err := os.Create(filepath.Join(installFlags.outputDir, t.Name()))
- if err != nil {
- return err
- }
- defer out.Close()
- if err := t.Execute(out, cfg); err != nil {
- return err
- }
- }
- break
- }
+ sshKey, err := os.ReadFile(installFlags.sshKey)
+ if err != nil {
+ return err
}
- return nil
+ signer, err := ssh.ParsePrivateKey(sshKey)
+ if err != nil {
+ return err
+ }
+ repo, err := cloneRepo(installFlags.repoAddr, signer)
+ if err != nil {
+ return err
+ }
+ wt, err := repo.Worktree()
+ if err != nil {
+ return err
+ }
+ appRoot, err := wt.Filesystem.Chroot(appDirName)
+ if err != nil {
+ return err
+ }
+ m, err := installer.NewAppManager(
+ appRoot,
+ cfg,
+ NewInMemoryAppRepository(installer.CreateAllApps()),
+ )
+ if err != nil {
+ return err
+ }
+ if err := m.Install(installFlags.appName); err != nil {
+ return err
+ }
+ if st, err := wt.Status(); err != nil {
+ return err
+ } else {
+ fmt.Printf("%+v\n", st)
+ }
+ wt.AddGlob("*")
+ if st, err := wt.Status(); err != nil {
+ return err
+ } else {
+ fmt.Printf("%+v\n", st)
+ }
+ if _, err := wt.Commit(fmt.Sprintf("install: %s", installFlags.appName), &git.CommitOptions{
+ Author: &object.Signature{
+ Name: "pcloud-appmanager",
+ When: time.Now(),
+ },
+ }); err != nil {
+ return err
+ }
+ return repo.Push(&git.PushOptions{
+ RemoteName: "origin",
+ Auth: auth(signer),
+ })
}
func readConfig(config string) (installer.Config, error) {
@@ -75,3 +148,25 @@
err = yaml.UnmarshalStrict(inp, &cfg)
return cfg, err
}
+
+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
+ },
+ },
+ }
+}