From ed84c5f136464b7de4d4d4351029ce506e6d95a9 Mon Sep 17 00:00:00 2001 From: Adam Tajti Date: Mon, 25 Sep 2023 17:17:40 +0200 Subject: [PATCH 01/16] rebase and secure the role arn to public ecr --- .github/actions/setup-ecr-buildx/action.yml | 34 ++++++++++ .github/workflows/build-and-push.yml | 68 +++++++++++++++++++ .github/workflows/pull-request.yml | 11 ++- Dockerfile.integration | 1 - README.md | 5 +- default.nix | 12 ++-- go.mod | 4 +- go.sum | 6 ++ integration-tests/acceptance/harness_test.go | 4 +- .../fault-injection/baseline_test.go | 4 ++ .../fault-injection/harness/inserter.go | 16 +++-- .../fault-injection/harness/mongo.go | 28 +++++--- .../fault-injection/harness/redis.go | 2 +- .../fault-injection/harness/redisVerifier.go | 36 ++++++++-- .../fault-injection/mongoStepdown_test.go | 2 +- .../fault-injection/mongoStopStart_test.go | 2 +- .../fault-injection/restart_test.go | 5 +- integration-tests/helpers/redis.go | 2 +- integration-tests/performance/bench_test.go | 4 +- lib/oplog/oplogEntry_test.go | 2 +- lib/oplog/tail.go | 2 +- lib/oplog/tail_test.go | 2 +- lib/redispub/lastProcessedTime.go | 5 +- lib/redispub/lastProcessedTime_test.go | 2 +- lib/redispub/publisher.go | 8 ++- lib/redispub/publisher_test.go | 20 +++--- main.go | 17 +++-- scripts/install-debian-mongo.sh | 4 +- scripts/runIntegrationFaultInjection.sh | 4 +- 29 files changed, 239 insertions(+), 73 deletions(-) create mode 100644 .github/actions/setup-ecr-buildx/action.yml create mode 100644 .github/workflows/build-and-push.yml diff --git a/.github/actions/setup-ecr-buildx/action.yml b/.github/actions/setup-ecr-buildx/action.yml new file mode 100644 index 00000000..c170178e --- /dev/null +++ b/.github/actions/setup-ecr-buildx/action.yml @@ -0,0 +1,34 @@ +name: Setup ECR / Buildx +description: Composite action to setup requirements for ECR and buildx for docker pushes + +inputs: + registry-type: + description: ECR Registry Type + default: private + role-to-assume: + description: ECR Role to Assume + required: true + +outputs: + ecr_registry: + description: ECR Registry + value: ${{ steps.login-ecr.outputs.registry }} + +runs: + using: "composite" + steps: + - name: Configure AWS Credentials + uses: aws-actions/configure-aws-credentials@v2 + with: + role-to-assume: ${{ inputs.role-to-assume }} + role-session-name: github-action-session + aws-region: us-east-1 + + - name: Login to Amazon ECR + id: login-ecr + uses: aws-actions/amazon-ecr-login@v1 + with: + registry-type: ${{ inputs.registry_type }} + + - name: Set up Docker Buildx + uses: docker/setup-buildx-action@ecf95283f03858871ff00b787d79c419715afc34 # v2.7.0 diff --git a/.github/workflows/build-and-push.yml b/.github/workflows/build-and-push.yml new file mode 100644 index 00000000..bd537f04 --- /dev/null +++ b/.github/workflows/build-and-push.yml @@ -0,0 +1,68 @@ +name: Build and Push + +# Builds and pushes the branch to ECR from master, or the manually selected branch when invoked manually. We stopped using Docker Hub for storing the image of oplogtoredis, where we used a Webhook to do the same thing. + +on: + push: + branches: + - master + # Left this here in-case the workflow needs to be developed further rapidly: + # pull_request: + # types: [ opened, synchronize, reopened ] + workflow_dispatch: + + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} + +permissions: + id-token: write # for the creds itself + contents: read # for checkout + +jobs: + build-and-push: + name: Build and Push + runs-on: ubuntu-latest + steps: + + - uses: actions/checkout@v3 + + - uses: cachix/install-nix-action@v22 + with: + nix_path: nixpkgs=channel:nixos-unstable + + # Examples of the generated tags: + # - v3.0.0 (branch: master) + # - v3.0.0-branch-name (branch: branch-name) + - name: Generate Tag + id: generate-tag + run: | + # Extract the current version from `default.nix`. This must pass. + version=$(nix flake show . --quiet --all-systems --json | jq -r '.defaultPackage."aarch64-darwin".name' | cut -d'-' -f2-) + + # Adds the branch name if the workflow is manually invoked from a branch. + tag_branch_segment="" + + branch_name=${{ github.event.pull_request && github.head_ref || github.ref_name }} + if [ "$branch_name" != "master" ]; then + tag_branch_segment="-${branch_name}" # adds a - as needed + fi + + tag="v${version}${tag_branch_segment}" + + echo "TAG=${tag}" >> $GITHUB_OUTPUT + + - name: Setup ECR/buildx + uses: ./.github/actions/setup-ecr-buildx + id: setup-ecr-buildx + with: + role-to-assume: ${{ secrets.AWS_PUBLIC_ECR_ROLE_ARN }} + registry-type: public + + - name: Build and push image + uses: docker/build-push-action@3b5e8027fcad23fda98b2e3ac259d8d67585f671 # 4.0.0 + with: + tags: ${{ steps.setup-ecr-buildx.outputs.ecr_registry }}/ecr-public/docker/tulip/oplogtoredis:${{ steps.generate-tag.outputs.TAG }} + provenance: false + push: true diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index 3991c7ff..953898a3 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -8,14 +8,13 @@ jobs: timeout-minutes: 60 steps: - uses: actions/checkout@v2 - - uses: actions/setup-go@v3 + - uses: actions/setup-go@v4 with: go-version: '1.17' - - name: setup golangci-lint - run: | - curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh -s -- -b $(go env GOPATH)/bin v1.42.0 - export PATH=$PATH:$(go env GOPATH)/bin - golangci-lint --version + - name: golangci-lint + uses: golangci/golangci-lint-action@v3 + with: + version: v1.42 - name: run lint run: ./scripts/runLint.sh - name: run unit tests diff --git a/Dockerfile.integration b/Dockerfile.integration index d4d4e7d5..29cb1946 100644 --- a/Dockerfile.integration +++ b/Dockerfile.integration @@ -15,7 +15,6 @@ RUN go mod download WORKDIR /oplogtoredis/integration-tests - FROM integration_base AS acceptance COPY integration-tests/acceptance/*.go ./acceptance/ WORKDIR ./acceptance diff --git a/README.md b/README.md index 2ea8d224..6b775a97 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,5 @@ # oplogtoredis -[![Build Status](https://app.travis-ci.com/tulip/oplogtoredis.svg?branch=master)](https://app.travis-ci.com/tulip/oplogtoredis) [![Go Report Card](https://goreportcard.com/badge/github.com/tulip/oplogtoredis)](https://goreportcard.com/report/github.com/tulip/oplogtoredis) [![GoDoc](https://godoc.org/github.com/tulip/oplogtoredis?status.svg)](http://godoc.org/github.com/tulip/oplogtoredis) @@ -61,9 +60,7 @@ you might use this config: ## Deploying oplogtoredis -You can build oplogtoredis from source with `go build .`, which produces a -statically-linked binary you can run. Alternatively, you can use [the public -docker image](https://hub.docker.com/r/tulip/oplogtoredis/tags/) +You can build oplogtoredis from source with `go build .`, which produces a statically-linked binary you can run. Alternatively, you can use [the public docker image](https://gallery.ecr.aws/u4f7y3k8/oplogtoredis). Previously we used to host these images in [Docker Hub](https://hub.docker.com/r/tulip/oplogtoredis/tags/). These won't be maintained anymore. ### Environment Variables diff --git a/default.nix b/default.nix index 4f1e1e1f..462f2959 100644 --- a/default.nix +++ b/default.nix @@ -1,14 +1,14 @@ { lib, stdenv, buildGoModule, fetchFromGitHub, installShellFiles }: buildGoModule { - pname = "oplogtoredis"; - version = "2.0.1"; + pname = "oplogtoredis"; + version = "3.0.0"; src = builtins.path { path = ./.; }; vendorSha256 = "sha256-VHiYVJUNtHN2IY4iXZ6kHAa3Avi2VwRH1ySKBrrCDu4="; - postInstall = '' + postInstall = '' ''; - nativeBuildInputs = [installShellFiles]; - doCheck = false; - doInstallCheck = false; + nativeBuildInputs = [ installShellFiles ]; + doCheck = false; + doInstallCheck = false; } diff --git a/go.mod b/go.mod index 91e32f93..762f455a 100644 --- a/go.mod +++ b/go.mod @@ -26,8 +26,10 @@ require ( require ( github.com/alicebob/gopher-json v0.0.0-20200520072559-a9ecdc9d1d3a // indirect github.com/beorn7/perks v1.0.1 // indirect - github.com/cespare/xxhash/v2 v2.1.1 // indirect + github.com/cespare/xxhash/v2 v2.2.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect + github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f // indirect + github.com/go-redis/redis/v8 v8.11.5 // indirect github.com/golang/protobuf v1.4.3 // indirect github.com/golang/snappy v0.0.1 // indirect github.com/gomodule/redigo v1.8.5 // indirect diff --git a/go.sum b/go.sum index 54a27890..731a13b0 100644 --- a/go.sum +++ b/go.sum @@ -51,6 +51,8 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.2.0 h1:DC2CZ1Ep5Y4k3ZQ899DldepgrayRUGE6BBZ/cd9Cj44= +github.com/cespare/xxhash/v2 v2.2.0/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= @@ -62,6 +64,8 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/deckarep/golang-set v1.7.1 h1:SCQV0S6gTtp6itiFrTqI+pfmJ4LN85S1YzhDf9rTHJQ= github.com/deckarep/golang-set v1.7.1/go.mod h1:93vsz/8Wt4joVM7c2AVqh+YRMiUSc14yDtF28KmMOgQ= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f h1:lO4WD4F/rVNCu3HqELle0jiPLLBs70cWOduZpkS1E78= +github.com/dgryski/go-rendezvous v0.0.0-20200823014737-9f7001d12a5f/go.mod h1:cuUVRXasLTGF7a8hSLbxyZXjz+1KgoB3wDUb6vlszIc= github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= @@ -78,6 +82,8 @@ github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V github.com/go-logfmt/logfmt v0.5.0/go.mod h1:wCYkCAKZfumFQihp8CzCvQ3paCTfi41vtzG1KdI/P7A= github.com/go-redis/redis/v7 v7.4.1 h1:PASvf36gyUpr2zdOUS/9Zqc80GbM+9BDyiJSJDDOrTI= github.com/go-redis/redis/v7 v7.4.1/go.mod h1:JDNMw23GTyLNC4GZu9njt15ctBQVn7xjRfnwdHj/Dcg= +github.com/go-redis/redis/v8 v8.11.5 h1:AcZZR7igkdvfVmQTPnu9WE37LRrO/YrBH5zWyjDC0oI= +github.com/go-redis/redis/v8 v8.11.5/go.mod h1:gREzHqY1hg6oD9ngVRbLStwAWKhA0FEgq8Jd4h5lpwo= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= diff --git a/integration-tests/acceptance/harness_test.go b/integration-tests/acceptance/harness_test.go index 0f4e30ca..8dbf8722 100644 --- a/integration-tests/acceptance/harness_test.go +++ b/integration-tests/acceptance/harness_test.go @@ -7,7 +7,7 @@ import ( "testing" "time" - "github.com/go-redis/redis/v7" + "github.com/go-redis/redis/v8" "github.com/kylelemons/godebug/pretty" "github.com/tulip/oplogtoredis/integration-tests/helpers" "go.mongodb.org/mongo-driver/mongo" @@ -30,7 +30,7 @@ func startHarness() *harness { // Connect to redis and start listening for the publication we expect h.redisClient = helpers.RedisClient() - h.subscription = h.redisClient.PSubscribe("*") + h.subscription = h.redisClient.PSubscribe(context.Background(), "*") h.subscriptionC = h.subscription.Channel() return &h diff --git a/integration-tests/fault-injection/baseline_test.go b/integration-tests/fault-injection/baseline_test.go index 3dcf94ae..3a8b5a0c 100644 --- a/integration-tests/fault-injection/baseline_test.go +++ b/integration-tests/fault-injection/baseline_test.go @@ -3,6 +3,7 @@ package main import ( "context" "testing" + "time" "github.com/tulip/oplogtoredis/integration-tests/fault-injection/harness" ) @@ -16,6 +17,9 @@ func TestBaseline(t *testing.T) { mongo := harness.StartMongoServer() defer mongo.Stop() + // Sleeping here for a while as the initial connection seems to be unreliable + time.Sleep(time.Second * 1) + redis := harness.StartRedisServer() defer redis.Stop() diff --git a/integration-tests/fault-injection/harness/inserter.go b/integration-tests/fault-injection/harness/inserter.go index de9cb7ee..7048d71f 100644 --- a/integration-tests/fault-injection/harness/inserter.go +++ b/integration-tests/fault-injection/harness/inserter.go @@ -21,17 +21,23 @@ func RunInserts(client *mongo.Database, numInserts int, frequency time.Duration) for i := 0; i < numInserts; i++ { id := fmt.Sprintf("doc%d", i) - // We set a 50ms timout for the insert: long enough that the insert will + // We set a 100ms timeout for the insert: long enough that the insert will // succeed if Mongo is working normally, but too short for it to retry during - // a failover - ctx, cancel := context.WithTimeout(context.Background(), 50*time.Millisecond) + // a failover. + + // The write may still get through even if the InsertOne call errors out and if the resulting InsertedID is nil. + ctx, cancel := context.WithTimeout(context.Background(), 100*time.Millisecond) defer cancel() - _, err := client.Collection("Test").InsertOne(ctx, bson.M{ + insertResult, err := client.Collection("Test").InsertOne(ctx, bson.M{ "_id": id, }) if err != nil { - log.Printf("Warning: mongo insert failed: %s", err) + log.Printf("Warning: mongo insert failed for doc %s: %s", id, err) + if insertResult != nil && insertResult.InsertedID != nil { + log.Printf("Warning: although the previous insert faced this error, the InsertedID wasn't nil, so we'll conclude it was a success (InterruptedDueToReplStateChange). InsertedID: %s", insertResult.InsertedID) + result = append(result, id) + } } else { log.Printf("Inserted doc %s", id) result = append(result, id) diff --git a/integration-tests/fault-injection/harness/mongo.go b/integration-tests/fault-injection/harness/mongo.go index cf4fd5bb..0f9cc929 100644 --- a/integration-tests/fault-injection/harness/mongo.go +++ b/integration-tests/fault-injection/harness/mongo.go @@ -40,7 +40,7 @@ func StartMongoServer() *MongoServer { } server := MongoServer{ - Addr: "mongodb://localhost:27001,localhost:27002,localhost:27003/testdb?replicaSet=test", + Addr: "mongodb://127.0.0.1:27001,127.0.0.1:27002,127.0.0.1:27003/testdb?replicaSet=test", dataPrefix: dir, } @@ -68,7 +68,7 @@ func (server *MongoServer) Start() { client := server.clientNoReplLegacyMgo() // Initiate - err := replicaset.Initiate(client, "localhost:27001", "test", map[string]string{}) + err := replicaset.Initiate(client, "127.0.0.1:27001", "test", map[string]string{}) if err != nil { panic("Error initiating replica set: " + err.Error()) } @@ -76,13 +76,13 @@ func (server *MongoServer) Start() { // Add first member - need to add them one at a time in mongo 4.4 err = replicaset.Add(client, replicaset.Member{ - Address: "localhost:27002"}) + Address: "127.0.0.1:27002"}) if err != nil { panic("Error adding replica set member 27002: " + err.Error()) } // Add second member - need to add them one at a time in mongo 4.4 err = replicaset.Add(client, replicaset.Member{ - Address: "localhost:27003"}) + Address: "127.0.0.1:27003"}) if err != nil { panic("Error adding replica set member 27003: " + err.Error()) } @@ -116,9 +116,10 @@ func (server *MongoServer) Client() *mongo.Client { server.DBName = cs.Database clientOptions := options.Client() + + // This is true by default in mongo 4.4, but our failover tests require failed writes clientOptions.SetRetryWrites(false) - // This is true by default in mongo 4.4 - //- our failover tests require failed writes + clientOptions.ApplyURI(server.Addr) ctx, cancel := context.WithTimeout(context.Background(), 3*time.Second) @@ -131,7 +132,12 @@ func (server *MongoServer) Client() *mongo.Client { err = client.Ping(ctx, readpref.Primary()) if err != nil { - panic("Error pinging Mongo") + panic("Error pinging primary Mongo for read") + } + + err = client.Ping(ctx, readpref.Secondary()) + if err != nil { + panic("Error pinging secondary Mongo for read") } return client @@ -186,9 +192,9 @@ func (server *MongoServer) Stop() { } // Wait for them to stop - waitTCPDown("localhost:27001") - waitTCPDown("localhost:27002") - waitTCPDown("localhost:27003") + waitTCPDown("127.0.0.1:27001") + waitTCPDown("127.0.0.1:27002") + waitTCPDown("127.0.0.1:27003") } // StepDown triggers a step-down of the primary @@ -226,7 +232,7 @@ func (server *MongoServer) startNode(name string, port int) *exec.Cmd { panic("Error starting up mongo node: " + err.Error()) } - waitTCP(fmt.Sprintf("localhost:%d", port)) + waitTCP(fmt.Sprintf("127.0.0.1:%d", port)) return cmd } diff --git a/integration-tests/fault-injection/harness/redis.go b/integration-tests/fault-injection/harness/redis.go index c06c1aff..12ff8508 100644 --- a/integration-tests/fault-injection/harness/redis.go +++ b/integration-tests/fault-injection/harness/redis.go @@ -4,7 +4,7 @@ import ( "log" "os/exec" - "github.com/go-redis/redis/v7" + "github.com/go-redis/redis/v8" ) // RedisServer represents a running Redis server diff --git a/integration-tests/fault-injection/harness/redisVerifier.go b/integration-tests/fault-injection/harness/redisVerifier.go index d0e14ae7..3e3bd000 100644 --- a/integration-tests/fault-injection/harness/redisVerifier.go +++ b/integration-tests/fault-injection/harness/redisVerifier.go @@ -1,13 +1,16 @@ package harness import ( + "context" "encoding/json" "log" "testing" "time" - "github.com/go-redis/redis/v7" + "github.com/go-redis/redis/v8" "github.com/tulip/oplogtoredis/integration-tests/helpers" + "go.mongodb.org/mongo-driver/bson" + "go.mongodb.org/mongo-driver/mongo" ) // RedisVerifier subscribes to the publications that a BackgroundInserter should @@ -21,19 +24,19 @@ type RedisVerifier struct { // NewRedisVerifier creates a RedisVerifier and starts reading messages from // Redis func NewRedisVerifier(client redis.UniversalClient, stopReceivingOnError bool) *RedisVerifier { - if pingErr := client.Ping().Err(); pingErr != nil { + if pingErr := client.Ping(context.Background()).Err(); pingErr != nil { panic("Ping error to redis: " + pingErr.Error()) } verifier := RedisVerifier{ client: client, receivedIDs: make(chan string, 100), - pubsub: client.Subscribe("testdb.Test"), + pubsub: client.Subscribe(context.Background(), "testdb.Test"), } go func() { for { - msg, err := verifier.pubsub.ReceiveMessage() + msg, err := verifier.pubsub.ReceiveMessage(context.Background()) if err != nil { log.Printf("Error receiving pubsub message: %s", err.Error()) if stopReceivingOnError { @@ -58,7 +61,7 @@ func NewRedisVerifier(client redis.UniversalClient, stopReceivingOnError bool) * return &verifier } -// Verify verifies that the given IDs match the messages published to Redis. +// Verify verifies that the messages received from Redis were destined to be written there // It blocks until all expected IDs have been received (timing out if nothing // is received for 10 seconds) func (verifier *RedisVerifier) Verify(t *testing.T, ids []string) { @@ -76,6 +79,29 @@ func (verifier *RedisVerifier) Verify(t *testing.T, ids []string) { } } +func (verifier *RedisVerifier) VerifyFlakyInserts(t *testing.T, mongoClient *mongo.Database, mongoIDs []string) { + for idx, id := range mongoIDs { + select { + case receivedID := <-verifier.receivedIDs: + if receivedID != id { + // Sometimes the Insert is detected as a failure, but the insert actually succeeds. + // This is a hacky case to check if this document was really written to Mongo + findOneResult := mongoClient.Collection("Test").FindOne(context.Background(), bson.M{ + "_id": receivedID, + }) + + if findOneResult.Err() != nil { + t.Errorf("On message %d, received %s but expected %s", + idx, receivedID, id) + } + } + case <-time.After(10 * time.Second): + t.Errorf("Timed out waiting for redis message %d", idx) + return + } + } +} + // ReceivedCount returns the number of Redis message received by this verifier func (verifier *RedisVerifier) ReceivedCount() int { // We wait until we're no longer actively receiving messages diff --git a/integration-tests/fault-injection/mongoStepdown_test.go b/integration-tests/fault-injection/mongoStepdown_test.go index 6195381d..effd8055 100644 --- a/integration-tests/fault-injection/mongoStepdown_test.go +++ b/integration-tests/fault-injection/mongoStepdown_test.go @@ -49,5 +49,5 @@ func TestMongoStepdown(t *testing.T) { t.Errorf("Expected no more than 100 successful writes, got %d", len(insertedIDs)) } - verifier.Verify(t, insertedIDs) + verifier.VerifyFlakyInserts(t, mongoClient.Database(mongo.DBName), insertedIDs) } diff --git a/integration-tests/fault-injection/mongoStopStart_test.go b/integration-tests/fault-injection/mongoStopStart_test.go index ae4780ca..e1ebe678 100644 --- a/integration-tests/fault-injection/mongoStopStart_test.go +++ b/integration-tests/fault-injection/mongoStopStart_test.go @@ -54,5 +54,5 @@ func TestMongoStopStart(t *testing.T) { t.Errorf("Expected at least 50 inserted IDs, got %d", len(insertedIDs)) } - verifier.Verify(t, insertedIDs) + verifier.VerifyFlakyInserts(t, mongoClient.Database(mongo.DBName), insertedIDs) } diff --git a/integration-tests/fault-injection/restart_test.go b/integration-tests/fault-injection/restart_test.go index b8d4921c..5af3bf17 100644 --- a/integration-tests/fault-injection/restart_test.go +++ b/integration-tests/fault-injection/restart_test.go @@ -15,6 +15,9 @@ func TestRestart(t *testing.T) { mongo := harness.StartMongoServer() defer mongo.Stop() + // Sleeping here for a while as the initial connection seems to be unreliable + time.Sleep(time.Second * 1) + redis := harness.StartRedisServer() defer redis.Stop() @@ -42,7 +45,7 @@ func TestRestart(t *testing.T) { t.Errorf("Expected 100 inserted IDs, got %d", len(insertedIDs)) } - verifier.Verify(t, insertedIDs) + verifier.VerifyFlakyInserts(t, mongoClient.Database(mongo.DBName), insertedIDs) // We also want to verify that we picked up from where we left off (rather // that starting from the beginning of the oplog or something). The first diff --git a/integration-tests/helpers/redis.go b/integration-tests/helpers/redis.go index e3dd8fe2..dea42afc 100644 --- a/integration-tests/helpers/redis.go +++ b/integration-tests/helpers/redis.go @@ -3,7 +3,7 @@ package helpers import ( "os" - "github.com/go-redis/redis/v7" + "github.com/go-redis/redis/v8" ) // RedisClient returns a redis client to the URL specified in the REDIS_URL diff --git a/integration-tests/performance/bench_test.go b/integration-tests/performance/bench_test.go index 2db1ae0b..7685b15e 100644 --- a/integration-tests/performance/bench_test.go +++ b/integration-tests/performance/bench_test.go @@ -35,7 +35,7 @@ func BenchmarkInsertWaitForRedis(b *testing.B) { client := helpers.RedisClient() defer client.Close() - subscr := client.Subscribe("tests.Foo2") + subscr := client.Subscribe(context.Background(), "tests.Foo2") defer subscr.Close() db := helpers.SeedTestDB(helpers.DBData{}) @@ -45,7 +45,7 @@ func BenchmarkInsertWaitForRedis(b *testing.B) { wg.Add(1) go func() { for i := 0; i < b.N; i++ { - _, err := subscr.ReceiveMessage() + _, err := subscr.ReceiveMessage(context.Background()) if err != nil { panic(err) } diff --git a/lib/oplog/oplogEntry_test.go b/lib/oplog/oplogEntry_test.go index 6f9ac265..055bb1fb 100644 --- a/lib/oplog/oplogEntry_test.go +++ b/lib/oplog/oplogEntry_test.go @@ -387,7 +387,7 @@ func TestUpdateIsV2Formatted(t *testing.T) { for testName, test := range tests { t.Run(testName, func(t *testing.T) { - got := (&oplogEntry{Data: test.in}).UpdateIsV2Formatted() + got := (&oplogEntry{Data: test.in}).IsV2Update() if got != test.expectedResult { t.Errorf("UpdateIsV2Formatted(%#v) = %t; want %t", diff --git a/lib/oplog/tail.go b/lib/oplog/tail.go index 5316b57c..d3af6af0 100644 --- a/lib/oplog/tail.go +++ b/lib/oplog/tail.go @@ -16,7 +16,7 @@ import ( "go.mongodb.org/mongo-driver/mongo" "go.mongodb.org/mongo-driver/mongo/options" - "github.com/go-redis/redis/v7" + "github.com/go-redis/redis/v8" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" "go.mongodb.org/mongo-driver/bson" diff --git a/lib/oplog/tail_test.go b/lib/oplog/tail_test.go index 5970649b..1429a253 100644 --- a/lib/oplog/tail_test.go +++ b/lib/oplog/tail_test.go @@ -7,7 +7,7 @@ import ( "time" "github.com/alicebob/miniredis" - "github.com/go-redis/redis/v7" + "github.com/go-redis/redis/v8" "github.com/kylelemons/godebug/pretty" "github.com/stretchr/testify/require" "go.mongodb.org/mongo-driver/bson" diff --git a/lib/redispub/lastProcessedTime.go b/lib/redispub/lastProcessedTime.go index ceb0b300..dbfa44ba 100644 --- a/lib/redispub/lastProcessedTime.go +++ b/lib/redispub/lastProcessedTime.go @@ -1,9 +1,10 @@ package redispub import ( + "context" "time" - "github.com/go-redis/redis/v7" + "github.com/go-redis/redis/v8" "go.mongodb.org/mongo-driver/bson/primitive" ) @@ -17,7 +18,7 @@ import ( // If oplogtoredis has not processed any messages, returns redis.Nil as an // error. func LastProcessedTimestamp(redisClient redis.UniversalClient, metadataPrefix string) (primitive.Timestamp, time.Time, error) { - str, err := redisClient.Get(metadataPrefix + "lastProcessedEntry").Result() + str, err := redisClient.Get(context.Background(), metadataPrefix+"lastProcessedEntry").Result() if err != nil { return primitive.Timestamp{}, time.Unix(0, 0), err } diff --git a/lib/redispub/lastProcessedTime_test.go b/lib/redispub/lastProcessedTime_test.go index 259c4f8e..ffb4b185 100644 --- a/lib/redispub/lastProcessedTime_test.go +++ b/lib/redispub/lastProcessedTime_test.go @@ -5,7 +5,7 @@ import ( "time" "github.com/alicebob/miniredis" - "github.com/go-redis/redis/v7" + "github.com/go-redis/redis/v8" "github.com/stretchr/testify/require" "go.mongodb.org/mongo-driver/bson/primitive" ) diff --git a/lib/redispub/publisher.go b/lib/redispub/publisher.go index e51aa941..9373325b 100644 --- a/lib/redispub/publisher.go +++ b/lib/redispub/publisher.go @@ -5,14 +5,15 @@ package redispub import ( + "context" "fmt" - "time" "strings" + "time" "github.com/tulip/oplogtoredis/lib/log" "go.mongodb.org/mongo-driver/bson/primitive" - "github.com/go-redis/redis/v7" + "github.com/go-redis/redis/v8" "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" @@ -126,6 +127,7 @@ func publishSingleMessageWithRetries(p *Publication, maxRetries int, sleepTime t func publishSingleMessage(p *Publication, client redis.UniversalClient, prefix string, dedupeExpirationSeconds int) error { _, err := publishDedupe.Run( + context.Background(), client, []string{ // The key used for deduplication @@ -162,7 +164,7 @@ func periodicallyUpdateTimestamp(client redis.UniversalClient, timestamps <-chan flush := func() { if needFlush { - client.Set(opts.MetadataPrefix+"lastProcessedEntry", encodeMongoTimestamp(mostRecentTimestamp), 0) + client.Set(context.Background(), opts.MetadataPrefix+"lastProcessedEntry", encodeMongoTimestamp(mostRecentTimestamp), 0) lastFlush = time.Now() needFlush = false } diff --git a/lib/redispub/publisher_test.go b/lib/redispub/publisher_test.go index dc763ec0..0d7f39fa 100644 --- a/lib/redispub/publisher_test.go +++ b/lib/redispub/publisher_test.go @@ -7,7 +7,7 @@ import ( "time" "github.com/alicebob/miniredis" - "github.com/go-redis/redis/v7" + "github.com/go-redis/redis/v8" "go.mongodb.org/mongo-driver/bson/primitive" ) @@ -17,9 +17,9 @@ import ( func TestPublishSingleMessageWithRetriesImmediateSuccess(t *testing.T) { publication := &Publication{ - Channels: []string{"a", "b"}, - Msg: []byte("asdf"), - OplogTimestamp: primitive.Timestamp{}, + Channels: []string{"a", "b"}, + Msg: []byte("asdf"), + OplogTimestamp: primitive.Timestamp{}, } callCount := 0 @@ -46,9 +46,9 @@ func TestPublishSingleMessageWithRetriesImmediateSuccess(t *testing.T) { func TestPublishSingleMessageWithRetriesTransientFailure(t *testing.T) { publication := &Publication{ - Channels: []string{"a", "b"}, - Msg: []byte("asdf"), - OplogTimestamp: primitive.Timestamp{}, + Channels: []string{"a", "b"}, + Msg: []byte("asdf"), + OplogTimestamp: primitive.Timestamp{}, } callCount := 0 @@ -76,9 +76,9 @@ func TestPublishSingleMessageWithRetriesTransientFailure(t *testing.T) { func TestPublishSingleMessageWithRetriesPermanentFailure(t *testing.T) { publication := &Publication{ - Channels: []string{"a", "b"}, - Msg: []byte("asdf"), - OplogTimestamp: primitive.Timestamp{}, + Channels: []string{"a", "b"}, + Msg: []byte("asdf"), + OplogTimestamp: primitive.Timestamp{}, } publishFn := func(p *Publication) error { diff --git a/main.go b/main.go index 8427756a..471cc4ed 100644 --- a/main.go +++ b/main.go @@ -4,6 +4,7 @@ import ( "context" "crypto/tls" "encoding/json" + stdlog "log" "net/http" "os" "os/signal" @@ -18,7 +19,7 @@ import ( "github.com/tulip/oplogtoredis/lib/oplog" "github.com/tulip/oplogtoredis/lib/redispub" - "github.com/go-redis/redis/v7" + "github.com/go-redis/redis/v8" "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus/promhttp" "go.uber.org/zap" @@ -162,6 +163,14 @@ func createMongoClient() (*mongo.Client, error) { return client, nil } +type redisLogger struct { + log *stdlog.Logger +} + +func (l redisLogger) Printf(ctx context.Context, format string, v ...interface{}) { + l.log.Printf(format, v...) +} + // Goroutine that just reads messages and sends them to Redis. We don't do this // inline above so that messages can queue up in the channel if we lose our // redis connection @@ -172,7 +181,7 @@ func createRedisClient() (redis.UniversalClient, error) { return nil, errors.Wrap(err, "creating std logger") } - redis.SetLogger(stdLog) + redis.SetLogger(redisLogger{log: stdLog}) // Parse the Redis URL parsedRedisURL, err := redis.ParseURL(config.RedisURL()) @@ -198,7 +207,7 @@ func createRedisClient() (redis.UniversalClient, error) { client := redis.NewUniversalClient(&clientOptions) // Check that we have a connection - _, err = client.Ping().Result() + _, err = client.Ping(context.Background()).Result() if err != nil { return nil, errors.Wrap(err, "pinging redis") } @@ -210,7 +219,7 @@ func makeHTTPServer(redis redis.UniversalClient, mongo *mongo.Client) *http.Serv mux := http.NewServeMux() mux.HandleFunc("/healthz", func(w http.ResponseWriter, r *http.Request) { - redisErr := redis.Ping().Err() + redisErr := redis.Ping(r.Context()).Err() redisOK := redisErr == nil if !redisOK { log.Log.Errorw("Error connecting to Redis during healthz check", diff --git a/scripts/install-debian-mongo.sh b/scripts/install-debian-mongo.sh index 8b50238d..2d5f694a 100755 --- a/scripts/install-debian-mongo.sh +++ b/scripts/install-debian-mongo.sh @@ -6,5 +6,7 @@ wget -qO - https://pgp.mongodb.com/server-5.0.asc | gpg -o /usr/share/keyrings/m echo "deb [ signed-by=/usr/share/keyrings/mongodb-server-5.0.gpg ] https://repo.mongodb.org/apt/debian buster/mongodb-org/5.0 main" > /etc/apt/sources.list.d/mongodb-org-5.0.list apt-get update -apt-get install -y mongodb-org-server mongodb-org-shell +apt-get install -y mongodb-org-server=5.0.19 mongodb-org-shell=5.0.19 +echo "mongodb-org-server hold" | dpkg --set-selections +echo "mongodb-org-shell hold" | dpkg --set-selections diff --git a/scripts/runIntegrationFaultInjection.sh b/scripts/runIntegrationFaultInjection.sh index e19c9548..a1eea34b 100755 --- a/scripts/runIntegrationFaultInjection.sh +++ b/scripts/runIntegrationFaultInjection.sh @@ -5,5 +5,7 @@ cd `dirname "$0"`'/..' docker build --platform=linux/amd64 . -f Dockerfile -t local-oplogtoredis docker build --platform=linux/amd64 . -f Dockerfile.integration -t oltr-integration + +# based image: redis, copies from local-oplogtoredis and oltr-integration docker build --platform=linux/amd64 . -f integration-tests/fault-injection/Dockerfile -t oplogtoredis-fault-injection -docker run --rm -e TERM=xterm oplogtoredis-fault-injection +docker run --platform=linux/amd64 -e TERM=xterm oplogtoredis-fault-injection From 2cec5c87ab6a254049d391ce99cca9bbc26ef60f Mon Sep 17 00:00:00 2001 From: Adam Tajti Date: Mon, 25 Sep 2023 17:26:06 +0200 Subject: [PATCH 02/16] enable the pull request build-and-push again --- .github/workflows/build-and-push.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-and-push.yml b/.github/workflows/build-and-push.yml index bd537f04..6bdaf70c 100644 --- a/.github/workflows/build-and-push.yml +++ b/.github/workflows/build-and-push.yml @@ -7,8 +7,8 @@ on: branches: - master # Left this here in-case the workflow needs to be developed further rapidly: - # pull_request: - # types: [ opened, synchronize, reopened ] + pull_request: + types: [ opened, synchronize, reopened ] workflow_dispatch: From b672efd9bbb0eb9931d42f42131cea02381d1021 Mon Sep 17 00:00:00 2001 From: Adam Tajti Date: Mon, 25 Sep 2023 18:09:42 +0200 Subject: [PATCH 03/16] bump versions, fix registry-type inputs typo --- .github/actions/setup-ecr-buildx/action.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/actions/setup-ecr-buildx/action.yml b/.github/actions/setup-ecr-buildx/action.yml index c170178e..6035062b 100644 --- a/.github/actions/setup-ecr-buildx/action.yml +++ b/.github/actions/setup-ecr-buildx/action.yml @@ -18,7 +18,7 @@ runs: using: "composite" steps: - name: Configure AWS Credentials - uses: aws-actions/configure-aws-credentials@v2 + uses: aws-actions/configure-aws-credentials@v4 with: role-to-assume: ${{ inputs.role-to-assume }} role-session-name: github-action-session @@ -28,7 +28,7 @@ runs: id: login-ecr uses: aws-actions/amazon-ecr-login@v1 with: - registry-type: ${{ inputs.registry_type }} + registry-type: ${{ inputs.registry-type }} - name: Set up Docker Buildx uses: docker/setup-buildx-action@ecf95283f03858871ff00b787d79c419715afc34 # v2.7.0 From 7002f49410748a1fdf3ad5645db498daafdd6c38 Mon Sep 17 00:00:00 2001 From: Adam Tajti Date: Mon, 25 Sep 2023 18:13:12 +0200 Subject: [PATCH 04/16] fix tag for public ecr --- .github/workflows/build-and-push.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-and-push.yml b/.github/workflows/build-and-push.yml index 6bdaf70c..7cabdd66 100644 --- a/.github/workflows/build-and-push.yml +++ b/.github/workflows/build-and-push.yml @@ -63,6 +63,6 @@ jobs: - name: Build and push image uses: docker/build-push-action@3b5e8027fcad23fda98b2e3ac259d8d67585f671 # 4.0.0 with: - tags: ${{ steps.setup-ecr-buildx.outputs.ecr_registry }}/ecr-public/docker/tulip/oplogtoredis:${{ steps.generate-tag.outputs.TAG }} + tags: ${{ steps.setup-ecr-buildx.outputs.ecr_registry }}/tulip/oplogtoredis:${{ steps.generate-tag.outputs.TAG }} provenance: false push: true From ba96ded455ca0b32d9680e2faf0af4ad41a438b7 Mon Sep 17 00:00:00 2001 From: Adam Tajti Date: Wed, 27 Sep 2023 15:06:45 +0200 Subject: [PATCH 05/16] comment out the pr trigger again for now --- .github/workflows/build-and-push.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-and-push.yml b/.github/workflows/build-and-push.yml index 7cabdd66..7ee46d72 100644 --- a/.github/workflows/build-and-push.yml +++ b/.github/workflows/build-and-push.yml @@ -7,8 +7,8 @@ on: branches: - master # Left this here in-case the workflow needs to be developed further rapidly: - pull_request: - types: [ opened, synchronize, reopened ] + # pull_request: + # types: [ opened, synchronize, reopened ] workflow_dispatch: From 19b407967e8d80bc85610754aeace1586c04ac78 Mon Sep 17 00:00:00 2001 From: Adam Tajti Date: Fri, 29 Sep 2023 19:12:36 +0200 Subject: [PATCH 06/16] implementing review suggestions from elsewhere --- .github/actions/setup-ecr-buildx/action.yml | 6 +++--- .github/workflows/build-and-push.yml | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/actions/setup-ecr-buildx/action.yml b/.github/actions/setup-ecr-buildx/action.yml index 6035062b..e00082d2 100644 --- a/.github/actions/setup-ecr-buildx/action.yml +++ b/.github/actions/setup-ecr-buildx/action.yml @@ -5,8 +5,8 @@ inputs: registry-type: description: ECR Registry Type default: private - role-to-assume: - description: ECR Role to Assume + iam-role-to-assume: + description: IAM Role to Assume required: true outputs: @@ -20,7 +20,7 @@ runs: - name: Configure AWS Credentials uses: aws-actions/configure-aws-credentials@v4 with: - role-to-assume: ${{ inputs.role-to-assume }} + role-to-assume: ${{ inputs.iam-role-to-assume }} role-session-name: github-action-session aws-region: us-east-1 diff --git a/.github/workflows/build-and-push.yml b/.github/workflows/build-and-push.yml index 7ee46d72..c968da8b 100644 --- a/.github/workflows/build-and-push.yml +++ b/.github/workflows/build-and-push.yml @@ -57,7 +57,7 @@ jobs: uses: ./.github/actions/setup-ecr-buildx id: setup-ecr-buildx with: - role-to-assume: ${{ secrets.AWS_PUBLIC_ECR_ROLE_ARN }} + iam-role-to-assume: ${{ secrets.AWS_PUBLIC_PUBLIC_ECR_ROLE_ARN }} registry-type: public - name: Build and push image From dfe4d8424447eb4c07868e6f7a7f80a25947a7c3 Mon Sep 17 00:00:00 2001 From: Adam Tajti Date: Fri, 29 Sep 2023 19:18:10 +0200 Subject: [PATCH 07/16] ops --- .github/workflows/build-and-push.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-and-push.yml b/.github/workflows/build-and-push.yml index c968da8b..b320222b 100644 --- a/.github/workflows/build-and-push.yml +++ b/.github/workflows/build-and-push.yml @@ -57,7 +57,7 @@ jobs: uses: ./.github/actions/setup-ecr-buildx id: setup-ecr-buildx with: - iam-role-to-assume: ${{ secrets.AWS_PUBLIC_PUBLIC_ECR_ROLE_ARN }} + iam-role-to-assume: ${{ secrets.AWS_PUBLIC_ECR_IAM_ROLE_ARN }} registry-type: public - name: Build and push image From 33a35a06d2131fe5bee57b15fc64281e45b0c4a3 Mon Sep 17 00:00:00 2001 From: Adam Tajti Date: Fri, 6 Oct 2023 08:01:50 +0200 Subject: [PATCH 08/16] pin versions --- .github/workflows/build-and-push.yml | 4 ++-- .github/workflows/pull-request.yml | 16 ++++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/.github/workflows/build-and-push.yml b/.github/workflows/build-and-push.yml index b320222b..9e2cff51 100644 --- a/.github/workflows/build-and-push.yml +++ b/.github/workflows/build-and-push.yml @@ -26,9 +26,9 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 - - uses: cachix/install-nix-action@v22 + - uses: cachix/install-nix-action@6ed004b9ccb68dbc28e7c85bee15fa93dbd214ac with: nix_path: nixpkgs=channel:nixos-unstable diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index 953898a3..01f406d4 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -7,12 +7,12 @@ jobs: runs-on: ubuntu-20.04 timeout-minutes: 60 steps: - - uses: actions/checkout@v2 - - uses: actions/setup-go@v4 + - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 + - uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe with: go-version: '1.17' - name: golangci-lint - uses: golangci/golangci-lint-action@v3 + uses: golangci/golangci-lint-action@3a919529898de77ec3da873e3063ca4b10e7f5cc with: version: v1.42 - name: run lint @@ -23,34 +23,34 @@ jobs: runs-on: ubuntu-20.04 timeout-minutes: 60 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 - name: run acceptance tests run: ./scripts/runIntegrationAcceptance.sh performance: runs-on: ubuntu-20.04 timeout-minutes: 60 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 - name: run performance tests run: ./scripts/runIntegrationPerformance.sh fault_injection: runs-on: ubuntu-20.04 timeout-minutes: 60 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 - name: run fault injection tests run: ./scripts/runIntegrationFaultInjection.sh meteor: runs-on: ubuntu-20.04 timeout-minutes: 60 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 - name: run meteor tests run: ./scripts/runIntegrationMeteor.sh blackbox: runs-on: ubuntu-20.04 timeout-minutes: 60 steps: - - uses: actions/checkout@v2 + - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 - name: run blackbox tests run: ./scripts/runBlackboxTests.sh From 0afa173f68f80dbeea57aec0ffa5b28920dd698b Mon Sep 17 00:00:00 2001 From: Adam Tajti Date: Tue, 10 Oct 2023 20:11:35 +0200 Subject: [PATCH 09/16] missing vendorHash update, documented the process on how to update it --- README.md | 13 +++++++++++++ default.nix | 15 +++++++++++++-- flake.lock | 6 +++--- 3 files changed, 29 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 6b775a97..b3deb529 100644 --- a/README.md +++ b/README.md @@ -23,6 +23,19 @@ There are a few things that don't currently work in `redis-oplog` when using the - Custom namespaces and channels ([`redis-oplog` issue #279](https://github.com/cult-of-coders/redis-oplog/issues/279)) - Synthetic mutations ([`redis-oplog` issue #277](https://github.com/cult-of-coders/redis-oplog/issues/277)) +## Nix + +We are using Nix at Tulip so we're rolling a `default.nix` and a `flake.nix` wrapper around it for Flake support. The `default.nix` file contains a `vendorHash` attribute, which would be the calculated hash of the downloaded modules to be vendored. To update this value after a `go.sum` file change (which means that different modules were downloaded), refer to the following snippet: + +```bash +# TODO: default.nix: Change the `vendorHash` property to an empty string and run `nix build`. +nix build +# ... +# error: hash mismatch in fixed-output derivation '/nix/store/by8bc99ywfw6j1i6zjxcwdmc5b3mmgzv-oplogtoredis-3.0.0-go-modules.drv': +# specified: sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= +# got: sha256-ceToA2DC1bhmg9WIeNSAfoNoU7sk9PrQqgqt5UbpivQ= +``` + ### MongoDB v5 MongoDB v5 makes a substantial change to the format of the oplog, which makes it much more difficult to assemble the list of changed fields from an oplog entry. Meteor has handled this with a full [oplog v2 to v1 converter](https://github.com/meteor/meteor/blob/devel/packages/mongo/oplog_v2_converter.js), which entails substantial complexity and a high level of dependence on the (undocumented) oplog format, and requires testing against every new version of Mongo. To reduce this maintenance burden, oplogtoredis implements a simplified version of this algorithm that just extracts changed top-level fields. diff --git a/default.nix b/default.nix index 462f2959..a1d735a6 100644 --- a/default.nix +++ b/default.nix @@ -1,14 +1,25 @@ { lib, stdenv, buildGoModule, fetchFromGitHub, installShellFiles }: + buildGoModule { pname = "oplogtoredis"; version = "3.0.0"; - src = builtins.path { path = ./.; }; - vendorSha256 = "sha256-VHiYVJUNtHN2IY4iXZ6kHAa3Avi2VwRH1ySKBrrCDu4="; postInstall = '' ''; + + # update: set value to an empty string and run `nix build`. This will download Go, fetch the dependencies and calculates their hash. + vendorHash = "sha256-ceToA2DC1bhmg9WIeNSAfoNoU7sk9PrQqgqt5UbpivQ="; + nativeBuildInputs = [ installShellFiles ]; doCheck = false; doInstallCheck = false; + + meta = with lib; { + description = '' + This program tails the oplog of a Mongo server, and publishes changes to Redis. + It's designed to work with the redis-oplog Meteor package''; + homepage = "https://github.com/tulip/oplogtoredis"; + license = licenses.mit; + }; } diff --git a/flake.lock b/flake.lock index 4b9ffde9..e9ed62bb 100644 --- a/flake.lock +++ b/flake.lock @@ -2,11 +2,11 @@ "nodes": { "nixpkgs": { "locked": { - "lastModified": 1670955002, - "narHash": "sha256-x2c/du9ba+S1EhNzjntOPNcnHsS3ym1JIEXsk6VtxM0=", + "lastModified": 1696748797, + "narHash": "sha256-pbZyaPq4A/bMNA+cXqEBZ7dbd8L6oeUQkZjFlgNFUyM=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "28c1f459e8b1b06420bfaa2f59c4638b40750b5c", + "rev": "546637df9d1832176640b959b9f5562ea4b474c2", "type": "github" }, "original": { From 2e8b84f3dd0b858c35451aedb8a267f3542f9075 Mon Sep 17 00:00:00 2001 From: Adam Tajti Date: Tue, 10 Oct 2023 20:22:14 +0200 Subject: [PATCH 10/16] modify the pull request workflow to do a nix build as well, which verifies that the vendorHash has been properly updated. --- .github/workflows/pull-request.yml | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index 01f406d4..b26687c5 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -3,6 +3,19 @@ name: Pull Request on: [ pull_request ] jobs: + nix_build: + runs-on: ubuntu-20.04 + timeout-minutes: 60 + steps: + - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 + - uses: actions/setup-go@93397bea11091df50f3d7e59dc26a7711a8bcfbe + with: + go-version: '1.17' + - uses: cachix/install-nix-action@6ed004b9ccb68dbc28e7c85bee15fa93dbd214ac + with: + nix_path: nixpkgs=channel:nixos-unstable + - name: run nix build + run: nix build lint_and_units: runs-on: ubuntu-20.04 timeout-minutes: 60 From a0a04c6a1e184dbfdc8ef48dfcdd3c48fdfcd304 Mon Sep 17 00:00:00 2001 From: Adam Tajti Date: Wed, 11 Oct 2023 18:07:27 +0200 Subject: [PATCH 11/16] test read permissions for access-id --- .github/workflows/build-and-push.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/build-and-push.yml b/.github/workflows/build-and-push.yml index 9e2cff51..d8dfc505 100644 --- a/.github/workflows/build-and-push.yml +++ b/.github/workflows/build-and-push.yml @@ -7,8 +7,8 @@ on: branches: - master # Left this here in-case the workflow needs to be developed further rapidly: - # pull_request: - # types: [ opened, synchronize, reopened ] + pull_request: + types: [ opened, synchronize, reopened ] workflow_dispatch: @@ -17,8 +17,8 @@ concurrency: cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} permissions: - id-token: write # for the creds itself - contents: read # for checkout + id-token: read + contents: read jobs: build-and-push: From 16926f3f83313495b1debf9619f6f9bee8723efd Mon Sep 17 00:00:00 2001 From: Adam Tajti Date: Wed, 11 Oct 2023 18:16:57 +0200 Subject: [PATCH 12/16] run nix-build on ubuntu-latest --- .github/workflows/pull-request.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/pull-request.yml b/.github/workflows/pull-request.yml index b26687c5..067a3f64 100644 --- a/.github/workflows/pull-request.yml +++ b/.github/workflows/pull-request.yml @@ -4,7 +4,7 @@ on: [ pull_request ] jobs: nix_build: - runs-on: ubuntu-20.04 + runs-on: ubuntu-latest timeout-minutes: 60 steps: - uses: actions/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 From 63571c8d581d50bd32fbe0614e1e83f35c835120 Mon Sep 17 00:00:00 2001 From: Adam Tajti Date: Wed, 11 Oct 2023 18:17:32 +0200 Subject: [PATCH 13/16] provenance: true --- .github/workflows/build-and-push.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-and-push.yml b/.github/workflows/build-and-push.yml index d8dfc505..a930d275 100644 --- a/.github/workflows/build-and-push.yml +++ b/.github/workflows/build-and-push.yml @@ -64,5 +64,5 @@ jobs: uses: docker/build-push-action@3b5e8027fcad23fda98b2e3ac259d8d67585f671 # 4.0.0 with: tags: ${{ steps.setup-ecr-buildx.outputs.ecr_registry }}/tulip/oplogtoredis:${{ steps.generate-tag.outputs.TAG }} - provenance: false + provenance: true push: true From 40acf515d57bb6d6d868d2e173f36be49c9a5161 Mon Sep 17 00:00:00 2001 From: Adam Tajti Date: Wed, 11 Oct 2023 18:20:48 +0200 Subject: [PATCH 14/16] readme: gallery.ecr.aws/tulip --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index b3deb529..2fc15707 100644 --- a/README.md +++ b/README.md @@ -73,7 +73,7 @@ you might use this config: ## Deploying oplogtoredis -You can build oplogtoredis from source with `go build .`, which produces a statically-linked binary you can run. Alternatively, you can use [the public docker image](https://gallery.ecr.aws/u4f7y3k8/oplogtoredis). Previously we used to host these images in [Docker Hub](https://hub.docker.com/r/tulip/oplogtoredis/tags/). These won't be maintained anymore. +You can build oplogtoredis from source with `go build .`, which produces a statically-linked binary you can run. Alternatively, you can use [the public docker image](https://gallery.ecr.aws/tulip/oplogtoredis). Previously we used to host these images in [Docker Hub](https://hub.docker.com/r/tulip/oplogtoredis/tags/). These won't be maintained anymore. ### Environment Variables From 78f00f565dc31cf7a06c059d1b6cc893df161a18 Mon Sep 17 00:00:00 2001 From: Adam Tajti Date: Wed, 11 Oct 2023 18:26:38 +0200 Subject: [PATCH 15/16] readme: restructure the version bump and vendorHash update instructions --- README.md | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/README.md b/README.md index 2fc15707..c57e0ccf 100644 --- a/README.md +++ b/README.md @@ -25,16 +25,17 @@ There are a few things that don't currently work in `redis-oplog` when using the ## Nix -We are using Nix at Tulip so we're rolling a `default.nix` and a `flake.nix` wrapper around it for Flake support. The `default.nix` file contains a `vendorHash` attribute, which would be the calculated hash of the downloaded modules to be vendored. To update this value after a `go.sum` file change (which means that different modules were downloaded), refer to the following snippet: - -```bash -# TODO: default.nix: Change the `vendorHash` property to an empty string and run `nix build`. -nix build -# ... -# error: hash mismatch in fixed-output derivation '/nix/store/by8bc99ywfw6j1i6zjxcwdmc5b3mmgzv-oplogtoredis-3.0.0-go-modules.drv': -# specified: sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= -# got: sha256-ceToA2DC1bhmg9WIeNSAfoNoU7sk9PrQqgqt5UbpivQ= -``` +We are using Nix at Tulip so we're rolling a `default.nix` and a `flake.nix` wrapper around it for Flake support. The `default.nix` file contains a `vendorHash` attribute, which would be the calculated hash of the downloaded modules to be vendored. To update this value after a `go.sum` file change (which means that different modules were downloaded), refer to the following instructions: + +1. Edit `default.nix` and change the `vendorHash` attribute to an empty string then run `nix build` +1. Run `nix build` and observe the output. You are looking for this section: + + ```text + error: hash mismatch in fixed-output derivation '/nix/store/by8bc99ywfw6j1i6zjxcwdmc5b3mmgzv-oplogtoredis-3.0.0-go-modules.drv': + specified: sha256-AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA= + got: sha256-ceToA2DC1bhmg9WIeNSAfoNoU7sk9PrQqgqt5UbpivQ= + ``` +1. Use the `sha256-ceToA2DC1bhmg9WIeNSAfoNoU7sk9PrQqgqt5UbpivQ=` for the value of `vendorHash` and verify that `nix build` succeeds. ### MongoDB v5 From 5e01112f7d62be02223e5ee354818648008e9757 Mon Sep 17 00:00:00 2001 From: Adam Tajti Date: Sat, 14 Oct 2023 06:16:38 +0200 Subject: [PATCH 16/16] Update build-and-push.yml --- .github/workflows/build-and-push.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-and-push.yml b/.github/workflows/build-and-push.yml index a930d275..d79beb1e 100644 --- a/.github/workflows/build-and-push.yml +++ b/.github/workflows/build-and-push.yml @@ -17,7 +17,7 @@ concurrency: cancel-in-progress: ${{ github.ref != 'refs/heads/master' }} permissions: - id-token: read + id-token: write contents: read jobs: