DodoApp: VMs load dodo specific env vars from the dodo app manager

Change-Id: I522619a3ba6cd6c78eb4fe1dd8c91ec490759fdf
diff --git a/core/installer/welcome/dodo_app.go b/core/installer/welcome/dodo_app.go
index 9f60449..7f3d383 100644
--- a/core/installer/welcome/dodo_app.go
+++ b/core/installer/welcome/dodo_app.go
@@ -235,6 +235,7 @@
 		r.HandleFunc("/update", s.handleAPIUpdate)
 		r.HandleFunc("/api/apps/{app-name}/workers", s.handleAPIRegisterWorker).Methods(http.MethodPost)
 		r.HandleFunc("/api/add-public-key", s.handleAPIAddPublicKey).Methods(http.MethodPost)
+		r.HandleFunc("/api/apps/{app-name}/branch/{branch}/env-profile", s.handleBranchEnvProfile).Methods(http.MethodGet)
 		if !s.external {
 			r.HandleFunc("/api/sync-users", s.handleAPISyncUsers).Methods(http.MethodGet)
 		}
@@ -528,6 +529,34 @@
 	}
 }
 
+type appEnv struct {
+	Profile string `json:"envProfile"`
+}
+
+func (s *DodoAppServer) handleBranchEnvProfile(w http.ResponseWriter, r *http.Request) {
+	vars := mux.Vars(r)
+	appName, ok := vars["app-name"]
+	if !ok || appName == "" {
+		http.Error(w, "missing app-name", http.StatusBadRequest)
+		return
+	}
+	branch, ok := vars["branch"]
+	if !ok || branch == "" {
+		branch = "master"
+	}
+	info, err := s.st.GetLastCommitInfo(appName, branch)
+	if err != nil {
+		http.Error(w, err.Error(), http.StatusInternalServerError)
+		return
+	}
+	var e appEnv
+	if err := json.NewDecoder(bytes.NewReader(info.Resources.RenderedRaw)).Decode(&e); err != nil {
+		http.Error(w, err.Error(), http.StatusInternalServerError)
+		return
+	}
+	fmt.Fprintln(w, e.Profile)
+}
+
 type volume struct {
 	Name string
 	Size string
diff --git a/core/installer/welcome/store.go b/core/installer/welcome/store.go
index 3f8428d..7efdeaf 100644
--- a/core/installer/welcome/store.go
+++ b/core/installer/welcome/store.go
@@ -32,6 +32,11 @@
 	Resources installer.ReleaseResources
 }
 
+type LastCommitInfo struct {
+	Hash      string
+	Resources installer.ReleaseResources
+}
+
 type Store interface {
 	CreateUser(username string, password []byte, network string) error
 	GetUserPassword(username string) ([]byte, error)
@@ -43,6 +48,7 @@
 	CreateCommit(name, branch, hash, message, status, error string, resources []byte) error
 	GetCommitHistory(name, branch string) ([]CommitMeta, error)
 	GetCommit(hash string) (Commit, error)
+	GetLastCommitInfo(name, branch string) (LastCommitInfo, error)
 	GetBranches(name string) ([]string, error)
 }
 
@@ -79,6 +85,12 @@
             error TEXT,
             resources JSONB
 		);
+		CREATE TABLE IF NOT EXISTS branches (
+			app_name TEXT,
+			branch TEXT,
+            hash TEXT,
+            resources JSONB
+		);
 	`)
 	return err
 
@@ -189,9 +201,38 @@
 }
 
 func (s *storeImpl) CreateCommit(name, branch, hash, message, status, error string, resources []byte) error {
+	tx, err := s.db.Begin()
+	if err != nil {
+		return err
+	}
 	query := `INSERT INTO commits (app_name, branch, hash, message, status, error, resources) VALUES (?, ?, ?, ?, ?, ?, ?)`
-	_, err := s.db.Exec(query, name, branch, hash, message, status, error, resources)
-	return err
+	_, err = tx.Exec(query, name, branch, hash, message, status, error, resources)
+	if err != nil {
+		tx.Rollback()
+		return err
+	}
+	branchQuery := `UPDATE branches SET hash = ?, resources = ? WHERE app_name = ? AND branch = ?`
+	r, err := tx.Exec(branchQuery, hash, resources, name, branch)
+	if err != nil {
+		tx.Rollback()
+		return err
+	}
+	if cnt, err := r.RowsAffected(); err != nil {
+		tx.Rollback()
+		return err
+	} else if cnt == 0 {
+		branchQuery := `INSERT INTO branches (app_name, branch, hash, resources) VALUES (?, ?, ?, ?)`
+		_, err := tx.Exec(branchQuery, name, branch, hash, resources)
+		if err != nil {
+			tx.Rollback()
+			return err
+		}
+	}
+	if err := tx.Commit(); err != nil {
+		tx.Rollback()
+		return err
+	}
+	return nil
 }
 
 func (s *storeImpl) GetCommitHistory(name, branch string) ([]CommitMeta, error) {
@@ -234,6 +275,23 @@
 	return ret, nil
 }
 
+func (s *storeImpl) GetLastCommitInfo(name, branch string) (LastCommitInfo, error) {
+	query := `SELECT hash, resources FROM branches WHERE app_name = ? AND branch = ?`
+	row := s.db.QueryRow(query, name, branch)
+	if err := row.Err(); err != nil {
+		return LastCommitInfo{}, err
+	}
+	var ret LastCommitInfo
+	var res []byte
+	if err := row.Scan(&ret.Hash, &res); err != nil {
+		return LastCommitInfo{}, err
+	}
+	if err := json.NewDecoder(bytes.NewBuffer(res)).Decode(&ret.Resources); err != nil {
+		return LastCommitInfo{}, err
+	}
+	return ret, nil
+}
+
 func (s *storeImpl) GetBranches(name string) ([]string, error) {
 	query := `SELECT DISTINCT branch FROM commits WHERE app_name = ?`
 	rows, err := s.db.Query(query, name)