AppRunner: Reload app on configuration change

Change-Id: I2c5ea0eaf3453815c8c89c9290edba250ca4fbaa
diff --git a/apps/app-runner/main.go b/apps/app-runner/main.go
index b11a977..6aa487c 100644
--- a/apps/app-runner/main.go
+++ b/apps/app-runner/main.go
@@ -11,6 +11,7 @@
 	"path/filepath"
 	"strings"
 	"syscall"
+	"time"
 
 	"golang.org/x/crypto/ssh"
 
@@ -94,6 +95,19 @@
 	}, nil
 }
 
+func readRunConfiguration(p string) []Command {
+	r, err := os.Open(p)
+	if err != nil {
+		panic(err)
+	}
+	defer r.Close()
+	var cmds []Command
+	if err := json.NewDecoder(r).Decode(&cmds); err != nil {
+		log.Fatal(err)
+	}
+	return cmds
+}
+
 func main() {
 	flag.Parse()
 	self, ok := os.LookupEnv("SELF_IP")
@@ -121,15 +135,7 @@
 			panic(err)
 		}
 	}
-	r, err := os.Open(*runCfg)
-	if err != nil {
-		panic(err)
-	}
-	defer r.Close()
-	var cmds []Command
-	if err := json.NewDecoder(r).Decode(&cmds); err != nil {
-		panic(err)
-	}
+	cmds := readRunConfiguration(*runCfg)
 	s := NewServer(*agentMode, *port, *appId, *service, id, *repoAddr, *branch, *rootDir, signer, *appDir, cmds, self, *managerAddr)
 	go func() {
 		if err := s.Start(); err != nil {
@@ -139,8 +145,51 @@
 			os.Exit(0)
 		}
 	}()
+	go func() {
+		for {
+			time.Sleep(30 * time.Second)
+			newCmds := readRunConfiguration(*runCfg)
+			if commandsChanged(cmds, newCmds) {
+				s.UpdateRunCommands(newCmds)
+				cmds = newCmds
+			}
+		}
+	}()
 	sigChan := make(chan os.Signal, 1)
 	signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM)
 	<-sigChan
 	s.Stop()
 }
+
+func commandsChanged(a, b []Command) bool {
+	if len(a) != len(b) {
+		return true
+	}
+	for i, x := range a {
+		y := b[i]
+		if x.Bin != y.Bin {
+			return true
+		}
+		if len(x.Args) != len(y.Args) {
+			return true
+		}
+		for j, k := range x.Args {
+			l := y.Args[j]
+			if k != l {
+				return true
+			}
+		}
+		if !*agentMode {
+			if len(x.Env) != len(y.Env) {
+				return true
+			}
+			for j, k := range x.Env {
+				l := y.Env[j]
+				if k != l {
+					return true
+				}
+			}
+		}
+	}
+	return false
+}
diff --git a/apps/app-runner/server.go b/apps/app-runner/server.go
index 44e86fc..080a134 100644
--- a/apps/app-runner/server.go
+++ b/apps/app-runner/server.go
@@ -128,6 +128,13 @@
 	}
 }
 
+func (s *Server) UpdateRunCommands(runCommands []Command) {
+	s.l.Lock()
+	defer s.l.Unlock()
+	s.runCommands = runCommands
+	s.run()
+}
+
 func (s *Server) handleQuit(w http.ResponseWriter, r *http.Request) {
 	go s.Stop()
 }