[status] No more statefulset

- Workdir is no longer used, therefore we no longer need the disk.
- Clients need a single running server to keep incremental updates
  consistent. Use a single replica and have the clients track the pod ID
  of the server and reload from scratch when it changes.
- Trim "k" and "-kube" suffixes; they're unnecessary and ugly.

Change-Id: Ida644fe4d2889d7201845e7dbb9427d6d460a347
Reviewed-on: https://skia-review.googlesource.com/c/buildbot/+/233163
Reviewed-by: Ben Wagner aka dogben <benjaminwagner@google.com>
Commit-Queue: Eric Boren <borenet@google.com>
diff --git a/status/Dockerfile b/status/Dockerfile
index e49d6d8..9c8f7c4 100644
--- a/status/Dockerfile
+++ b/status/Dockerfile
@@ -4,4 +4,4 @@
 
 COPY . /
 
-ENTRYPOINT ["/usr/local/bin/statusk"]
+ENTRYPOINT ["/usr/local/bin/status"]
diff --git a/status/Makefile b/status/Makefile
index 7146a7c..756de82 100644
--- a/status/Makefile
+++ b/status/Makefile
@@ -9,9 +9,7 @@
 
 BOWER_DIR=third_party/bower_components
 
-all: clean_webtools statusk
-
-include ../go/skiaversion/skiaversion.mk
+all: clean_webtools status
 
 # Build the web assets in production mode.
 .PHONY: web
@@ -26,22 +24,24 @@
 testgo: skiaversion
 	go test ./go/... -v
 
-statusk: web skiaversion
-	CGO_ENABLED=0 GOOS=linux go install -a ./go/statusk
+status: web skiaversion
+	CGO_ENABLED=0 GOOS=linux go install -a ./go/status
 
-release_kube: statusk
+release: status
 	./build_docker_release
 
-run_kube: release
+run_docker: release
 	docker run status
 
-push_kube: release_kube skia-public
-	pushk --message="$(MESSAGE)" statusk
+push: release skia-public pushk
+	pushk --message="$(MESSAGE)" status
 
 # Build debug versions of core.js and elements.html.
 .PHONY: debug
 debug: clean_webtools debug_core_js debug_elements_html
 
-include ../webtools/webtools.mk
+include ../kube/kube.mk
 include ../make/clusters.mk
+include ../go/skiaversion/skiaversion.mk
+include ../webtools/webtools.mk
 include webpack/webpack.mk
diff --git a/status/build_docker_release b/status/build_docker_release
index 46f6d29..9630198 100755
--- a/status/build_docker_release
+++ b/status/build_docker_release
@@ -1,5 +1,5 @@
 #!/bin/bash
-APPNAME=statusk
+APPNAME=status
 
 set -x -e
 
diff --git a/status/go/statusk/main.go b/status/go/status/main.go
similarity index 97%
rename from status/go/statusk/main.go
rename to status/go/status/main.go
index b2194ee..ec7685e 100644
--- a/status/go/statusk/main.go
+++ b/status/go/status/main.go
@@ -23,6 +23,7 @@
 
 	"cloud.google.com/go/bigtable"
 	"cloud.google.com/go/datastore"
+	"github.com/google/uuid"
 	"github.com/gorilla/mux"
 	autoroll_status "go.skia.org/infra/autoroll/go/status"
 	"go.skia.org/infra/go/allowed"
@@ -117,8 +118,8 @@
 	swarmingUrl                 = flag.String("swarming_url", "https://chromium-swarm.appspot.com", "URL of the Swarming server.")
 	taskSchedulerUrl            = flag.String("task_scheduler_url", "https://task-scheduler.skia.org", "URL of the Task Scheduler server.")
 	testing                     = flag.Bool("testing", false, "Set to true for locally testing rules. No email will be sent.")
-	workdir                     = flag.String("workdir", ".", "Directory to use for scratch work.")
 
+	podId string
 	repos repograph.Map
 )
 
@@ -166,6 +167,14 @@
 	return &v, nil
 }
 
+func getStringParam(name string, r *http.Request) string {
+	raw, ok := r.URL.Query()[name]
+	if !ok {
+		return ""
+	}
+	return raw[0]
+}
+
 // repoUrlToName returns a short repo nickname given a full repo URL.
 func repoUrlToName(repoUrl string) string {
 	// Special case: we like "infra" better than "buildbot".
@@ -252,6 +261,7 @@
 		httputils.ReportError(w, r, err, fmt.Sprintf("Invalid parameter for \"n\": %s", err))
 		return
 	}
+	expectPodId := getStringParam("pod", r)
 	numCommits := DEFAULT_COMMITS_TO_LOAD
 	if n != nil {
 		numCommits = int(*n)
@@ -259,17 +269,22 @@
 			numCommits = MAX_COMMITS_TO_LOAD
 		}
 	}
-	var update *incremental.Update
-	if from != nil {
+	update := struct {
+		*incremental.Update
+		Pod string `json:"pod"`
+	}{
+		Pod: podId,
+	}
+	if (expectPodId != "" && expectPodId != podId) || from == nil {
+		update.Update, err = iCache.GetAll(repoUrl, numCommits)
+	} else {
 		fromTime := time.Unix(0, (*from)*util.MILLIS_TO_NANOS)
 		if to != nil {
 			toTime := time.Unix(0, (*to)*util.MILLIS_TO_NANOS)
-			update, err = iCache.GetRange(repoUrl, fromTime, toTime, numCommits)
+			update.Update, err = iCache.GetRange(repoUrl, fromTime, toTime, numCommits)
 		} else {
-			update, err = iCache.Get(repoUrl, fromTime, numCommits)
+			update.Update, err = iCache.Get(repoUrl, fromTime, numCommits)
 		}
-	} else {
-		update, err = iCache.GetAll(repoUrl, numCommits)
 	}
 	if err != nil {
 		httputils.ReportError(w, r, err, fmt.Sprintf("Failed to retrieve updates: %s", err))
@@ -710,6 +725,12 @@
 	}
 	ctx := context.Background()
 
+	podId = os.Getenv("POD_ID")
+	if podId == "" {
+		sklog.Error("POD_ID not defined; falling back to UUID.")
+		podId = uuid.New().String()
+	}
+
 	ts, err := auth.NewDefaultTokenSource(*testing, auth.SCOPE_USERINFO_EMAIL, auth.SCOPE_GERRIT, bigtable.Scope, pubsub.AUTH_SCOPE, datastore.ScopeDatastore)
 	if err != nil {
 		sklog.Fatal(err)
@@ -756,10 +777,6 @@
 	login.InitWithAllow(serverURL+login.DEFAULT_OAUTH2_CALLBACK, adminAllowed, editAllowed, nil)
 
 	// Check out source code.
-	reposDir := path.Join(*workdir, "repos")
-	if err := os.MkdirAll(reposDir, os.ModePerm); err != nil {
-		sklog.Fatalf("Failed to create repos dir: %s", err)
-	}
 	if *repoUrls == nil {
 		sklog.Fatal("At least one --repo is required.")
 	}
diff --git a/status/go/statusk/tasks_per_commit.go b/status/go/status/tasks_per_commit.go
similarity index 100%
rename from status/go/statusk/tasks_per_commit.go
rename to status/go/status/tasks_per_commit.go
diff --git a/status/res/imp/commits-data-sk.html b/status/res/imp/commits-data-sk.html
index 9c157cc..9b386ac 100644
--- a/status/res/imp/commits-data-sk.html
+++ b/status/res/imp/commits-data-sk.html
@@ -343,6 +343,10 @@
           type: Number,
           value: 0,
         },
+        _server_pod_id: {
+          type: String,
+          value: "",
+        },
         _updateRequested: {
           type: Boolean,
           value: false,
@@ -431,12 +435,19 @@
         if (this._last_load_ts && !fromScratch) {
           url += "&from=" + this._last_load_ts;
         }
+        if (this._server_pod_id) {
+          url += "&pod=" + this._server_pod_id;
+        }
         sk.get(url).then(JSON.parse).then(function(json) {
           // Clear out the existing data if necessary.
           if (json.start_over || fromScratch) {
             this._clearData();
           }
 
+          // Keep track of the server pod ID. This ensures that we're in sync
+          // with the server.
+          this._server_pod_id = json.pod;
+
           // Mix the new data into the existing.
           if (!json.commits) {
             json.commits = [];