AppManager: Add API endpoint to install dodo app

Refactors cue definitions.

Next steps:
* Needs some cleanup, namespace is hard coded ...
* Maybe merge with regular install API
* Support exposing ports across clusters

Change-Id: Ibfc3c3f742b61f2c5874012fe6c77b958eae81d9
diff --git a/apps/app-runner/main.go b/apps/app-runner/main.go
index 9296749..2f4f5a8 100644
--- a/apps/app-runner/main.go
+++ b/apps/app-runner/main.go
@@ -21,6 +21,7 @@
 var appId = flag.String("app-id", "", "Application ID")
 var repoAddr = flag.String("repo-addr", "", "Git repository address")
 var branch = flag.String("branch", "", "Name of the branch to process")
+var rootDir = flag.String("root-dir", "/", "Path to the app code")
 var sshKey = flag.String("ssh-key", "", "Private SSH key to access Git repository")
 var appDir = flag.String("app-dir", "", "Path to store application repository locally")
 var runCfg = flag.String("run-cfg", "", "Run configuration")
@@ -32,11 +33,19 @@
 	Env  []string `json:"env"`
 }
 
-func CloneRepositoryBranch(addr, branch string, signer ssh.Signer, path string) error {
+func CloneRepositoryBranch(addr, branch, rootDir string, signer ssh.Signer, path string) error {
 	ref := fmt.Sprintf("refs/heads/%s", branch)
-	c, err := git.Clone(memory.NewStorage(), osfs.New(path, osfs.WithBoundOS()), &git.CloneOptions{
-		URL: addr,
-		Auth: &gitssh.PublicKeys{
+	opts := &git.CloneOptions{
+		URL:             addr,
+		RemoteName:      "origin",
+		ReferenceName:   plumbing.ReferenceName(ref),
+		SingleBranch:    true,
+		Depth:           1,
+		InsecureSkipTLS: true,
+		Progress:        os.Stdout,
+	}
+	if signer != nil {
+		opts.Auth = &gitssh.PublicKeys{
 			User:   "git",
 			Signer: signer,
 			HostKeyCallbackHelper: gitssh.HostKeyCallbackHelper{
@@ -46,14 +55,9 @@
 					return nil
 				},
 			},
-		},
-		RemoteName:      "origin",
-		ReferenceName:   plumbing.ReferenceName(ref),
-		SingleBranch:    true,
-		Depth:           1,
-		InsecureSkipTLS: true,
-		Progress:        os.Stdout,
-	})
+		}
+	}
+	c, err := git.Clone(memory.NewStorage(), osfs.New(path, osfs.WithBoundOS()), opts)
 	if err != nil {
 		return err
 	}
@@ -61,18 +65,22 @@
 	if err != nil {
 		return err
 	}
-	sb, err := wt.Submodules()
-	if err != nil {
-		return err
+	if wt == nil {
+		panic(wt)
 	}
-	if err := sb.Init(); err != nil {
-		return err
-	}
-	if err := sb.Update(&git.SubmoduleUpdateOptions{
-		Depth: 1,
-	}); err != nil {
-		return err
-	}
+	// TODO(gio): This should probably be removed.
+	// sb, err := wt.Submodules()
+	// if err != nil {
+	// 	return err
+	// }
+	// if err := sb.Init(); err != nil {
+	// 	return err
+	// }
+	// if err := sb.Update(&git.SubmoduleUpdateOptions{
+	// 	Depth: 1,
+	// }); err != nil {
+	// 	return err
+	// }
 	return err
 }
 
@@ -82,15 +90,18 @@
 	if !ok {
 		panic("no SELF_IP")
 	}
-	key, err := os.ReadFile(*sshKey)
-	if err != nil {
-		panic(err)
+	var signer ssh.Signer
+	if *sshKey != "" {
+		key, err := os.ReadFile(*sshKey)
+		if err != nil {
+			panic(err)
+		}
+		signer, err = ssh.ParsePrivateKey(key)
+		if err != nil {
+			panic(err)
+		}
 	}
-	signer, err := ssh.ParsePrivateKey(key)
-	if err != nil {
-		panic(err)
-	}
-	if err := CloneRepositoryBranch(*repoAddr, *branch, signer, *appDir); err != nil {
+	if err := CloneRepositoryBranch(*repoAddr, *branch, *rootDir, signer, *appDir); err != nil {
 		panic(err)
 	}
 	r, err := os.Open(*runCfg)
@@ -102,7 +113,7 @@
 	if err := json.NewDecoder(r).Decode(&cmds); err != nil {
 		panic(err)
 	}
-	s := NewServer(*port, *appId, *repoAddr, *branch, signer, *appDir, cmds, self, *managerAddr)
+	s := NewServer(*port, *appId, *repoAddr, *branch, *rootDir, signer, *appDir, cmds, self, *managerAddr)
 	if err := s.Start(); err != nil {
 		log.Fatal(err)
 	}