Welcome: Create new users via Memberships API

Change-Id: Iaa12b3438340a5ca4c4fdb2157d1e8f064d56139
diff --git a/core/installer/cmd/welcome.go b/core/installer/cmd/welcome.go
index db1ce4a..30ed48f 100644
--- a/core/installer/cmd/welcome.go
+++ b/core/installer/cmd/welcome.go
@@ -11,12 +11,12 @@
 )
 
 var welcomeFlags struct {
-	repo                string
-	sshKey              string
-	port                int
-	createAccountAddr   string
-	loginAddr           string
-	membershipsInitAddr string
+	repo              string
+	sshKey            string
+	port              int
+	createAccountAddr string
+	loginAddr         string
+	membershipsAddr   string
 }
 
 func welcomeCmd() *cobra.Command {
@@ -55,8 +55,8 @@
 		"",
 	)
 	cmd.Flags().StringVar(
-		&welcomeFlags.membershipsInitAddr,
-		"memberships-init-addr",
+		&welcomeFlags.membershipsAddr,
+		"memberships-addr",
 		"",
 		"",
 	)
@@ -95,7 +95,7 @@
 		installer.NewGitHelmFetcher(),
 		welcomeFlags.createAccountAddr,
 		welcomeFlags.loginAddr,
-		welcomeFlags.membershipsInitAddr,
+		welcomeFlags.membershipsAddr,
 	)
 	s.Start()
 	return nil
diff --git a/core/installer/tasks/infra.go b/core/installer/tasks/infra.go
index f855adf..eb4840f 100644
--- a/core/installer/tasks/infra.go
+++ b/core/installer/tasks/infra.go
@@ -78,6 +78,7 @@
 
 type firstAccount struct {
 	Created bool     `json:"created"`
+	Domain  string   `json:"domain"`
 	Groups  []string `json:"groups"`
 }
 
@@ -88,7 +89,7 @@
 			return err
 		}
 		return r.Do(func(r soft.RepoFS) (string, error) {
-			fa := firstAccount{false, initGroups}
+			fa := firstAccount{false, env.Domain, initGroups}
 			if err := soft.WriteYaml(r, "first-account.yaml", fa); err != nil {
 				return "", err
 			}
diff --git a/core/installer/values-tmpl/welcome.cue b/core/installer/values-tmpl/welcome.cue
index 55f4e14..3e385ab 100644
--- a/core/installer/values-tmpl/welcome.cue
+++ b/core/installer/values-tmpl/welcome.cue
@@ -37,7 +37,7 @@
 			sshPrivateKey: base64.Encode(null, input.sshPrivateKey)
 			createAccountAddr: "http://api.\(global.namespacePrefix)core-auth.svc.cluster.local/identities"
 			loginAddr: "https://launcher.\(networks.public.domain)"
-			membershipsInitAddr: "http://memberships-api.\(global.namespacePrefix)core-auth-memberships.svc.cluster.local/api/init"
+			membershipsAddr: "http://memberships-api.\(global.namespacePrefix)core-auth-memberships.svc.cluster.local"
 			ingress: {
 				className: input.network.ingressClass
 				domain: "welcome.\(input.network.domain)"
diff --git a/core/installer/welcome/welcome.go b/core/installer/welcome/welcome.go
index 80bbb64..85d7f61 100644
--- a/core/installer/welcome/welcome.go
+++ b/core/installer/welcome/welcome.go
@@ -28,13 +28,13 @@
 var staticAssets embed.FS
 
 type Server struct {
-	port                int
-	repo                soft.RepoIO
-	nsCreator           installer.NamespaceCreator
-	hf                  installer.HelmFetcher
-	createAccountAddr   string
-	loginAddr           string
-	membershipsInitAddr string
+	port              int
+	repo              soft.RepoIO
+	nsCreator         installer.NamespaceCreator
+	hf                installer.HelmFetcher
+	createAccountAddr string
+	loginAddr         string
+	membershipsAddr   string
 }
 
 func NewServer(
@@ -44,7 +44,7 @@
 	hf installer.HelmFetcher,
 	createAccountAddr string,
 	loginAddr string,
-	membershipsInitAddr string,
+	membershipsAddr string,
 ) *Server {
 	return &Server{
 		port,
@@ -53,7 +53,7 @@
 		hf,
 		createAccountAddr,
 		loginAddr,
-		membershipsInitAddr,
+		membershipsAddr,
 	}
 }
 
@@ -205,7 +205,7 @@
 			return
 		}
 	}
-	if err := s.initMemberships(req.Username); err != nil {
+	if err := s.createUser(req.Username); err != nil {
 		http.Error(w, err.Error(), http.StatusInternalServerError)
 		return
 	}
@@ -245,40 +245,66 @@
 	renderRegistrationSuccess(w, s.loginAddr)
 }
 
-type firstaccount struct {
+type firstAccount struct {
 	Created bool     `json:"created"`
+	Domain  string   `json:"domain"`
 	Groups  []string `json:"groups"`
 }
 
 type initRequest struct {
-	Owner  string   `json:"owner"`
+	User   string   `json:"user"`
+	Email  string   `json:"email"`
 	Groups []string `json:"groups"`
 }
 
-func (s *Server) initMemberships(username string) error {
+type createUserRequest struct {
+	User  string `json:"user"`
+	Email string `json:"email"`
+}
+
+func (s *Server) createUser(username string) error {
 	return s.repo.Do(func(r soft.RepoFS) (string, error) {
-		var fa firstaccount
+		var fa firstAccount
 		if err := soft.ReadYaml(r, "first-account.yaml", &fa); err != nil {
 			return "", err
 		}
+		var resp *http.Response
+		var err error
 		if fa.Created {
-			return "", nil
+			req := createUserRequest{username, fmt.Sprintf("%s@%s", username, fa.Domain)}
+			var buf bytes.Buffer
+			if err := json.NewEncoder(&buf).Encode(req); err != nil {
+				return "", err
+			}
+			resp, err = http.Post(
+				fmt.Sprintf("%s/api/users", s.membershipsAddr),
+				"applications/json",
+				&buf,
+			)
+		} else {
+			req := initRequest{username, fmt.Sprintf("%s@%s", username, fa.Domain), fa.Groups}
+			var buf bytes.Buffer
+			if err := json.NewEncoder(&buf).Encode(req); err != nil {
+				return "", err
+			}
+			resp, err = http.Post(
+				fmt.Sprintf("%s/api/init", s.membershipsAddr),
+				"applications/json",
+				&buf,
+			)
+			fa.Created = true
+			if err := soft.WriteYaml(r, "first-account.yaml", fa); err != nil {
+				return "", err
+			}
 		}
-		req := initRequest{username, fa.Groups}
-		var buf bytes.Buffer
-		if err := json.NewEncoder(&buf).Encode(req); err != nil {
-			return "", err
-		}
-		resp, err := http.Post(s.membershipsInitAddr, "applications/json", &buf)
 		if err != nil {
 			return "", err
 		}
 		defer resp.Body.Close()
 		fmt.Printf("Memberships resp: %d", resp.StatusCode)
 		io.Copy(os.Stdout, resp.Body)
-		fa.Created = true
-		if err := soft.WriteYaml(r, "first-account.yaml", fa); err != nil {
-			return "", err
+		if resp.StatusCode != http.StatusOK {
+			return "", fmt.Errorf("memberships error")
 		}
 		return "initialized groups for first account", nil
 	})