[gold] Add service for gitiles follower
Tested it on the 4 instances for which there is a json5 file.
A follow up CL will land it for all instances.
Bug: skia:10582
Change-Id: I40bffde6596dafb1ac54220f6494bd8483c0a754
Reviewed-on: https://skia-review.googlesource.com/c/buildbot/+/376836
Reviewed-by: Leandro Lovisolo <lovisolo@google.com>
diff --git a/golden/Makefile b/golden/Makefile
index 03b7278..ec57a91 100644
--- a/golden/Makefile
+++ b/golden/Makefile
@@ -80,6 +80,10 @@
k8s-release-diffcalculator: build-static-diffcalculator
./k8s_release_diffcalculator
+.PHONY: k8s-release-gitilesfollower
+k8s-release-gitilesfollower: build-static-gitilesfollower
+ ./k8s_release_gitilesfollower
+
.PHONY: k8s-release-ingestion
k8s-release-ingestion: build-static-ingestion
./k8s_release_ingestion
@@ -110,6 +114,12 @@
rm -f ./build/diffcalculator_k8s
$(KGO) -o build/diffcalculator_k8s -a ./cmd/diffcalculator/...
+.PHONY: build-static-gitilesfollower
+build-static-gitilesfollower:
+ mkdir -p ./build
+ rm -f ./build/gitilesfollower_k8s
+ $(KGO) -o build/gitilesfollower_k8s -a ./cmd/gitilesfollower/gitilesfollower.go
+
.PHONY: build-static-diffserver
build-static-diffserver:
mkdir -p ./build
diff --git a/golden/cmd/gitilesfollower/gitilesfollower.go b/golden/cmd/gitilesfollower/gitilesfollower.go
index 40fbd0c..2213b03 100644
--- a/golden/cmd/gitilesfollower/gitilesfollower.go
+++ b/golden/cmd/gitilesfollower/gitilesfollower.go
@@ -25,6 +25,7 @@
"go.skia.org/infra/go/httputils"
"go.skia.org/infra/go/skerr"
"go.skia.org/infra/go/sklog"
+ "go.skia.org/infra/go/util"
"go.skia.org/infra/go/vcsinfo"
"go.skia.org/infra/golden/go/config"
"go.skia.org/infra/golden/go/sql"
@@ -107,10 +108,11 @@
}
client := httputils.DefaultClientConfig().WithTokenSource(ts).Client()
gitilesClient := gitiles.NewRepo(rfc.GitRepoURL, client)
- go pollRepo(ctx, db, gitilesClient, rfc)
-
- // Wait at least 5 seconds for polling to start before signaling all is well.
- time.Sleep(5 * time.Second)
+ // This starts a goroutine in the background
+ if err := pollRepo(ctx, db, gitilesClient, rfc); err != nil {
+ sklog.Fatalf("Could not do initial update: %s", err)
+ }
+ sklog.Infof("Initial update complete")
http.HandleFunc("/healthz", httputils.ReadyHandleFunc)
sklog.Fatal(http.ListenAndServe(rfc.ReadyPort, nil))
}
@@ -134,22 +136,31 @@
return db
}
-// pollRepo polls the gitiles repo according to the provided duration for as long as the
-// context remains ok.
-func pollRepo(ctx context.Context, db *pgxpool.Pool, client *gitiles.Repo, rfc repoFollowerConfig) {
- ct := time.Tick(rfc.PollPeriod.Duration)
- for {
- select {
- case <-ctx.Done():
- sklog.Errorf("Stopping polling due to context error: %s", ctx.Err())
- return
- case <-ct:
- err := updateCycle(ctx, db, client, rfc)
- if err != nil {
- sklog.Errorf("Error on this cycle for talking to %s: %s", rfc.GitRepoURL, rfc)
+// pollRepo does an initial updateCycle and starts a goroutine to continue updating according
+// to the provided duration for as long as the context remains ok.
+func pollRepo(ctx context.Context, db *pgxpool.Pool, client *gitiles.Repo, rfc repoFollowerConfig) error {
+ sklog.Infof("Doing initial update")
+ err := updateCycle(ctx, db, client, rfc)
+ if err != nil {
+ return skerr.Wrap(err)
+ }
+ go func() {
+ ct := time.Tick(rfc.PollPeriod.Duration)
+ sklog.Infof("Polling every %s", rfc.PollPeriod.Duration)
+ for {
+ select {
+ case <-ctx.Done():
+ sklog.Errorf("Stopping polling due to context error: %s", ctx.Err())
+ return
+ case <-ct:
+ err := updateCycle(ctx, db, client, rfc)
+ if err != nil {
+ sklog.Errorf("Error on this cycle for talking to %s: %s", rfc.GitRepoURL, rfc)
+ }
}
}
- }
+ }()
+ return nil
}
// GitilesLogger is a subset of the gitiles client library that we need. This allows us to mock
@@ -190,6 +201,7 @@
return skerr.Wrapf(err, "getting backlog of commits from %s..%s", previousHash, latestHash)
}
// commits is backwards and LogFirstParent does not respect gitiles.LogReverse()
+ reverse(commits)
sklog.Infof("Got %d commits to store", len(commits))
if err := storeCommits(ctx, db, previousID, commits); err != nil {
return skerr.Wrapf(err, "storing %d commits to GitCommits table", len(commits))
@@ -197,6 +209,14 @@
return nil
}
+// reverses the order of the slice.
+func reverse(commits []*vcsinfo.LongCommit) {
+ total := len(commits)
+ for i := 0; i < total/2; i++ {
+ commits[i], commits[total-i-1] = commits[total-i-1], commits[i]
+ }
+}
+
// getLatestCommitFromRepo returns the git hash of the latest git commit known on the configured
// branch. If overrideLatestCommitKey has a value set, that will be used instead.
func getLatestCommitFromRepo(ctx context.Context, client GitilesLogger, rfc repoFollowerConfig) (string, error) {
@@ -212,7 +232,6 @@
if len(latestCommit) < 1 {
return "", skerr.Fmt("No commits returned")
}
- sklog.Debugf("latest commit: %#v", latestCommit[0])
return latestCommit[0].Hash, nil
}
@@ -245,26 +264,31 @@
}
// storeCommits writes the given commits to the SQL database, assigning them commitIDs in
-// monotonically increasing order. The commits slice is expected to be sorted with the most recent
-// commit first (as is returned by gitiles).
+// monotonically increasing order. The commits slice is expected to be sorted with the oldest
+// commit first (the opposite of how gitiles returns it).
func storeCommits(ctx context.Context, db *pgxpool.Pool, lastCommitID int64, commits []*vcsinfo.LongCommit) error {
ctx, span := trace.StartSpan(ctx, "gitilesfollower_storeCommits")
defer span.End()
+ commitID := lastCommitID + 1
+ // batchSize is only really relevant in the initial load. But we need it to avoid going over
+ // the 65k limit of placeholder indexes.
+ const batchSize = 1000
const statement = `UPSERT INTO GitCommits (git_hash, commit_id, commit_time, author_email, subject) VALUES `
const valuesPerRow = 5
- arguments := make([]interface{}, 0, len(commits)*valuesPerRow)
- commitID := lastCommitID + 1
- for i := range commits {
- // commits is in backwards order. This reverses things.
- c := commits[len(commits)-i-1]
- cid := fmt.Sprintf("%012d", commitID)
- arguments = append(arguments, c.Hash, cid, c.Timestamp, c.Author, c.Subject)
- commitID++
- }
- vp := sql.ValuesPlaceholders(valuesPerRow, len(commits))
- if _, err := db.Exec(ctx, statement+vp, arguments...); err != nil {
- return skerr.Wrap(err)
- }
- return nil
+ err := util.ChunkIter(len(commits), batchSize, func(startIdx int, endIdx int) error {
+ chunk := commits[startIdx:endIdx]
+ arguments := make([]interface{}, 0, len(chunk)*valuesPerRow)
+ for _, c := range chunk {
+ cid := fmt.Sprintf("%012d", commitID)
+ arguments = append(arguments, c.Hash, cid, c.Timestamp, c.Author, c.Subject)
+ commitID++
+ }
+ vp := sql.ValuesPlaceholders(valuesPerRow, len(chunk))
+ if _, err := db.Exec(ctx, statement+vp, arguments...); err != nil {
+ return skerr.Wrap(err)
+ }
+ return nil
+ })
+ return skerr.Wrap(err)
}
diff --git a/golden/cmd/goldpushk/goldpushk/services_map.go b/golden/cmd/goldpushk/goldpushk/services_map.go
index 1cbdea3..a5eee4f 100644
--- a/golden/cmd/goldpushk/goldpushk/services_map.go
+++ b/golden/cmd/goldpushk/goldpushk/services_map.go
@@ -20,11 +20,12 @@
SkiaPublic Instance = "skia-public"
// Gold services.
- BaselineServer Service = "baselineserver"
- DiffCalculator Service = "diffcalculator"
- DiffServer Service = "diffserver"
- IngestionBT Service = "ingestion-bt"
- Frontend Service = "frontend"
+ BaselineServer Service = "baselineserver"
+ DiffCalculator Service = "diffcalculator"
+ DiffServer Service = "diffserver"
+ IngestionBT Service = "ingestion-bt"
+ Frontend Service = "frontend"
+ GitilesFollower Service = "gitilesfollower"
// Testing Gold instances.
TestInstance1 Instance = "goldpushk-test1"
@@ -69,10 +70,11 @@
},
knownServices: []Service{
BaselineServer,
- DiffServer,
- IngestionBT,
- Frontend,
DiffCalculator,
+ DiffServer,
+ Frontend,
+ GitilesFollower,
+ IngestionBT,
},
}
@@ -83,10 +85,14 @@
s.add(instance, Frontend)
} else {
// Add common services for regular instances.
- s.add(instance, DiffServer)
- s.add(instance, IngestionBT)
- s.add(instance, Frontend)
s.add(instance, DiffCalculator)
+ s.add(instance, DiffServer)
+ s.add(instance, Frontend)
+ // See skbug.com/11367
+ if instance != ChromiumOSTastDev {
+ s.add(instance, GitilesFollower)
+ }
+ s.add(instance, IngestionBT)
}
}
@@ -97,18 +103,18 @@
for _, instance := range publicInstancesNeedingBaselineServer {
s.add(instance, BaselineServer)
}
+
// Internal baseline options.
s.addWithOptions(Fuchsia, BaselineServer, DeploymentOptions{
internal: true,
})
// Overwrite common services for "fuchsia" instance, which need to run on skia-corp.
- s.addWithOptions(Fuchsia, DiffServer, DeploymentOptions{
- internal: true,
- })
- s.addWithOptions(Fuchsia, IngestionBT, DeploymentOptions{internal: true})
- s.addWithOptions(Fuchsia, Frontend, DeploymentOptions{internal: true})
s.addWithOptions(Fuchsia, DiffCalculator, DeploymentOptions{internal: true})
+ s.addWithOptions(Fuchsia, DiffServer, DeploymentOptions{internal: true})
+ s.addWithOptions(Fuchsia, Frontend, DeploymentOptions{internal: true})
+ s.addWithOptions(Fuchsia, GitilesFollower, DeploymentOptions{internal: true})
+ s.addWithOptions(Fuchsia, IngestionBT, DeploymentOptions{internal: true})
return s
}
diff --git a/golden/cmd/goldpushk/main_test.go b/golden/cmd/goldpushk/main_test.go
index d1a5000..7d195db 100644
--- a/golden/cmd/goldpushk/main_test.go
+++ b/golden/cmd/goldpushk/main_test.go
@@ -130,6 +130,7 @@
chromeDiffServer := makeID(goldpushk.Chrome, goldpushk.DiffServer)
chromeIngestionBT := makeID(goldpushk.Chrome, goldpushk.IngestionBT)
chromeFrontend := makeID(goldpushk.Chrome, goldpushk.Frontend)
+ chromeGitilesFollower := makeID(goldpushk.Chrome, goldpushk.GitilesFollower)
chromePublicFrontend := makeID(goldpushk.ChromePublic, goldpushk.Frontend)
chromiumTastFrontend := makeID(goldpushk.ChromiumOSTastDev, goldpushk.Frontend)
chromiumTastDiffServer := makeID(goldpushk.ChromiumOSTastDev, goldpushk.DiffServer)
@@ -152,6 +153,7 @@
skiaIngestionBT := makeID(goldpushk.Skia, goldpushk.IngestionBT)
skiaPublicFrontend := makeID(goldpushk.SkiaPublic, goldpushk.Frontend)
skiaFrontend := makeID(goldpushk.Skia, goldpushk.Frontend)
+ skiaGitilesFollower := makeID(goldpushk.Skia, goldpushk.GitilesFollower)
test := func(name string, flagInstances, flagServices, flagCanaries []string, expectedDeployableUnitIDs, expectedCanariedDeployableUnitIDs []goldpushk.DeployableUnitID) {
t.Run(name, func(t *testing.T) {
@@ -212,27 +214,27 @@
////////////////////////////////////////////////////////////////////////////////////////////////
test("Single instance, all services, no canary",
[]string{"chrome"}, []string{"all"}, nil,
- []goldpushk.DeployableUnitID{chromeBaselineServer, chromeDiffCalculator, chromeDiffServer, chromeIngestionBT, chromeFrontend},
+ []goldpushk.DeployableUnitID{chromeBaselineServer, chromeDiffCalculator, chromeDiffServer, chromeIngestionBT, chromeFrontend, chromeGitilesFollower},
nil)
test("Single instance, all services, one canary",
[]string{"chrome"}, []string{"all"}, []string{"chrome:frontend"},
- []goldpushk.DeployableUnitID{chromeBaselineServer, chromeDiffCalculator, chromeDiffServer, chromeIngestionBT},
+ []goldpushk.DeployableUnitID{chromeBaselineServer, chromeDiffCalculator, chromeDiffServer, chromeIngestionBT, chromeGitilesFollower},
[]goldpushk.DeployableUnitID{chromeFrontend})
test("Single instance, all services, multiple canaries",
[]string{"chrome"}, []string{"all"}, []string{"chrome:ingestion-bt", "chrome:frontend"},
- []goldpushk.DeployableUnitID{chromeBaselineServer, chromeDiffCalculator, chromeDiffServer},
+ []goldpushk.DeployableUnitID{chromeBaselineServer, chromeDiffCalculator, chromeDiffServer, chromeGitilesFollower},
[]goldpushk.DeployableUnitID{chromeIngestionBT, chromeFrontend})
test("Multiple instances, all services, no canary",
[]string{"chrome", "skia"}, []string{"all"}, nil,
- []goldpushk.DeployableUnitID{chromeBaselineServer, chromeDiffCalculator, chromeDiffServer, chromeIngestionBT, chromeFrontend, skiaDiffCalculator, skiaDiffServer, skiaIngestionBT, skiaFrontend},
+ []goldpushk.DeployableUnitID{chromeBaselineServer, chromeDiffCalculator, chromeDiffServer, chromeIngestionBT, chromeFrontend, chromeGitilesFollower, skiaDiffCalculator, skiaDiffServer, skiaIngestionBT, skiaFrontend, skiaGitilesFollower},
nil)
test("Multiple instances, all services, one canary",
[]string{"chrome", "skia"}, []string{"all"}, []string{"skia:frontend"},
- []goldpushk.DeployableUnitID{chromeBaselineServer, chromeDiffCalculator, chromeDiffServer, chromeIngestionBT, chromeFrontend, skiaDiffCalculator, skiaDiffServer, skiaIngestionBT},
+ []goldpushk.DeployableUnitID{chromeBaselineServer, chromeDiffCalculator, chromeDiffServer, chromeIngestionBT, chromeFrontend, chromeGitilesFollower, skiaDiffCalculator, skiaDiffServer, skiaIngestionBT, skiaGitilesFollower},
[]goldpushk.DeployableUnitID{skiaFrontend})
test("Multiple instances, all services, multiple canaries",
[]string{"chrome", "skia"}, []string{"all"}, []string{"skia:ingestion-bt", "skia:frontend"},
- []goldpushk.DeployableUnitID{chromeBaselineServer, chromeDiffCalculator, chromeDiffServer, chromeIngestionBT, chromeFrontend, skiaDiffCalculator, skiaDiffServer},
+ []goldpushk.DeployableUnitID{chromeBaselineServer, chromeDiffCalculator, chromeDiffServer, chromeIngestionBT, chromeFrontend, chromeGitilesFollower, skiaDiffCalculator, skiaDiffServer, skiaGitilesFollower},
[]goldpushk.DeployableUnitID{skiaIngestionBT, skiaFrontend})
////////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/golden/dockerfiles/Dockerfile_gitilesfollower b/golden/dockerfiles/Dockerfile_gitilesfollower
new file mode 100644
index 0000000..9605669
--- /dev/null
+++ b/golden/dockerfiles/Dockerfile_gitilesfollower
@@ -0,0 +1,9 @@
+FROM gcr.io/skia-public/basealpine:3.8
+
+USER root
+
+COPY . /
+
+USER skia
+
+ENTRYPOINT ["/usr/local/bin/gold-gitilesfollower"]
diff --git a/golden/k8s-config-templates/gold-common.json5 b/golden/k8s-config-templates/gold-common.json5
index 198ae99..9bf02ed 100644
--- a/golden/k8s-config-templates/gold-common.json5
+++ b/golden/k8s-config-templates/gold-common.json5
@@ -3,6 +3,7 @@
"DIFFCALCULATOR_IMAGE": "gcr.io/skia-public/gold-diffcalculator:2021-02-22T12_23_04Z-kjlubick-d23f6c7-clean",
"DIFF_SERVER_IMAGE": "gcr.io/skia-public/gold-diff-server:2021-01-19T14_27_42Z-kjlubick-450bea3-clean",
"FRONTEND_IMAGE": "gcr.io/skia-public/gold-frontend:2021-02-23T13_50_54Z-kjlubick-6d6951a-clean",
+ "GITILESFOLLOWER_IMAGE": "gcr.io/skia-public/gold-gitilesfollower:2021-02-26T18_42_54Z-kjlubick-dacfd05-dirty",
"INGESTION_BT_IMAGE": "gcr.io/skia-public/gold-ingestion:2021-02-15T14_17_39Z-kjlubick-b37d281-clean",
// Services for testing goldpushk.
diff --git a/golden/k8s-config-templates/gold-gitilesfollower-template.yaml b/golden/k8s-config-templates/gold-gitilesfollower-template.yaml
new file mode 100644
index 0000000..697a10bc
--- /dev/null
+++ b/golden/k8s-config-templates/gold-gitilesfollower-template.yaml
@@ -0,0 +1,79 @@
+apiVersion: v1
+kind: Service
+metadata:
+ labels:
+ app: gold-{{.INSTANCE_ID}}-gitilesfollower
+ name: gold-{{.INSTANCE_ID}}-gitilesfollower
+spec:
+ ports:
+ - name: metrics
+ port: 20000
+ selector:
+ app: gold-{{.INSTANCE_ID}}-gitilesfollower
+ type: NodePort
+---
+apiVersion: apps/v1
+kind: Deployment
+metadata:
+ name: gold-{{.INSTANCE_ID}}-gitilesfollower
+spec:
+ replicas: 1
+ selector:
+ matchLabels:
+ app: gold-{{.INSTANCE_ID}}-gitilesfollower
+ strategy:
+ type: RollingUpdate
+ template:
+ metadata:
+ labels:
+ app: gold-{{.INSTANCE_ID}}-gitilesfollower
+ appgroup: gold-{{.INSTANCE_ID}}
+ date: "{{.NOW}}" # Forces a re-deploy even if just the config file changes.
+ annotations:
+ prometheus.io.scrape: "true"
+ prometheus.io.port: "20000"
+ spec:
+ automountServiceAccountToken: false
+ securityContext:
+ runAsUser: 2000 # aka skia
+ fsGroup: 2000 # aka skia
+ containers:
+ - name: gold-{{.INSTANCE_ID}}-gitilesfollower
+ image: {{.GITILESFOLLOWER_IMAGE}}
+ args:
+ - "--common_instance_config=/etc/gold-config/{{.INSTANCE_ID}}.json5"
+ - "--config=/etc/gold-config/{{.INSTANCE_ID}}-gitilesfollower.json5"
+ - "--logtostderr"
+ ports:
+ - containerPort: 20000
+ name: prom
+ volumeMounts:
+ - name: gold-{{.INSTANCE_ID}}-config-volume
+ mountPath: /etc/gold-config/
+ - name: gold-service-account-secrets
+ mountPath: /etc/gold-secrets/
+ env:
+ - name: GOOGLE_APPLICATION_CREDENTIALS
+ value: /etc/gold-secrets/service-account.json
+ - name: K8S_POD_NAME
+ valueFrom:
+ fieldRef:
+ fieldPath: metadata.name
+ resources:
+ requests:
+ memory: "100Mi"
+ cpu: "10m"
+ readinessProbe:
+ httpGet:
+ path: /healthz
+ port: 8000
+ initialDelaySeconds: 5
+ periodSeconds: 3
+ volumes:
+ - name: gold-{{.INSTANCE_ID}}-config-volume
+ configMap:
+ defaultMode: 400
+ name: gold-{{.INSTANCE_ID}}-config
+ - name: gold-service-account-secrets
+ secret:
+ secretName: gold-service-account-secrets
diff --git a/golden/k8s-instances/chrome/chrome-gitilesfollower.json5 b/golden/k8s-instances/chrome/chrome-gitilesfollower.json5
new file mode 100644
index 0000000..d45aa53
--- /dev/null
+++ b/golden/k8s-instances/chrome/chrome-gitilesfollower.json5
@@ -0,0 +1,7 @@
+{
+ // Arbitrary commit from 17 Dec 2020
+ initial_commit: "971e0b95aba2fe33d26f14cc19e346e81d6b6a34",
+ poll_period: "1m",
+ prom_port: ":20000",
+ ready_port: ":8000"
+}
\ No newline at end of file
diff --git a/golden/k8s-instances/flutter/flutter-gitilesfollower.json5 b/golden/k8s-instances/flutter/flutter-gitilesfollower.json5
new file mode 100644
index 0000000..2fa5c1b
--- /dev/null
+++ b/golden/k8s-instances/flutter/flutter-gitilesfollower.json5
@@ -0,0 +1,9 @@
+{
+ // Arbitrary commit from 28 Dec 2020
+ initial_commit: "36373f8d08742468541cbaca35f20810662b2436",
+ // Need to use a gitiles mirror
+ git_repo_url: "https://chromium.googlesource.com/external/github.com/flutter/flutter",
+ poll_period: "1m",
+ prom_port: ":20000",
+ ready_port: ":8000"
+}
\ No newline at end of file
diff --git a/golden/k8s-instances/skia-infra/skia-infra-gitilesfollower.json5 b/golden/k8s-instances/skia-infra/skia-infra-gitilesfollower.json5
new file mode 100644
index 0000000..ccaeaf4
--- /dev/null
+++ b/golden/k8s-instances/skia-infra/skia-infra-gitilesfollower.json5
@@ -0,0 +1,7 @@
+{
+ // Arbitrary commit from 9 Dec 2020
+ initial_commit: "7f4ddfca8eb543bdc427173a7c3e10d69f960722",
+ poll_period: "1m",
+ prom_port: ":20000",
+ ready_port: ":8000"
+}
\ No newline at end of file
diff --git a/golden/k8s-instances/skia/skia-gitilesfollower.json5 b/golden/k8s-instances/skia/skia-gitilesfollower.json5
new file mode 100644
index 0000000..410c1bd
--- /dev/null
+++ b/golden/k8s-instances/skia/skia-gitilesfollower.json5
@@ -0,0 +1,7 @@
+{
+ // Arbitrary commit from 14 Dec 2020
+ initial_commit: "9b395f55ea0f8f92103d33f1ea8e8217bee8aaea",
+ poll_period: "1m",
+ prom_port: ":20000",
+ ready_port: ":8000"
+}
\ No newline at end of file
diff --git a/golden/k8s_release_gitilesfollower b/golden/k8s_release_gitilesfollower
new file mode 100755
index 0000000..9fbbda5
--- /dev/null
+++ b/golden/k8s_release_gitilesfollower
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+set -x -e
+
+# Create and upload a container image for a server that syncs the gitiles repo into SQL.
+APPNAME=gold-gitilesfollower
+
+# Copy files into the right locations in ${ROOT}.
+copy_release_files()
+{
+INSTALL="install -D --verbose --backup=none"
+INSTALL_DIR="install -d --verbose --backup=none"
+
+# Add the dockerfile and binary.
+${INSTALL} --mode=644 -T ./dockerfiles/Dockerfile_gitilesfollower ${ROOT}/Dockerfile
+${INSTALL} --mode=755 -T ./build/gitilesfollower_k8s ${ROOT}/usr/local/bin/${APPNAME}
+}
+
+source ../bash/docker_build.sh