diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 2fccaad8..41d86f06 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -3,8 +3,18 @@ updates: - package-ecosystem: gomod directory: / schedule: - interval: daily + interval: "monthly" + groups: + dev-dependencies: + applies-to: version-updates + patterns: + - "*" - package-ecosystem: github-actions directory: / schedule: - interval: daily + interval: "monthly" + groups: + actions-dependencies: + applies-to: version-updates + patterns: + - "*" diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 00000000..71124ddf --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,36 @@ +name: CodeQL + +on: + push: + branches: [ master ] + pull_request: + branches: [ master ] + schedule: + - cron: '30 06 * * 6' + +env: + GO_VERSION: 1.22.1 + +jobs: + analyze: + runs-on: ubuntu-latest + permissions: + security-events: write + steps: + - name: Check out code into the Go module directory + uses: actions/checkout@v4 + - name: Set up Go 1.x + uses: actions/setup-go@v5 + with: + go-version: ${{ env.GO_VERSION }} + - name: Initialize CodeQL + uses: github/codeql-action/init@v3 + with: + languages: go + build-mode: manual + - name: Build + run: go build -tags netgo,osusergo -o ./cmd/mysync/mysync ./cmd/mysync/... + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@v3 + with: + category: "/language:go" diff --git a/.github/workflows/golangci-lint.yml b/.github/workflows/golangci-lint.yml index 27762597..08a84817 100644 --- a/.github/workflows/golangci-lint.yml +++ b/.github/workflows/golangci-lint.yml @@ -19,6 +19,6 @@ jobs: go-version: 1.21.3 - uses: actions/checkout@v4 - name: golangci-lint - uses: golangci/golangci-lint-action@v4 + uses: golangci/golangci-lint-action@v5 with: version: latest diff --git a/Makefile b/Makefile index 606b6e49..09fbe342 100644 --- a/Makefile +++ b/Makefile @@ -33,7 +33,7 @@ jepsen_test: GOOS=linux go build -tags netgo,osusergo -o ./cmd/mysync/mysync ./cmd/mysync/... go build ./tests/... rm -fr ./tests/images/mysql_jepsen/mysync && cp ./cmd/mysync/mysync ./tests/images/mysql_jepsen/mysync - docker-compose -p mysync -f ./tests/images/jepsen-compose.yml up -d --force-recreate --build + docker compose -p mysync -f ./tests/images/jepsen-compose.yml up -d --force-recreate --build timeout 600 docker exec mysync_zoo1_1 /usr/local/bin/generate_certs_with_restart.sh mysync_zookeeper1_1.mysync_mysql_net timeout 600 docker exec mysync_zoo2_1 /usr/local/bin/generate_certs_with_restart.sh mysync_zookeeper2_1.mysync_mysql_net timeout 600 docker exec mysync_zoo3_1 /usr/local/bin/generate_certs_with_restart.sh mysync_zookeeper3_1.mysync_mysql_net @@ -48,7 +48,7 @@ jepsen_test: timeout 600 docker exec mysync_mysql1_1 setup.sh mkdir -p ./tests/logs (docker exec mysync_jepsen_1 /root/jepsen/run.sh > ./tests/logs/jepsen.log 2>&1 && tail -n 4 ./tests/logs/jepsen.log) || ./tests/images/jepsen_main/save_logs.sh - docker-compose -p mysync -f ./tests/images/jepsen-compose.yml down --rmi all + docker compose -p mysync -f ./tests/images/jepsen-compose.yml down --rmi all clean: docker ps | grep mysync | awk '{print $$1}' | xargs docker rm -f || true diff --git a/go.mod b/go.mod index 4f1fccf8..374fe81a 100644 --- a/go.mod +++ b/go.mod @@ -3,25 +3,27 @@ module github.com/yandex/mysync go 1.21 require ( - github.com/cenkalti/backoff/v4 v4.2.1 - github.com/cucumber/godog v0.14.0 - github.com/docker/docker v25.0.3+incompatible + github.com/cenkalti/backoff/v4 v4.3.0 + github.com/cucumber/godog v0.14.1 + github.com/docker/docker v26.1.1+incompatible github.com/go-mysql-org/go-mysql v1.7.0 - github.com/go-sql-driver/mysql v1.7.1 + github.com/go-sql-driver/mysql v1.8.1 github.com/go-zookeeper/zk v1.0.3 github.com/gofrs/flock v0.8.1 github.com/gofrs/uuid v4.4.0+incompatible github.com/golang/mock v1.6.0 + github.com/google/uuid v1.6.0 github.com/heetch/confita v0.10.0 - github.com/jmoiron/sqlx v1.3.5 - github.com/shirou/gopsutil/v3 v3.24.1 + github.com/jmoiron/sqlx v1.4.0 + github.com/shirou/gopsutil/v3 v3.24.3 github.com/spf13/cobra v1.8.0 github.com/spf13/pflag v1.0.5 - github.com/stretchr/testify v1.8.4 + github.com/stretchr/testify v1.9.0 gopkg.in/yaml.v2 v2.4.0 ) require ( + filippo.io/edwards25519 v1.1.0 // indirect github.com/BurntSushi/toml v1.3.2 // indirect github.com/Microsoft/go-winio v0.6.1 // indirect github.com/containerd/log v0.1.0 // indirect @@ -36,12 +38,12 @@ require ( github.com/go-logr/stdr v1.2.2 // indirect github.com/go-ole/go-ole v1.3.0 // indirect github.com/gogo/protobuf v1.3.2 // indirect - github.com/google/uuid v1.5.0 // indirect github.com/hashicorp/go-immutable-radix v1.3.1 // indirect github.com/hashicorp/go-memdb v1.3.4 // indirect github.com/hashicorp/golang-lru v0.5.4 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/lufia/plan9stats v0.0.0-20231016141302-07b5767bb0ed // indirect + github.com/moby/docker-image-spec v1.3.1 // indirect github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae // indirect github.com/morikuni/aec v1.0.0 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect @@ -55,7 +57,7 @@ require ( github.com/siddontang/go-log v0.0.0-20190221022429-1e957dd83bed // indirect github.com/tklauser/go-sysconf v0.3.13 // indirect github.com/tklauser/numcpus v0.7.0 // indirect - github.com/yusufpapurcu/wmi v1.2.3 // indirect + github.com/yusufpapurcu/wmi v1.2.4 // indirect go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0 // indirect go.opentelemetry.io/otel v1.22.0 // indirect go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.22.0 // indirect @@ -64,7 +66,7 @@ require ( go.opentelemetry.io/otel/trace v1.22.0 // indirect go.uber.org/atomic v1.11.0 // indirect golang.org/x/mod v0.14.0 // indirect - golang.org/x/sys v0.16.0 // indirect + golang.org/x/sys v0.18.0 // indirect golang.org/x/text v0.14.0 // indirect golang.org/x/tools v0.17.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect diff --git a/go.sum b/go.sum index 53cbfec2..952da198 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,6 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +filippo.io/edwards25519 v1.1.0 h1:FNf4tywRC1HmFuKW5xopWpigGjJKiJSV0Cqo0cJWDaA= +filippo.io/edwards25519 v1.1.0/go.mod h1:BxyFTGdWcka3PhytdK4V28tE5sGfRvvvRV7EaN4VDT4= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1 h1:UQHMgLO+TxOElx5B5HZ4hJQsoJ/PvUvKRhJHDQXO8P8= github.com/Azure/go-ansiterm v0.0.0-20210617225240-d185dfc1b5a1/go.mod h1:xomTg63KZ2rFqZQzSB4Vz2SUXa1BpHTVz9L5PTmPC4E= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= @@ -17,8 +19,8 @@ github.com/aws/aws-sdk-go v1.23.20/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpi github.com/benbjohnson/clock v1.1.0/go.mod h1:J11/hYXuz8f4ySSvYwY0FKfm+ezbsZBKZxNJlLklBHA= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs= -github.com/cenkalti/backoff/v4 v4.2.1 h1:y4OZtCnogmCPw98Zjyt5a6+QwPLGkiQsYW5oUqylYbM= -github.com/cenkalti/backoff/v4 v4.2.1/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= +github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= +github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= github.com/circonus-labs/circonus-gometrics v2.3.1+incompatible/go.mod h1:nmEj6Dob7S7YxXgwXpfOuvO54S+tGdZdw9fuRZt25Ag= github.com/circonus-labs/circonusllhist v0.1.3/go.mod h1:kMXHVDlOchFAehlya5ePtbp5jckzBHf4XRpQvBOLI+I= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= @@ -34,8 +36,8 @@ github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46t github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/cucumber/gherkin/go/v26 v26.2.0 h1:EgIjePLWiPeslwIWmNQ3XHcypPsWAHoMCz/YEBKP4GI= github.com/cucumber/gherkin/go/v26 v26.2.0/go.mod h1:t2GAPnB8maCT4lkHL99BDCVNzCh1d7dBhCLt150Nr/0= -github.com/cucumber/godog v0.14.0 h1:h/K4t7XBxsFBF+UJEahNqJ1/2VHVepRXCSq3WWWnehs= -github.com/cucumber/godog v0.14.0/go.mod h1:FX3rzIDybWABU4kuIXLZ/qtqEe1Ac5RdXmqvACJOces= +github.com/cucumber/godog v0.14.1 h1:HGZhcOyyfaKclHjJ+r/q93iaTJZLKYW6Tv3HkmUE6+M= +github.com/cucumber/godog v0.14.1/go.mod h1:FX3rzIDybWABU4kuIXLZ/qtqEe1Ac5RdXmqvACJOces= github.com/cucumber/messages/go/v21 v21.0.1 h1:wzA0LxwjlWQYZd32VTlAVDTkW6inOFmSM+RuOwHZiMI= github.com/cucumber/messages/go/v21 v21.0.1/go.mod h1:zheH/2HS9JLVFukdrsPWoPdmUtmYQAQPLk7w5vWsk5s= github.com/cucumber/messages/go/v22 v22.0.0/go.mod h1:aZipXTKc0JnjCsXrJnuZpWhtay93k7Rn3Dee7iyPJjs= @@ -48,8 +50,8 @@ github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSs github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= github.com/distribution/reference v0.5.0 h1:/FUIFXtfc/x2gpa5/VGfiGLuOIdYa1t65IKK2OFGvA0= github.com/distribution/reference v0.5.0/go.mod h1:BbU0aIcezP1/5jX/8MP0YiH4SdvB5Y4f/wlDRiLyi3E= -github.com/docker/docker v25.0.3+incompatible h1:D5fy/lYmY7bvZa0XTZ5/UJPljor41F+vdyJG5luQLfQ= -github.com/docker/docker v25.0.3+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker v26.1.1+incompatible h1:oI+4kkAgIwwb54b9OC7Xc3hSgu1RlJA/Lln/DF72djQ= +github.com/docker/docker v26.1.1+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= github.com/docker/go-connections v0.5.0 h1:USnMq7hx7gwdVZq1L49hLXaFtUdTADjXGp+uj1Br63c= github.com/docker/go-connections v0.5.0/go.mod h1:ov60Kzw0kKElRwhNs9UlUHAE/F9Fe6GLaXnqyDdmEXc= github.com/docker/go-units v0.5.0 h1:69rxXcBk27SvSaaxTtLh/8llcHD8vYHT7WSdRZ/jvr4= @@ -75,8 +77,8 @@ github.com/go-ole/go-ole v1.3.0 h1:Dt6ye7+vXGIKZ7Xtk4s6/xVdGDQynvom7xCFEdWr6uE= github.com/go-ole/go-ole v1.3.0/go.mod h1:5LS6F96DhAwUc7C+1HLexzMXY1xGRSryjyPPKW6zv78= github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-sql-driver/mysql v1.6.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= -github.com/go-sql-driver/mysql v1.7.1 h1:lUIinVbN1DY0xBg0eMOzmmtGoHwWBbvnWubQUrtU8EI= -github.com/go-sql-driver/mysql v1.7.1/go.mod h1:OXbVy3sEdcQ2Doequ6Z5BW6fXNQTmx+9S1MCJN5yJMI= +github.com/go-sql-driver/mysql v1.8.1 h1:LedoTUt/eveggdHS9qUFC1EFSa8bU2+1pZjSRpvNJ1Y= +github.com/go-sql-driver/mysql v1.8.1/go.mod h1:wEBSXgmK//2ZFJyE+qWnIsVGmvmEKlqwuVSjsCm7DZg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/go-test/deep v1.0.2-0.20181118220953-042da051cf31/go.mod h1:wGDj63lr65AM2AQyKZd/NYHGb0R+1RLqB8NKt3aSFNA= github.com/go-zookeeper/zk v1.0.3 h1:7M2kwOsc//9VeeFiPtf+uSJlVpU66x9Ba5+8XK7/TDg= @@ -112,8 +114,8 @@ github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeN github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/google/uuid v1.5.0 h1:1p67kYwdtXjb0gL0BPiP1Av9wiZPo5A8z2cWkTZ+eyU= -github.com/google/uuid v1.5.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= +github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= +github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/websocket v1.4.0/go.mod h1:E7qHFY5m1UJ88s3WnNqhKjPHQ0heANvMoAMk2YaljkQ= github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk= github.com/grpc-ecosystem/grpc-gateway v1.8.6 h1:XvND7+MPP7Jp+JpqSZ7naSl5nVZf6k0LbL1V3EKh0zc= @@ -169,8 +171,8 @@ github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2 github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/jmoiron/sqlx v1.3.3/go.mod h1:2BljVx/86SuTyjE+aPYlHCTNvZrnJXghYGpNiXLBMCQ= -github.com/jmoiron/sqlx v1.3.5 h1:vFFPA71p1o5gAeqtEAwLU4dnX2napprKtHr7PYIcN3g= -github.com/jmoiron/sqlx v1.3.5/go.mod h1:nRVWtLre0KfCLJvgxzCsLVMogSvQ1zNJtpYr2Ccp0mQ= +github.com/jmoiron/sqlx v1.4.0 h1:1PLqN7S1UYp5t4SrVVnt4nUVNemrDAtxlulVe+Qgm3o= +github.com/jmoiron/sqlx v1.4.0/go.mod h1:ZrZ7UsYB/weZdl2Bxg6jCRO9c3YHl8r3ahlKmRT4JLY= github.com/jonboulle/clockwork v0.1.0/go.mod h1:Ii8DK3G1RaLaWxj9trq07+26W01tbo22gdxWY5EU2bo= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8= @@ -184,15 +186,17 @@ github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= -github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/lib/pq v1.10.9 h1:YXG7RB+JIjhP29X+OtkiDnYaXQwpS4JEWq7dtCCRUEw= +github.com/lib/pq v1.10.9/go.mod h1:AlVN5x4E4T544tWzH6hKfbfQvm3HdbOxrmggDNAPY9o= github.com/lufia/plan9stats v0.0.0-20211012122336-39d0f177ccd0/go.mod h1:zJYVVT2jmtg6P3p1VtQj7WsuWi/y4VnjVBn7F8KPB3I= github.com/lufia/plan9stats v0.0.0-20231016141302-07b5767bb0ed h1:036IscGBfJsFIgJQzlui7nK1Ncm0tp2ktmPj8xO4N/0= github.com/lufia/plan9stats v0.0.0-20231016141302-07b5767bb0ed/go.mod h1:ilwx/Dta8jXAgpFYFvSWEMwxmbWXyiUHkd5FwyKhb5k= github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= -github.com/mattn/go-sqlite3 v1.14.6 h1:dNPt6NO46WmLVt2DLNpwczCmdV5boIZ6g/tlDrlRUbg= github.com/mattn/go-sqlite3 v1.14.6/go.mod h1:NyWgC/yNuGj7Q9rpYnZvas74GogHl5/Z4A/KQRfk6bU= +github.com/mattn/go-sqlite3 v1.14.22 h1:2gZY6PC6kBnID23Tichd1K+Z0oS6nE/XwU+Vz/5o4kU= +github.com/mattn/go-sqlite3 v1.14.22/go.mod h1:Uh1q+B4BYcTPb+yiD3kU8Ct7aC0hY9fxUwlHK0RXw+Y= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= github.com/mitchellh/cli v1.0.0/go.mod h1:hNIlj7HEI86fIcpObd7a0FcrxTWetlwJDGcceTlRvqc= @@ -207,6 +211,8 @@ github.com/mitchellh/iochan v1.0.0/go.mod h1:JwYml1nuB7xOzsp52dPpHFffvOCDupsG0Qu github.com/mitchellh/mapstructure v0.0.0-20160808181253-ca63d7c062ee/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= +github.com/moby/docker-image-spec v1.3.1 h1:jMKff3w6PgbfSa69GfNg+zN/XLhfXJGnEx3Nl2EsFP0= +github.com/moby/docker-image-spec v1.3.1/go.mod h1:eKmb5VW8vQEh/BAr2yvVNvuiJuY6UIocYsFu/DxxRpo= github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae h1:O4SWKdcHVCvYqyDV+9CJA1fcDN2L11Bule0iFy3YlAI= github.com/moby/term v0.0.0-20220808134915-39b0c02b01ae/go.mod h1:E2VnQOmVuvZB6UYnnDB0qG5Nq/1tD9acaOpo6xmt0Kw= github.com/morikuni/aec v1.0.0 h1:nP9CBfwrvYnBRgY6qfDQkygYDmYwOilePFkwzv4dU8A= @@ -255,8 +261,8 @@ github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb github.com/ryanuber/columnize v2.1.0+incompatible/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts= github.com/ryanuber/go-glob v1.0.0/go.mod h1:807d1WSdnB0XRJzKNil9Om6lcp/3a0v4qIHxIXzX/Yc= github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc= -github.com/shirou/gopsutil/v3 v3.24.1 h1:R3t6ondCEvmARp3wxODhXMTLC/klMa87h2PHUw5m7QI= -github.com/shirou/gopsutil/v3 v3.24.1/go.mod h1:UU7a2MSBQa+kW1uuDq8DeEBS8kmrnQwsv2b5O513rwU= +github.com/shirou/gopsutil/v3 v3.24.3 h1:eoUGJSmdfLzJ3mxIhmOAhgKEKgQkeOwKpz1NbhVnuPE= +github.com/shirou/gopsutil/v3 v3.24.3/go.mod h1:JpND7O217xa72ewWz9zN2eIIkPWsDN/3pl0H8Qt0uwg= github.com/shoenig/go-m1cpu v0.1.6 h1:nxdKQNcEB6vzgA2E2bvzKIYRuNj7XNJ4S/aRSwKzFtM= github.com/shoenig/go-m1cpu v0.1.6/go.mod h1:1JJMcUBvfNwpq05QDQVAnx3gUHr9IYF7GNg9SUEw2VQ= github.com/shoenig/test v0.6.4 h1:kVTaSd7WLz5WZ2IaoM0RSzRsUD+m8wRR+5qvntpn4LU= @@ -281,6 +287,7 @@ github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+ github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA= github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= @@ -289,8 +296,9 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= +github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg= +github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= github.com/tklauser/go-sysconf v0.3.12/go.mod h1:Ho14jnntGE1fpdOqQEEaiKRpvIavV0hSfmBq8nJbHYI= github.com/tklauser/go-sysconf v0.3.13 h1:GBUpcahXSpR2xN01jhkNAbTLRk2Yzgggk8IM08lq3r4= github.com/tklauser/go-sysconf v0.3.13/go.mod h1:zwleP4Q4OehZHGn4CYZDipCgg9usW5IJePewFCGVEa0= @@ -304,8 +312,8 @@ github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= -github.com/yusufpapurcu/wmi v1.2.3 h1:E1ctvB7uKFMOJw3fdOW32DwGE9I7t++CRUEMKvFoFiw= -github.com/yusufpapurcu/wmi v1.2.3/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= +github.com/yusufpapurcu/wmi v1.2.4 h1:zFUKzehAFReQwLys1b/iSMl+JQGSCSjtVqQn9bBrPo0= +github.com/yusufpapurcu/wmi v1.2.4/go.mod h1:SBZ9tNy3G9/m5Oi98Zks0QjeHVDvuK0qfxQmPyzfmi0= go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0 h1:sv9kVfal0MK0wBMCOGr+HeJm9v803BkJxGrk2au7j08= go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.47.0/go.mod h1:SK2UL73Zy1quvRPonmOmRDiWk1KBV3LyIeeIxcEApWw= @@ -399,8 +407,8 @@ golang.org/x/sys v0.0.0-20210616094352-59db8d763f22/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.11.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU= -golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= +golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20181227161524-e6919f6577db/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= diff --git a/internal/app/app.go b/internal/app/app.go index a8f73b97..236ddde5 100644 --- a/internal/app/app.go +++ b/internal/app/app.go @@ -832,6 +832,12 @@ func (app *App) calcActiveNodes(clusterState, clusterStateDcs map[string]*NodeSt app.logger.Warnf("failed to get master status %v", err) return nil, err } + muuid, err := masterNode.UUID() + if err != nil { + app.logger.Warnf("failed to get master uuid %v", err) + return nil, err + } + for host, node := range clusterState { if host == master { activeNodes = append(activeNodes, master) @@ -874,7 +880,7 @@ func (app *App) calcActiveNodes(clusterState, clusterStateDcs map[string]*NodeSt continue } sgtids := gtids.ParseGtidSet(sstatus.ExecutedGtidSet) - if !(sstatus.ReplicationState == mysql.ReplicationRunning && isGTIDLessOrEqual(sgtids, mgtids)) { + if sstatus.ReplicationState != mysql.ReplicationRunning || isSplitBrained(sgtids, mgtids, muuid) { app.logger.Errorf("calc active nodes: %s is not replicating or splitbrained, deleting from active...", host) continue } diff --git a/internal/app/util.go b/internal/app/util.go index 4cb79076..3e878b98 100644 --- a/internal/app/util.go +++ b/internal/app/util.go @@ -4,6 +4,8 @@ import ( "fmt" "time" + gomysql "github.com/go-mysql-org/go-mysql/mysql" + "github.com/google/uuid" "github.com/yandex/mysync/internal/log" "github.com/yandex/mysync/internal/mysql" "github.com/yandex/mysync/internal/mysql/gtids" @@ -233,6 +235,29 @@ func isGTIDLessOrEqual(slaveGtidSet, masterGtidSet gtids.GTIDSet) bool { return masterGtidSet.Contain(slaveGtidSet) || masterGtidSet.Equal(slaveGtidSet) } +func isSplitBrained(slaveGtidSet, masterGtidSet gtids.GTIDSet, masterUUID uuid.UUID) bool { + mysqlSlaveGtidSet := slaveGtidSet.(*gomysql.MysqlGTIDSet) + mysqlMasterGtidSet := masterGtidSet.(*gomysql.MysqlGTIDSet) + for _, slaveSet := range mysqlSlaveGtidSet.Sets { + masterSet, ok := mysqlMasterGtidSet.Sets[slaveSet.SID.String()] + if !ok { + return true + } + + if masterSet.Contain(slaveSet) { + continue + } + + if masterSet.SID == masterUUID { + continue + } + + return true + } + + return false +} + func validatePriority(priority *int64) error { if priority == nil || *priority >= 0 { return nil diff --git a/internal/app/util_test.go b/internal/app/util_test.go index 8a71e8cb..efc21df0 100644 --- a/internal/app/util_test.go +++ b/internal/app/util_test.go @@ -327,3 +327,52 @@ func getLogger() *log.Logger { } return l } + +func TestIsSplitBrained(t *testing.T) { + masterGTID := mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-100," + + "09978591-5754-4710-BF67-062880ABE1B4:1-100," + + "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-100") + masterUUID := masterGTID.(*gomysql.MysqlGTIDSet).Sets["6dbc0b04-4b09-43dc-86cc-9af852ded919"].SID + + // equal gtids + slaveGTID := mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-100," + + "09978591-5754-4710-BF67-062880ABE1B4:1-100," + + "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-100") + ok := isSplitBrained(slaveGTID, masterGTID, masterUUID) + require.False(t, ok) + + // the replica is lagging behind the master + slaveGTID = mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-99," + + "09978591-5754-4710-BF67-062880ABE1B4:1-100," + + "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-100") + ok = isSplitBrained(slaveGTID, masterGTID, masterUUID) + require.False(t, ok) + + // the replica is lagging behind the new master + slaveGTID = mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-100," + + "09978591-5754-4710-BF67-062880ABE1B4:1-100") + ok = isSplitBrained(slaveGTID, masterGTID, masterUUID) + require.False(t, ok) + + // the replica applied the transaction from the master before the master + slaveGTID = mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-101," + + "09978591-5754-4710-BF67-062880ABE1B4:1-100," + + "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-100") + ok = isSplitBrained(slaveGTID, masterGTID, masterUUID) + require.False(t, ok) + + // the replica applied a transaction not from the master + slaveGTID = mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-100," + + "09978591-5754-4710-BF67-062880ABE1B4:1-100," + + "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-101") + ok = isSplitBrained(slaveGTID, masterGTID, masterUUID) + require.True(t, ok) + + // the replica applied a new transaction not from the master + slaveGTID = mustGTIDSet("6DBC0B04-4B09-43DC-86CC-9AF852DED919:1-101," + + "09978591-5754-4710-BF67-062880ABE1B4:1-100," + + "AA6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-100," + + "BB6890C8-69F8-4BC4-B3A5-5D3FEA8C28CF:1-100") + ok = isSplitBrained(slaveGTID, masterGTID, masterUUID) + require.True(t, ok) +} diff --git a/internal/mysql/data.go b/internal/mysql/data.go index f8e1502f..c3c03b8d 100644 --- a/internal/mysql/data.go +++ b/internal/mysql/data.go @@ -28,6 +28,10 @@ type readOnlyResult struct { SuperReadOnly int `db:"SuperReadOnly"` } +type ServerUUIDResult struct { + ServerUUID string `db:"server_uuid"` +} + // CascadeNodeConfiguration is a dcs node configuration for cascade mysql replica type CascadeNodeConfiguration struct { // StreamFrom - is a host to stream from. Can be changed from CLI. diff --git a/internal/mysql/node.go b/internal/mysql/node.go index 20cdbb0a..2808f685 100644 --- a/internal/mysql/node.go +++ b/internal/mysql/node.go @@ -18,9 +18,9 @@ import ( "time" "github.com/go-sql-driver/mysql" + "github.com/google/uuid" "github.com/jmoiron/sqlx" "github.com/shirou/gopsutil/v3/process" - "github.com/yandex/mysync/internal/config" "github.com/yandex/mysync/internal/log" "github.com/yandex/mysync/internal/mysql/gtids" @@ -34,6 +34,7 @@ type Node struct { db *sqlx.DB version *Version host string + uuid uuid.UUID } var ( @@ -457,7 +458,7 @@ func (n *Node) GetDaemonStartTime() (time.Time, error) { } return time.Time{}, err } - pid, err := strconv.Atoi(strings.TrimSpace(string(pidB))) + pid, err := strconv.ParseInt(strings.TrimSpace(string(pidB)), 10, 32) if err != nil { return time.Time{}, err } @@ -602,6 +603,24 @@ func (n *Node) GetBinlogs() ([]Binlog, error) { return binlogs, err } +// UUID returns server_uuid +func (n *Node) UUID() (uuid.UUID, error) { + if n.uuid.ID() != 0 { + return n.uuid, nil + } + var r ServerUUIDResult + err := n.queryRow(queryGetUUID, nil, &r) + if err != nil { + return uuid.UUID{}, err + } + v, err := uuid.Parse(r.ServerUUID) + if err != nil { + return uuid.UUID{}, err + } + n.uuid = v + return v, err +} + // IsReadOnly returns (true, true) if MySQL Node in (read-only, super-read-only) mode func (n *Node) IsReadOnly() (bool, bool, error) { var ror readOnlyResult diff --git a/internal/mysql/queries.go b/internal/mysql/queries.go index f59c5181..5c3b5600 100644 --- a/internal/mysql/queries.go +++ b/internal/mysql/queries.go @@ -6,6 +6,7 @@ const ( queryReplicaStatus = "replica_status" queryGetVersion = "get_version" queryGTIDExecuted = "gtid_executed" + queryGetUUID = "get_uuid" queryShowBinaryLogs = "binary_logs" queryReplicationLag = "replication_lag" querySlaveHosts = "slave_hosts" @@ -55,6 +56,7 @@ var DefaultQueries = map[string]string{ queryReplicaStatus: `SHOW REPLICA STATUS FOR CHANNEL :channel`, queryGetVersion: `SELECT sys.version_major() AS MajorVersion, sys.version_minor() AS MinorVersion, sys.version_patch() AS PatchVersion`, queryGTIDExecuted: `SELECT @@GLOBAL.gtid_executed as Executed_Gtid_Set`, + queryGetUUID: `SELECT @@server_uuid as server_uuid`, queryShowBinaryLogs: `SHOW BINARY LOGS`, querySlaveHosts: `SHOW SLAVE HOSTS`, queryReplicationLag: ``, diff --git a/tests/features/external_replication.feature b/tests/features/external_replication.feature index 12f6a220..b2314ff6 100644 --- a/tests/features/external_replication.feature +++ b/tests/features/external_replication.feature @@ -40,7 +40,7 @@ Feature: external replication [{ "source_host": "test_source_2", "source_password": "test_pass_2", - "source_port": "2222", + "source_port": 2222, "source_user": "test_user_2" }] """ @@ -53,7 +53,7 @@ Feature: external replication """ [{ "source_host": "test_source_2", - "source_port": "2222", + "source_port": 2222, "source_password": "test_pass_2", "source_user": "test_user_2" }] @@ -86,11 +86,11 @@ Feature: external replication Then SQL result should match json """ [{ - "Exec_Source_Log_Pos": "0", + "Exec_Source_Log_Pos": 0, "Replica_IO_State": "Connecting to source", "Replica_SQL_Running": "Yes", "Source_Host": "test_source", - "Source_Port": "1111", + "Source_Port": 1111, "Source_User": "test_user", "Replica_IO_Running": "Connecting", "Relay_Source_Log_File": "", @@ -182,12 +182,12 @@ YZQy1bHIhscLf8wjTYbzAg== [{ "Replica_IO_State": "Connecting to source", "Source_Host": "test_source_2", - "Source_Port": "2222", + "Source_Port": 2222, "Source_User": "test_user_2", "Replica_IO_Running": "Connecting", "Replica_SQL_Running": "Yes", "Relay_Source_Log_File": "", - "Exec_Source_Log_Pos": "0", + "Exec_Source_Log_Pos": 0, "Channel_Name": "external", "Replicate_Ignore_DB": "mysql", "Source_SSL_CA_File": "/etc/mysql/ssl/external_CA.pem" @@ -212,7 +212,7 @@ YZQy1bHIhscLf8wjTYbzAg== "source_host": "test_source_2", "source_user": "test_user_2", "source_password": "test_pass_2", - "source_port": "2222" + "source_port": 2222 }] """ @@ -260,13 +260,13 @@ YZQy1bHIhscLf8wjTYbzAg== [{ "Replica_IO_State": "", "Source_Host": "test_source", - "Source_Port": "1111", + "Source_Port": 1111, "Source_User": "test_user", "Replica_IO_Running": "No", "Replica_SQL_Running": "No", "Source_SSL_CA_File": "", "Relay_Source_Log_File": "", - "Exec_Source_Log_Pos": "0", + "Exec_Source_Log_Pos": 0, "Channel_Name": "external" }] """ @@ -280,13 +280,13 @@ YZQy1bHIhscLf8wjTYbzAg== [{ "Replica_IO_State": "", "Source_Host": "test_source", - "Source_Port": "1111", + "Source_Port": 1111, "Source_User": "test_user", "Replica_IO_Running": "No", "Replica_SQL_Running": "No", "Source_SSL_CA_File": "", "Relay_Source_Log_File": "", - "Exec_Source_Log_Pos": "0", + "Exec_Source_Log_Pos": 0, "Channel_Name": "external" }] """ @@ -324,13 +324,13 @@ YZQy1bHIhscLf8wjTYbzAg== [{ "Replica_IO_State": "", "Source_Host": "test_source", - "Source_Port": "1111", + "Source_Port": 1111, "Source_User": "test_user", "Replica_IO_Running": "No", "Replica_SQL_Running": "No", "Source_SSL_CA_File": "", "Relay_Source_Log_File": "", - "Exec_Source_Log_Pos": "0", + "Exec_Source_Log_Pos": 0, "Channel_Name": "external" }] """ @@ -350,13 +350,13 @@ YZQy1bHIhscLf8wjTYbzAg== [{ "Replica_IO_State": "", "Source_Host": "test_source", - "Source_Port": "1111", + "Source_Port": 1111, "Source_User": "test_user", "Replica_IO_Running": "No", "Replica_SQL_Running": "No", "Source_SSL_CA_File": "", "Relay_Source_Log_File": "", - "Exec_Source_Log_Pos": "0", + "Exec_Source_Log_Pos": 0, "Channel_Name": "external" }] """ @@ -394,13 +394,13 @@ Y2AirKuDzA5GErKOfQ== [{ "Replica_IO_State": "", "Source_Host": "test_source", - "Source_Port": "1111", + "Source_Port": 1111, "Source_User": "test_user", "Replica_IO_Running": "No", "Replica_SQL_Running": "No", "Source_SSL_CA_File": "", "Relay_Source_Log_File": "", - "Exec_Source_Log_Pos": "0", + "Exec_Source_Log_Pos": 0, "Channel_Name": "external" }] """ @@ -418,13 +418,13 @@ Y2AirKuDzA5GErKOfQ== [{ "Replica_IO_State": "Connecting to source", "Source_Host": "test_source", - "Source_Port": "1111", + "Source_Port": 1111, "Source_User": "test_user", "Replica_IO_Running": "Connecting", "Replica_SQL_Running": "Yes", "Source_SSL_CA_File": "", "Relay_Source_Log_File": "", - "Exec_Source_Log_Pos": "0", + "Exec_Source_Log_Pos": 0, "Channel_Name": "external" }] """ @@ -469,7 +469,7 @@ Y2AirKuDzA5GErKOfQ== [{ "source_host": "test_source_2", "source_password": "test_pass_2", - "source_port": "2222", + "source_port": 2222, "source_user": "test_user_2" }] """ @@ -482,7 +482,7 @@ Y2AirKuDzA5GErKOfQ== """ [{ "source_host": "test_source_2", - "source_port": "2222", + "source_port": 2222, "source_password": "test_pass_2", "source_user": "test_user_2" }] @@ -515,10 +515,10 @@ Y2AirKuDzA5GErKOfQ== Then SQL result should match json """ [{ - "Exec_Source_Log_Pos": "0", + "Exec_Source_Log_Pos": 0, "Replica_IO_State": "Connecting to source", "Source_Host": "test_source", - "Source_Port": "1111", + "Source_Port": 1111, "Source_User": "test_user", "Replica_IO_Running": "Connecting", "Replica_SQL_Running": "Yes", @@ -564,12 +564,12 @@ Y2AirKuDzA5GErKOfQ== [{ "Replica_IO_State": "", "Source_Host": "test_source_2", - "Source_Port": "2222", + "Source_Port": 2222, "Source_User": "test_user_2", "Replica_IO_Running": "No", "Replica_SQL_Running": "No", "Relay_Source_Log_File": "", - "Exec_Source_Log_Pos": "0", + "Exec_Source_Log_Pos": 0, "Channel_Name": "external", "Replicate_Ignore_DB": "mysql", "Source_SSL_CA_File": "" @@ -592,7 +592,7 @@ Y2AirKuDzA5GErKOfQ== "source_host": "test_source_2", "source_user": "test_user_2", "source_password": "test_pass_2", - "source_port": "2222" + "source_port": 2222 }] """ diff --git a/tests/features/maintenance.feature b/tests/features/maintenance.feature index 3f0b6059..1d49427a 100644 --- a/tests/features/maintenance.feature +++ b/tests/features/maintenance.feature @@ -64,25 +64,37 @@ Feature: maintenance mode """ When I run SQL on mysql host "mysql2" """ - SELECT @@rpl_semi_sync_master_enabled AS MasterEnabled, @@rpl_semi_sync_slave_enabled AS SlaveEnabled; + SHOW GLOBAL VARIABLES LIKE 'rpl_semi_sync_%_enabled' """ - Then SQL result should match regexp + Then SQL result should match json """ - [{ - "MasterEnabled":"0", - "SlaveEnabled":"1" - }] + [ + { + "Value":"OFF", + "Variable_name":"rpl_semi_sync_master_enabled" + }, + { + "Value":"ON", + "Variable_name":"rpl_semi_sync_slave_enabled" + } + ] """ When I run SQL on mysql host "mysql1" """ - SELECT @@rpl_semi_sync_master_enabled AS MasterEnabled, @@rpl_semi_sync_slave_enabled AS SlaveEnabled; + SHOW GLOBAL VARIABLES LIKE 'rpl_semi_sync_%_enabled' """ - Then SQL result should match regexp + Then SQL result should match json """ - [{ - "MasterEnabled":"1", - "SlaveEnabled":"0" - }] + [ + { + "Value":"ON", + "Variable_name":"rpl_semi_sync_master_enabled" + }, + { + "Value":"OFF", + "Variable_name":"rpl_semi_sync_slave_enabled" + } + ] """ When I run command on host "mysql1" """ @@ -103,25 +115,37 @@ Feature: maintenance mode And zookeeper node "/test/active_nodes" should not exist When I run SQL on mysql host "mysql2" """ - SELECT @@rpl_semi_sync_master_enabled AS MasterEnabled, @@rpl_semi_sync_slave_enabled AS SlaveEnabled; + SHOW GLOBAL VARIABLES LIKE 'rpl_semi_sync_%_enabled' """ - Then SQL result should match regexp + Then SQL result should match json """ - [{ - "MasterEnabled":"0", - "SlaveEnabled":"1" - }] + [ + { + "Value":"OFF", + "Variable_name":"rpl_semi_sync_master_enabled" + }, + { + "Value":"ON", + "Variable_name":"rpl_semi_sync_slave_enabled" + } + ] """ When I run SQL on mysql host "mysql1" """ - SELECT @@rpl_semi_sync_master_enabled AS MasterEnabled, @@rpl_semi_sync_slave_enabled AS SlaveEnabled; + SHOW GLOBAL VARIABLES LIKE 'rpl_semi_sync_%_enabled' """ - Then SQL result should match regexp + Then SQL result should match json """ - [{ - "MasterEnabled":"0", - "SlaveEnabled":"0" - }] + [ + { + "Value":"OFF", + "Variable_name":"rpl_semi_sync_master_enabled" + }, + { + "Value":"OFF", + "Variable_name":"rpl_semi_sync_slave_enabled" + } + ] """ When I run command on host "mysql1" """ @@ -135,25 +159,37 @@ Feature: maintenance mode """ When I run SQL on mysql host "mysql2" """ - SELECT @@rpl_semi_sync_master_enabled AS MasterEnabled, @@rpl_semi_sync_slave_enabled AS SlaveEnabled; + SHOW GLOBAL VARIABLES LIKE 'rpl_semi_sync_%_enabled' """ - Then SQL result should match regexp + Then SQL result should match json """ - [{ - "MasterEnabled":"0", - "SlaveEnabled":"1" - }] + [ + { + "Value":"OFF", + "Variable_name":"rpl_semi_sync_master_enabled" + }, + { + "Value":"ON", + "Variable_name":"rpl_semi_sync_slave_enabled" + } + ] """ When I run SQL on mysql host "mysql1" """ - SELECT @@rpl_semi_sync_master_enabled AS MasterEnabled, @@rpl_semi_sync_slave_enabled AS SlaveEnabled; + SHOW GLOBAL VARIABLES LIKE 'rpl_semi_sync_%_enabled' """ - Then SQL result should match regexp + Then SQL result should match json """ - [{ - "MasterEnabled":"1", - "SlaveEnabled":"0" - }] + [ + { + "Value":"ON", + "Variable_name":"rpl_semi_sync_master_enabled" + }, + { + "Value":"OFF", + "Variable_name":"rpl_semi_sync_slave_enabled" + } + ] """ Scenario: master host in DCS updated correctly after manual master change diff --git a/tests/mysync_test.go b/tests/mysync_test.go index 44258a4c..84b26958 100644 --- a/tests/mysync_test.go +++ b/tests/mysync_test.go @@ -9,7 +9,6 @@ import ( "log" "os" "path/filepath" - "strconv" "strings" "sync" "testing" @@ -371,19 +370,13 @@ func (tctx *testContext) runSlaveStatusQuery(host string) (map[string]string, er if err != nil { return nil, err } - MajorVersion, err := strconv.Atoi(res[0]["MajorVersion"].(string)) + MajorVersion := res[0]["MajorVersion"].(int64) + MinorVersion := res[0]["MinorVersion"].(int64) + PatchVersion := res[0]["PatchVersion"].(int64) if err != nil { return nil, err } - MinorVersion, err := strconv.Atoi(res[0]["MinorVersion"].(string)) - if err != nil { - return nil, err - } - PatchVersion, err := strconv.Atoi(res[0]["PatchVersion"].(string)) - if err != nil { - return nil, err - } - v := mysql_internal.Version{MajorVersion: MajorVersion, MinorVersion: MinorVersion, PatchVersion: PatchVersion} + v := mysql_internal.Version{MajorVersion: int(MajorVersion), MinorVersion: int(MinorVersion), PatchVersion: int(PatchVersion)} query = mysql_internal.DefaultQueries[v.GetSlaveStatusQuery()] query = mysql_internal.Mogrify(query, map[string]interface{}{ "channel": replicationChannel, @@ -910,7 +903,7 @@ func (tctx *testContext) stepBreakReplicationOnHostInARepairableWay(host string) if err != nil { return err } - if _, err := tctx.queryMysql(host, fmt.Sprintf("KILL %s", queryReqult[0]["id"]), struct{}{}); err != nil { + if _, err := tctx.queryMysql(host, fmt.Sprintf("KILL %d", queryReqult[0]["id"].(uint64)), struct{}{}); err != nil { return err } return nil @@ -1036,7 +1029,13 @@ func (tctx *testContext) stepMysqlHostShouldHaveVariableSet(host string, name st if err != nil { return err } - actual := res[0]["actual"].(string) + actual := "" + switch res[0]["actual"].(type) { + case int64: + actual = fmt.Sprint(res[0]["actual"].(int64)) + default: + actual = res[0]["actual"].(string) + } if actual != value { return fmt.Errorf("@@%s is %s, while expected %s", name, actual, value) } @@ -1218,9 +1217,9 @@ func (tctx *testContext) queryMysqlReadOnlyStatus(host string) (bool, bool, erro if err != nil { return false, false, err } - ro := res[0]["ro"].(string) - superRo := res[0]["superRo"].(string) - return ro == "1", superRo == "1", nil + ro := res[0]["ro"].(int64) + superRo := res[0]["superRo"].(int64) + return ro == 1, superRo == 1, nil } func (tctx *testContext) stepMysqlHostShouldBeReadOnly(host string) error { diff --git a/tests/testutil/docker_composer.go b/tests/testutil/docker_composer.go index f1a0e257..94635e1f 100644 --- a/tests/testutil/docker_composer.go +++ b/tests/testutil/docker_composer.go @@ -56,7 +56,7 @@ type Composer interface { CheckIfFileExist(service, path string) (bool, error) } -// DockerComposer is a Composer implementation based on docker and docker-compose +// DockerComposer is a Composer implementation based on docker and docker compose type DockerComposer struct { projectName string config string @@ -92,14 +92,14 @@ func NewDockerComposer(project, config string) (*DockerComposer, error) { } func (dc *DockerComposer) runCompose(args []string, env []string) error { - args2 := []string{} + args2 := []string{"compose"} args2 = append(args2, "-f", dc.config, "-p", dc.projectName) args2 = append(args2, args...) - cmd := exec.Command("docker-compose", args2...) + cmd := exec.Command("docker", args2...) cmd.Env = append(os.Environ(), env...) out, err := cmd.CombinedOutput() if err != nil { - return fmt.Errorf("failed to run 'docker-compose %s': %s\n%s", strings.Join(args2, " "), err, out) + return fmt.Errorf("failed to run 'docker compose %s': %s\n%s", strings.Join(args2, " "), err, out) } return nil }