Installer: Clean up RepoIO interface

Change-Id: If80d7be1460c725b7df9d1d27c9354cb9141acfe
diff --git a/core/installer/welcome/appmanager.go b/core/installer/welcome/appmanager.go
index 1206a73..b26a001 100644
--- a/core/installer/welcome/appmanager.go
+++ b/core/installer/welcome/appmanager.go
@@ -222,9 +222,14 @@
 		return err
 	}
 	log.Printf("Configuration: %+v\n", config)
-	nsGen := installer.NewPrefixGenerator(config.Values.NamespacePrefix)
 	suffixGen := installer.NewFixedLengthRandomSuffixGenerator(3)
-	if err := s.m.Install(a, nsGen, suffixGen, values); err != nil {
+	suffix, err := suffixGen.Generate()
+	if err != nil {
+		return err
+	}
+	appDir := fmt.Sprintf("/apps/%s%s", a.Name(), suffix)
+	namespace := fmt.Sprintf("%s%s%s", config.Values.NamespacePrefix, a.Namespace(), suffix)
+	if err := s.m.Install(a, appDir, namespace, values); err != nil {
 		log.Printf("%s\n", err.Error())
 		return err
 	}
diff --git a/core/installer/welcome/env.go b/core/installer/welcome/env.go
index e0d5a3f..3efe330 100644
--- a/core/installer/welcome/env.go
+++ b/core/installer/welcome/env.go
@@ -327,13 +327,7 @@
 		return
 	}
 	var env installer.EnvConfig
-	cr, err := s.repo.Reader("config.yaml")
-	if err != nil {
-		http.Error(w, err.Error(), http.StatusInternalServerError)
-		return
-	}
-	defer cr.Close()
-	if err := installer.ReadYaml(cr, &env); err != nil {
+	if err := installer.ReadYaml(s.repo, "config.yaml", &env); err != nil {
 		http.Error(w, err.Error(), http.StatusInternalServerError)
 		return
 	}
@@ -348,13 +342,7 @@
 		req.Name = name
 	}
 	var cidrs installer.EnvCIDRs
-	cidrsR, err := s.repo.Reader("env-cidrs.yaml")
-	if err != nil {
-		http.Error(w, err.Error(), http.StatusInternalServerError)
-		return
-	}
-	defer cidrsR.Close()
-	if err := installer.ReadYaml(cidrsR, &cidrs); err != nil {
+	if err := installer.ReadYaml(s.repo, "env-cidrs.yaml", &cidrs); err != nil {
 		http.Error(w, err.Error(), http.StatusInternalServerError)
 		return
 	}
@@ -364,7 +352,7 @@
 		return
 	}
 	cidrs = append(cidrs, installer.EnvCIDR{req.Name, startIP})
-	if err := s.repo.WriteYaml("env-cidrs.yaml", cidrs); err != nil {
+	if err := installer.WriteYaml(s.repo, "env-cidrs.yaml", cidrs); err != nil {
 		http.Error(w, err.Error(), http.StatusInternalServerError)
 		return
 	}
@@ -385,11 +373,12 @@
 	}
 	t, dns := tasks.NewCreateEnvTask(
 		tasks.Env{
-			PCloudEnvName:  env.Name,
-			Name:           req.Name,
-			ContactEmail:   req.ContactEmail,
-			Domain:         req.Domain,
-			AdminPublicKey: req.AdminPublicKey,
+			PCloudEnvName:   env.Name,
+			Name:            req.Name,
+			ContactEmail:    req.ContactEmail,
+			Domain:          req.Domain,
+			AdminPublicKey:  req.AdminPublicKey,
+			NamespacePrefix: fmt.Sprintf("%s-", req.Name),
 		},
 		[]net.IP{
 			net.ParseIP("135.181.48.180"),
diff --git a/core/installer/welcome/welcome.go b/core/installer/welcome/welcome.go
index 9411747..697fd07 100644
--- a/core/installer/welcome/welcome.go
+++ b/core/installer/welcome/welcome.go
@@ -205,22 +205,16 @@
 		return
 	}
 	{
-		config, err := s.repo.ReadConfig()
-		if err != nil {
-			http.Error(w, err.Error(), http.StatusInternalServerError)
-			return
-		}
-		if err != nil {
-			http.Error(w, err.Error(), http.StatusInternalServerError)
-			return
-		}
-		nsGen := installer.NewPrefixGenerator(config.Values.NamespacePrefix)
-		suffixGen := installer.NewFixedLengthRandomSuffixGenerator(3)
 		appManager, err := installer.NewAppManager(s.repo, s.nsCreator)
 		if err != nil {
 			http.Error(w, err.Error(), http.StatusInternalServerError)
 			return
 		}
+		config, err := appManager.Config()
+		if err != nil {
+			http.Error(w, err.Error(), http.StatusInternalServerError)
+			return
+		}
 		appsRepo := installer.NewInMemoryAppRepository(installer.CreateAllApps())
 		{
 			app, err := appsRepo.Find("headscale-user")
@@ -228,7 +222,9 @@
 				http.Error(w, err.Error(), http.StatusInternalServerError)
 				return
 			}
-			if err := appManager.Install(app, nsGen, suffixGen, map[string]any{
+			appDir := fmt.Sprintf("/apps/%s-%s", app.Name(), req.Username)
+			namespace := fmt.Sprintf("%s%s", config.Values.NamespacePrefix, app.Namespace())
+			if err := appManager.Install(app, appDir, namespace, map[string]any{
 				"username": req.Username,
 				"preAuthKey": map[string]any{
 					"enabled": false,
@@ -253,28 +249,26 @@
 }
 
 func (s *Server) initMemberships(username string) error {
-	inp, err := s.repo.Reader("first-account.yaml")
-	if err != nil {
-		return err
-	}
-	var fa firstaccount
-	if err := installer.ReadYaml(inp, &fa); err != nil {
-		return err
-	}
-	if fa.Created {
-		return nil
-	}
-	req := initRequest{username, fa.Groups}
-	var buf bytes.Buffer
-	if err := json.NewEncoder(&buf).Encode(req); err != nil {
-		return err
-	}
-	if _, err = http.Post(s.membershipsInitAddr, "applications/json", &buf); err != nil {
-		return err
-	}
-	fa.Created = true
-	if err := s.repo.WriteYaml("first-account.yaml", fa); err != nil {
-		return err
-	}
-	return s.repo.CommitAndPush("initialized groups for first account")
+	return s.repo.Atomic(func(r installer.RepoFS) (string, error) {
+		var fa firstaccount
+		if err := installer.ReadYaml(r, "first-account.yaml", &fa); err != nil {
+			return "", err
+		}
+		if fa.Created {
+			return "", nil
+		}
+		req := initRequest{username, fa.Groups}
+		var buf bytes.Buffer
+		if err := json.NewEncoder(&buf).Encode(req); err != nil {
+			return "", err
+		}
+		if _, err := http.Post(s.membershipsInitAddr, "applications/json", &buf); err != nil {
+			return "", err
+		}
+		fa.Created = true
+		if err := installer.WriteYaml(r, "first-account.yaml", fa); err != nil {
+			return "", err
+		}
+		return "initialized groups for first account", nil
+	})
 }