Compare commits
165 Commits
client/v3.
...
pkg/v3.5.9
Author | SHA1 | Date | |
---|---|---|---|
bdbbde998b | |||
d5069486cc | |||
f53707edfa | |||
45d8cb254e | |||
e38eb678bb | |||
d1b1aa9dbe | |||
d6bc827955 | |||
fb8fba710b | |||
b91025abbb | |||
f4f5ac93ca | |||
c0f2954e9f | |||
217d183e5a | |||
9d2cda4e44 | |||
3cd07fe17c | |||
cd019255ba | |||
643e6e1993 | |||
5872b80ed5 | |||
4501fd88c7 | |||
7f4eef09a3 | |||
b31caa3f12 | |||
b1df3df2b1 | |||
e6c2e380a9 | |||
291cb7172a | |||
070341c69f | |||
f905e2c264 | |||
e6eeca6885 | |||
65635e426c | |||
55bce22e97 | |||
7230b943d0 | |||
77baf66b52 | |||
1259884695 | |||
9e506593bf | |||
c5b670bff1 | |||
073c530989 | |||
6637aee804 | |||
c0421c7330 | |||
2d5f48a7ef | |||
a9e0a04c9a | |||
245067b15d | |||
63576a25f5 | |||
8b4549d534 | |||
f7ac9dfcd6 | |||
dcb1bf6078 | |||
44d78bf9aa | |||
fe37277c7e | |||
9e974792f9 | |||
15b3756abd | |||
92e56ab61e | |||
dafdaaedf2 | |||
930a450a55 | |||
86101d333b | |||
eb614c35f7 | |||
2eeb26083f | |||
00e1e5db21 | |||
46d6c1d7b2 | |||
2f4d75feb1 | |||
4e9911ec26 | |||
64bc55ef4e | |||
11ca1d356a | |||
358bcf3fb6 | |||
3a63da9609 | |||
55bfad950c | |||
3f96014d2d | |||
98861410f3 | |||
6ddb23ce7a | |||
e44995e670 | |||
b10adb6abe | |||
f0aa228dbf | |||
c602942246 | |||
1ea808b5ba | |||
183af509f6 | |||
1bd835383b | |||
5996b5faa3 | |||
d41d8ac1da | |||
e896cc7201 | |||
346f1d325a | |||
bc5445c00c | |||
452164a1c7 | |||
1664b4f828 | |||
b9568dba32 | |||
238da4b3f5 | |||
2a0ecd4078 | |||
78e739083e | |||
747de58414 | |||
41ed809c38 | |||
82004d0197 | |||
215b53cf3b | |||
638c6f1bb1 | |||
53300ece3b | |||
816c2e2b8a | |||
e1fc545d8a | |||
9e3966fbce | |||
cff304502c | |||
dd30268727 | |||
1293f5d4b7 | |||
f12f162587 | |||
cf379a79ea | |||
4e0385134e | |||
925c0611e0 | |||
413ec16175 | |||
bf1b902111 | |||
a612b9285f | |||
69ee8a83ab | |||
3337f35f17 | |||
b766840c3b | |||
410a987cbf | |||
d178292fec | |||
3b7248bc87 | |||
4d3c840a9b | |||
f1842b6ecf | |||
1fdfb4292c | |||
96ca27a3f2 | |||
127e9c05b0 | |||
c1a89973f0 | |||
0b47579263 | |||
22f599a2b7 | |||
378ad6b517 | |||
5454ca67bd | |||
ba122c9d56 | |||
cecbe35ce0 | |||
d0424a7bf1 | |||
1a9742c9c4 | |||
7ccca083eb | |||
c91978077b | |||
b2821631aa | |||
4097c24783 | |||
9849fa7c66 | |||
69aace20c8 | |||
5f387e6b7d | |||
563713e128 | |||
c2378be1b5 | |||
6797856841 | |||
cc6a082f9e | |||
27707209ae | |||
be4adc0c55 | |||
8902fe9246 | |||
45e31f6c80 | |||
8e26a1fff1 | |||
0a0f0e3617 | |||
bd7405a52e | |||
17cb291f15 | |||
1e96e0be38 | |||
efb9480b96 | |||
7cd9e5a338 | |||
d78f6f7f14 | |||
ec6f0a74ba | |||
62169d12eb | |||
d3da22fb1f | |||
acc7463fb2 | |||
2fb9be6f7d | |||
f6c4c84da3 | |||
3afd0735e0 | |||
e712234a1a | |||
3e195ba473 | |||
25ef9b6f46 | |||
5ff0d7fe26 | |||
dce3fdbeb1 | |||
07c7a98371 | |||
dd983c662b | |||
5daf35bb4a | |||
528dd82be9 | |||
7b568f23ab | |||
db55011d7c | |||
89d0fc49fc | |||
653d6e18c3 |
13
.github/workflows/e2e.yaml
vendored
13
.github/workflows/e2e.yaml
vendored
@ -1,8 +1,11 @@
|
|||||||
name: E2E
|
name: E2E
|
||||||
on: [push, pull_request]
|
on: [push, pull_request]
|
||||||
jobs:
|
jobs:
|
||||||
|
goversion:
|
||||||
|
uses: ./.github/workflows/go-version.yaml
|
||||||
test:
|
test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
needs: goversion
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: true
|
fail-fast: true
|
||||||
matrix:
|
matrix:
|
||||||
@ -13,20 +16,20 @@ jobs:
|
|||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- uses: actions/setup-go@v2
|
- uses: actions/setup-go@v2
|
||||||
with:
|
with:
|
||||||
go-version: "1.16.15"
|
go-version: ${{ needs.goversion.outputs.goversion }}
|
||||||
- run: date
|
- run: date
|
||||||
- env:
|
- env:
|
||||||
TARGET: ${{ matrix.target }}
|
TARGET: ${{ matrix.target }}
|
||||||
run: |
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
echo "${TARGET}"
|
echo "${TARGET}"
|
||||||
case "${TARGET}" in
|
case "${TARGET}" in
|
||||||
linux-amd64-e2e)
|
linux-amd64-e2e)
|
||||||
PASSES='build release e2e' MANUAL_VER=v3.4.7 CPU='4' EXPECT_DEBUG='true' COVER='false' RACE='true' ./test.sh 2>&1 | tee test.log
|
PASSES='build release e2e' MANUAL_VER=v3.4.7 CPU='4' EXPECT_DEBUG='true' COVER='false' RACE='true' ./test.sh
|
||||||
! egrep "(--- FAIL:|DATA RACE|panic: test timed out|appears to have leaked)" -B50 -A10 test.log
|
|
||||||
;;
|
;;
|
||||||
linux-386-e2e)
|
linux-386-e2e)
|
||||||
GOARCH=386 PASSES='build e2e' CPU='4' EXPECT_DEBUG='true' COVER='false' RACE='true' ./test.sh 2>&1 | tee test.log
|
GOARCH=386 PASSES='build e2e' CPU='4' EXPECT_DEBUG='true' COVER='false' RACE='true' ./test.sh
|
||||||
! egrep "(--- FAIL:|DATA RACE|panic: test timed out|appears to have leaked)" -B50 -A10 test.log
|
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
echo "Failed to find target"
|
echo "Failed to find target"
|
||||||
|
7
.github/workflows/functional.yaml
vendored
7
.github/workflows/functional.yaml
vendored
@ -1,8 +1,11 @@
|
|||||||
name: functional-tests
|
name: functional-tests
|
||||||
on: [push, pull_request]
|
on: [push, pull_request]
|
||||||
jobs:
|
jobs:
|
||||||
|
goversion:
|
||||||
|
uses: ./.github/workflows/go-version.yaml
|
||||||
test:
|
test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
needs: goversion
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: true
|
fail-fast: true
|
||||||
matrix:
|
matrix:
|
||||||
@ -12,11 +15,13 @@ jobs:
|
|||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- uses: actions/setup-go@v2
|
- uses: actions/setup-go@v2
|
||||||
with:
|
with:
|
||||||
go-version: "1.16.15"
|
go-version: ${{ needs.goversion.outputs.goversion }}
|
||||||
- run: date
|
- run: date
|
||||||
- env:
|
- env:
|
||||||
TARGET: ${{ matrix.target }}
|
TARGET: ${{ matrix.target }}
|
||||||
run: |
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
echo "${TARGET}"
|
echo "${TARGET}"
|
||||||
case "${TARGET}" in
|
case "${TARGET}" in
|
||||||
linux-amd64-functional)
|
linux-amd64-functional)
|
||||||
|
21
.github/workflows/go-version.yaml
vendored
Normal file
21
.github/workflows/go-version.yaml
vendored
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
name: Go version setup
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_call:
|
||||||
|
outputs:
|
||||||
|
goversion:
|
||||||
|
value: ${{ jobs.version.outputs.goversion }}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
version:
|
||||||
|
name: Set Go version variable for all the workflows
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
outputs:
|
||||||
|
goversion: ${{ steps.goversion.outputs.goversion }}
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@8e5e7e5ab8b370d6c329ec480221332ada57f0ab # v3.5.2
|
||||||
|
- id: goversion
|
||||||
|
run: |
|
||||||
|
GO_VERSION=$(cat .go-version)
|
||||||
|
echo "Go Version: $GO_VERSION"
|
||||||
|
echo "goversion=$GO_VERSION" >> $GITHUB_OUTPUT
|
10
.github/workflows/grpcproxy.yaml
vendored
10
.github/workflows/grpcproxy.yaml
vendored
@ -1,8 +1,11 @@
|
|||||||
name: grpcProxy-tests
|
name: grpcProxy-tests
|
||||||
on: [push, pull_request]
|
on: [push, pull_request]
|
||||||
jobs:
|
jobs:
|
||||||
|
goversion:
|
||||||
|
uses: ./.github/workflows/go-version.yaml
|
||||||
test:
|
test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
needs: goversion
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: true
|
fail-fast: true
|
||||||
matrix:
|
matrix:
|
||||||
@ -12,16 +15,17 @@ jobs:
|
|||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- uses: actions/setup-go@v2
|
- uses: actions/setup-go@v2
|
||||||
with:
|
with:
|
||||||
go-version: "1.16.15"
|
go-version: ${{ needs.goversion.outputs.goversion }}
|
||||||
- run: date
|
- run: date
|
||||||
- env:
|
- env:
|
||||||
TARGET: ${{ matrix.target }}
|
TARGET: ${{ matrix.target }}
|
||||||
run: |
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
echo "${TARGET}"
|
echo "${TARGET}"
|
||||||
case "${TARGET}" in
|
case "${TARGET}" in
|
||||||
linux-amd64-grpcproxy)
|
linux-amd64-grpcproxy)
|
||||||
PASSES='build grpcproxy' CPU='4' COVER='false' RACE='true' ./test.sh 2>&1 | tee test.log
|
PASSES='build grpcproxy' CPU='4' COVER='false' RACE='true' ./test.sh
|
||||||
! egrep "(--- FAIL:|DATA RACE|panic: test timed out|appears to have leaked)" -B50 -A10 test.log
|
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
echo "Failed to find target"
|
echo "Failed to find target"
|
||||||
|
15
.github/workflows/release.yaml
vendored
15
.github/workflows/release.yaml
vendored
@ -1,14 +1,20 @@
|
|||||||
name: Release
|
name: Release
|
||||||
on: [push, pull_request]
|
on: [push, pull_request]
|
||||||
jobs:
|
jobs:
|
||||||
|
goversion:
|
||||||
|
uses: ./.github/workflows/go-version.yaml
|
||||||
main:
|
main:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
needs: goversion
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- uses: actions/setup-go@v2
|
- uses: actions/setup-go@v2
|
||||||
with:
|
with:
|
||||||
go-version: "1.16.15"
|
go-version: ${{ needs.goversion.outputs.goversion }}
|
||||||
- run: |
|
- name: release
|
||||||
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
git config --global user.email "github-action@etcd.io"
|
git config --global user.email "github-action@etcd.io"
|
||||||
git config --global user.name "Github Action"
|
git config --global user.name "Github Action"
|
||||||
gpg --batch --gen-key <<EOF
|
gpg --batch --gen-key <<EOF
|
||||||
@ -21,4 +27,7 @@ jobs:
|
|||||||
Name-Email: github-action@etcd.io
|
Name-Email: github-action@etcd.io
|
||||||
Expire-Date: 0
|
Expire-Date: 0
|
||||||
EOF
|
EOF
|
||||||
DRY_RUN=true BRANCH=release-3.5 ./scripts/release --no-upload --no-docker-push 3.5.99
|
DRY_RUN=true ./scripts/release --no-upload --no-docker-push --in-place 3.5.99
|
||||||
|
- name: test-image
|
||||||
|
run: |
|
||||||
|
VERSION=3.5.99 ./scripts/test_images.sh
|
||||||
|
7
.github/workflows/tests.yaml
vendored
7
.github/workflows/tests.yaml
vendored
@ -1,8 +1,11 @@
|
|||||||
name: Tests
|
name: Tests
|
||||||
on: [push, pull_request]
|
on: [push, pull_request]
|
||||||
jobs:
|
jobs:
|
||||||
|
goversion:
|
||||||
|
uses: ./.github/workflows/go-version.yaml
|
||||||
test:
|
test:
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
needs: goversion
|
||||||
strategy:
|
strategy:
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
matrix:
|
matrix:
|
||||||
@ -18,11 +21,13 @@ jobs:
|
|||||||
- uses: actions/checkout@v2
|
- uses: actions/checkout@v2
|
||||||
- uses: actions/setup-go@v2
|
- uses: actions/setup-go@v2
|
||||||
with:
|
with:
|
||||||
go-version: "1.16.15"
|
go-version: ${{ needs.goversion.outputs.goversion }}
|
||||||
- run: date
|
- run: date
|
||||||
- env:
|
- env:
|
||||||
TARGET: ${{ matrix.target }}
|
TARGET: ${{ matrix.target }}
|
||||||
run: |
|
run: |
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
echo "${TARGET}"
|
echo "${TARGET}"
|
||||||
case "${TARGET}" in
|
case "${TARGET}" in
|
||||||
linux-amd64-fmt)
|
linux-amd64-fmt)
|
||||||
|
37
.github/workflows/trivy-nightly-scan.yaml
vendored
Normal file
37
.github/workflows/trivy-nightly-scan.yaml
vendored
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
name: Trivy Nightly Scan
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: '0 2 * * *' # run at 2 AM UTC
|
||||||
|
|
||||||
|
permissions: read-all
|
||||||
|
jobs:
|
||||||
|
nightly-scan:
|
||||||
|
name: Trivy Scan nightly
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
# maintain the versions of etcd that need to be actively
|
||||||
|
# security scanned
|
||||||
|
versions: [v3.5.6]
|
||||||
|
permissions:
|
||||||
|
security-events: write # for github/codeql-action/upload-sarif to upload SARIF results
|
||||||
|
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@93ea575cb5d8a053eaa0ac8fa3b40d7e05a33cc8 # v3.1.0
|
||||||
|
with:
|
||||||
|
ref: release-3.5
|
||||||
|
- name: Run Trivy vulnerability scanner
|
||||||
|
uses: aquasecurity/trivy-action@9ab158e8597f3b310480b9a69402b419bc03dbd5 # master
|
||||||
|
with:
|
||||||
|
image-ref: 'gcr.io/etcd-development/etcd:${{ matrix.versions }}'
|
||||||
|
severity: 'CRITICAL,HIGH'
|
||||||
|
format: 'template'
|
||||||
|
template: '@/contrib/sarif.tpl'
|
||||||
|
output: 'trivy-results-3-5.sarif'
|
||||||
|
|
||||||
|
- name: Upload Trivy scan results to GitHub Security tab
|
||||||
|
uses: github/codeql-action/upload-sarif@a669cc5936cc5e1b6a362ec1ff9e410dc570d190 # v2.1.36
|
||||||
|
with:
|
||||||
|
sarif_file: 'trivy-results-3-5.sarif'
|
1
.go-version
Normal file
1
.go-version
Normal file
@ -0,0 +1 @@
|
|||||||
|
1.19.9
|
51
.travis.yml
51
.travis.yml
@ -1,51 +0,0 @@
|
|||||||
language: go
|
|
||||||
go_import_path: go.etcd.io/etcd/v3
|
|
||||||
|
|
||||||
sudo: required
|
|
||||||
|
|
||||||
services: docker
|
|
||||||
|
|
||||||
go:
|
|
||||||
- "1.16.15"
|
|
||||||
- tip
|
|
||||||
|
|
||||||
notifications:
|
|
||||||
on_success: never
|
|
||||||
on_failure: never
|
|
||||||
|
|
||||||
env:
|
|
||||||
matrix:
|
|
||||||
- TARGET=linux-amd64-coverage
|
|
||||||
- TARGET=linux-amd64-fmt-unit-go-tip-2-cpu
|
|
||||||
|
|
||||||
matrix:
|
|
||||||
fast_finish: true
|
|
||||||
allow_failures:
|
|
||||||
- go: "1.16.15"
|
|
||||||
env: TARGET=linux-amd64-coverage
|
|
||||||
- go: tip
|
|
||||||
env: TARGET=linux-amd64-fmt-unit-go-tip-2-cpu
|
|
||||||
exclude:
|
|
||||||
- go: tip
|
|
||||||
env: TARGET=linux-amd64-coverage
|
|
||||||
- go: "1.16.15"
|
|
||||||
env: TARGET=linux-amd64-fmt-unit-go-tip-2-cpu
|
|
||||||
|
|
||||||
before_install:
|
|
||||||
- if [[ $TRAVIS_GO_VERSION == 1.* ]]; then docker pull gcr.io/etcd-development/etcd-test:go${TRAVIS_GO_VERSION}; fi
|
|
||||||
|
|
||||||
install:
|
|
||||||
- date
|
|
||||||
|
|
||||||
script:
|
|
||||||
- date
|
|
||||||
- echo "TRAVIS_GO_VERSION=${TRAVIS_GO_VERSION}"
|
|
||||||
- >
|
|
||||||
case "${TARGET}" in
|
|
||||||
linux-amd64-coverage)
|
|
||||||
sudo HOST_TMP_DIR=/tmp TEST_OPTS="VERBOSE='1'" make docker-test-coverage
|
|
||||||
;;
|
|
||||||
linux-amd64-fmt-unit-go-tip-2-cpu)
|
|
||||||
GOARCH=amd64 PASSES='fmt unit' CPU='2' RACE='false' ./test.sh -p=2
|
|
||||||
;;
|
|
||||||
esac
|
|
@ -1,17 +1,11 @@
|
|||||||
# TODO: move to k8s.gcr.io/build-image/debian-base:bullseye-v1.y.z when patched
|
FROM --platform=linux/amd64 gcr.io/distroless/static-debian11
|
||||||
FROM debian:bullseye-20220328
|
|
||||||
|
|
||||||
ADD etcd /usr/local/bin/
|
ADD etcd /usr/local/bin/
|
||||||
ADD etcdctl /usr/local/bin/
|
ADD etcdctl /usr/local/bin/
|
||||||
ADD etcdutl /usr/local/bin/
|
ADD etcdutl /usr/local/bin/
|
||||||
RUN mkdir -p /var/etcd/
|
|
||||||
RUN mkdir -p /var/lib/etcd/
|
|
||||||
|
|
||||||
# Alpine Linux doesn't use pam, which means that there is no /etc/nsswitch.conf,
|
WORKDIR /var/etcd/
|
||||||
# but Golang relies on /etc/nsswitch.conf to check the order of DNS resolving
|
WORKDIR /var/lib/etcd/
|
||||||
# (see https://github.com/golang/go/commit/9dee7771f561cf6aee081c0af6658cc81fac3918)
|
|
||||||
# To fix this we just create /etc/nsswitch.conf and add the following line:
|
|
||||||
RUN echo 'hosts: files mdns4_minimal [NOTFOUND=return] dns mdns4' >> /etc/nsswitch.conf
|
|
||||||
|
|
||||||
EXPOSE 2379 2380
|
EXPOSE 2379 2380
|
||||||
|
|
||||||
|
@ -1,12 +1,11 @@
|
|||||||
# TODO: move to k8s.gcr.io/build-image/debian-base-arm64:bullseye-1.y.z when patched
|
FROM --platform=linux/arm64 gcr.io/distroless/static-debian11
|
||||||
FROM arm64v8/debian:bullseye-20220328
|
|
||||||
|
|
||||||
ADD etcd /usr/local/bin/
|
ADD etcd /usr/local/bin/
|
||||||
ADD etcdctl /usr/local/bin/
|
ADD etcdctl /usr/local/bin/
|
||||||
ADD etcdutl /usr/local/bin/
|
ADD etcdutl /usr/local/bin/
|
||||||
ADD var/etcd /var/etcd
|
|
||||||
ADD var/lib/etcd /var/lib/etcd
|
WORKDIR /var/etcd/
|
||||||
ENV ETCD_UNSUPPORTED_ARCH=arm64
|
WORKDIR /var/lib/etcd/
|
||||||
|
|
||||||
EXPOSE 2379 2380
|
EXPOSE 2379 2380
|
||||||
|
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
# TODO: move to k8s.gcr.io/build-image/debian-base-ppc64le:bullseye-1.y.z when patched
|
FROM --platform=linux/ppc64le gcr.io/distroless/static-debian11
|
||||||
FROM ppc64le/debian:bullseye-20220328
|
|
||||||
|
|
||||||
ADD etcd /usr/local/bin/
|
ADD etcd /usr/local/bin/
|
||||||
ADD etcdctl /usr/local/bin/
|
ADD etcdctl /usr/local/bin/
|
||||||
ADD etcdutl /usr/local/bin/
|
ADD etcdutl /usr/local/bin/
|
||||||
ADD var/etcd /var/etcd
|
|
||||||
ADD var/lib/etcd /var/lib/etcd
|
WORKDIR /var/etcd/
|
||||||
|
WORKDIR /var/lib/etcd/
|
||||||
|
|
||||||
EXPOSE 2379 2380
|
EXPOSE 2379 2380
|
||||||
|
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
# TODO: move to k8s.gcr.io/build-image/debian-base-s390x:bullseye-1.y.z when patched
|
FROM --platform=linux/s390x gcr.io/distroless/static-debian11
|
||||||
FROM s390x/debian:bullseye-20220328
|
|
||||||
|
|
||||||
ADD etcd /usr/local/bin/
|
ADD etcd /usr/local/bin/
|
||||||
ADD etcdctl /usr/local/bin/
|
ADD etcdctl /usr/local/bin/
|
||||||
ADD etcdutl /usr/local/bin/
|
ADD etcdutl /usr/local/bin/
|
||||||
ADD var/etcd /var/etcd
|
|
||||||
ADD var/lib/etcd /var/lib/etcd
|
WORKDIR /var/etcd/
|
||||||
|
WORKDIR /var/lib/etcd/
|
||||||
|
|
||||||
EXPOSE 2379 2380
|
EXPOSE 2379 2380
|
||||||
|
|
||||||
|
4
Makefile
4
Makefile
@ -55,7 +55,7 @@ docker-remove:
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
GO_VERSION ?= 1.16.15
|
GO_VERSION ?= 1.19.9
|
||||||
ETCD_VERSION ?= $(shell git rev-parse --short HEAD || echo "GitNotFound")
|
ETCD_VERSION ?= $(shell git rev-parse --short HEAD || echo "GitNotFound")
|
||||||
|
|
||||||
TEST_SUFFIX = $(shell date +%s | base64 | head -c 15)
|
TEST_SUFFIX = $(shell date +%s | base64 | head -c 15)
|
||||||
@ -162,7 +162,7 @@ test-full:
|
|||||||
PASSES="fmt build release unit integration functional e2e grpcproxy" ./test.sh 2<&1 | tee test-$(TEST_SUFFIX).log
|
PASSES="fmt build release unit integration functional e2e grpcproxy" ./test.sh 2<&1 | tee test-$(TEST_SUFFIX).log
|
||||||
|
|
||||||
ensure-docker-test-image-exists:
|
ensure-docker-test-image-exists:
|
||||||
make pull-docker-test || echo "WARNING: Container Image not found in registry, building locally"; make build-docker-test
|
make pull-docker-test || ( echo "WARNING: Container Image not found in registry, building locally"; make build-docker-test )
|
||||||
|
|
||||||
docker-test: ensure-docker-test-image-exists
|
docker-test: ensure-docker-test-image-exists
|
||||||
$(info GO_VERSION: $(GO_VERSION))
|
$(info GO_VERSION: $(GO_VERSION))
|
||||||
|
@ -20,7 +20,7 @@ import (
|
|||||||
pb "go.etcd.io/etcd/api/v3/etcdserverpb"
|
pb "go.etcd.io/etcd/api/v3/etcdserverpb"
|
||||||
)
|
)
|
||||||
|
|
||||||
// TestInvalidGoYypeIntPanic tests conditions that caused
|
// TestInvalidGoTypeIntPanic tests conditions that caused
|
||||||
// panic: invalid Go type int for field k8s_io.kubernetes.vendor.go_etcd_io.etcd.etcdserver.etcdserverpb.loggablePutRequest.value_size
|
// panic: invalid Go type int for field k8s_io.kubernetes.vendor.go_etcd_io.etcd.etcdserver.etcdserverpb.loggablePutRequest.value_size
|
||||||
// See https://github.com/kubernetes/kubernetes/issues/91937 for more details
|
// See https://github.com/kubernetes/kubernetes/issues/91937 for more details
|
||||||
func TestInvalidGoTypeIntPanic(t *testing.T) {
|
func TestInvalidGoTypeIntPanic(t *testing.T) {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
module go.etcd.io/etcd/api/v3
|
module go.etcd.io/etcd/api/v3
|
||||||
|
|
||||||
go 1.16
|
go 1.19
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/coreos/go-semver v0.3.0
|
github.com/coreos/go-semver v0.3.0
|
||||||
@ -9,6 +9,13 @@ require (
|
|||||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0
|
github.com/grpc-ecosystem/grpc-gateway v1.16.0
|
||||||
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c
|
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c
|
||||||
google.golang.org/grpc v1.41.0
|
google.golang.org/grpc v1.41.0
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect
|
||||||
|
golang.org/x/sys v0.0.0-20210510120138-977fb7262007 // indirect
|
||||||
|
golang.org/x/text v0.3.5 // indirect
|
||||||
|
google.golang.org/protobuf v1.26.0 // indirect
|
||||||
gopkg.in/yaml.v2 v2.4.0 // indirect
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -26,7 +26,7 @@ import (
|
|||||||
var (
|
var (
|
||||||
// MinClusterVersion is the min cluster version this etcd binary is compatible with.
|
// MinClusterVersion is the min cluster version this etcd binary is compatible with.
|
||||||
MinClusterVersion = "3.0.0"
|
MinClusterVersion = "3.0.0"
|
||||||
Version = "3.5.5"
|
Version = "3.5.9"
|
||||||
APIVersion = "unknown"
|
APIVersion = "unknown"
|
||||||
|
|
||||||
// Git SHA Value will be set during build
|
// Git SHA Value will be set during build
|
||||||
|
@ -26,15 +26,6 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"project": "github.com/certifi/gocertifi",
|
|
||||||
"licenses": [
|
|
||||||
{
|
|
||||||
"type": "Mozilla Public License 2.0",
|
|
||||||
"confidence": 1
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"project": "github.com/cespare/xxhash/v2",
|
"project": "github.com/cespare/xxhash/v2",
|
||||||
"licenses": [
|
"licenses": [
|
||||||
@ -53,24 +44,6 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"project": "github.com/cockroachdb/errors",
|
|
||||||
"licenses": [
|
|
||||||
{
|
|
||||||
"type": "Apache License 2.0",
|
|
||||||
"confidence": 1
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"project": "github.com/cockroachdb/logtags",
|
|
||||||
"licenses": [
|
|
||||||
{
|
|
||||||
"type": "Apache License 2.0",
|
|
||||||
"confidence": 1
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"project": "github.com/coreos/go-semver/semver",
|
"project": "github.com/coreos/go-semver/semver",
|
||||||
"licenses": [
|
"licenses": [
|
||||||
@ -134,24 +107,6 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"project": "github.com/form3tech-oss/jwt-go",
|
|
||||||
"licenses": [
|
|
||||||
{
|
|
||||||
"type": "MIT License",
|
|
||||||
"confidence": 0.9891304347826086
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"project": "github.com/getsentry/raven-go",
|
|
||||||
"licenses": [
|
|
||||||
{
|
|
||||||
"type": "BSD 3-clause \"New\" or \"Revised\" License",
|
|
||||||
"confidence": 0.9663865546218487
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"project": "github.com/gogo/protobuf",
|
"project": "github.com/gogo/protobuf",
|
||||||
"licenses": [
|
"licenses": [
|
||||||
@ -161,6 +116,15 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"project": "github.com/golang-jwt/jwt/v4",
|
||||||
|
"licenses": [
|
||||||
|
{
|
||||||
|
"type": "MIT License",
|
||||||
|
"confidence": 0.9891304347826086
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"project": "github.com/golang/groupcache/lru",
|
"project": "github.com/golang/groupcache/lru",
|
||||||
"licenses": [
|
"licenses": [
|
||||||
@ -296,15 +260,6 @@
|
|||||||
}
|
}
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
|
||||||
"project": "github.com/pkg/errors",
|
|
||||||
"licenses": [
|
|
||||||
{
|
|
||||||
"type": "BSD 2-clause \"Simplified\" License",
|
|
||||||
"confidence": 1
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
{
|
||||||
"project": "github.com/pmezard/go-difflib/difflib",
|
"project": "github.com/pmezard/go-difflib/difflib",
|
||||||
"licenses": [
|
"licenses": [
|
||||||
@ -657,7 +612,16 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"project": "golang.org/x/sys",
|
"project": "golang.org/x/sync/errgroup",
|
||||||
|
"licenses": [
|
||||||
|
{
|
||||||
|
"type": "BSD 3-clause \"New\" or \"Revised\" License",
|
||||||
|
"confidence": 0.9663865546218487
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"project": "golang.org/x/sys/unix",
|
||||||
"licenses": [
|
"licenses": [
|
||||||
{
|
{
|
||||||
"type": "BSD 3-clause \"New\" or \"Revised\" License",
|
"type": "BSD 3-clause \"New\" or \"Revised\" License",
|
||||||
|
2
build
2
build
@ -1,5 +1,7 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
echo -e "\\e[91mDEPRECATED!!! Use build.sh script instead.\\e[0m\\n"
|
echo -e "\\e[91mDEPRECATED!!! Use build.sh script instead.\\e[0m\\n"
|
||||||
sleep 1
|
sleep 1
|
||||||
|
|
||||||
|
40
build.sh
40
build.sh
@ -1,24 +1,30 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
source ./scripts/test_lib.sh
|
source ./scripts/test_lib.sh
|
||||||
|
|
||||||
GIT_SHA=$(git rev-parse --short HEAD || echo "GitNotFound")
|
GIT_SHA=$(git rev-parse --short HEAD || echo "GitNotFound")
|
||||||
if [[ -n "$FAILPOINTS" ]]; then
|
if [[ -n "${FAILPOINTS:-}" ]]; then
|
||||||
GIT_SHA="$GIT_SHA"-FAILPOINTS
|
GIT_SHA="$GIT_SHA"-FAILPOINTS
|
||||||
fi
|
fi
|
||||||
|
|
||||||
VERSION_SYMBOL="${ROOT_MODULE}/api/v3/version.GitSHA"
|
VERSION_SYMBOL="${ROOT_MODULE}/api/v3/version.GitSHA"
|
||||||
|
|
||||||
|
# use go env if noset
|
||||||
|
GOOS=${GOOS:-$(go env GOOS)}
|
||||||
|
GOARCH=${GOARCH:-$(go env GOARCH)}
|
||||||
|
|
||||||
# Set GO_LDFLAGS="-s" for building without symbols for debugging.
|
# Set GO_LDFLAGS="-s" for building without symbols for debugging.
|
||||||
# shellcheck disable=SC2206
|
# shellcheck disable=SC2206
|
||||||
GO_LDFLAGS=(${GO_LDFLAGS} "-X=${VERSION_SYMBOL}=${GIT_SHA}")
|
GO_LDFLAGS=(${GO_LDFLAGS:-} "-X=${VERSION_SYMBOL}=${GIT_SHA}")
|
||||||
GO_BUILD_ENV=("CGO_ENABLED=0" "GO_BUILD_FLAGS=${GO_BUILD_FLAGS}" "GOOS=${GOOS}" "GOARCH=${GOARCH}")
|
GO_BUILD_ENV=("CGO_ENABLED=0" "GO_BUILD_FLAGS=${GO_BUILD_FLAGS:-}" "GOOS=${GOOS}" "GOARCH=${GOARCH}")
|
||||||
|
|
||||||
# enable/disable failpoints
|
# enable/disable failpoints
|
||||||
toggle_failpoints() {
|
toggle_failpoints() {
|
||||||
mode="$1"
|
mode="$1"
|
||||||
if command -v gofail >/dev/null 2>&1; then
|
if command -v gofail >/dev/null 2>&1; then
|
||||||
run gofail "$mode" server/etcdserver/ server/mvcc/backend/
|
run gofail "$mode" server/etcdserver/ server/mvcc/backend/ server/wal/
|
||||||
elif [[ "$mode" != "disable" ]]; then
|
elif [[ "$mode" != "disable" ]]; then
|
||||||
log_error "FAILPOINTS set but gofail not found"
|
log_error "FAILPOINTS set but gofail not found"
|
||||||
exit 1
|
exit 1
|
||||||
@ -27,13 +33,13 @@ toggle_failpoints() {
|
|||||||
|
|
||||||
toggle_failpoints_default() {
|
toggle_failpoints_default() {
|
||||||
mode="disable"
|
mode="disable"
|
||||||
if [[ -n "$FAILPOINTS" ]]; then mode="enable"; fi
|
if [[ -n "${FAILPOINTS:-}" ]]; then mode="enable"; fi
|
||||||
toggle_failpoints "$mode"
|
toggle_failpoints "$mode"
|
||||||
}
|
}
|
||||||
|
|
||||||
etcd_build() {
|
etcd_build() {
|
||||||
out="bin"
|
out="bin"
|
||||||
if [[ -n "${BINDIR}" ]]; then out="${BINDIR}"; fi
|
if [[ -n "${BINDIR:-}" ]]; then out="${BINDIR}"; fi
|
||||||
toggle_failpoints_default
|
toggle_failpoints_default
|
||||||
|
|
||||||
run rm -f "${out}/etcd"
|
run rm -f "${out}/etcd"
|
||||||
@ -41,7 +47,8 @@ etcd_build() {
|
|||||||
cd ./server
|
cd ./server
|
||||||
# Static compilation is useful when etcd is run in a container. $GO_BUILD_FLAGS is OK
|
# Static compilation is useful when etcd is run in a container. $GO_BUILD_FLAGS is OK
|
||||||
# shellcheck disable=SC2086
|
# shellcheck disable=SC2086
|
||||||
run env "${GO_BUILD_ENV[@]}" go build $GO_BUILD_FLAGS \
|
run env "${GO_BUILD_ENV[@]}" go build ${GO_BUILD_FLAGS:-} \
|
||||||
|
-trimpath \
|
||||||
-installsuffix=cgo \
|
-installsuffix=cgo \
|
||||||
"-ldflags=${GO_LDFLAGS[*]}" \
|
"-ldflags=${GO_LDFLAGS[*]}" \
|
||||||
-o="../${out}/etcd" . || return 2
|
-o="../${out}/etcd" . || return 2
|
||||||
@ -51,7 +58,8 @@ etcd_build() {
|
|||||||
# shellcheck disable=SC2086
|
# shellcheck disable=SC2086
|
||||||
(
|
(
|
||||||
cd ./etcdutl
|
cd ./etcdutl
|
||||||
run env GO_BUILD_FLAGS="${GO_BUILD_FLAGS}" "${GO_BUILD_ENV[@]}" go build $GO_BUILD_FLAGS \
|
run env GO_BUILD_FLAGS="${GO_BUILD_FLAGS:-}" "${GO_BUILD_ENV[@]}" go build ${GO_BUILD_FLAGS:-} \
|
||||||
|
-trimpath \
|
||||||
-installsuffix=cgo \
|
-installsuffix=cgo \
|
||||||
"-ldflags=${GO_LDFLAGS[*]}" \
|
"-ldflags=${GO_LDFLAGS[*]}" \
|
||||||
-o="../${out}/etcdutl" . || return 2
|
-o="../${out}/etcdutl" . || return 2
|
||||||
@ -61,7 +69,8 @@ etcd_build() {
|
|||||||
# shellcheck disable=SC2086
|
# shellcheck disable=SC2086
|
||||||
(
|
(
|
||||||
cd ./etcdctl
|
cd ./etcdctl
|
||||||
run env GO_BUILD_FLAGS="${GO_BUILD_FLAGS}" "${GO_BUILD_ENV[@]}" go build $GO_BUILD_FLAGS \
|
run env GO_BUILD_FLAGS="${GO_BUILD_FLAGS:-}" "${GO_BUILD_ENV[@]}" go build ${GO_BUILD_FLAGS:-} \
|
||||||
|
-trimpath \
|
||||||
-installsuffix=cgo \
|
-installsuffix=cgo \
|
||||||
"-ldflags=${GO_LDFLAGS[*]}" \
|
"-ldflags=${GO_LDFLAGS[*]}" \
|
||||||
-o="../${out}/etcdctl" . || return 2
|
-o="../${out}/etcdctl" . || return 2
|
||||||
@ -81,7 +90,7 @@ etcd_build() {
|
|||||||
|
|
||||||
tools_build() {
|
tools_build() {
|
||||||
out="bin"
|
out="bin"
|
||||||
if [[ -n "${BINDIR}" ]]; then out="${BINDIR}"; fi
|
if [[ -n "${BINDIR:-}" ]]; then out="${BINDIR}"; fi
|
||||||
tools_path="tools/benchmark
|
tools_path="tools/benchmark
|
||||||
tools/etcd-dump-db
|
tools/etcd-dump-db
|
||||||
tools/etcd-dump-logs
|
tools/etcd-dump-logs
|
||||||
@ -91,9 +100,10 @@ tools_build() {
|
|||||||
echo "Building" "'${tool}'"...
|
echo "Building" "'${tool}'"...
|
||||||
run rm -f "${out}/${tool}"
|
run rm -f "${out}/${tool}"
|
||||||
# shellcheck disable=SC2086
|
# shellcheck disable=SC2086
|
||||||
run env GO_BUILD_FLAGS="${GO_BUILD_FLAGS}" CGO_ENABLED=0 go build ${GO_BUILD_FLAGS} \
|
run env GO_BUILD_FLAGS="${GO_BUILD_FLAGS:-}" CGO_ENABLED=0 go build ${GO_BUILD_FLAGS:-} \
|
||||||
|
-trimpath \
|
||||||
-installsuffix=cgo \
|
-installsuffix=cgo \
|
||||||
"-ldflags='${GO_LDFLAGS[*]}'" \
|
"-ldflags=${GO_LDFLAGS[*]}" \
|
||||||
-o="${out}/${tool}" "./${tool}" || return 2
|
-o="${out}/${tool}" "./${tool}" || return 2
|
||||||
done
|
done
|
||||||
tests_build "${@}"
|
tests_build "${@}"
|
||||||
@ -101,7 +111,7 @@ tools_build() {
|
|||||||
|
|
||||||
tests_build() {
|
tests_build() {
|
||||||
out="bin"
|
out="bin"
|
||||||
if [[ -n "${BINDIR}" ]]; then out="${BINDIR}"; fi
|
if [[ -n "${BINDIR:-}" ]]; then out="${BINDIR}"; fi
|
||||||
tools_path="
|
tools_path="
|
||||||
functional/cmd/etcd-agent
|
functional/cmd/etcd-agent
|
||||||
functional/cmd/etcd-proxy
|
functional/cmd/etcd-proxy
|
||||||
@ -114,9 +124,9 @@ tests_build() {
|
|||||||
run rm -f "../${out}/${tool}"
|
run rm -f "../${out}/${tool}"
|
||||||
|
|
||||||
# shellcheck disable=SC2086
|
# shellcheck disable=SC2086
|
||||||
run env CGO_ENABLED=0 GO_BUILD_FLAGS="${GO_BUILD_FLAGS}" go build ${GO_BUILD_FLAGS} \
|
run env CGO_ENABLED=0 GO_BUILD_FLAGS="${GO_BUILD_FLAGS:-}" go build ${GO_BUILD_FLAGS:-} \
|
||||||
-installsuffix=cgo \
|
-installsuffix=cgo \
|
||||||
"-ldflags='${GO_LDFLAGS[*]}'" \
|
"-ldflags=${GO_LDFLAGS[*]}" \
|
||||||
-o="../${out}/${tool}" "./${tool}" || return 2
|
-o="../${out}/${tool}" "./${tool}" || return 2
|
||||||
done
|
done
|
||||||
) || return 2
|
) || return 2
|
||||||
|
@ -44,16 +44,12 @@ func IsDirWriteable(dir string) error {
|
|||||||
|
|
||||||
// TouchDirAll is similar to os.MkdirAll. It creates directories with 0700 permission if any directory
|
// TouchDirAll is similar to os.MkdirAll. It creates directories with 0700 permission if any directory
|
||||||
// does not exists. TouchDirAll also ensures the given directory is writable.
|
// does not exists. TouchDirAll also ensures the given directory is writable.
|
||||||
func TouchDirAll(dir string) error {
|
func TouchDirAll(lg *zap.Logger, dir string) error {
|
||||||
// If path is already a directory, MkdirAll does nothing and returns nil, so,
|
// If path is already a directory, MkdirAll does nothing and returns nil, so,
|
||||||
// first check if dir exist with an expected permission mode.
|
// first check if dir exist with an expected permission mode.
|
||||||
if Exist(dir) {
|
if Exist(dir) {
|
||||||
err := CheckDirPermission(dir, PrivateDirMode)
|
err := CheckDirPermission(dir, PrivateDirMode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
lg, _ := zap.NewProduction()
|
|
||||||
if lg == nil {
|
|
||||||
lg = zap.NewExample()
|
|
||||||
}
|
|
||||||
lg.Warn("check file permission", zap.Error(err))
|
lg.Warn("check file permission", zap.Error(err))
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -70,8 +66,8 @@ func TouchDirAll(dir string) error {
|
|||||||
|
|
||||||
// CreateDirAll is similar to TouchDirAll but returns error
|
// CreateDirAll is similar to TouchDirAll but returns error
|
||||||
// if the deepest directory was not empty.
|
// if the deepest directory was not empty.
|
||||||
func CreateDirAll(dir string) error {
|
func CreateDirAll(lg *zap.Logger, dir string) error {
|
||||||
err := TouchDirAll(dir)
|
err := TouchDirAll(lg, dir)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
var ns []string
|
var ns []string
|
||||||
ns, err = ReadDir(dir)
|
ns, err = ReadDir(dir)
|
||||||
|
@ -67,7 +67,7 @@ func TestCreateDirAll(t *testing.T) {
|
|||||||
defer os.RemoveAll(tmpdir)
|
defer os.RemoveAll(tmpdir)
|
||||||
|
|
||||||
tmpdir2 := filepath.Join(tmpdir, "testdir")
|
tmpdir2 := filepath.Join(tmpdir, "testdir")
|
||||||
if err = CreateDirAll(tmpdir2); err != nil {
|
if err = CreateDirAll(zaptest.NewLogger(t), tmpdir2); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,7 +75,7 @@ func TestCreateDirAll(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err = CreateDirAll(tmpdir2); err == nil || !strings.Contains(err.Error(), "to be empty, got") {
|
if err = CreateDirAll(zaptest.NewLogger(t), tmpdir2); err == nil || !strings.Contains(err.Error(), "to be empty, got") {
|
||||||
t.Fatalf("unexpected error %v", err)
|
t.Fatalf("unexpected error %v", err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -186,7 +186,7 @@ func TestDirPermission(t *testing.T) {
|
|||||||
|
|
||||||
tmpdir2 := filepath.Join(tmpdir, "testpermission")
|
tmpdir2 := filepath.Join(tmpdir, "testpermission")
|
||||||
// create a new dir with 0700
|
// create a new dir with 0700
|
||||||
if err = CreateDirAll(tmpdir2); err != nil {
|
if err = CreateDirAll(zaptest.NewLogger(t), tmpdir2); err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
// check dir permission with mode different than created dir
|
// check dir permission with mode different than created dir
|
||||||
|
@ -41,6 +41,12 @@ func purgeFile(lg *zap.Logger, dirname string, suffix string, max uint, interval
|
|||||||
lg = zap.NewNop()
|
lg = zap.NewNop()
|
||||||
}
|
}
|
||||||
errC := make(chan error, 1)
|
errC := make(chan error, 1)
|
||||||
|
lg.Info("started to purge file",
|
||||||
|
zap.String("dir", dirname),
|
||||||
|
zap.String("suffix", suffix),
|
||||||
|
zap.Uint("max", max),
|
||||||
|
zap.Duration("interval", interval))
|
||||||
|
|
||||||
go func() {
|
go func() {
|
||||||
if donec != nil {
|
if donec != nil {
|
||||||
defer close(donec)
|
defer close(donec)
|
||||||
@ -63,14 +69,16 @@ func purgeFile(lg *zap.Logger, dirname string, suffix string, max uint, interval
|
|||||||
f := filepath.Join(dirname, newfnames[0])
|
f := filepath.Join(dirname, newfnames[0])
|
||||||
l, err := TryLockFile(f, os.O_WRONLY, PrivateFileMode)
|
l, err := TryLockFile(f, os.O_WRONLY, PrivateFileMode)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
lg.Warn("failed to lock file", zap.String("path", f), zap.Error(err))
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
if err = os.Remove(f); err != nil {
|
if err = os.Remove(f); err != nil {
|
||||||
|
lg.Error("failed to remove file", zap.String("path", f), zap.Error(err))
|
||||||
errC <- err
|
errC <- err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if err = l.Close(); err != nil {
|
if err = l.Close(); err != nil {
|
||||||
lg.Warn("failed to unlock/close", zap.String("path", l.Name()), zap.Error(err))
|
lg.Error("failed to unlock/close", zap.String("path", l.Name()), zap.Error(err))
|
||||||
errC <- err
|
errC <- err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,18 @@
|
|||||||
module go.etcd.io/etcd/client/pkg/v3
|
module go.etcd.io/etcd/client/pkg/v3
|
||||||
|
|
||||||
go 1.16
|
go 1.19
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/coreos/go-systemd/v22 v22.3.2
|
github.com/coreos/go-systemd/v22 v22.3.2
|
||||||
github.com/stretchr/testify v1.7.0
|
github.com/stretchr/testify v1.8.1
|
||||||
go.uber.org/zap v1.17.0
|
go.uber.org/zap v1.17.0
|
||||||
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57
|
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57
|
||||||
)
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
|
go.uber.org/atomic v1.7.0 // indirect
|
||||||
|
go.uber.org/multierr v1.6.0 // indirect
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
|
)
|
||||||
|
@ -9,9 +9,14 @@ github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINE
|
|||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/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/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
|
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||||
|
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
|
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
|
||||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||||
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
|
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
|
||||||
@ -25,5 +30,6 @@ gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8
|
|||||||
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
gopkg.in/yaml.v2 v2.2.8 h1:obN1ZagJSUGI0Ek/LBmuj4SNLPfIny3KsKFopxRdj10=
|
||||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
@ -16,6 +16,7 @@ package logutil
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"sort"
|
"sort"
|
||||||
|
"time"
|
||||||
|
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"go.uber.org/zap/zapcore"
|
"go.uber.org/zap/zapcore"
|
||||||
@ -46,15 +47,20 @@ var DefaultZapLoggerConfig = zap.Config{
|
|||||||
|
|
||||||
// copied from "zap.NewProductionEncoderConfig" with some updates
|
// copied from "zap.NewProductionEncoderConfig" with some updates
|
||||||
EncoderConfig: zapcore.EncoderConfig{
|
EncoderConfig: zapcore.EncoderConfig{
|
||||||
TimeKey: "ts",
|
TimeKey: "ts",
|
||||||
LevelKey: "level",
|
LevelKey: "level",
|
||||||
NameKey: "logger",
|
NameKey: "logger",
|
||||||
CallerKey: "caller",
|
CallerKey: "caller",
|
||||||
MessageKey: "msg",
|
MessageKey: "msg",
|
||||||
StacktraceKey: "stacktrace",
|
StacktraceKey: "stacktrace",
|
||||||
LineEnding: zapcore.DefaultLineEnding,
|
LineEnding: zapcore.DefaultLineEnding,
|
||||||
EncodeLevel: zapcore.LowercaseLevelEncoder,
|
EncodeLevel: zapcore.LowercaseLevelEncoder,
|
||||||
EncodeTime: zapcore.ISO8601TimeEncoder,
|
|
||||||
|
// Custom EncodeTime function to ensure we match format and precision of historic capnslog timestamps
|
||||||
|
EncodeTime: func(t time.Time, enc zapcore.PrimitiveArrayEncoder) {
|
||||||
|
enc.AppendString(t.Format("2006-01-02T15:04:05.999999Z0700"))
|
||||||
|
},
|
||||||
|
|
||||||
EncodeDuration: zapcore.StringDurationEncoder,
|
EncodeDuration: zapcore.StringDurationEncoder,
|
||||||
EncodeCaller: zapcore.ShortCallerEncoder,
|
EncodeCaller: zapcore.ShortCallerEncoder,
|
||||||
},
|
},
|
||||||
|
@ -14,7 +14,10 @@
|
|||||||
|
|
||||||
package tlsutil
|
package tlsutil
|
||||||
|
|
||||||
import "crypto/tls"
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
// GetCipherSuite returns the corresponding cipher suite,
|
// GetCipherSuite returns the corresponding cipher suite,
|
||||||
// and boolean value if it is supported.
|
// and boolean value if it is supported.
|
||||||
@ -37,3 +40,17 @@ func GetCipherSuite(s string) (uint16, bool) {
|
|||||||
}
|
}
|
||||||
return 0, false
|
return 0, false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// GetCipherSuites returns list of corresponding cipher suite IDs.
|
||||||
|
func GetCipherSuites(ss []string) ([]uint16, error) {
|
||||||
|
cs := make([]uint16, len(ss))
|
||||||
|
for i, s := range ss {
|
||||||
|
var ok bool
|
||||||
|
cs[i], ok = GetCipherSuite(s)
|
||||||
|
if !ok {
|
||||||
|
return nil, fmt.Errorf("unexpected TLS cipher suite %q", s)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return cs, nil
|
||||||
|
}
|
||||||
|
47
client/pkg/tlsutil/versions.go
Normal file
47
client/pkg/tlsutil/versions.go
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
// Copyright 2023 The etcd Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package tlsutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
type TLSVersion string
|
||||||
|
|
||||||
|
// Constants for TLS versions.
|
||||||
|
const (
|
||||||
|
TLSVersionDefault TLSVersion = ""
|
||||||
|
TLSVersion12 TLSVersion = "TLS1.2"
|
||||||
|
TLSVersion13 TLSVersion = "TLS1.3"
|
||||||
|
)
|
||||||
|
|
||||||
|
// GetTLSVersion returns the corresponding tls.Version or error.
|
||||||
|
func GetTLSVersion(version string) (uint16, error) {
|
||||||
|
var v uint16
|
||||||
|
|
||||||
|
switch version {
|
||||||
|
case string(TLSVersionDefault):
|
||||||
|
v = 0 // 0 means let Go decide.
|
||||||
|
case string(TLSVersion12):
|
||||||
|
v = tls.VersionTLS12
|
||||||
|
case string(TLSVersion13):
|
||||||
|
v = tls.VersionTLS13
|
||||||
|
default:
|
||||||
|
return 0, fmt.Errorf("unexpected TLS version %q (must be one of: TLS1.2, TLS1.3)", version)
|
||||||
|
}
|
||||||
|
|
||||||
|
return v, nil
|
||||||
|
}
|
63
client/pkg/tlsutil/versions_test.go
Normal file
63
client/pkg/tlsutil/versions_test.go
Normal file
@ -0,0 +1,63 @@
|
|||||||
|
// Copyright 2023 The etcd Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package tlsutil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"testing"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestGetVersion(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
version string
|
||||||
|
want uint16
|
||||||
|
expectError bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "TLS1.2",
|
||||||
|
version: "TLS1.2",
|
||||||
|
want: tls.VersionTLS12,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "TLS1.3",
|
||||||
|
version: "TLS1.3",
|
||||||
|
want: tls.VersionTLS13,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Empty version",
|
||||||
|
version: "",
|
||||||
|
want: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Converting invalid version string to TLS version",
|
||||||
|
version: "not_existing",
|
||||||
|
expectError: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
got, err := GetTLSVersion(tt.version)
|
||||||
|
if err != nil {
|
||||||
|
assert.True(t, tt.expectError, "GetTLSVersion() returned error while expecting success: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
assert.Equal(t, tt.want, got)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
@ -165,6 +165,14 @@ type TLSInfo struct {
|
|||||||
// Note that cipher suites are prioritized in the given order.
|
// Note that cipher suites are prioritized in the given order.
|
||||||
CipherSuites []uint16
|
CipherSuites []uint16
|
||||||
|
|
||||||
|
// MinVersion is the minimum TLS version that is acceptable.
|
||||||
|
// If not set, the minimum version is TLS 1.2.
|
||||||
|
MinVersion uint16
|
||||||
|
|
||||||
|
// MaxVersion is the maximum TLS version that is acceptable.
|
||||||
|
// If not set, the default used by Go is selected (see tls.Config.MaxVersion).
|
||||||
|
MaxVersion uint16
|
||||||
|
|
||||||
selfCert bool
|
selfCert bool
|
||||||
|
|
||||||
// parseFunc exists to simplify testing. Typically, parseFunc
|
// parseFunc exists to simplify testing. Typically, parseFunc
|
||||||
@ -205,7 +213,7 @@ func SelfCert(lg *zap.Logger, dirpath string, hosts []string, selfSignedCertVali
|
|||||||
)
|
)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
err = fileutil.TouchDirAll(dirpath)
|
err = fileutil.TouchDirAll(lg, dirpath)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if info.Logger != nil {
|
if info.Logger != nil {
|
||||||
info.Logger.Warn(
|
info.Logger.Warn(
|
||||||
@ -339,8 +347,8 @@ func SelfCert(lg *zap.Logger, dirpath string, hosts []string, selfSignedCertVali
|
|||||||
// Previously,
|
// Previously,
|
||||||
// 1. Server has non-empty (*tls.Config).Certificates on client hello
|
// 1. Server has non-empty (*tls.Config).Certificates on client hello
|
||||||
// 2. Server calls (*tls.Config).GetCertificate iff:
|
// 2. Server calls (*tls.Config).GetCertificate iff:
|
||||||
// - Server's (*tls.Config).Certificates is not empty, or
|
// - Server's (*tls.Config).Certificates is not empty, or
|
||||||
// - Client supplies SNI; non-empty (*tls.ClientHelloInfo).ServerName
|
// - Client supplies SNI; non-empty (*tls.ClientHelloInfo).ServerName
|
||||||
//
|
//
|
||||||
// When (*tls.Config).Certificates is always populated on initial handshake,
|
// When (*tls.Config).Certificates is always populated on initial handshake,
|
||||||
// client is expected to provide a valid matching SNI to pass the TLS
|
// client is expected to provide a valid matching SNI to pass the TLS
|
||||||
@ -378,8 +386,17 @@ func (info TLSInfo) baseConfig() (*tls.Config, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var minVersion uint16
|
||||||
|
if info.MinVersion != 0 {
|
||||||
|
minVersion = info.MinVersion
|
||||||
|
} else {
|
||||||
|
// Default minimum version is TLS 1.2, previous versions are insecure and deprecated.
|
||||||
|
minVersion = tls.VersionTLS12
|
||||||
|
}
|
||||||
|
|
||||||
cfg := &tls.Config{
|
cfg := &tls.Config{
|
||||||
MinVersion: tls.VersionTLS12,
|
MinVersion: minVersion,
|
||||||
|
MaxVersion: info.MaxVersion,
|
||||||
ServerName: info.ServerName,
|
ServerName: info.ServerName,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -510,11 +527,6 @@ func (info TLSInfo) ServerConfig() (*tls.Config, error) {
|
|||||||
// "h2" NextProtos is necessary for enabling HTTP2 for go's HTTP server
|
// "h2" NextProtos is necessary for enabling HTTP2 for go's HTTP server
|
||||||
cfg.NextProtos = []string{"h2"}
|
cfg.NextProtos = []string{"h2"}
|
||||||
|
|
||||||
// go1.13 enables TLS 1.3 by default
|
|
||||||
// and in TLS 1.3, cipher suites are not configurable
|
|
||||||
// setting Max TLS version to TLS 1.2 for go 1.13
|
|
||||||
cfg.MaxVersion = tls.VersionTLS12
|
|
||||||
|
|
||||||
return cfg, nil
|
return cfg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -569,11 +581,6 @@ func (info TLSInfo) ClientConfig() (*tls.Config, error) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// go1.13 enables TLS 1.3 by default
|
|
||||||
// and in TLS 1.3, cipher suites are not configurable
|
|
||||||
// setting Max TLS version to TLS 1.2 for go 1.13
|
|
||||||
cfg.MaxVersion = tls.VersionTLS12
|
|
||||||
|
|
||||||
return cfg, nil
|
return cfg, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
35
client/pkg/transport/sockopt_solaris.go
Normal file
35
client/pkg/transport/sockopt_solaris.go
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
// Copyright 2021 The etcd Authors
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
//go:build solaris
|
||||||
|
// +build solaris
|
||||||
|
|
||||||
|
package transport
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"syscall"
|
||||||
|
|
||||||
|
"golang.org/x/sys/unix"
|
||||||
|
)
|
||||||
|
|
||||||
|
func setReusePort(network, address string, c syscall.RawConn) error {
|
||||||
|
return fmt.Errorf("port reuse is not supported on Solaris")
|
||||||
|
}
|
||||||
|
|
||||||
|
func setReuseAddress(network, address string, conn syscall.RawConn) error {
|
||||||
|
return conn.Control(func(fd uintptr) {
|
||||||
|
syscall.SetsockoptInt(int(fd), syscall.SOL_SOCKET, unix.SO_REUSEADDR, 1)
|
||||||
|
})
|
||||||
|
}
|
@ -1,5 +1,19 @@
|
|||||||
//go:build !windows
|
// Copyright 2021 The etcd Authors
|
||||||
// +build !windows
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
//go:build !windows && !solaris
|
||||||
|
// +build !windows,!solaris
|
||||||
|
|
||||||
package transport
|
package transport
|
||||||
|
|
||||||
|
@ -68,6 +68,5 @@ Use a custom context to set timeouts on your operations:
|
|||||||
// handle error
|
// handle error
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*/
|
*/
|
||||||
package client
|
package client
|
||||||
|
@ -1,12 +1,17 @@
|
|||||||
module go.etcd.io/etcd/client/v2
|
module go.etcd.io/etcd/client/v2
|
||||||
|
|
||||||
go 1.16
|
go 1.19
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/json-iterator/go v1.1.11
|
github.com/json-iterator/go v1.1.11
|
||||||
github.com/modern-go/reflect2 v1.0.1
|
github.com/modern-go/reflect2 v1.0.1
|
||||||
go.etcd.io/etcd/api/v3 v3.5.5
|
go.etcd.io/etcd/api/v3 v3.5.9
|
||||||
go.etcd.io/etcd/client/pkg/v3 v3.5.5
|
go.etcd.io/etcd/client/pkg/v3 v3.5.9
|
||||||
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/coreos/go-semver v0.3.0 // indirect
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
replace (
|
replace (
|
||||||
|
156
client/v2/go.sum
156
client/v2/go.sum
@ -1,172 +1,20 @@
|
|||||||
cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
|
||||||
cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw=
|
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
|
||||||
github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY=
|
|
||||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
|
||||||
github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
|
||||||
github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw=
|
|
||||||
github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGXZJjfX53e64911xZQV5JYwmTeXPW+k8Sc=
|
|
||||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
|
||||||
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
|
||||||
github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM=
|
github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM=
|
||||||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||||
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
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/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
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=
|
|
||||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
|
||||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk=
|
|
||||||
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
|
|
||||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
|
||||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
|
||||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
|
||||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
|
||||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
|
||||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
|
||||||
github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
|
||||||
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
|
|
||||||
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
|
|
||||||
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
|
|
||||||
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
|
|
||||||
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
|
|
||||||
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
|
|
||||||
github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8=
|
|
||||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
|
||||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
|
||||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
|
||||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
|
||||||
github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M=
|
|
||||||
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
|
||||||
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
|
|
||||||
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
|
||||||
github.com/google/go-cmp v0.5.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
|
||||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
|
||||||
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
|
||||||
github.com/google/uuid v1.1.2/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
|
|
||||||
github.com/grpc-ecosystem/grpc-gateway v1.16.0/go.mod h1:BDjrQk3hbvj6Nolgz8mAMFbcEtjT1g+wF4CSlocrBnw=
|
|
||||||
github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ=
|
github.com/json-iterator/go v1.1.11 h1:uVUAXhF2To8cbw/3xN3pxj6kk7TYKs98NIrTqPlMWAQ=
|
||||||
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
github.com/json-iterator/go v1.1.11/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
|
||||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
|
||||||
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
|
||||||
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
|
github.com/modern-go/reflect2 v1.0.1 h1:9f412s+6RmYXLWZSEzVVgPGK7C2PphHj5RJrvfx9AWI=
|
||||||
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
|
||||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA=
|
|
||||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
|
||||||
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=
|
|
||||||
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
|
||||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
|
||||||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
|
||||||
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
|
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
|
||||||
golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA=
|
|
||||||
golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE=
|
|
||||||
golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU=
|
|
||||||
golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc=
|
|
||||||
golang.org/x/lint v0.0.0-20210508222113-6edffad5e616/go.mod h1:3xt1FjdF8hUf6vQPIChWIBhFzV8gjjsPE/fR3IyQdNY=
|
|
||||||
golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg=
|
|
||||||
golang.org/x/mod v0.2.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
|
||||||
golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
|
||||||
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
|
|
||||||
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
|
||||||
golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
|
||||||
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
|
|
||||||
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
|
|
||||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
|
||||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
|
||||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
|
||||||
golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
|
||||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
|
||||||
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.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
|
||||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
|
||||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
|
||||||
golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q=
|
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
|
||||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
|
||||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
|
||||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
|
||||||
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
|
||||||
google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM=
|
|
||||||
google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4=
|
|
||||||
google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc=
|
|
||||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
|
||||||
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
|
||||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
|
||||||
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
|
|
||||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
|
||||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
|
||||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
|
||||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
|
||||||
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
|
|
||||||
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
|
||||||
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
|
||||||
google.golang.org/grpc v1.41.0/go.mod h1:U3l9uK9J0sini8mHphKoXyaqDA/8VyGnDee1zzIUK6k=
|
|
||||||
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
|
|
||||||
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
|
|
||||||
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
|
|
||||||
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
|
|
||||||
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
|
|
||||||
google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
|
||||||
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
|
||||||
google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=
|
|
||||||
google.golang.org/protobuf v1.25.0/go.mod h1:9JNX74DMeImyA3h4bdi1ymwjUzf21/xIlbajtzgsN7c=
|
|
||||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
|
||||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
|
||||||
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|
||||||
gopkg.in/yaml.v2 v2.2.3/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|
||||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|
||||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
|
||||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
|
||||||
|
@ -61,7 +61,8 @@
|
|||||||
//
|
//
|
||||||
// 1. context error: canceled or deadline exceeded.
|
// 1. context error: canceled or deadline exceeded.
|
||||||
// 2. gRPC error: e.g. when clock drifts in server-side before client's context deadline exceeded.
|
// 2. gRPC error: e.g. when clock drifts in server-side before client's context deadline exceeded.
|
||||||
// See https://github.com/etcd-io/etcd/blob/main/api/v3rpc/rpctypes/error.go
|
//
|
||||||
|
// See https://github.com/etcd-io/etcd/blob/main/api/v3rpc/rpctypes/error.go
|
||||||
//
|
//
|
||||||
// Here is the example code to handle client errors:
|
// Here is the example code to handle client errors:
|
||||||
//
|
//
|
||||||
@ -102,5 +103,4 @@
|
|||||||
// The grpc load balancer is registered statically and is shared across etcd clients.
|
// The grpc load balancer is registered statically and is shared across etcd clients.
|
||||||
// To enable detailed load balancer logging, set the ETCD_CLIENT_DEBUG environment
|
// To enable detailed load balancer logging, set the ETCD_CLIENT_DEBUG environment
|
||||||
// variable. E.g. "ETCD_CLIENT_DEBUG=1".
|
// variable. E.g. "ETCD_CLIENT_DEBUG=1".
|
||||||
//
|
|
||||||
package clientv3
|
package clientv3
|
||||||
|
@ -45,25 +45,46 @@ func NewDoubleBarrier(s *concurrency.Session, key string, count int) *DoubleBarr
|
|||||||
// Enter waits for "count" processes to enter the barrier then returns
|
// Enter waits for "count" processes to enter the barrier then returns
|
||||||
func (b *DoubleBarrier) Enter() error {
|
func (b *DoubleBarrier) Enter() error {
|
||||||
client := b.s.Client()
|
client := b.s.Client()
|
||||||
|
|
||||||
|
// Check the entered clients before creating the UniqueEphemeralKey,
|
||||||
|
// fail the request if there are already too many clients.
|
||||||
|
if resp1, err := b.enteredClients(client); err != nil {
|
||||||
|
return err
|
||||||
|
} else if len(resp1.Kvs) >= b.count {
|
||||||
|
return ErrTooManyClients
|
||||||
|
}
|
||||||
|
|
||||||
ek, err := newUniqueEphemeralKey(b.s, b.key+"/waiters")
|
ek, err := newUniqueEphemeralKey(b.s, b.key+"/waiters")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
b.myKey = ek
|
b.myKey = ek
|
||||||
|
|
||||||
resp, err := client.Get(b.ctx, b.key+"/waiters", clientv3.WithPrefix())
|
// Check the entered clients after creating the UniqueEphemeralKey
|
||||||
|
resp2, err := b.enteredClients(client)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if len(resp2.Kvs) >= b.count {
|
||||||
|
lastWaiter := resp2.Kvs[b.count-1]
|
||||||
|
if ek.rev > lastWaiter.CreateRevision {
|
||||||
|
// delete itself now, otherwise other processes may need to wait
|
||||||
|
// until these keys are automatically deleted when the related
|
||||||
|
// lease expires.
|
||||||
|
if err = b.myKey.Delete(); err != nil {
|
||||||
|
// Nothing to do here. We have to wait for the key to be
|
||||||
|
// deleted when the lease expires.
|
||||||
|
}
|
||||||
|
return ErrTooManyClients
|
||||||
|
}
|
||||||
|
|
||||||
if len(resp.Kvs) > b.count {
|
if ek.rev == lastWaiter.CreateRevision {
|
||||||
return ErrTooManyClients
|
// TODO(ahrtr): we might need to compare ek.key and
|
||||||
}
|
// string(lastWaiter.Key), they should be equal.
|
||||||
|
// unblock all other waiters
|
||||||
if len(resp.Kvs) == b.count {
|
_, err = client.Put(b.ctx, b.key+"/ready", "")
|
||||||
// unblock waiters
|
return err
|
||||||
_, err = client.Put(b.ctx, b.key+"/ready", "")
|
}
|
||||||
return err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = WaitEvents(
|
_, err = WaitEvents(
|
||||||
@ -74,6 +95,18 @@ func (b *DoubleBarrier) Enter() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// enteredClients gets all the entered clients, which are ordered by the
|
||||||
|
// createRevision in ascending order.
|
||||||
|
func (b *DoubleBarrier) enteredClients(cli *clientv3.Client) (*clientv3.GetResponse, error) {
|
||||||
|
resp, err := cli.Get(b.ctx, b.key+"/waiters", clientv3.WithPrefix(),
|
||||||
|
clientv3.WithSort(clientv3.SortByCreateRevision, clientv3.SortAscend))
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
// Leave waits for "count" processes to leave the barrier then returns
|
// Leave waits for "count" processes to leave the barrier then returns
|
||||||
func (b *DoubleBarrier) Leave() error {
|
func (b *DoubleBarrier) Leave() error {
|
||||||
client := b.s.Client()
|
client := b.s.Client()
|
||||||
@ -96,7 +129,7 @@ func (b *DoubleBarrier) Leave() error {
|
|||||||
}
|
}
|
||||||
isLowest := string(lowest.Key) == b.myKey.Key()
|
isLowest := string(lowest.Key) == b.myKey.Key()
|
||||||
|
|
||||||
if len(resp.Kvs) == 1 {
|
if len(resp.Kvs) == 1 && isLowest {
|
||||||
// this is the only node in the barrier; finish up
|
// this is the only node in the barrier; finish up
|
||||||
if _, err = client.Delete(b.ctx, b.key+"/ready"); err != nil {
|
if _, err = client.Delete(b.ctx, b.key+"/ready"); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -1,18 +1,39 @@
|
|||||||
module go.etcd.io/etcd/client/v3
|
module go.etcd.io/etcd/client/v3
|
||||||
|
|
||||||
go 1.16
|
go 1.19
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/dustin/go-humanize v1.0.0
|
github.com/dustin/go-humanize v1.0.0
|
||||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0
|
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0
|
||||||
github.com/prometheus/client_golang v1.11.1
|
github.com/prometheus/client_golang v1.11.1
|
||||||
go.etcd.io/etcd/api/v3 v3.5.5
|
go.etcd.io/etcd/api/v3 v3.5.9
|
||||||
go.etcd.io/etcd/client/pkg/v3 v3.5.5
|
go.etcd.io/etcd/client/pkg/v3 v3.5.9
|
||||||
go.uber.org/zap v1.17.0
|
go.uber.org/zap v1.17.0
|
||||||
google.golang.org/grpc v1.41.0
|
google.golang.org/grpc v1.41.0
|
||||||
sigs.k8s.io/yaml v1.2.0
|
sigs.k8s.io/yaml v1.2.0
|
||||||
)
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
|
github.com/cespare/xxhash/v2 v2.1.1 // indirect
|
||||||
|
github.com/coreos/go-semver v0.3.0 // indirect
|
||||||
|
github.com/coreos/go-systemd/v22 v22.3.2 // indirect
|
||||||
|
github.com/gogo/protobuf v1.3.2 // indirect
|
||||||
|
github.com/golang/protobuf v1.5.2 // indirect
|
||||||
|
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
|
||||||
|
github.com/prometheus/client_model v0.2.0 // indirect
|
||||||
|
github.com/prometheus/common v0.26.0 // indirect
|
||||||
|
github.com/prometheus/procfs v0.6.0 // indirect
|
||||||
|
go.uber.org/atomic v1.7.0 // indirect
|
||||||
|
go.uber.org/multierr v1.6.0 // indirect
|
||||||
|
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 // indirect
|
||||||
|
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40 // indirect
|
||||||
|
golang.org/x/text v0.3.5 // indirect
|
||||||
|
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c // indirect
|
||||||
|
google.golang.org/protobuf v1.26.0 // indirect
|
||||||
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
|
)
|
||||||
|
|
||||||
replace (
|
replace (
|
||||||
go.etcd.io/etcd/api/v3 => ../../api
|
go.etcd.io/etcd/api/v3 => ../../api
|
||||||
go.etcd.io/etcd/client/pkg/v3 => ../pkg
|
go.etcd.io/etcd/client/pkg/v3 => ../pkg
|
||||||
|
@ -135,8 +135,8 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
|
|||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
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.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||||
@ -200,7 +200,6 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40 h1:JWgyZ1qgdTaF3N3oxC+MdTV7qvEEgHo3otj+HB5CM7Q=
|
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40 h1:JWgyZ1qgdTaF3N3oxC+MdTV7qvEEgHo3otj+HB5CM7Q=
|
||||||
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
@ -268,8 +267,8 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|||||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
|
sigs.k8s.io/yaml v1.2.0 h1:kr/MCeFWJWTwyaHoR9c8EjH9OumOmoF9YGiZd7lFm/Q=
|
||||||
|
@ -45,8 +45,8 @@ func extractHostFromPath(pathStr string) string {
|
|||||||
return extractHostFromHostPort(path.Base(pathStr))
|
return extractHostFromHostPort(path.Base(pathStr))
|
||||||
}
|
}
|
||||||
|
|
||||||
//mustSplit2 returns the values from strings.SplitN(s, sep, 2).
|
// mustSplit2 returns the values from strings.SplitN(s, sep, 2).
|
||||||
//If sep is not found, it returns ("", "", false) instead.
|
// If sep is not found, it returns ("", "", false) instead.
|
||||||
func mustSplit2(s, sep string) (string, string) {
|
func mustSplit2(s, sep string) (string, string) {
|
||||||
spl := strings.SplitN(s, sep, 2)
|
spl := strings.SplitN(s, sep, 2)
|
||||||
if len(spl) < 2 {
|
if len(spl) < 2 {
|
||||||
@ -81,11 +81,12 @@ func schemeToCredsRequirement(schema string) CredsRequirement {
|
|||||||
// The main differences:
|
// The main differences:
|
||||||
// - etcd supports unixs & https names as opposed to unix & http to
|
// - etcd supports unixs & https names as opposed to unix & http to
|
||||||
// distinguish need to configure certificates.
|
// distinguish need to configure certificates.
|
||||||
// - etcd support http(s) names as opposed to tcp supported by grpc/dial method.
|
// - etcd support http(s) names as opposed to tcp supported by grpc/dial method.
|
||||||
// - etcd supports unix(s)://local-file naming schema
|
// - etcd supports unix(s)://local-file naming schema
|
||||||
// (as opposed to unix:local-file canonical name used by grpc for current dir files).
|
// (as opposed to unix:local-file canonical name used by grpc for current dir files).
|
||||||
// - Within the unix(s) schemas, the last segment (filename) without 'port' (content after colon)
|
// - Within the unix(s) schemas, the last segment (filename) without 'port' (content after colon)
|
||||||
// is considered serverName - to allow local testing of cert-protected communication.
|
// is considered serverName - to allow local testing of cert-protected communication.
|
||||||
|
//
|
||||||
// See more:
|
// See more:
|
||||||
// - https://github.com/grpc/grpc-go/blob/26c143bd5f59344a4b8a1e491e0f5e18aa97abc7/internal/grpcutil/target.go#L47
|
// - https://github.com/grpc/grpc-go/blob/26c143bd5f59344a4b8a1e491e0f5e18aa97abc7/internal/grpcutil/target.go#L47
|
||||||
// - https://golang.org/pkg/net/#Dial
|
// - https://golang.org/pkg/net/#Dial
|
||||||
|
@ -19,28 +19,27 @@
|
|||||||
//
|
//
|
||||||
// First, create a leasing KV from a clientv3.Client 'cli':
|
// First, create a leasing KV from a clientv3.Client 'cli':
|
||||||
//
|
//
|
||||||
// lkv, err := leasing.NewKV(cli, "leasing-prefix")
|
// lkv, err := leasing.NewKV(cli, "leasing-prefix")
|
||||||
// if err != nil {
|
// if err != nil {
|
||||||
// // handle error
|
// // handle error
|
||||||
// }
|
// }
|
||||||
//
|
//
|
||||||
// A range request for a key "abc" tries to acquire a leasing key so it can cache the range's
|
// A range request for a key "abc" tries to acquire a leasing key so it can cache the range's
|
||||||
// key locally. On the server, the leasing key is stored to "leasing-prefix/abc":
|
// key locally. On the server, the leasing key is stored to "leasing-prefix/abc":
|
||||||
//
|
//
|
||||||
// resp, err := lkv.Get(context.TODO(), "abc")
|
// resp, err := lkv.Get(context.TODO(), "abc")
|
||||||
//
|
//
|
||||||
// Future linearized read requests using 'lkv' will be served locally for the lease's lifetime:
|
// Future linearized read requests using 'lkv' will be served locally for the lease's lifetime:
|
||||||
//
|
//
|
||||||
// resp, err = lkv.Get(context.TODO(), "abc")
|
// resp, err = lkv.Get(context.TODO(), "abc")
|
||||||
//
|
//
|
||||||
// If another leasing client writes to a leased key, then the owner relinquishes its exclusive
|
// If another leasing client writes to a leased key, then the owner relinquishes its exclusive
|
||||||
// access, permitting the writer to modify the key:
|
// access, permitting the writer to modify the key:
|
||||||
//
|
//
|
||||||
// lkv2, err := leasing.NewKV(cli, "leasing-prefix")
|
// lkv2, err := leasing.NewKV(cli, "leasing-prefix")
|
||||||
// if err != nil {
|
// if err != nil {
|
||||||
// // handle error
|
// // handle error
|
||||||
// }
|
// }
|
||||||
// lkv2.Put(context.TODO(), "abc", "456")
|
// lkv2.Put(context.TODO(), "abc", "456")
|
||||||
// resp, err = lkv.Get("abc")
|
// resp, err = lkv.Get("abc")
|
||||||
//
|
|
||||||
package leasing
|
package leasing
|
||||||
|
@ -92,6 +92,7 @@ func NewMaintenance(c *Client) Maintenance {
|
|||||||
err = c.getToken(dctx)
|
err = c.getToken(dctx)
|
||||||
cancel()
|
cancel()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
conn.Close()
|
||||||
return nil, nil, fmt.Errorf("failed to getToken from endpoint %s with maintenance client: %v", endpoint, err)
|
return nil, nil, fmt.Errorf("failed to getToken from endpoint %s with maintenance client: %v", endpoint, err)
|
||||||
}
|
}
|
||||||
cancel = func() { conn.Close() }
|
cancel = func() { conn.Close() }
|
||||||
|
@ -39,5 +39,4 @@
|
|||||||
// resp, _ = cli.Get(context.TODO(), "abc")
|
// resp, _ = cli.Get(context.TODO(), "abc")
|
||||||
// fmt.Printf("%s\n", resp.Kvs[0].Value)
|
// fmt.Printf("%s\n", resp.Kvs[0].Value)
|
||||||
// // Output: 456
|
// // Output: 456
|
||||||
//
|
|
||||||
package namespace
|
package namespace
|
||||||
|
@ -13,10 +13,10 @@
|
|||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
// Package naming provides:
|
// Package naming provides:
|
||||||
// - subpackage endpoints: an abstraction layer to store and read endpoints
|
// - subpackage endpoints: an abstraction layer to store and read endpoints
|
||||||
// information from etcd.
|
// information from etcd.
|
||||||
// - subpackage resolver: an etcd-backed gRPC resolver for discovering gRPC
|
// - subpackage resolver: an etcd-backed gRPC resolver for discovering gRPC
|
||||||
// services based on the endpoints configuration
|
// services based on the endpoints configuration
|
||||||
//
|
//
|
||||||
// To use, first import the packages:
|
// To use, first import the packages:
|
||||||
//
|
//
|
||||||
@ -55,5 +55,4 @@
|
|||||||
// em := endpoints.NewManager(c, service)
|
// em := endpoints.NewManager(c, service)
|
||||||
// return em.AddEndpoint(c.Ctx(), service+"/"+addr, endpoints.Endpoint{Addr:addr}, clientv3.WithLease(lid));
|
// return em.AddEndpoint(c.Ctx(), service+"/"+addr, endpoints.Endpoint{Addr:addr}, clientv3.WithLease(lid));
|
||||||
// }
|
// }
|
||||||
//
|
|
||||||
package naming
|
package naming
|
||||||
|
@ -38,5 +38,4 @@
|
|||||||
// cli.KV = ordering.NewKV(cli.KV, vf)
|
// cli.KV = ordering.NewKV(cli.KV, vf)
|
||||||
//
|
//
|
||||||
// Now calls using 'cli' will reject order violations with an error.
|
// Now calls using 'cli' will reject order violations with an error.
|
||||||
//
|
|
||||||
package ordering
|
package ordering
|
||||||
|
@ -74,13 +74,7 @@ func (c *Client) unaryClientInterceptor(optFuncs ...retryOption) grpc.UnaryClien
|
|||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if c.shouldRefreshToken(lastErr, callOpts) {
|
if c.shouldRefreshToken(lastErr, callOpts) {
|
||||||
// clear auth token before refreshing it.
|
gterr := c.refreshToken(ctx)
|
||||||
// call c.Auth.Authenticate with an invalid token will always fail the auth check on the server-side,
|
|
||||||
// if the server has not apply the patch of pr #12165 (https://github.com/etcd-io/etcd/pull/12165)
|
|
||||||
// and a rpctypes.ErrInvalidAuthToken will recursively call c.getToken until system run out of resource.
|
|
||||||
c.authTokenBundle.UpdateAuthToken("")
|
|
||||||
|
|
||||||
gterr := c.getToken(ctx)
|
|
||||||
if gterr != nil {
|
if gterr != nil {
|
||||||
c.GetLogger().Warn(
|
c.GetLogger().Warn(
|
||||||
"retrying of unary invoker failed to fetch new auth token",
|
"retrying of unary invoker failed to fetch new auth token",
|
||||||
@ -161,6 +155,24 @@ func (c *Client) shouldRefreshToken(err error, callOpts *options) bool {
|
|||||||
(rpctypes.Error(err) == rpctypes.ErrInvalidAuthToken || rpctypes.Error(err) == rpctypes.ErrAuthOldRevision)
|
(rpctypes.Error(err) == rpctypes.ErrInvalidAuthToken || rpctypes.Error(err) == rpctypes.ErrAuthOldRevision)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (c *Client) refreshToken(ctx context.Context) error {
|
||||||
|
if c.authTokenBundle == nil {
|
||||||
|
// c.authTokenBundle will be initialized only when
|
||||||
|
// c.Username != "" && c.Password != "".
|
||||||
|
//
|
||||||
|
// When users use the TLS CommonName based authentication, the
|
||||||
|
// authTokenBundle is always nil. But it's possible for the clients
|
||||||
|
// to get `rpctypes.ErrAuthOldRevision` response when the clients
|
||||||
|
// concurrently modify auth data (e.g, addUser, deleteUser etc.).
|
||||||
|
// In this case, there is no need to refresh the token; instead the
|
||||||
|
// clients just need to retry the operations (e.g. Put, Delete etc).
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
// clear auth token before refreshing it.
|
||||||
|
c.authTokenBundle.UpdateAuthToken("")
|
||||||
|
return c.getToken(ctx)
|
||||||
|
}
|
||||||
|
|
||||||
// type serverStreamingRetryingStream is the implementation of grpc.ClientStream that acts as a
|
// type serverStreamingRetryingStream is the implementation of grpc.ClientStream that acts as a
|
||||||
// proxy to the underlying call. If any of the RecvMsg() calls fail, it will try to reestablish
|
// proxy to the underlying call. If any of the RecvMsg() calls fail, it will try to reestablish
|
||||||
// a new ClientStream according to the retry policy.
|
// a new ClientStream according to the retry policy.
|
||||||
@ -259,10 +271,7 @@ func (s *serverStreamingRetryingStream) receiveMsgAndIndicateRetry(m interface{}
|
|||||||
return true, err
|
return true, err
|
||||||
}
|
}
|
||||||
if s.client.shouldRefreshToken(err, s.callOpts) {
|
if s.client.shouldRefreshToken(err, s.callOpts) {
|
||||||
// clear auth token to avoid failure when call getToken
|
gterr := s.client.refreshToken(s.ctx)
|
||||||
s.client.authTokenBundle.UpdateAuthToken("")
|
|
||||||
|
|
||||||
gterr := s.client.getToken(s.ctx)
|
|
||||||
if gterr != nil {
|
if gterr != nil {
|
||||||
s.client.lg.Warn("retry failed to fetch new auth token", zap.Error(gterr))
|
s.client.lg.Warn("retry failed to fetch new auth token", zap.Error(gterr))
|
||||||
return false, err // return the original error for simplicity
|
return false, err // return the original error for simplicity
|
||||||
|
@ -25,15 +25,14 @@ import (
|
|||||||
|
|
||||||
// Txn is the interface that wraps mini-transactions.
|
// Txn is the interface that wraps mini-transactions.
|
||||||
//
|
//
|
||||||
// Txn(context.TODO()).If(
|
// Txn(context.TODO()).If(
|
||||||
// Compare(Value(k1), ">", v1),
|
// Compare(Value(k1), ">", v1),
|
||||||
// Compare(Version(k1), "=", 2)
|
// Compare(Version(k1), "=", 2)
|
||||||
// ).Then(
|
// ).Then(
|
||||||
// OpPut(k2,v2), OpPut(k3,v3)
|
// OpPut(k2,v2), OpPut(k3,v3)
|
||||||
// ).Else(
|
// ).Else(
|
||||||
// OpPut(k4,v4), OpPut(k5,v5)
|
// OpPut(k4,v4), OpPut(k5,v5)
|
||||||
// ).Commit()
|
// ).Commit()
|
||||||
//
|
|
||||||
type Txn interface {
|
type Txn interface {
|
||||||
// If takes a list of comparison. If all comparisons passed in succeed,
|
// If takes a list of comparison. If all comparisons passed in succeed,
|
||||||
// the operations passed into Then() will be executed. Or the operations
|
// the operations passed into Then() will be executed. Or the operations
|
||||||
|
@ -37,6 +37,13 @@ const (
|
|||||||
EventTypePut = mvccpb.PUT
|
EventTypePut = mvccpb.PUT
|
||||||
|
|
||||||
closeSendErrTimeout = 250 * time.Millisecond
|
closeSendErrTimeout = 250 * time.Millisecond
|
||||||
|
|
||||||
|
// AutoWatchID is the watcher ID passed in WatchStream.Watch when no
|
||||||
|
// user-provided ID is available. If pass, an ID will automatically be assigned.
|
||||||
|
AutoWatchID = 0
|
||||||
|
|
||||||
|
// InvalidWatchID represents an invalid watch ID and prevents duplication with an existing watch.
|
||||||
|
InvalidWatchID = -1
|
||||||
)
|
)
|
||||||
|
|
||||||
type Event mvccpb.Event
|
type Event mvccpb.Event
|
||||||
@ -450,7 +457,7 @@ func (w *watcher) closeStream(wgs *watchGrpcStream) {
|
|||||||
|
|
||||||
func (w *watchGrpcStream) addSubstream(resp *pb.WatchResponse, ws *watcherStream) {
|
func (w *watchGrpcStream) addSubstream(resp *pb.WatchResponse, ws *watcherStream) {
|
||||||
// check watch ID for backward compatibility (<= v3.3)
|
// check watch ID for backward compatibility (<= v3.3)
|
||||||
if resp.WatchId == -1 || (resp.Canceled && resp.CancelReason != "") {
|
if resp.WatchId == InvalidWatchID || (resp.Canceled && resp.CancelReason != "") {
|
||||||
w.closeErr = v3rpc.Error(errors.New(resp.CancelReason))
|
w.closeErr = v3rpc.Error(errors.New(resp.CancelReason))
|
||||||
// failed; no channel
|
// failed; no channel
|
||||||
close(ws.recvc)
|
close(ws.recvc)
|
||||||
@ -481,7 +488,7 @@ func (w *watchGrpcStream) closeSubstream(ws *watcherStream) {
|
|||||||
} else if ws.outc != nil {
|
} else if ws.outc != nil {
|
||||||
close(ws.outc)
|
close(ws.outc)
|
||||||
}
|
}
|
||||||
if ws.id != -1 {
|
if ws.id != InvalidWatchID {
|
||||||
delete(w.substreams, ws.id)
|
delete(w.substreams, ws.id)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -533,6 +540,7 @@ func (w *watchGrpcStream) run() {
|
|||||||
cancelSet := make(map[int64]struct{})
|
cancelSet := make(map[int64]struct{})
|
||||||
|
|
||||||
var cur *pb.WatchResponse
|
var cur *pb.WatchResponse
|
||||||
|
backoff := time.Millisecond
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
// Watch() requested
|
// Watch() requested
|
||||||
@ -543,7 +551,7 @@ func (w *watchGrpcStream) run() {
|
|||||||
// TODO: pass custom watch ID?
|
// TODO: pass custom watch ID?
|
||||||
ws := &watcherStream{
|
ws := &watcherStream{
|
||||||
initReq: *wreq,
|
initReq: *wreq,
|
||||||
id: -1,
|
id: InvalidWatchID,
|
||||||
outc: outc,
|
outc: outc,
|
||||||
// unbuffered so resumes won't cause repeat events
|
// unbuffered so resumes won't cause repeat events
|
||||||
recvc: make(chan *WatchResponse),
|
recvc: make(chan *WatchResponse),
|
||||||
@ -649,6 +657,7 @@ func (w *watchGrpcStream) run() {
|
|||||||
closeErr = err
|
closeErr = err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
backoff = w.backoffIfUnavailable(backoff, err)
|
||||||
if wc, closeErr = w.newWatchClient(); closeErr != nil {
|
if wc, closeErr = w.newWatchClient(); closeErr != nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -669,7 +678,7 @@ func (w *watchGrpcStream) run() {
|
|||||||
if len(w.substreams)+len(w.resuming) == 0 {
|
if len(w.substreams)+len(w.resuming) == 0 {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if ws.id != -1 {
|
if ws.id != InvalidWatchID {
|
||||||
// client is closing an established watch; close it on the server proactively instead of waiting
|
// client is closing an established watch; close it on the server proactively instead of waiting
|
||||||
// to close when the next message arrives
|
// to close when the next message arrives
|
||||||
cancelSet[ws.id] = struct{}{}
|
cancelSet[ws.id] = struct{}{}
|
||||||
@ -716,9 +725,9 @@ func (w *watchGrpcStream) dispatchEvent(pbresp *pb.WatchResponse) bool {
|
|||||||
cancelReason: pbresp.CancelReason,
|
cancelReason: pbresp.CancelReason,
|
||||||
}
|
}
|
||||||
|
|
||||||
// watch IDs are zero indexed, so request notify watch responses are assigned a watch ID of -1 to
|
// watch IDs are zero indexed, so request notify watch responses are assigned a watch ID of InvalidWatchID to
|
||||||
// indicate they should be broadcast.
|
// indicate they should be broadcast.
|
||||||
if wr.IsProgressNotify() && pbresp.WatchId == -1 {
|
if wr.IsProgressNotify() && pbresp.WatchId == InvalidWatchID {
|
||||||
return w.broadcastResponse(wr)
|
return w.broadcastResponse(wr)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -839,7 +848,7 @@ func (w *watchGrpcStream) serveSubstream(ws *watcherStream, resumec chan struct{
|
|||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// current progress of watch; <= store revision
|
// current progress of watch; <= store revision
|
||||||
nextRev = wr.Header.Revision
|
nextRev = wr.Header.Revision + 1
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(wr.Events) > 0 {
|
if len(wr.Events) > 0 {
|
||||||
@ -873,7 +882,7 @@ func (w *watchGrpcStream) newWatchClient() (pb.Watch_WatchClient, error) {
|
|||||||
w.resumec = make(chan struct{})
|
w.resumec = make(chan struct{})
|
||||||
w.joinSubstreams()
|
w.joinSubstreams()
|
||||||
for _, ws := range w.substreams {
|
for _, ws := range w.substreams {
|
||||||
ws.id = -1
|
ws.id = InvalidWatchID
|
||||||
w.resuming = append(w.resuming, ws)
|
w.resuming = append(w.resuming, ws)
|
||||||
}
|
}
|
||||||
// strip out nils, if any
|
// strip out nils, if any
|
||||||
@ -963,6 +972,21 @@ func (w *watchGrpcStream) joinSubstreams() {
|
|||||||
|
|
||||||
var maxBackoff = 100 * time.Millisecond
|
var maxBackoff = 100 * time.Millisecond
|
||||||
|
|
||||||
|
func (w *watchGrpcStream) backoffIfUnavailable(backoff time.Duration, err error) time.Duration {
|
||||||
|
if isUnavailableErr(w.ctx, err) {
|
||||||
|
// retry, but backoff
|
||||||
|
if backoff < maxBackoff {
|
||||||
|
// 25% backoff factor
|
||||||
|
backoff = backoff + backoff/4
|
||||||
|
if backoff > maxBackoff {
|
||||||
|
backoff = maxBackoff
|
||||||
|
}
|
||||||
|
}
|
||||||
|
time.Sleep(backoff)
|
||||||
|
}
|
||||||
|
return backoff
|
||||||
|
}
|
||||||
|
|
||||||
// openWatchClient retries opening a watch client until success or halt.
|
// openWatchClient retries opening a watch client until success or halt.
|
||||||
// manually retry in case "ws==nil && err==nil"
|
// manually retry in case "ws==nil && err==nil"
|
||||||
// TODO: remove FailFast=false
|
// TODO: remove FailFast=false
|
||||||
@ -983,17 +1007,7 @@ func (w *watchGrpcStream) openWatchClient() (ws pb.Watch_WatchClient, err error)
|
|||||||
if isHaltErr(w.ctx, err) {
|
if isHaltErr(w.ctx, err) {
|
||||||
return nil, v3rpc.Error(err)
|
return nil, v3rpc.Error(err)
|
||||||
}
|
}
|
||||||
if isUnavailableErr(w.ctx, err) {
|
backoff = w.backoffIfUnavailable(backoff, err)
|
||||||
// retry, but backoff
|
|
||||||
if backoff < maxBackoff {
|
|
||||||
// 25% backoff factor
|
|
||||||
backoff = backoff + backoff/4
|
|
||||||
if backoff > maxBackoff {
|
|
||||||
backoff = maxBackoff
|
|
||||||
}
|
|
||||||
}
|
|
||||||
time.Sleep(backoff)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return ws, nil
|
return ws, nil
|
||||||
}
|
}
|
||||||
|
@ -16,9 +16,10 @@ package command
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"os"
|
||||||
|
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"go.etcd.io/etcd/client/v3"
|
clientv3 "go.etcd.io/etcd/client/v3"
|
||||||
"go.etcd.io/etcd/pkg/v3/cobrautl"
|
"go.etcd.io/etcd/pkg/v3/cobrautl"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -26,6 +27,7 @@ var (
|
|||||||
delPrefix bool
|
delPrefix bool
|
||||||
delPrevKV bool
|
delPrevKV bool
|
||||||
delFromKey bool
|
delFromKey bool
|
||||||
|
delRange bool
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewDelCommand returns the cobra command for "del".
|
// NewDelCommand returns the cobra command for "del".
|
||||||
@ -39,6 +41,7 @@ func NewDelCommand() *cobra.Command {
|
|||||||
cmd.Flags().BoolVar(&delPrefix, "prefix", false, "delete keys with matching prefix")
|
cmd.Flags().BoolVar(&delPrefix, "prefix", false, "delete keys with matching prefix")
|
||||||
cmd.Flags().BoolVar(&delPrevKV, "prev-kv", false, "return deleted key-value pairs")
|
cmd.Flags().BoolVar(&delPrevKV, "prev-kv", false, "return deleted key-value pairs")
|
||||||
cmd.Flags().BoolVar(&delFromKey, "from-key", false, "delete keys that are greater than or equal to the given key using byte compare")
|
cmd.Flags().BoolVar(&delFromKey, "from-key", false, "delete keys that are greater than or equal to the given key using byte compare")
|
||||||
|
cmd.Flags().BoolVar(&delRange, "range", false, "delete range of keys")
|
||||||
return cmd
|
return cmd
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -70,6 +73,9 @@ func getDelOp(args []string) (string, []clientv3.OpOption) {
|
|||||||
cobrautl.ExitWithError(cobrautl.ExitBadArgs, fmt.Errorf("too many arguments, only accept one argument when `--prefix` or `--from-key` is set"))
|
cobrautl.ExitWithError(cobrautl.ExitBadArgs, fmt.Errorf("too many arguments, only accept one argument when `--prefix` or `--from-key` is set"))
|
||||||
}
|
}
|
||||||
opts = append(opts, clientv3.WithRange(args[1]))
|
opts = append(opts, clientv3.WithRange(args[1]))
|
||||||
|
if !delRange {
|
||||||
|
fmt.Fprintln(os.Stderr, "In etcd v3.6, the operation will be suspended for a few seconds to provide the user time to verify range.")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if delPrefix {
|
if delPrefix {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
module go.etcd.io/etcd/etcdctl/v3
|
module go.etcd.io/etcd/etcdctl/v3
|
||||||
|
|
||||||
go 1.16
|
go 1.19
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/bgentry/speakeasy v0.1.0
|
github.com/bgentry/speakeasy v0.1.0
|
||||||
@ -9,18 +9,58 @@ require (
|
|||||||
github.com/spf13/cobra v1.1.3
|
github.com/spf13/cobra v1.1.3
|
||||||
github.com/spf13/pflag v1.0.5
|
github.com/spf13/pflag v1.0.5
|
||||||
github.com/urfave/cli v1.22.4
|
github.com/urfave/cli v1.22.4
|
||||||
go.etcd.io/etcd/api/v3 v3.5.5
|
go.etcd.io/etcd/api/v3 v3.5.9
|
||||||
go.etcd.io/etcd/client/pkg/v3 v3.5.5
|
go.etcd.io/etcd/client/pkg/v3 v3.5.9
|
||||||
go.etcd.io/etcd/client/v2 v2.305.5
|
go.etcd.io/etcd/client/v2 v2.305.9
|
||||||
go.etcd.io/etcd/client/v3 v3.5.5
|
go.etcd.io/etcd/client/v3 v3.5.9
|
||||||
go.etcd.io/etcd/etcdutl/v3 v3.5.5
|
go.etcd.io/etcd/etcdutl/v3 v3.5.9
|
||||||
go.etcd.io/etcd/pkg/v3 v3.5.5
|
go.etcd.io/etcd/pkg/v3 v3.5.9
|
||||||
go.uber.org/zap v1.17.0
|
go.uber.org/zap v1.17.0
|
||||||
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba
|
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba
|
||||||
google.golang.org/grpc v1.41.0
|
google.golang.org/grpc v1.41.0
|
||||||
gopkg.in/cheggaaa/pb.v1 v1.0.28
|
gopkg.in/cheggaaa/pb.v1 v1.0.28
|
||||||
)
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
|
github.com/cespare/xxhash/v2 v2.1.1 // indirect
|
||||||
|
github.com/coreos/go-semver v0.3.0 // indirect
|
||||||
|
github.com/coreos/go-systemd/v22 v22.3.2 // indirect
|
||||||
|
github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect
|
||||||
|
github.com/gogo/protobuf v1.3.2 // indirect
|
||||||
|
github.com/golang-jwt/jwt/v4 v4.4.2 // indirect
|
||||||
|
github.com/golang/protobuf v1.5.2 // indirect
|
||||||
|
github.com/google/btree v1.0.1 // indirect
|
||||||
|
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||||
|
github.com/jonboulle/clockwork v0.2.2 // indirect
|
||||||
|
github.com/json-iterator/go v1.1.11 // indirect
|
||||||
|
github.com/mattn/go-runewidth v0.0.9 // indirect
|
||||||
|
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
|
github.com/modern-go/reflect2 v1.0.1 // indirect
|
||||||
|
github.com/prometheus/client_golang v1.11.1 // indirect
|
||||||
|
github.com/prometheus/client_model v0.2.0 // indirect
|
||||||
|
github.com/prometheus/common v0.26.0 // indirect
|
||||||
|
github.com/prometheus/procfs v0.6.0 // indirect
|
||||||
|
github.com/russross/blackfriday/v2 v2.0.1 // indirect
|
||||||
|
github.com/shurcooL/sanitized_anchor_name v1.0.0 // indirect
|
||||||
|
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 // indirect
|
||||||
|
go.etcd.io/bbolt v1.3.7 // indirect
|
||||||
|
go.etcd.io/etcd/raft/v3 v3.5.9 // indirect
|
||||||
|
go.etcd.io/etcd/server/v3 v3.5.9 // indirect
|
||||||
|
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.25.0 // indirect
|
||||||
|
go.opentelemetry.io/otel v1.0.1 // indirect
|
||||||
|
go.opentelemetry.io/otel/trace v1.0.1 // indirect
|
||||||
|
go.uber.org/atomic v1.7.0 // indirect
|
||||||
|
go.uber.org/multierr v1.6.0 // indirect
|
||||||
|
golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 // indirect
|
||||||
|
golang.org/x/net v0.7.0 // indirect
|
||||||
|
golang.org/x/sys v0.5.0 // indirect
|
||||||
|
golang.org/x/text v0.7.0 // indirect
|
||||||
|
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c // indirect
|
||||||
|
google.golang.org/protobuf v1.27.1 // indirect
|
||||||
|
)
|
||||||
|
|
||||||
replace (
|
replace (
|
||||||
go.etcd.io/etcd/api/v3 => ../api
|
go.etcd.io/etcd/api/v3 => ../api
|
||||||
go.etcd.io/etcd/client/pkg/v3 => ../client/pkg
|
go.etcd.io/etcd/client/pkg/v3 => ../client/pkg
|
||||||
|
@ -31,12 +31,7 @@ github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6r
|
|||||||
github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY=
|
github.com/bgentry/speakeasy v0.1.0 h1:ByYyxL9InA1OWqxJqqp2A5pYHUrCiAL6K3J+LKSsQkY=
|
||||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||||
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
|
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
|
||||||
github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
|
|
||||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
github.com/certifi/gocertifi v0.0.0-20191021191039-0944d244cd40/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
|
|
||||||
github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054 h1:uH66TXeswKn5PW5zdZ39xEwfS9an067BirqA+P4QaLI=
|
|
||||||
github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
|
|
||||||
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
|
|
||||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||||
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
|
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.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
@ -45,17 +40,11 @@ github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGX
|
|||||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||||
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||||
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||||
github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5 h1:xD/lrqdvwsc+O2bjSSi3YqY73Ke3LAiSCx49aCesA0E=
|
github.com/cockroachdb/datadriven v1.0.2 h1:H9MtNqVoVhvd9nCBwOyDjUEdZCREqbIdCJD93PBm/jA=
|
||||||
github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo=
|
|
||||||
github.com/cockroachdb/errors v1.2.4 h1:Lap807SXTH5tri2TivECb/4abUkMZC9zRoLarvcKDqs=
|
|
||||||
github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA=
|
|
||||||
github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f h1:o/kfcElHqOiXqcou5a3rIlMc7oJbMQkeLk0VQJ7zgqY=
|
|
||||||
github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI=
|
|
||||||
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
||||||
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||||
github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM=
|
github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM=
|
||||||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8=
|
|
||||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||||
github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI=
|
github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI=
|
||||||
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||||
@ -63,8 +52,6 @@ github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfc
|
|||||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM=
|
github.com/cpuguy83/go-md2man/v2 v2.0.0 h1:EoUDS0afbrsXAZ9YQ9jdu/mZ2sXgT1/2yyNng4PGlyM=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
|
||||||
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
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/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
@ -82,11 +69,7 @@ github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.
|
|||||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||||
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
|
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
|
||||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||||
github.com/form3tech-oss/jwt-go v3.2.3+incompatible h1:7ZaBxOI7TMoYBfyA3cQHErNNyAWIKUMIwqxEtgHOs5c=
|
|
||||||
github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
|
|
||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
github.com/getsentry/raven-go v0.2.0 h1:no+xWJRb5ZI7eE8TWgIq1jLulQiIoLG0IfYxv5JYMGs=
|
|
||||||
github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ=
|
|
||||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||||
@ -99,12 +82,12 @@ github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/me
|
|||||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||||
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
|
||||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||||
|
github.com/golang-jwt/jwt/v4 v4.4.2 h1:rcc4lwaZgFMCZ5jxF9ABolDcIHdBytAFgqFPbSJQAYs=
|
||||||
|
github.com/golang-jwt/jwt/v4 v4.4.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
|
||||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||||
@ -121,7 +104,6 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD
|
|||||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||||
github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
|
|
||||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
@ -148,7 +130,6 @@ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5m
|
|||||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||||
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y=
|
|
||||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho=
|
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho=
|
||||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||||
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||||
@ -188,7 +169,6 @@ github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfV
|
|||||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||||
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
||||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||||
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
|
|
||||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
@ -197,7 +177,6 @@ github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFB
|
|||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
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.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
|
||||||
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||||
github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4=
|
github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4=
|
||||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||||
@ -227,7 +206,6 @@ github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRW
|
|||||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||||
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
||||||
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
||||||
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
|
||||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
@ -273,11 +251,9 @@ github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeV
|
|||||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
|
||||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||||
github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0=
|
|
||||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||||
@ -294,11 +270,10 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
|
|||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
|
||||||
github.com/urfave/cli v1.22.4 h1:u7tSpNPPswAFymm8IehJhy4uJMlUuU/GmqSkvJ1InXA=
|
github.com/urfave/cli v1.22.4 h1:u7tSpNPPswAFymm8IehJhy4uJMlUuU/GmqSkvJ1InXA=
|
||||||
github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
||||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8=
|
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8=
|
||||||
@ -307,21 +282,17 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de
|
|||||||
github.com/yuin/goldmark v1.2.1/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/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||||
go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU=
|
go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ=
|
||||||
go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
|
go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw=
|
||||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.25.0 h1:Wx7nFnvCaissIUZxPkBqDz2963Z+Cl+PkYbDKzTxDqQ=
|
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.25.0 h1:Wx7nFnvCaissIUZxPkBqDz2963Z+Cl+PkYbDKzTxDqQ=
|
||||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.25.0/go.mod h1:E5NNboN0UqSAki0Atn9kVwaN7I+l25gGxDqBueo/74E=
|
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.25.0/go.mod h1:E5NNboN0UqSAki0Atn9kVwaN7I+l25gGxDqBueo/74E=
|
||||||
go.opentelemetry.io/otel v1.0.1 h1:4XKyXmfqJLOQ7feyV5DB6gsBFZ0ltB8vLtp6pj4JIcc=
|
go.opentelemetry.io/otel v1.0.1 h1:4XKyXmfqJLOQ7feyV5DB6gsBFZ0ltB8vLtp6pj4JIcc=
|
||||||
go.opentelemetry.io/otel v1.0.1/go.mod h1:OPEOD4jIT2SlZPMmwT6FqZz2C0ZNdQqiWcoK6M0SNFU=
|
go.opentelemetry.io/otel v1.0.1/go.mod h1:OPEOD4jIT2SlZPMmwT6FqZz2C0ZNdQqiWcoK6M0SNFU=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.0.1/go.mod h1:Kv8liBeVNFkkkbilbgWRpV+wWuu+H5xdOT6HAgd30iw=
|
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.0.1/go.mod h1:xOvWoTOrQjxjW61xtOmD/WKGRYb/P4NzRo3bs65U6Rk=
|
|
||||||
go.opentelemetry.io/otel/sdk v1.0.1/go.mod h1:HrdXne+BiwsOHYYkBE5ysIcv2bvdZstxzmCQhxTcZkI=
|
|
||||||
go.opentelemetry.io/otel/trace v1.0.1 h1:StTeIH6Q3G4r0Fiw34LTokUFESZgIDUr0qIJ7mKmAfw=
|
go.opentelemetry.io/otel/trace v1.0.1 h1:StTeIH6Q3G4r0Fiw34LTokUFESZgIDUr0qIJ7mKmAfw=
|
||||||
go.opentelemetry.io/otel/trace v1.0.1/go.mod h1:5g4i4fKLaX2BQpSBsxw8YYcgKpMMSW3x7ZTuYBr3sUk=
|
go.opentelemetry.io/otel/trace v1.0.1/go.mod h1:5g4i4fKLaX2BQpSBsxw8YYcgKpMMSW3x7ZTuYBr3sUk=
|
||||||
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
||||||
go.opentelemetry.io/proto/otlp v0.9.0/go.mod h1:1vKfU9rv61e9EVGthD1zNvUbiwPcimSsOPU9brfSHJg=
|
|
||||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||||
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
|
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
|
||||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||||
@ -382,10 +353,9 @@ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLL
|
|||||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
|
||||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE=
|
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
|
||||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
@ -414,38 +384,32 @@ golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4=
|
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
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.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
|
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba h1:O8mE0/t419eoIwhTFpKVkHiTs/Igowgfkj25AcZrtiE=
|
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba h1:O8mE0/t419eoIwhTFpKVkHiTs/Igowgfkj25AcZrtiE=
|
||||||
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
@ -491,7 +455,6 @@ google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98
|
|||||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||||
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
|
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
|
||||||
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||||
google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
|
||||||
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||||
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c h1:wtujag7C+4D6KMoulW9YauvK2lgdvCMS260jsqqBXr0=
|
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c h1:wtujag7C+4D6KMoulW9YauvK2lgdvCMS260jsqqBXr0=
|
||||||
@ -502,10 +465,8 @@ google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ij
|
|||||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||||
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
|
||||||
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
|
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
|
||||||
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||||
google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
|
||||||
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
||||||
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
|
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
|
||||||
google.golang.org/grpc v1.41.0 h1:f+PlOh7QV4iIJkPrx5NQ7qaNGFQ3OTse67yaDHfju4E=
|
google.golang.org/grpc v1.41.0 h1:f+PlOh7QV4iIJkPrx5NQ7qaNGFQ3OTse67yaDHfju4E=
|
||||||
@ -531,7 +492,6 @@ gopkg.in/cheggaaa/pb.v1 v1.0.28 h1:n1tBJnnK2r7g9OW2btFH91V92STTUevLXYFb8gy9EMk=
|
|||||||
gopkg.in/cheggaaa/pb.v1 v1.0.28/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
|
gopkg.in/cheggaaa/pb.v1 v1.0.28/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw=
|
||||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||||
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
|
|
||||||
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||||
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
||||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
@ -544,12 +504,11 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|||||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||||
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
|
|
||||||
|
@ -27,7 +27,7 @@ const (
|
|||||||
apiEnv = "ETCDCTL_API"
|
apiEnv = "ETCDCTL_API"
|
||||||
)
|
)
|
||||||
|
|
||||||
/**
|
/*
|
||||||
mainWithError is fully analogous to main, but instead of signaling errors
|
mainWithError is fully analogous to main, but instead of signaling errors
|
||||||
by os.Exit, it exposes the error explicitly, such that test-logic can intercept
|
by os.Exit, it exposes the error explicitly, such that test-logic can intercept
|
||||||
control to e.g. dump coverage data (even for test-for-failure scenarios).
|
control to e.g. dump coverage data (even for test-for-failure scenarios).
|
||||||
|
@ -36,7 +36,7 @@ func SplitTestArgs(args []string) (testArgs, appArgs []string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Empty test to avoid no-tests warning.
|
// TestEmpty to avoid no-tests warning.
|
||||||
func TestEmpty(t *testing.T) {}
|
func TestEmpty(t *testing.T) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -114,7 +114,7 @@ func HandleBackup(withV3 bool, srcDir string, destDir string, srcWAL string, des
|
|||||||
destWAL = datadir.ToWalDir(destDir)
|
destWAL = datadir.ToWalDir(destDir)
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := fileutil.CreateDirAll(destSnap); err != nil {
|
if err := fileutil.CreateDirAll(lg, destSnap); err != nil {
|
||||||
lg.Fatal("failed creating backup snapshot dir", zap.String("dest-snap", destSnap), zap.Error(err))
|
lg.Fatal("failed creating backup snapshot dir", zap.String("dest-snap", destSnap), zap.Error(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
module go.etcd.io/etcd/etcdutl/v3
|
module go.etcd.io/etcd/etcdutl/v3
|
||||||
|
|
||||||
go 1.16
|
go 1.19
|
||||||
|
|
||||||
replace (
|
replace (
|
||||||
go.etcd.io/etcd/api/v3 => ../api
|
go.etcd.io/etcd/api/v3 => ../api
|
||||||
@ -24,12 +24,50 @@ require (
|
|||||||
github.com/dustin/go-humanize v1.0.0
|
github.com/dustin/go-humanize v1.0.0
|
||||||
github.com/olekukonko/tablewriter v0.0.5
|
github.com/olekukonko/tablewriter v0.0.5
|
||||||
github.com/spf13/cobra v1.1.3
|
github.com/spf13/cobra v1.1.3
|
||||||
go.etcd.io/bbolt v1.3.6
|
go.etcd.io/bbolt v1.3.7
|
||||||
go.etcd.io/etcd/api/v3 v3.5.5
|
go.etcd.io/etcd/api/v3 v3.5.9
|
||||||
go.etcd.io/etcd/client/pkg/v3 v3.5.5
|
go.etcd.io/etcd/client/pkg/v3 v3.5.9
|
||||||
go.etcd.io/etcd/client/v3 v3.5.5
|
go.etcd.io/etcd/client/v3 v3.5.9
|
||||||
go.etcd.io/etcd/pkg/v3 v3.5.5
|
go.etcd.io/etcd/pkg/v3 v3.5.9
|
||||||
go.etcd.io/etcd/raft/v3 v3.5.5
|
go.etcd.io/etcd/raft/v3 v3.5.9
|
||||||
go.etcd.io/etcd/server/v3 v3.5.5
|
go.etcd.io/etcd/server/v3 v3.5.9
|
||||||
go.uber.org/zap v1.17.0
|
go.uber.org/zap v1.17.0
|
||||||
)
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
|
github.com/cespare/xxhash/v2 v2.1.1 // indirect
|
||||||
|
github.com/coreos/go-semver v0.3.0 // indirect
|
||||||
|
github.com/coreos/go-systemd/v22 v22.3.2 // indirect
|
||||||
|
github.com/gogo/protobuf v1.3.2 // indirect
|
||||||
|
github.com/golang-jwt/jwt/v4 v4.4.2 // indirect
|
||||||
|
github.com/golang/protobuf v1.5.2 // indirect
|
||||||
|
github.com/google/btree v1.0.1 // indirect
|
||||||
|
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||||
|
github.com/jonboulle/clockwork v0.2.2 // indirect
|
||||||
|
github.com/json-iterator/go v1.1.11 // indirect
|
||||||
|
github.com/mattn/go-runewidth v0.0.9 // indirect
|
||||||
|
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
|
github.com/modern-go/reflect2 v1.0.1 // indirect
|
||||||
|
github.com/prometheus/client_golang v1.11.1 // indirect
|
||||||
|
github.com/prometheus/client_model v0.2.0 // indirect
|
||||||
|
github.com/prometheus/common v0.26.0 // indirect
|
||||||
|
github.com/prometheus/procfs v0.6.0 // indirect
|
||||||
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
|
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 // indirect
|
||||||
|
go.etcd.io/etcd/client/v2 v2.305.9 // indirect
|
||||||
|
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.25.0 // indirect
|
||||||
|
go.opentelemetry.io/otel v1.0.1 // indirect
|
||||||
|
go.opentelemetry.io/otel/trace v1.0.1 // indirect
|
||||||
|
go.uber.org/atomic v1.7.0 // indirect
|
||||||
|
go.uber.org/multierr v1.6.0 // indirect
|
||||||
|
golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 // indirect
|
||||||
|
golang.org/x/net v0.7.0 // indirect
|
||||||
|
golang.org/x/sys v0.5.0 // indirect
|
||||||
|
golang.org/x/text v0.7.0 // indirect
|
||||||
|
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba // indirect
|
||||||
|
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c // indirect
|
||||||
|
google.golang.org/grpc v1.41.0 // indirect
|
||||||
|
google.golang.org/protobuf v1.27.1 // indirect
|
||||||
|
)
|
||||||
|
@ -30,12 +30,7 @@ github.com/beorn7/perks v1.0.1 h1:VlbKKnNfV8bJzeqoa4cOKqO6bYr3WgKZxO8Z16+hsOM=
|
|||||||
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
github.com/beorn7/perks v1.0.1/go.mod h1:G2ZrVWU2WbWT9wwq4/hrbKbnv/1ERSJQ0ibhJ6rlkpw=
|
||||||
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
github.com/bgentry/speakeasy v0.1.0/go.mod h1:+zsyZBPWlz7T6j88CTgSN5bM796AkVf0kBD4zp0CCIs=
|
||||||
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
|
github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJmJgSg28kpZDP6UIiPt0e0Oz0kqKNGyRaWEPv84=
|
||||||
github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
|
|
||||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
github.com/certifi/gocertifi v0.0.0-20191021191039-0944d244cd40/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
|
|
||||||
github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054 h1:uH66TXeswKn5PW5zdZ39xEwfS9an067BirqA+P4QaLI=
|
|
||||||
github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
|
|
||||||
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
|
|
||||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||||
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
|
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.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
@ -44,24 +39,16 @@ github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGX
|
|||||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||||
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||||
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||||
github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5 h1:xD/lrqdvwsc+O2bjSSi3YqY73Ke3LAiSCx49aCesA0E=
|
github.com/cockroachdb/datadriven v1.0.2 h1:H9MtNqVoVhvd9nCBwOyDjUEdZCREqbIdCJD93PBm/jA=
|
||||||
github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo=
|
|
||||||
github.com/cockroachdb/errors v1.2.4 h1:Lap807SXTH5tri2TivECb/4abUkMZC9zRoLarvcKDqs=
|
|
||||||
github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA=
|
|
||||||
github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f h1:o/kfcElHqOiXqcou5a3rIlMc7oJbMQkeLk0VQJ7zgqY=
|
|
||||||
github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI=
|
|
||||||
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
||||||
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||||
github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM=
|
github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM=
|
||||||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8=
|
|
||||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||||
github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI=
|
github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI=
|
||||||
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
|
||||||
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
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/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
@ -78,11 +65,7 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.m
|
|||||||
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
|
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
|
||||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||||
github.com/form3tech-oss/jwt-go v3.2.3+incompatible h1:7ZaBxOI7TMoYBfyA3cQHErNNyAWIKUMIwqxEtgHOs5c=
|
|
||||||
github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
|
|
||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
github.com/getsentry/raven-go v0.2.0 h1:no+xWJRb5ZI7eE8TWgIq1jLulQiIoLG0IfYxv5JYMGs=
|
|
||||||
github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ=
|
|
||||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||||
@ -95,12 +78,12 @@ github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/me
|
|||||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||||
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
|
||||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||||
|
github.com/golang-jwt/jwt/v4 v4.4.2 h1:rcc4lwaZgFMCZ5jxF9ABolDcIHdBytAFgqFPbSJQAYs=
|
||||||
|
github.com/golang-jwt/jwt/v4 v4.4.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
|
||||||
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A=
|
||||||
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y=
|
||||||
@ -117,7 +100,6 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD
|
|||||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||||
github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
|
|
||||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
@ -144,7 +126,6 @@ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5m
|
|||||||
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY=
|
||||||
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
github.com/gorilla/websocket v1.4.2/go.mod h1:YR8l580nyteQvAITg2hZ9XVh4b55+EU/adAjf1fMHhE=
|
||||||
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
github.com/grpc-ecosystem/go-grpc-middleware v1.0.0/go.mod h1:FiyG127CGDf3tlThmgyCl78X/SZQqEOJBCDaAfeWzPs=
|
||||||
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0/go.mod h1:z0ButlSOZa5vEBq9m2m2hlwIgKw+rp3sdCBRoJY+30Y=
|
|
||||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho=
|
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 h1:Ovs26xHkKqVztRpIrF/92BcuyuQ/YW4NSIpoGtfXNho=
|
||||||
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0/go.mod h1:8NvIoxWQoOIhqOTXgfV/d3M/q6VIi02HzZEHgUlZvzk=
|
||||||
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
github.com/grpc-ecosystem/grpc-gateway v1.9.0/go.mod h1:vNeuVxBJEsws4ogUvrchl83t/GYV9WGTSLVdBhOQFDY=
|
||||||
@ -184,7 +165,6 @@ github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfV
|
|||||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||||
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
||||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||||
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
|
|
||||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
@ -193,7 +173,6 @@ github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFB
|
|||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
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.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
|
||||||
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
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-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||||
@ -221,7 +200,6 @@ github.com/mwitkow/go-conntrack v0.0.0-20190716064945-2f068394615f/go.mod h1:qRW
|
|||||||
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
github.com/oklog/ulid v1.3.1/go.mod h1:CirwcVhetQ6Lv90oh/F+FBtV6XMibvdAFo93nm5qn4U=
|
||||||
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
|
||||||
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
|
||||||
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
|
||||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
@ -265,11 +243,9 @@ github.com/shurcooL/sanitized_anchor_name v1.0.0/go.mod h1:1NzhyTcUVG4SuEtjjoZeV
|
|||||||
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo=
|
||||||
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE=
|
||||||
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88=
|
||||||
github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0=
|
|
||||||
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc=
|
||||||
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA=
|
||||||
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4kGIyLM=
|
||||||
github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0=
|
|
||||||
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA=
|
||||||
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ=
|
||||||
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE=
|
||||||
@ -286,32 +262,27 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
|
|||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
|
||||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8=
|
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8=
|
||||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
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.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||||
go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU=
|
go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ=
|
||||||
go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
|
go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw=
|
||||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.25.0 h1:Wx7nFnvCaissIUZxPkBqDz2963Z+Cl+PkYbDKzTxDqQ=
|
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.25.0 h1:Wx7nFnvCaissIUZxPkBqDz2963Z+Cl+PkYbDKzTxDqQ=
|
||||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.25.0/go.mod h1:E5NNboN0UqSAki0Atn9kVwaN7I+l25gGxDqBueo/74E=
|
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.25.0/go.mod h1:E5NNboN0UqSAki0Atn9kVwaN7I+l25gGxDqBueo/74E=
|
||||||
go.opentelemetry.io/otel v1.0.1 h1:4XKyXmfqJLOQ7feyV5DB6gsBFZ0ltB8vLtp6pj4JIcc=
|
go.opentelemetry.io/otel v1.0.1 h1:4XKyXmfqJLOQ7feyV5DB6gsBFZ0ltB8vLtp6pj4JIcc=
|
||||||
go.opentelemetry.io/otel v1.0.1/go.mod h1:OPEOD4jIT2SlZPMmwT6FqZz2C0ZNdQqiWcoK6M0SNFU=
|
go.opentelemetry.io/otel v1.0.1/go.mod h1:OPEOD4jIT2SlZPMmwT6FqZz2C0ZNdQqiWcoK6M0SNFU=
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.0.1/go.mod h1:Kv8liBeVNFkkkbilbgWRpV+wWuu+H5xdOT6HAgd30iw=
|
|
||||||
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.0.1/go.mod h1:xOvWoTOrQjxjW61xtOmD/WKGRYb/P4NzRo3bs65U6Rk=
|
|
||||||
go.opentelemetry.io/otel/sdk v1.0.1/go.mod h1:HrdXne+BiwsOHYYkBE5ysIcv2bvdZstxzmCQhxTcZkI=
|
|
||||||
go.opentelemetry.io/otel/trace v1.0.1 h1:StTeIH6Q3G4r0Fiw34LTokUFESZgIDUr0qIJ7mKmAfw=
|
go.opentelemetry.io/otel/trace v1.0.1 h1:StTeIH6Q3G4r0Fiw34LTokUFESZgIDUr0qIJ7mKmAfw=
|
||||||
go.opentelemetry.io/otel/trace v1.0.1/go.mod h1:5g4i4fKLaX2BQpSBsxw8YYcgKpMMSW3x7ZTuYBr3sUk=
|
go.opentelemetry.io/otel/trace v1.0.1/go.mod h1:5g4i4fKLaX2BQpSBsxw8YYcgKpMMSW3x7ZTuYBr3sUk=
|
||||||
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqeYNgFYFoEGnI=
|
||||||
go.opentelemetry.io/proto/otlp v0.9.0/go.mod h1:1vKfU9rv61e9EVGthD1zNvUbiwPcimSsOPU9brfSHJg=
|
|
||||||
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE=
|
||||||
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
|
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
|
||||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
||||||
@ -372,10 +343,9 @@ golang.org/x/net v0.0.0-20200226121028-0de0cce0169b/go.mod h1:z5CRVTTTmAJ677TzLL
|
|||||||
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
golang.org/x/net v0.0.0-20200625001655-4c5254603344/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81Ro3o1hOxt32SMVPicZroKQ2sZA=
|
||||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
|
||||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE=
|
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
|
||||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
@ -404,38 +374,32 @@ golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4=
|
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
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.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
|
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba h1:O8mE0/t419eoIwhTFpKVkHiTs/Igowgfkj25AcZrtiE=
|
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba h1:O8mE0/t419eoIwhTFpKVkHiTs/Igowgfkj25AcZrtiE=
|
||||||
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
@ -481,7 +445,6 @@ google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98
|
|||||||
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc=
|
||||||
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
|
google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8=
|
||||||
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc=
|
||||||
google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
|
||||||
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||||
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c h1:wtujag7C+4D6KMoulW9YauvK2lgdvCMS260jsqqBXr0=
|
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c h1:wtujag7C+4D6KMoulW9YauvK2lgdvCMS260jsqqBXr0=
|
||||||
@ -492,10 +455,8 @@ google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ij
|
|||||||
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg=
|
||||||
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=
|
||||||
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk=
|
||||||
google.golang.org/grpc v1.29.1/go.mod h1:itym6AZVZYACWQqET3MqgPpjcuV5QH3BxFS3IjizoKk=
|
|
||||||
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
|
google.golang.org/grpc v1.33.1/go.mod h1:fr5YgcSWrqhRRxogOsw7RzIpsmvOZ6IcH4kBYTpR3n0=
|
||||||
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
google.golang.org/grpc v1.36.0/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAGRRjU=
|
||||||
google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
|
||||||
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM=
|
||||||
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
|
google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34=
|
||||||
google.golang.org/grpc v1.41.0 h1:f+PlOh7QV4iIJkPrx5NQ7qaNGFQ3OTse67yaDHfju4E=
|
google.golang.org/grpc v1.41.0 h1:f+PlOh7QV4iIJkPrx5NQ7qaNGFQ3OTse67yaDHfju4E=
|
||||||
@ -519,7 +480,6 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8
|
|||||||
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
||||||
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
|
||||||
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
gopkg.in/ini.v1 v1.51.0/go.mod h1:pNLf8WUiyNEtQjuu5G5vTm06TEv9tsIgeAvK8hOrP4k=
|
||||||
gopkg.in/natefinch/lumberjack.v2 v2.0.0/go.mod h1:l0ndWWf7gzL7RNwBG7wST/UCcT4T24xpD6X8LsfU/+k=
|
|
||||||
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
gopkg.in/resty.v1 v1.12.0/go.mod h1:mDo4pnntr5jdWRML875a/NmxYqAlA73dVijT2AXvQQo=
|
||||||
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
gopkg.in/yaml.v2 v2.0.0-20170812160011-eb3733d160e7/go.mod h1:JAlM8MvJe8wmxCU4Bli9HhUf9+ttbYbLASfIpnQbh74=
|
||||||
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
||||||
@ -532,12 +492,11 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|||||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg=
|
||||||
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8=
|
||||||
sigs.k8s.io/yaml v1.2.0/go.mod h1:yfXDCHCao9+ENCvLSE62v9VSji2MKu5jeNfTrofGhJc=
|
|
||||||
|
@ -36,7 +36,7 @@ func SplitTestArgs(args []string) (testArgs, appArgs []string) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Empty test to avoid no-tests warning.
|
// TestEmpty to avoid no-tests warning.
|
||||||
func TestEmpty(t *testing.T) {}
|
func TestEmpty(t *testing.T) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -322,7 +322,7 @@ func (s *v3Manager) copyAndVerifyDB() error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if err := fileutil.CreateDirAll(s.snapDir); err != nil {
|
if err := fileutil.CreateDirAll(s.lg, s.snapDir); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -383,7 +383,7 @@ func (s *v3Manager) copyAndVerifyDB() error {
|
|||||||
//
|
//
|
||||||
// TODO: This code ignores learners !!!
|
// TODO: This code ignores learners !!!
|
||||||
func (s *v3Manager) saveWALAndSnap() (*raftpb.HardState, error) {
|
func (s *v3Manager) saveWALAndSnap() (*raftpb.HardState, error) {
|
||||||
if err := fileutil.CreateDirAll(s.walDir); err != nil {
|
if err := fileutil.CreateDirAll(s.lg, s.walDir); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
|
79
go.mod
79
go.mod
@ -1,6 +1,6 @@
|
|||||||
module go.etcd.io/etcd/v3
|
module go.etcd.io/etcd/v3
|
||||||
|
|
||||||
go 1.16
|
go 1.19
|
||||||
|
|
||||||
replace (
|
replace (
|
||||||
go.etcd.io/etcd/api/v3 => ./api
|
go.etcd.io/etcd/api/v3 => ./api
|
||||||
@ -19,19 +19,74 @@ require (
|
|||||||
github.com/bgentry/speakeasy v0.1.0
|
github.com/bgentry/speakeasy v0.1.0
|
||||||
github.com/dustin/go-humanize v1.0.0
|
github.com/dustin/go-humanize v1.0.0
|
||||||
github.com/spf13/cobra v1.1.3
|
github.com/spf13/cobra v1.1.3
|
||||||
go.etcd.io/bbolt v1.3.6
|
go.etcd.io/bbolt v1.3.7
|
||||||
go.etcd.io/etcd/api/v3 v3.5.5
|
go.etcd.io/etcd/api/v3 v3.5.9
|
||||||
go.etcd.io/etcd/client/pkg/v3 v3.5.5
|
go.etcd.io/etcd/client/pkg/v3 v3.5.9
|
||||||
go.etcd.io/etcd/client/v2 v2.305.5
|
go.etcd.io/etcd/client/v2 v2.305.9
|
||||||
go.etcd.io/etcd/client/v3 v3.5.5
|
go.etcd.io/etcd/client/v3 v3.5.9
|
||||||
go.etcd.io/etcd/etcdctl/v3 v3.5.5
|
go.etcd.io/etcd/etcdctl/v3 v3.5.9
|
||||||
go.etcd.io/etcd/etcdutl/v3 v3.5.5
|
go.etcd.io/etcd/etcdutl/v3 v3.5.9
|
||||||
go.etcd.io/etcd/pkg/v3 v3.5.5
|
go.etcd.io/etcd/pkg/v3 v3.5.9
|
||||||
go.etcd.io/etcd/raft/v3 v3.5.5
|
go.etcd.io/etcd/raft/v3 v3.5.9
|
||||||
go.etcd.io/etcd/server/v3 v3.5.5
|
go.etcd.io/etcd/server/v3 v3.5.9
|
||||||
go.etcd.io/etcd/tests/v3 v3.5.5
|
go.etcd.io/etcd/tests/v3 v3.5.9
|
||||||
go.uber.org/zap v1.17.0
|
go.uber.org/zap v1.17.0
|
||||||
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba
|
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba
|
||||||
google.golang.org/grpc v1.41.0
|
google.golang.org/grpc v1.41.0
|
||||||
gopkg.in/cheggaaa/pb.v1 v1.0.28
|
gopkg.in/cheggaaa/pb.v1 v1.0.28
|
||||||
)
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/beorn7/perks v1.0.1 // indirect
|
||||||
|
github.com/cenkalti/backoff/v4 v4.1.1 // indirect
|
||||||
|
github.com/cespare/xxhash/v2 v2.1.1 // indirect
|
||||||
|
github.com/coreos/go-semver v0.3.0 // indirect
|
||||||
|
github.com/coreos/go-systemd/v22 v22.3.2 // indirect
|
||||||
|
github.com/gogo/protobuf v1.3.2 // indirect
|
||||||
|
github.com/golang-jwt/jwt/v4 v4.4.2 // indirect
|
||||||
|
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
|
||||||
|
github.com/golang/protobuf v1.5.2 // indirect
|
||||||
|
github.com/google/btree v1.0.1 // indirect
|
||||||
|
github.com/gorilla/websocket v1.4.2 // indirect
|
||||||
|
github.com/grpc-ecosystem/go-grpc-middleware v1.3.0 // indirect
|
||||||
|
github.com/grpc-ecosystem/go-grpc-prometheus v1.2.0 // indirect
|
||||||
|
github.com/grpc-ecosystem/grpc-gateway v1.16.0 // indirect
|
||||||
|
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||||
|
github.com/jonboulle/clockwork v0.2.2 // indirect
|
||||||
|
github.com/json-iterator/go v1.1.11 // indirect
|
||||||
|
github.com/kr/pretty v0.3.0 // indirect
|
||||||
|
github.com/mattn/go-colorable v0.1.11 // indirect
|
||||||
|
github.com/mattn/go-runewidth v0.0.9 // indirect
|
||||||
|
github.com/matttproud/golang_protobuf_extensions v1.0.1 // indirect
|
||||||
|
github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd // indirect
|
||||||
|
github.com/modern-go/reflect2 v1.0.1 // indirect
|
||||||
|
github.com/olekukonko/tablewriter v0.0.5 // indirect
|
||||||
|
github.com/prometheus/client_golang v1.11.1 // indirect
|
||||||
|
github.com/prometheus/client_model v0.2.0 // indirect
|
||||||
|
github.com/prometheus/common v0.26.0 // indirect
|
||||||
|
github.com/prometheus/procfs v0.6.0 // indirect
|
||||||
|
github.com/rogpeppe/go-internal v1.8.1 // indirect
|
||||||
|
github.com/sirupsen/logrus v1.7.0 // indirect
|
||||||
|
github.com/soheilhy/cmux v0.1.5 // indirect
|
||||||
|
github.com/spf13/pflag v1.0.5 // indirect
|
||||||
|
github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802 // indirect
|
||||||
|
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 // indirect
|
||||||
|
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.25.0 // indirect
|
||||||
|
go.opentelemetry.io/otel v1.0.1 // indirect
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace v1.0.1 // indirect
|
||||||
|
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracegrpc v1.0.1 // indirect
|
||||||
|
go.opentelemetry.io/otel/sdk v1.0.1 // indirect
|
||||||
|
go.opentelemetry.io/otel/trace v1.0.1 // indirect
|
||||||
|
go.opentelemetry.io/proto/otlp v0.9.0 // indirect
|
||||||
|
go.uber.org/atomic v1.7.0 // indirect
|
||||||
|
go.uber.org/multierr v1.6.0 // indirect
|
||||||
|
golang.org/x/crypto v0.0.0-20220411220226-7b82a4e95df4 // indirect
|
||||||
|
golang.org/x/net v0.7.0 // indirect
|
||||||
|
golang.org/x/sys v0.5.0 // indirect
|
||||||
|
golang.org/x/text v0.7.0 // indirect
|
||||||
|
google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84 // indirect
|
||||||
|
google.golang.org/protobuf v1.27.1 // indirect
|
||||||
|
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
|
||||||
|
gopkg.in/yaml.v2 v2.4.0 // indirect
|
||||||
|
sigs.k8s.io/yaml v1.2.0 // indirect
|
||||||
|
)
|
||||||
|
72
go.sum
72
go.sum
@ -35,10 +35,6 @@ github.com/bketelsen/crypt v0.0.3-0.20200106085610-5cbc8cc4026c/go.mod h1:MKsuJm
|
|||||||
github.com/cenkalti/backoff/v4 v4.1.1 h1:G2HAfAmvm/GcKan2oOQpBXOd2tT2G57ZnZGWa1PxPBQ=
|
github.com/cenkalti/backoff/v4 v4.1.1 h1:G2HAfAmvm/GcKan2oOQpBXOd2tT2G57ZnZGWa1PxPBQ=
|
||||||
github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
|
github.com/cenkalti/backoff/v4 v4.1.1/go.mod h1:scbssz8iZGpm3xbr14ovlUdkxfGXNInqkPWOWmG2CLw=
|
||||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
github.com/certifi/gocertifi v0.0.0-20191021191039-0944d244cd40/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
|
|
||||||
github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054 h1:uH66TXeswKn5PW5zdZ39xEwfS9an067BirqA+P4QaLI=
|
|
||||||
github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
|
|
||||||
github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko=
|
|
||||||
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc=
|
||||||
github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY=
|
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.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs=
|
||||||
@ -47,25 +43,17 @@ github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGX
|
|||||||
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk=
|
||||||
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||||
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs=
|
||||||
github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5 h1:xD/lrqdvwsc+O2bjSSi3YqY73Ke3LAiSCx49aCesA0E=
|
github.com/cockroachdb/datadriven v1.0.2 h1:H9MtNqVoVhvd9nCBwOyDjUEdZCREqbIdCJD93PBm/jA=
|
||||||
github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo=
|
|
||||||
github.com/cockroachdb/errors v1.2.4 h1:Lap807SXTH5tri2TivECb/4abUkMZC9zRoLarvcKDqs=
|
|
||||||
github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA=
|
|
||||||
github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f h1:o/kfcElHqOiXqcou5a3rIlMc7oJbMQkeLk0VQJ7zgqY=
|
|
||||||
github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI=
|
|
||||||
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkEiiKk=
|
||||||
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||||
github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM=
|
github.com/coreos/go-semver v0.3.0 h1:wkHLiw0WNATZnSG7epLsujiMCgPAc9xhjJ4tgnAxmfM=
|
||||||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e h1:Wf6HqHfScWJN9/ZjdUKyjop4mf3Qdd+1TvvltAvM3m8=
|
|
||||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||||
github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI=
|
github.com/coreos/go-systemd/v22 v22.3.2 h1:D9/bQk5vlXQFZ6Kwuu6zaiXJ9oTPe68++AzAJc1DzSI=
|
||||||
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
||||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.0-20190314233015-f79a8a8ca69d/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||||
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
||||||
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
|
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
|
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/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
||||||
@ -81,14 +69,9 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.m
|
|||||||
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
|
github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ=
|
||||||
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
|
github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0=
|
||||||
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c=
|
||||||
github.com/etcd-io/gofail v0.0.0-20190801230047-ad7f989257ca/go.mod h1:49H/RkXP8pKaZy4h0d+NW16rSLhyVBt4o6VLJbmOqDE=
|
|
||||||
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
|
github.com/fatih/color v1.7.0 h1:DkWD4oS2D8LGGgTQ6IvwJJXSL5Vp2ffcQg58nFV38Ys=
|
||||||
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4=
|
||||||
github.com/form3tech-oss/jwt-go v3.2.3+incompatible h1:7ZaBxOI7TMoYBfyA3cQHErNNyAWIKUMIwqxEtgHOs5c=
|
|
||||||
github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k=
|
|
||||||
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo=
|
||||||
github.com/getsentry/raven-go v0.2.0 h1:no+xWJRb5ZI7eE8TWgIq1jLulQiIoLG0IfYxv5JYMGs=
|
|
||||||
github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ=
|
|
||||||
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
github.com/ghodss/yaml v1.0.0/go.mod h1:4dBDuWmgqj2HViK6kFavaiC9ZROes6MMH2rRYeMEF04=
|
||||||
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU=
|
||||||
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as=
|
||||||
@ -101,9 +84,10 @@ github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/me
|
|||||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
||||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||||
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
|
||||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||||
|
github.com/golang-jwt/jwt/v4 v4.4.2 h1:rcc4lwaZgFMCZ5jxF9ABolDcIHdBytAFgqFPbSJQAYs=
|
||||||
|
github.com/golang-jwt/jwt/v4 v4.4.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
github.com/golang/groupcache v0.0.0-20190129154638-5b532d6fd5ef/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
|
||||||
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
|
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
|
||||||
@ -124,7 +108,6 @@ github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QD
|
|||||||
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
github.com/golang/protobuf v1.4.2/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||||
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
|
||||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||||
github.com/golang/protobuf v1.5.1/go.mod h1:DopwsBzvsk0Fs44TXzsVbJyPhcCPeIwnvohx4u74HPM=
|
|
||||||
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw=
|
||||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||||
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ=
|
||||||
@ -194,23 +177,25 @@ github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfV
|
|||||||
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w=
|
||||||
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
|
||||||
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
github.com/kisielk/errcheck v1.1.0/go.mod h1:EZBBE59ingxPouuu3KfxchcWSUPOHkagtvWXihfKN4Q=
|
||||||
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
|
|
||||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
github.com/konsorten/go-windows-terminal-sequences v1.0.3/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||||
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc=
|
||||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||||
|
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
|
||||||
|
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
|
||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
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.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 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
|
||||||
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
|
||||||
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||||
github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRUIY4=
|
|
||||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||||
github.com/mattn/go-isatty v0.0.3 h1:ns/ykhmWi7G9O+8a448SecJU3nSMBXJfqQkl0upE1jI=
|
github.com/mattn/go-colorable v0.1.11 h1:nQ+aFkoE2TMGc0b68U2OKSexC+eq46+XwZzWXHRmPYs=
|
||||||
|
github.com/mattn/go-colorable v0.1.11/go.mod h1:u5H1YNBxpqRaxsYJYSkiCWKzEfiAb1Gb520KVy5xxl4=
|
||||||
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
github.com/mattn/go-isatty v0.0.3/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||||
|
github.com/mattn/go-isatty v0.0.14 h1:yVuAays6BHfxijgZPzw+3Zlu5yQgKGP2/hcQbHb7S9Y=
|
||||||
|
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
|
||||||
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
|
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
|
||||||
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
|
||||||
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
github.com/matttproud/golang_protobuf_extensions v1.0.1 h1:4hp9jkHxhMHkqkrB3Ix0jegS5sx/RkqARlsWZ6pIwiU=
|
||||||
@ -238,6 +223,7 @@ github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6
|
|||||||
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
github.com/opentracing/opentracing-go v1.1.0/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o=
|
||||||
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
github.com/pascaldekloe/goe v0.0.0-20180627143212-57f6aae5913c/go.mod h1:lzWF7FIEvWOWxwDKqyGYQf6ZUaNfKdP144TG7ZOy1lc=
|
||||||
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic=
|
||||||
|
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
|
||||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
||||||
@ -272,6 +258,9 @@ github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40T
|
|||||||
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg=
|
||||||
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ=
|
||||||
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||||
|
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
|
||||||
|
github.com/rogpeppe/go-internal v1.8.1 h1:geMPLpDpQOgVyCg5z5GoRwLHepNdb71NXb67XFkP+Eg=
|
||||||
|
github.com/rogpeppe/go-internal v1.8.1/go.mod h1:JeRgkft04UBgHMgCIwADu4Pn6Mtm5d4nPKWu0nJ5d+o=
|
||||||
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
github.com/russross/blackfriday/v2 v2.0.1/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
|
||||||
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
github.com/ryanuber/columnize v0.0.0-20160712163229-9b3edd62028f/go.mod h1:sm1tb6uqfes/u+d4ooFouqFdy9/2g9QGwK3SQygK0Ts=
|
||||||
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
github.com/sean-/seed v0.0.0-20170313163322-e2103e2c3529/go.mod h1:DxrIzT+xaE7yg65j358z/aeFdxmN0P9QXhEzd20vsDc=
|
||||||
@ -302,21 +291,20 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
|
|||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
|
||||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802 h1:uruHq4dN7GR16kFc5fp3d1RIYzJW5onx8Ybykw2YQFA=
|
github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802 h1:uruHq4dN7GR16kFc5fp3d1RIYzJW5onx8Ybykw2YQFA=
|
||||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
github.com/tmc/grpc-websocket-proxy v0.0.0-20201229170055-e5319fda7802/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||||
github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0=
|
|
||||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8=
|
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2 h1:eY9dn8+vbi4tKz5Qo6v2eYzo7kUS51QINcR5jNpbZS8=
|
||||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
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.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
|
||||||
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
go.etcd.io/bbolt v1.3.2/go.mod h1:IbVyRI1SCnLcuJnV2u8VeU0CEYM7e686BmAb1XKL+uU=
|
||||||
go.etcd.io/bbolt v1.3.6 h1:/ecaJf0sk1l4l6V4awd65v2C3ILy7MSj+s/x1ADCIMU=
|
go.etcd.io/bbolt v1.3.7 h1:j+zJOnnEjF/kyHlDDgGnVL/AIqIJPq8UoB2GSNfkUfQ=
|
||||||
go.etcd.io/bbolt v1.3.6/go.mod h1:qXsaaIqmgQH0T+OPdb99Bf+PKfBBQVAdyD6TY9G8XM4=
|
go.etcd.io/bbolt v1.3.7/go.mod h1:N9Mkw9X8x5fupy0IKsmuqVtoGDyxsaDlbk4Rd05IAQw=
|
||||||
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU=
|
||||||
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8=
|
||||||
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.25.0 h1:Wx7nFnvCaissIUZxPkBqDz2963Z+Cl+PkYbDKzTxDqQ=
|
go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc v0.25.0 h1:Wx7nFnvCaissIUZxPkBqDz2963Z+Cl+PkYbDKzTxDqQ=
|
||||||
@ -396,8 +384,8 @@ golang.org/x/net v0.0.0-20200822124328-c89045814202/go.mod h1:/O7V0waA8r7cgGh81R
|
|||||||
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
golang.org/x/net v0.0.0-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
golang.org/x/net v0.0.0-20201202161906-c7110b5ffcbb/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
|
||||||
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM=
|
||||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE=
|
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g=
|
||||||
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
|
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
|
||||||
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||||
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw=
|
||||||
@ -411,8 +399,8 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ
|
|||||||
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20201207232520-09787c993a3a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
|
|
||||||
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||||
|
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4 h1:uVc8UZUe6tr40fFVnUP5Oj+veunVezqYl9z7DYw9xzw=
|
||||||
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180823144017-11551d06cbcc/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
@ -432,33 +420,31 @@ golang.org/x/sys v0.0.0-20200106162015-b016eb3dc98e/go.mod h1:h1NjWce9XRLGQEsW7w
|
|||||||
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200615200032-f1bc736245b1/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200625212154-ddb9806d33ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210330210617-4fbd30eecc44/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20210423185535-09eb48e85fd7/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1 h1:SrN+KX8Art/Sf4HNj6Zcz06G7VEz+7w9tdXTPOZ7+l4=
|
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
golang.org/x/sys v0.0.0-20210927094055-39ccf1dd6fa6/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
|
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU=
|
||||||
|
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
|
||||||
golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
|
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.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/text v0.3.6 h1:aRYxNxv6iGQlyVaZmk6ZgYEDa+Jg18DxebPSrd6bg1M=
|
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo=
|
||||||
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
|
||||||
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba h1:O8mE0/t419eoIwhTFpKVkHiTs/Igowgfkj25AcZrtiE=
|
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba h1:O8mE0/t419eoIwhTFpKVkHiTs/Igowgfkj25AcZrtiE=
|
||||||
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
golang.org/x/time v0.0.0-20210220033141-f8bda1e9f3ba/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ=
|
||||||
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180221164845-07fd8470d635/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY=
|
||||||
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
|
||||||
@ -479,7 +465,7 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn
|
|||||||
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
golang.org/x/tools v0.0.0-20200130002326-2f3ba24bd6e7/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28=
|
||||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk=
|
||||||
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
|
||||||
@ -507,8 +493,8 @@ google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvx
|
|||||||
google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
google.golang.org/genproto v0.0.0-20200423170343-7949de9c1215/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||||
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
google.golang.org/genproto v0.0.0-20200513103714-09dca8ec2884/go.mod h1:55QSHmfGQM9UVYDPBsyGGes0y52j32PQ3BqQfXhyH3c=
|
||||||
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo=
|
||||||
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c h1:wtujag7C+4D6KMoulW9YauvK2lgdvCMS260jsqqBXr0=
|
google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84 h1:R1r5J0u6Cx+RNl/6mezTw6oA14cmKC96FeUwL6A9bd4=
|
||||||
google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0=
|
google.golang.org/genproto v0.0.0-20210624195500-8bfb893ecb84/go.mod h1:SzzZ/N+nwJDaO1kznhnlzqS8ocJICar6hYhVyhi++24=
|
||||||
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c=
|
||||||
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38=
|
||||||
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM=
|
||||||
@ -559,8 +545,8 @@ gopkg.in/yaml.v2 v2.3.0/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|||||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
@ -241,34 +241,34 @@ type intervalTree struct {
|
|||||||
//
|
//
|
||||||
// "Introduction to Algorithms" (Cormen et al, 3rd ed.), chapter 13.4, p324
|
// "Introduction to Algorithms" (Cormen et al, 3rd ed.), chapter 13.4, p324
|
||||||
//
|
//
|
||||||
// 0. RB-DELETE(T, z)
|
// RB-DELETE(T, z)
|
||||||
// 1.
|
//
|
||||||
// 2. y = z
|
// y = z
|
||||||
// 3. y-original-color = y.color
|
// y-original-color = y.color
|
||||||
// 4.
|
//
|
||||||
// 5. if z.left == T.nil
|
// if z.left == T.nil
|
||||||
// 6. x = z.right
|
// x = z.right
|
||||||
// 7. RB-TRANSPLANT(T, z, z.right)
|
// RB-TRANSPLANT(T, z, z.right)
|
||||||
// 8. else if z.right == T.nil
|
// else if z.right == T.nil
|
||||||
// 9. x = z.left
|
// x = z.left
|
||||||
// 10. RB-TRANSPLANT(T, z, z.left)
|
// RB-TRANSPLANT(T, z, z.left)
|
||||||
// 11. else
|
// else
|
||||||
// 12. y = TREE-MINIMUM(z.right)
|
// y = TREE-MINIMUM(z.right)
|
||||||
// 13. y-original-color = y.color
|
// y-original-color = y.color
|
||||||
// 14. x = y.right
|
// x = y.right
|
||||||
// 15. if y.p == z
|
// if y.p == z
|
||||||
// 16. x.p = y
|
// x.p = y
|
||||||
// 17. else
|
// else
|
||||||
// 18. RB-TRANSPLANT(T, y, y.right)
|
// RB-TRANSPLANT(T, y, y.right)
|
||||||
// 19. y.right = z.right
|
// y.right = z.right
|
||||||
// 20. y.right.p = y
|
// y.right.p = y
|
||||||
// 21. RB-TRANSPLANT(T, z, y)
|
// RB-TRANSPLANT(T, z, y)
|
||||||
// 22. y.left = z.left
|
// y.left = z.left
|
||||||
// 23. y.left.p = y
|
// y.left.p = y
|
||||||
// 24. y.color = z.color
|
// y.color = z.color
|
||||||
// 25.
|
//
|
||||||
// 26. if y-original-color == BLACK
|
// if y-original-color == BLACK
|
||||||
// 27. RB-DELETE-FIXUP(T, x)
|
// RB-DELETE-FIXUP(T, x)
|
||||||
|
|
||||||
// Delete removes the node with the given interval from the tree, returning
|
// Delete removes the node with the given interval from the tree, returning
|
||||||
// true if a node is in fact removed.
|
// true if a node is in fact removed.
|
||||||
@ -317,48 +317,47 @@ func (ivt *intervalTree) Delete(ivl Interval) bool {
|
|||||||
|
|
||||||
// "Introduction to Algorithms" (Cormen et al, 3rd ed.), chapter 13.4, p326
|
// "Introduction to Algorithms" (Cormen et al, 3rd ed.), chapter 13.4, p326
|
||||||
//
|
//
|
||||||
// 0. RB-DELETE-FIXUP(T, z)
|
// RB-DELETE-FIXUP(T, z)
|
||||||
// 1.
|
|
||||||
// 2. while x ≠ T.root and x.color == BLACK
|
|
||||||
// 3. if x == x.p.left
|
|
||||||
// 4. w = x.p.right
|
|
||||||
// 5. if w.color == RED
|
|
||||||
// 6. w.color = BLACK
|
|
||||||
// 7. x.p.color = RED
|
|
||||||
// 8. LEFT-ROTATE(T, x, p)
|
|
||||||
// 9. if w.left.color == BLACK and w.right.color == BLACK
|
|
||||||
// 10. w.color = RED
|
|
||||||
// 11. x = x.p
|
|
||||||
// 12. else if w.right.color == BLACK
|
|
||||||
// 13. w.left.color = BLACK
|
|
||||||
// 14. w.color = RED
|
|
||||||
// 15. RIGHT-ROTATE(T, w)
|
|
||||||
// 16. w = w.p.right
|
|
||||||
// 17. w.color = x.p.color
|
|
||||||
// 18. x.p.color = BLACK
|
|
||||||
// 19. LEFT-ROTATE(T, w.p)
|
|
||||||
// 20. x = T.root
|
|
||||||
// 21. else
|
|
||||||
// 22. w = x.p.left
|
|
||||||
// 23. if w.color == RED
|
|
||||||
// 24. w.color = BLACK
|
|
||||||
// 25. x.p.color = RED
|
|
||||||
// 26. RIGHT-ROTATE(T, x, p)
|
|
||||||
// 27. if w.right.color == BLACK and w.left.color == BLACK
|
|
||||||
// 28. w.color = RED
|
|
||||||
// 29. x = x.p
|
|
||||||
// 30. else if w.left.color == BLACK
|
|
||||||
// 31. w.right.color = BLACK
|
|
||||||
// 32. w.color = RED
|
|
||||||
// 33. LEFT-ROTATE(T, w)
|
|
||||||
// 34. w = w.p.left
|
|
||||||
// 35. w.color = x.p.color
|
|
||||||
// 36. x.p.color = BLACK
|
|
||||||
// 37. RIGHT-ROTATE(T, w.p)
|
|
||||||
// 38. x = T.root
|
|
||||||
// 39.
|
|
||||||
// 40. x.color = BLACK
|
|
||||||
//
|
//
|
||||||
|
// while x ≠ T.root and x.color == BLACK
|
||||||
|
// if x == x.p.left
|
||||||
|
// w = x.p.right
|
||||||
|
// if w.color == RED
|
||||||
|
// w.color = BLACK
|
||||||
|
// x.p.color = RED
|
||||||
|
// LEFT-ROTATE(T, x, p)
|
||||||
|
// if w.left.color == BLACK and w.right.color == BLACK
|
||||||
|
// w.color = RED
|
||||||
|
// x = x.p
|
||||||
|
// else if w.right.color == BLACK
|
||||||
|
// w.left.color = BLACK
|
||||||
|
// w.color = RED
|
||||||
|
// RIGHT-ROTATE(T, w)
|
||||||
|
// w = w.p.right
|
||||||
|
// w.color = x.p.color
|
||||||
|
// x.p.color = BLACK
|
||||||
|
// LEFT-ROTATE(T, w.p)
|
||||||
|
// x = T.root
|
||||||
|
// else
|
||||||
|
// w = x.p.left
|
||||||
|
// if w.color == RED
|
||||||
|
// w.color = BLACK
|
||||||
|
// x.p.color = RED
|
||||||
|
// RIGHT-ROTATE(T, x, p)
|
||||||
|
// if w.right.color == BLACK and w.left.color == BLACK
|
||||||
|
// w.color = RED
|
||||||
|
// x = x.p
|
||||||
|
// else if w.left.color == BLACK
|
||||||
|
// w.right.color = BLACK
|
||||||
|
// w.color = RED
|
||||||
|
// LEFT-ROTATE(T, w)
|
||||||
|
// w = w.p.left
|
||||||
|
// w.color = x.p.color
|
||||||
|
// x.p.color = BLACK
|
||||||
|
// RIGHT-ROTATE(T, w.p)
|
||||||
|
// x = T.root
|
||||||
|
//
|
||||||
|
// x.color = BLACK
|
||||||
func (ivt *intervalTree) deleteFixup(x *intervalNode) {
|
func (ivt *intervalTree) deleteFixup(x *intervalNode) {
|
||||||
for x != ivt.root && x.color(ivt.sentinel) == black {
|
for x != ivt.root && x.color(ivt.sentinel) == black {
|
||||||
if x == x.parent.left { // line 3-20
|
if x == x.parent.left { // line 3-20
|
||||||
@ -439,32 +438,32 @@ func (ivt *intervalTree) createIntervalNode(ivl Interval, val interface{}) *inte
|
|||||||
//
|
//
|
||||||
// "Introduction to Algorithms" (Cormen et al, 3rd ed.), chapter 13.3, p315
|
// "Introduction to Algorithms" (Cormen et al, 3rd ed.), chapter 13.3, p315
|
||||||
//
|
//
|
||||||
// 0. RB-INSERT(T, z)
|
// RB-INSERT(T, z)
|
||||||
// 1.
|
//
|
||||||
// 2. y = T.nil
|
// y = T.nil
|
||||||
// 3. x = T.root
|
// x = T.root
|
||||||
// 4.
|
//
|
||||||
// 5. while x ≠ T.nil
|
// while x ≠ T.nil
|
||||||
// 6. y = x
|
// y = x
|
||||||
// 7. if z.key < x.key
|
// if z.key < x.key
|
||||||
// 8. x = x.left
|
// x = x.left
|
||||||
// 9. else
|
// else
|
||||||
// 10. x = x.right
|
// x = x.right
|
||||||
// 11.
|
//
|
||||||
// 12. z.p = y
|
// z.p = y
|
||||||
// 13.
|
//
|
||||||
// 14. if y == T.nil
|
// if y == T.nil
|
||||||
// 15. T.root = z
|
// T.root = z
|
||||||
// 16. else if z.key < y.key
|
// else if z.key < y.key
|
||||||
// 17. y.left = z
|
// y.left = z
|
||||||
// 18. else
|
// else
|
||||||
// 19. y.right = z
|
// y.right = z
|
||||||
// 20.
|
//
|
||||||
// 21. z.left = T.nil
|
// z.left = T.nil
|
||||||
// 22. z.right = T.nil
|
// z.right = T.nil
|
||||||
// 23. z.color = RED
|
// z.color = RED
|
||||||
// 24.
|
//
|
||||||
// 25. RB-INSERT-FIXUP(T, z)
|
// RB-INSERT-FIXUP(T, z)
|
||||||
|
|
||||||
// Insert adds a node with the given interval into the tree.
|
// Insert adds a node with the given interval into the tree.
|
||||||
func (ivt *intervalTree) Insert(ivl Interval, val interface{}) {
|
func (ivt *intervalTree) Insert(ivl Interval, val interface{}) {
|
||||||
@ -499,38 +498,37 @@ func (ivt *intervalTree) Insert(ivl Interval, val interface{}) {
|
|||||||
|
|
||||||
// "Introduction to Algorithms" (Cormen et al, 3rd ed.), chapter 13.3, p316
|
// "Introduction to Algorithms" (Cormen et al, 3rd ed.), chapter 13.3, p316
|
||||||
//
|
//
|
||||||
// 0. RB-INSERT-FIXUP(T, z)
|
// RB-INSERT-FIXUP(T, z)
|
||||||
// 1.
|
|
||||||
// 2. while z.p.color == RED
|
|
||||||
// 3. if z.p == z.p.p.left
|
|
||||||
// 4. y = z.p.p.right
|
|
||||||
// 5. if y.color == RED
|
|
||||||
// 6. z.p.color = BLACK
|
|
||||||
// 7. y.color = BLACK
|
|
||||||
// 8. z.p.p.color = RED
|
|
||||||
// 9. z = z.p.p
|
|
||||||
// 10. else if z == z.p.right
|
|
||||||
// 11. z = z.p
|
|
||||||
// 12. LEFT-ROTATE(T, z)
|
|
||||||
// 13. z.p.color = BLACK
|
|
||||||
// 14. z.p.p.color = RED
|
|
||||||
// 15. RIGHT-ROTATE(T, z.p.p)
|
|
||||||
// 16. else
|
|
||||||
// 17. y = z.p.p.left
|
|
||||||
// 18. if y.color == RED
|
|
||||||
// 19. z.p.color = BLACK
|
|
||||||
// 20. y.color = BLACK
|
|
||||||
// 21. z.p.p.color = RED
|
|
||||||
// 22. z = z.p.p
|
|
||||||
// 23. else if z == z.p.right
|
|
||||||
// 24. z = z.p
|
|
||||||
// 25. RIGHT-ROTATE(T, z)
|
|
||||||
// 26. z.p.color = BLACK
|
|
||||||
// 27. z.p.p.color = RED
|
|
||||||
// 28. LEFT-ROTATE(T, z.p.p)
|
|
||||||
// 29.
|
|
||||||
// 30. T.root.color = BLACK
|
|
||||||
//
|
//
|
||||||
|
// while z.p.color == RED
|
||||||
|
// if z.p == z.p.p.left
|
||||||
|
// y = z.p.p.right
|
||||||
|
// if y.color == RED
|
||||||
|
// z.p.color = BLACK
|
||||||
|
// y.color = BLACK
|
||||||
|
// z.p.p.color = RED
|
||||||
|
// z = z.p.p
|
||||||
|
// else if z == z.p.right
|
||||||
|
// z = z.p
|
||||||
|
// LEFT-ROTATE(T, z)
|
||||||
|
// z.p.color = BLACK
|
||||||
|
// z.p.p.color = RED
|
||||||
|
// RIGHT-ROTATE(T, z.p.p)
|
||||||
|
// else
|
||||||
|
// y = z.p.p.left
|
||||||
|
// if y.color == RED
|
||||||
|
// z.p.color = BLACK
|
||||||
|
// y.color = BLACK
|
||||||
|
// z.p.p.color = RED
|
||||||
|
// z = z.p.p
|
||||||
|
// else if z == z.p.right
|
||||||
|
// z = z.p
|
||||||
|
// RIGHT-ROTATE(T, z)
|
||||||
|
// z.p.color = BLACK
|
||||||
|
// z.p.p.color = RED
|
||||||
|
// LEFT-ROTATE(T, z.p.p)
|
||||||
|
//
|
||||||
|
// T.root.color = BLACK
|
||||||
func (ivt *intervalTree) insertFixup(z *intervalNode) {
|
func (ivt *intervalTree) insertFixup(z *intervalNode) {
|
||||||
for z.parent.color(ivt.sentinel) == red {
|
for z.parent.color(ivt.sentinel) == red {
|
||||||
if z.parent == z.parent.parent.left { // line 3-15
|
if z.parent == z.parent.parent.left { // line 3-15
|
||||||
@ -578,26 +576,25 @@ func (ivt *intervalTree) insertFixup(z *intervalNode) {
|
|||||||
//
|
//
|
||||||
// "Introduction to Algorithms" (Cormen et al, 3rd ed.), chapter 13.2, p313
|
// "Introduction to Algorithms" (Cormen et al, 3rd ed.), chapter 13.2, p313
|
||||||
//
|
//
|
||||||
// 0. LEFT-ROTATE(T, x)
|
// LEFT-ROTATE(T, x)
|
||||||
// 1.
|
|
||||||
// 2. y = x.right
|
|
||||||
// 3. x.right = y.left
|
|
||||||
// 4.
|
|
||||||
// 5. if y.left ≠ T.nil
|
|
||||||
// 6. y.left.p = x
|
|
||||||
// 7.
|
|
||||||
// 8. y.p = x.p
|
|
||||||
// 9.
|
|
||||||
// 10. if x.p == T.nil
|
|
||||||
// 11. T.root = y
|
|
||||||
// 12. else if x == x.p.left
|
|
||||||
// 13. x.p.left = y
|
|
||||||
// 14. else
|
|
||||||
// 15. x.p.right = y
|
|
||||||
// 16.
|
|
||||||
// 17. y.left = x
|
|
||||||
// 18. x.p = y
|
|
||||||
//
|
//
|
||||||
|
// y = x.right
|
||||||
|
// x.right = y.left
|
||||||
|
//
|
||||||
|
// if y.left ≠ T.nil
|
||||||
|
// y.left.p = x
|
||||||
|
//
|
||||||
|
// y.p = x.p
|
||||||
|
//
|
||||||
|
// if x.p == T.nil
|
||||||
|
// T.root = y
|
||||||
|
// else if x == x.p.left
|
||||||
|
// x.p.left = y
|
||||||
|
// else
|
||||||
|
// x.p.right = y
|
||||||
|
//
|
||||||
|
// y.left = x
|
||||||
|
// x.p = y
|
||||||
func (ivt *intervalTree) rotateLeft(x *intervalNode) {
|
func (ivt *intervalTree) rotateLeft(x *intervalNode) {
|
||||||
// rotateLeft x must have right child
|
// rotateLeft x must have right child
|
||||||
if x.right == ivt.sentinel {
|
if x.right == ivt.sentinel {
|
||||||
@ -624,26 +621,25 @@ func (ivt *intervalTree) rotateLeft(x *intervalNode) {
|
|||||||
|
|
||||||
// rotateRight moves x so it is right of its left child
|
// rotateRight moves x so it is right of its left child
|
||||||
//
|
//
|
||||||
// 0. RIGHT-ROTATE(T, x)
|
// RIGHT-ROTATE(T, x)
|
||||||
// 1.
|
|
||||||
// 2. y = x.left
|
|
||||||
// 3. x.left = y.right
|
|
||||||
// 4.
|
|
||||||
// 5. if y.right ≠ T.nil
|
|
||||||
// 6. y.right.p = x
|
|
||||||
// 7.
|
|
||||||
// 8. y.p = x.p
|
|
||||||
// 9.
|
|
||||||
// 10. if x.p == T.nil
|
|
||||||
// 11. T.root = y
|
|
||||||
// 12. else if x == x.p.right
|
|
||||||
// 13. x.p.right = y
|
|
||||||
// 14. else
|
|
||||||
// 15. x.p.left = y
|
|
||||||
// 16.
|
|
||||||
// 17. y.right = x
|
|
||||||
// 18. x.p = y
|
|
||||||
//
|
//
|
||||||
|
// y = x.left
|
||||||
|
// x.left = y.right
|
||||||
|
//
|
||||||
|
// if y.right ≠ T.nil
|
||||||
|
// y.right.p = x
|
||||||
|
//
|
||||||
|
// y.p = x.p
|
||||||
|
//
|
||||||
|
// if x.p == T.nil
|
||||||
|
// T.root = y
|
||||||
|
// else if x == x.p.right
|
||||||
|
// x.p.right = y
|
||||||
|
// else
|
||||||
|
// x.p.left = y
|
||||||
|
//
|
||||||
|
// y.right = x
|
||||||
|
// x.p = y
|
||||||
func (ivt *intervalTree) rotateRight(x *intervalNode) {
|
func (ivt *intervalTree) rotateRight(x *intervalNode) {
|
||||||
// rotateRight x must have left child
|
// rotateRight x must have left child
|
||||||
if x.left == ivt.sentinel {
|
if x.left == ivt.sentinel {
|
||||||
|
@ -63,27 +63,28 @@ func TestIntervalTreeInsert(t *testing.T) {
|
|||||||
// Use https://www.cs.usfca.edu/~galles/visualization/RedBlack.html for test case creation.
|
// Use https://www.cs.usfca.edu/~galles/visualization/RedBlack.html for test case creation.
|
||||||
//
|
//
|
||||||
// Regular Binary Search Tree
|
// Regular Binary Search Tree
|
||||||
// [0,1]
|
//
|
||||||
// \
|
// [0,1]
|
||||||
// [1,2]
|
// \
|
||||||
// \
|
// [1,2]
|
||||||
// [3,4]
|
// \
|
||||||
// \
|
// [3,4]
|
||||||
// [5,6]
|
// \
|
||||||
// \
|
// [5,6]
|
||||||
// [7,8]
|
// \
|
||||||
// \
|
// [7,8]
|
||||||
// [8,9]
|
// \
|
||||||
|
// [8,9]
|
||||||
//
|
//
|
||||||
// Self-Balancing Binary Search Tree
|
// Self-Balancing Binary Search Tree
|
||||||
// [1,2]
|
|
||||||
// / \
|
|
||||||
// [0,1] [5,6]
|
|
||||||
// / \
|
|
||||||
// [3,4] [7,8]
|
|
||||||
// \
|
|
||||||
// [8,9]
|
|
||||||
//
|
//
|
||||||
|
// [1,2]
|
||||||
|
// / \
|
||||||
|
// [0,1] [5,6]
|
||||||
|
// / \
|
||||||
|
// [3,4] [7,8]
|
||||||
|
// \
|
||||||
|
// [8,9]
|
||||||
func TestIntervalTreeSelfBalanced(t *testing.T) {
|
func TestIntervalTreeSelfBalanced(t *testing.T) {
|
||||||
ivt := NewIntervalTree()
|
ivt := NewIntervalTree()
|
||||||
ivt.Insert(NewInt64Interval(0, 1), 0)
|
ivt.Insert(NewInt64Interval(0, 1), 0)
|
||||||
@ -120,58 +121,56 @@ func TestIntervalTreeSelfBalanced(t *testing.T) {
|
|||||||
// Use https://www.cs.usfca.edu/~galles/visualization/RedBlack.html for test case creation.
|
// Use https://www.cs.usfca.edu/~galles/visualization/RedBlack.html for test case creation.
|
||||||
// See https://github.com/etcd-io/etcd/issues/10877 for more detail.
|
// See https://github.com/etcd-io/etcd/issues/10877 for more detail.
|
||||||
//
|
//
|
||||||
//
|
|
||||||
// After insertion:
|
// After insertion:
|
||||||
// [510,511]
|
|
||||||
// / \
|
|
||||||
// ---------- -----------------------
|
|
||||||
// / \
|
|
||||||
// [82,83] [830,831]
|
|
||||||
// / \ / \
|
|
||||||
// / \ / \
|
|
||||||
// [11,12] [383,384](red) [647,648] [899,900](red)
|
|
||||||
// / \ / \ / \
|
|
||||||
// / \ / \ / \
|
|
||||||
// [261,262] [410,411] [514,515](red) [815,816](red) [888,889] [972,973]
|
|
||||||
// / \ /
|
|
||||||
// / \ /
|
|
||||||
// [238,239](red) [292,293](red) [953,954](red)
|
|
||||||
//
|
//
|
||||||
|
// [510,511]
|
||||||
|
// / \
|
||||||
|
// ---------- -----------------------
|
||||||
|
// / \
|
||||||
|
// [82,83] [830,831]
|
||||||
|
// / \ / \
|
||||||
|
// / \ / \
|
||||||
|
// [11,12] [383,384](red) [647,648] [899,900](red)
|
||||||
|
// / \ / \ / \
|
||||||
|
// / \ / \ / \
|
||||||
|
// [261,262] [410,411] [514,515](red) [815,816](red) [888,889] [972,973]
|
||||||
|
// / \ /
|
||||||
|
// / \ /
|
||||||
|
// [238,239](red) [292,293](red) [953,954](red)
|
||||||
//
|
//
|
||||||
// After deleting 514 (no rebalance):
|
// After deleting 514 (no rebalance):
|
||||||
// [510,511]
|
|
||||||
// / \
|
|
||||||
// ---------- -----------------------
|
|
||||||
// / \
|
|
||||||
// [82,83] [830,831]
|
|
||||||
// / \ / \
|
|
||||||
// / \ / \
|
|
||||||
// [11,12] [383,384](red) [647,648] [899,900](red)
|
|
||||||
// / \ \ / \
|
|
||||||
// / \ \ / \
|
|
||||||
// [261,262] [410,411] [815,816](red) [888,889] [972,973]
|
|
||||||
// / \ /
|
|
||||||
// / \ /
|
|
||||||
// [238,239](red) [292,293](red) [953,954](red)
|
|
||||||
//
|
//
|
||||||
|
// [510,511]
|
||||||
|
// / \
|
||||||
|
// ---------- -----------------------
|
||||||
|
// / \
|
||||||
|
// [82,83] [830,831]
|
||||||
|
// / \ / \
|
||||||
|
// / \ / \
|
||||||
|
// [11,12] [383,384](red) [647,648] [899,900](red)
|
||||||
|
// / \ \ / \
|
||||||
|
// / \ \ / \
|
||||||
|
// [261,262] [410,411] [815,816](red) [888,889] [972,973]
|
||||||
|
// / \ /
|
||||||
|
// / \ /
|
||||||
|
// [238,239](red) [292,293](red) [953,954](red)
|
||||||
//
|
//
|
||||||
// After deleting 11 (requires rebalancing):
|
// After deleting 11 (requires rebalancing):
|
||||||
// [510,511]
|
|
||||||
// / \
|
|
||||||
// ---------- --------------------------
|
|
||||||
// / \
|
|
||||||
// [383,384] [830,831]
|
|
||||||
// / \ / \
|
|
||||||
// / \ / \
|
|
||||||
// [261,262](red) [410,411] [647,648] [899,900](red)
|
|
||||||
// / \ \ / \
|
|
||||||
// / \ \ / \
|
|
||||||
// [82,83] [292,293] [815,816](red) [888,889] [972,973]
|
|
||||||
// \ /
|
|
||||||
// \ /
|
|
||||||
// [238,239](red) [953,954](red)
|
|
||||||
//
|
|
||||||
//
|
//
|
||||||
|
// [510,511]
|
||||||
|
// / \
|
||||||
|
// ---------- --------------------------
|
||||||
|
// / \
|
||||||
|
// [383,384] [830,831]
|
||||||
|
// / \ / \
|
||||||
|
// / \ / \
|
||||||
|
// [261,262](red) [410,411] [647,648] [899,900](red)
|
||||||
|
// / \ \ / \
|
||||||
|
// / \ \ / \
|
||||||
|
// [82,83] [292,293] [815,816](red) [888,889] [972,973]
|
||||||
|
// \ /
|
||||||
|
// \ /
|
||||||
|
// [238,239](red) [953,954](red)
|
||||||
func TestIntervalTreeDelete(t *testing.T) {
|
func TestIntervalTreeDelete(t *testing.T) {
|
||||||
ivt := NewIntervalTree()
|
ivt := NewIntervalTree()
|
||||||
ivt.Insert(NewInt64Interval(510, 511), 0)
|
ivt.Insert(NewInt64Interval(510, 511), 0)
|
||||||
|
@ -149,6 +149,11 @@ func (ep *ExpectProcess) Signal(sig os.Signal) error {
|
|||||||
return ep.cmd.Process.Signal(sig)
|
return ep.cmd.Process.Signal(sig)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Wait waits for the process to finish.
|
||||||
|
func (ep *ExpectProcess) Wait() {
|
||||||
|
ep.wg.Wait()
|
||||||
|
}
|
||||||
|
|
||||||
// Close waits for the expect process to exit.
|
// Close waits for the expect process to exit.
|
||||||
// Close currently does not return error if process exited with !=0 status.
|
// Close currently does not return error if process exited with !=0 status.
|
||||||
// TODO: Close should expose underlying proces failure by default.
|
// TODO: Close should expose underlying proces failure by default.
|
||||||
|
22
pkg/go.mod
22
pkg/go.mod
@ -1,19 +1,33 @@
|
|||||||
module go.etcd.io/etcd/pkg/v3
|
module go.etcd.io/etcd/pkg/v3
|
||||||
|
|
||||||
go 1.16
|
go 1.19
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/creack/pty v1.1.11
|
github.com/creack/pty v1.1.11
|
||||||
github.com/dustin/go-humanize v1.0.0
|
github.com/dustin/go-humanize v1.0.0
|
||||||
github.com/golang/protobuf v1.5.1 // indirect
|
|
||||||
github.com/spf13/cobra v1.1.3
|
github.com/spf13/cobra v1.1.3
|
||||||
github.com/spf13/pflag v1.0.5
|
github.com/spf13/pflag v1.0.5
|
||||||
github.com/stretchr/testify v1.7.0
|
github.com/stretchr/testify v1.8.1
|
||||||
go.etcd.io/etcd/client/pkg/v3 v3.5.5
|
go.etcd.io/etcd/client/pkg/v3 v3.5.9
|
||||||
go.uber.org/zap v1.17.0
|
go.uber.org/zap v1.17.0
|
||||||
google.golang.org/grpc v1.41.0
|
google.golang.org/grpc v1.41.0
|
||||||
)
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/davecgh/go-spew v1.1.1 // indirect
|
||||||
|
github.com/golang/protobuf v1.5.1 // indirect
|
||||||
|
github.com/inconshreveable/mousetrap v1.0.0 // indirect
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
|
go.uber.org/atomic v1.7.0 // indirect
|
||||||
|
go.uber.org/multierr v1.6.0 // indirect
|
||||||
|
golang.org/x/net v0.0.0-20200822124328-c89045814202 // indirect
|
||||||
|
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57 // indirect
|
||||||
|
golang.org/x/text v0.3.2 // indirect
|
||||||
|
google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013 // indirect
|
||||||
|
google.golang.org/protobuf v1.26.0 // indirect
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 // indirect
|
||||||
|
)
|
||||||
|
|
||||||
replace (
|
replace (
|
||||||
go.etcd.io/etcd => ./FORBIDDEN_DEPENDENCY
|
go.etcd.io/etcd => ./FORBIDDEN_DEPENDENCY
|
||||||
go.etcd.io/etcd/api/v3 => ./FORBIDDEN_DEPENDENCY
|
go.etcd.io/etcd/api/v3 => ./FORBIDDEN_DEPENDENCY
|
||||||
|
12
pkg/go.sum
12
pkg/go.sum
@ -35,7 +35,6 @@ github.com/coreos/bbolt v1.3.2/go.mod h1:iRUV2dpdMOn7Bo10OQBFzIJO9kkE559Wcmn+qkE
|
|||||||
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
github.com/coreos/etcd v3.3.13+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE=
|
||||||
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
github.com/coreos/go-semver v0.3.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk=
|
||||||
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
github.com/coreos/go-systemd v0.0.0-20190321100706-95778dfbb74e/go.mod h1:F5haX7vjVVG0kc13fIWeqUViNPyEJxv/OmvnBo0Yme4=
|
||||||
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
|
||||||
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
github.com/coreos/pkg v0.0.0-20180928190104-399ea9e2e55f/go.mod h1:E3G3o1h8I7cfcXa63jLwjI0eiQQMgzzUDFVpN/nH/eA=
|
||||||
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
github.com/cpuguy83/go-md2man/v2 v2.0.0/go.mod h1:maD7wRr/U5Z6m/iR4s+kqSMx2CaBsrgA7czyZG/E6dU=
|
||||||
github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw=
|
github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw=
|
||||||
@ -61,7 +60,6 @@ github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2
|
|||||||
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE=
|
||||||
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk=
|
||||||
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY=
|
||||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
|
||||||
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ=
|
||||||
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
github.com/gogo/protobuf v1.2.1/go.mod h1:hp+jE20tsWTFYpLwKvXlhS1hjn+gTNwPg2I6zVXpSg4=
|
||||||
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q=
|
||||||
@ -200,11 +198,16 @@ github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An
|
|||||||
github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
|
github.com/spf13/viper v1.7.0/go.mod h1:8WkrPz2fc9jxqZNCJI/76HCieCp4Q8HaLFoCha5qpdg=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
||||||
github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
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/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs=
|
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.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
||||||
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA=
|
||||||
github.com/stretchr/testify v1.7.0 h1:nwc3DEeHmmLAfoZucVR881uASk0Mfjw8xYJ99tb5CcY=
|
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
||||||
|
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
|
||||||
|
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
|
||||||
|
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
|
||||||
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
github.com/subosito/gotenv v1.2.0/go.mod h1:N0PQaV/YGNqwC0u51sEeR/aUtSLEXKX9iv69rRypqCw=
|
||||||
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
github.com/tmc/grpc-websocket-proxy v0.0.0-20190109142713-0ad062ec5ee5/go.mod h1:ncp9v5uamzpCO7NfCPTXjqaC+bZgJeR0sMTm6dMHP7U=
|
||||||
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
github.com/xiang90/probing v0.0.0-20190116061207-43a291ad63a2/go.mod h1:UETIi67q53MR2AWcXfiuqkDkRtnGDLqkBTpCHuJHxtU=
|
||||||
@ -373,8 +376,9 @@ gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|||||||
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
gopkg.in/yaml.v2 v2.4.0 h1:D8xgwECY7CYvx+Y2n4sBz93Jn9JRvxdiyyo8CTfuKaY=
|
||||||
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b h1:h8qDotaEPuJATrMmW04NCwg7v22aHH28wwpauUhK9Oo=
|
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
|
||||||
|
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
||||||
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=
|
||||||
|
@ -44,7 +44,7 @@ func TestPageWriterRandom(t *testing.T) {
|
|||||||
t.Logf("total write bytes: %d (of %d)", cw.writeBytes, n)
|
t.Logf("total write bytes: %d (of %d)", cw.writeBytes, n)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestPageWriterPariallack tests the case where a write overflows the buffer
|
// TestPageWriterPartialSlack tests the case where a write overflows the buffer
|
||||||
// but there is not enough data to complete the slack write.
|
// but there is not enough data to complete the slack write.
|
||||||
func TestPageWriterPartialSlack(t *testing.T) {
|
func TestPageWriterPartialSlack(t *testing.T) {
|
||||||
defaultBufferBytes = 1024
|
defaultBufferBytes = 1024
|
||||||
|
@ -103,7 +103,7 @@ func resolveURL(ctx context.Context, lg *zap.Logger, u url.URL) (string, error)
|
|||||||
)
|
)
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
if host == "localhost" || net.ParseIP(host) != nil {
|
if host == "localhost" {
|
||||||
return "", nil
|
return "", nil
|
||||||
}
|
}
|
||||||
for ctx.Err() == nil {
|
for ctx.Err() == nil {
|
||||||
@ -148,20 +148,31 @@ func urlsEqual(ctx context.Context, lg *zap.Logger, a []url.URL, b []url.URL) (b
|
|||||||
if len(a) != len(b) {
|
if len(a) != len(b) {
|
||||||
return false, fmt.Errorf("len(%q) != len(%q)", urlsToStrings(a), urlsToStrings(b))
|
return false, fmt.Errorf("len(%q) != len(%q)", urlsToStrings(a), urlsToStrings(b))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sort.Sort(types.URLs(a))
|
||||||
|
sort.Sort(types.URLs(b))
|
||||||
|
var needResolve bool
|
||||||
|
for i := range a {
|
||||||
|
if !reflect.DeepEqual(a[i], b[i]) {
|
||||||
|
needResolve = true
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if !needResolve {
|
||||||
|
return true, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// If URLs are not equal, try to resolve it and compare again.
|
||||||
urls, err := resolveTCPAddrs(ctx, lg, [][]url.URL{a, b})
|
urls, err := resolveTCPAddrs(ctx, lg, [][]url.URL{a, b})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return false, err
|
return false, err
|
||||||
}
|
}
|
||||||
preva, prevb := a, b
|
|
||||||
a, b = urls[0], urls[1]
|
a, b = urls[0], urls[1]
|
||||||
sort.Sort(types.URLs(a))
|
sort.Sort(types.URLs(a))
|
||||||
sort.Sort(types.URLs(b))
|
sort.Sort(types.URLs(b))
|
||||||
for i := range a {
|
for i := range a {
|
||||||
if !reflect.DeepEqual(a[i], b[i]) {
|
if !reflect.DeepEqual(a[i], b[i]) {
|
||||||
return false, fmt.Errorf("%q(resolved from %q) != %q(resolved from %q)",
|
return false, fmt.Errorf("resolved urls: %q != %q", a[i].String(), b[i].String())
|
||||||
a[i].String(), preva[i].String(),
|
|
||||||
b[i].String(), prevb[i].String(),
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return true, nil
|
return true, nil
|
||||||
@ -174,21 +185,13 @@ func URLStringsEqual(ctx context.Context, lg *zap.Logger, a []string, b []string
|
|||||||
if len(a) != len(b) {
|
if len(a) != len(b) {
|
||||||
return false, fmt.Errorf("len(%q) != len(%q)", a, b)
|
return false, fmt.Errorf("len(%q) != len(%q)", a, b)
|
||||||
}
|
}
|
||||||
urlsA := make([]url.URL, 0)
|
urlsA, err := stringsToURLs(a)
|
||||||
for _, str := range a {
|
if err != nil {
|
||||||
u, err := url.Parse(str)
|
return false, err
|
||||||
if err != nil {
|
|
||||||
return false, fmt.Errorf("failed to parse %q", str)
|
|
||||||
}
|
|
||||||
urlsA = append(urlsA, *u)
|
|
||||||
}
|
}
|
||||||
urlsB := make([]url.URL, 0)
|
urlsB, err := stringsToURLs(b)
|
||||||
for _, str := range b {
|
if err != nil {
|
||||||
u, err := url.Parse(str)
|
return false, err
|
||||||
if err != nil {
|
|
||||||
return false, fmt.Errorf("failed to parse %q", str)
|
|
||||||
}
|
|
||||||
urlsB = append(urlsB, *u)
|
|
||||||
}
|
}
|
||||||
return urlsEqual(ctx, lg, urlsA, urlsB)
|
return urlsEqual(ctx, lg, urlsA, urlsB)
|
||||||
}
|
}
|
||||||
@ -201,6 +204,18 @@ func urlsToStrings(us []url.URL) []string {
|
|||||||
return rs
|
return rs
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func stringsToURLs(us []string) ([]url.URL, error) {
|
||||||
|
urls := make([]url.URL, 0, len(us))
|
||||||
|
for _, str := range us {
|
||||||
|
u, err := url.Parse(str)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to parse string to URL: %q", str)
|
||||||
|
}
|
||||||
|
urls = append(urls, *u)
|
||||||
|
}
|
||||||
|
return urls, nil
|
||||||
|
}
|
||||||
|
|
||||||
func IsNetworkTimeoutError(err error) bool {
|
func IsNetworkTimeoutError(err error) bool {
|
||||||
nerr, ok := err.(net.Error)
|
nerr, ok := err.(net.Error)
|
||||||
return ok && nerr.Timeout()
|
return ok && nerr.Timeout()
|
||||||
|
@ -17,6 +17,7 @@ package netutil
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"net"
|
"net"
|
||||||
"net/url"
|
"net/url"
|
||||||
"reflect"
|
"reflect"
|
||||||
@ -119,13 +120,16 @@ func TestResolveTCPAddrs(t *testing.T) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if tt.hostMap[host] == "" {
|
|
||||||
return nil, errors.New("cannot resolve host")
|
|
||||||
}
|
|
||||||
i, err := strconv.Atoi(port)
|
i, err := strconv.Atoi(port)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if ip := net.ParseIP(host); ip != nil {
|
||||||
|
return &net.TCPAddr{IP: ip, Port: i, Zone: ""}, nil
|
||||||
|
}
|
||||||
|
if tt.hostMap[host] == "" {
|
||||||
|
return nil, errors.New("cannot resolve host")
|
||||||
|
}
|
||||||
return &net.TCPAddr{IP: net.ParseIP(tt.hostMap[host]), Port: i, Zone: ""}, nil
|
return &net.TCPAddr{IP: net.ParseIP(tt.hostMap[host]), Port: i, Zone: ""}, nil
|
||||||
}
|
}
|
||||||
ctx, cancel := context.WithTimeout(context.TODO(), time.Second)
|
ctx, cancel := context.WithTimeout(context.TODO(), time.Second)
|
||||||
@ -151,128 +155,151 @@ func TestURLsEqual(t *testing.T) {
|
|||||||
"second.com": "10.0.11.2",
|
"second.com": "10.0.11.2",
|
||||||
}
|
}
|
||||||
resolveTCPAddr = func(ctx context.Context, addr string) (*net.TCPAddr, error) {
|
resolveTCPAddr = func(ctx context.Context, addr string) (*net.TCPAddr, error) {
|
||||||
host, port, herr := net.SplitHostPort(addr)
|
host, port, err := net.SplitHostPort(addr)
|
||||||
if herr != nil {
|
if err != nil {
|
||||||
return nil, herr
|
return nil, err
|
||||||
}
|
|
||||||
if _, ok := hostm[host]; !ok {
|
|
||||||
return nil, errors.New("cannot resolve host.")
|
|
||||||
}
|
}
|
||||||
i, err := strconv.Atoi(port)
|
i, err := strconv.Atoi(port)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
if ip := net.ParseIP(host); ip != nil {
|
||||||
|
return &net.TCPAddr{IP: ip, Port: i, Zone: ""}, nil
|
||||||
|
}
|
||||||
|
if hostm[host] == "" {
|
||||||
|
return nil, errors.New("cannot resolve host")
|
||||||
|
}
|
||||||
return &net.TCPAddr{IP: net.ParseIP(hostm[host]), Port: i, Zone: ""}, nil
|
return &net.TCPAddr{IP: net.ParseIP(hostm[host]), Port: i, Zone: ""}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
|
n int
|
||||||
a []url.URL
|
a []url.URL
|
||||||
b []url.URL
|
b []url.URL
|
||||||
expect bool
|
expect bool
|
||||||
err error
|
err error
|
||||||
}{
|
}{
|
||||||
{
|
{
|
||||||
|
n: 0,
|
||||||
a: []url.URL{{Scheme: "http", Host: "127.0.0.1:2379"}},
|
a: []url.URL{{Scheme: "http", Host: "127.0.0.1:2379"}},
|
||||||
b: []url.URL{{Scheme: "http", Host: "127.0.0.1:2379"}},
|
b: []url.URL{{Scheme: "http", Host: "127.0.0.1:2379"}},
|
||||||
expect: true,
|
expect: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
n: 1,
|
||||||
a: []url.URL{{Scheme: "http", Host: "example.com:2379"}},
|
a: []url.URL{{Scheme: "http", Host: "example.com:2379"}},
|
||||||
b: []url.URL{{Scheme: "http", Host: "10.0.10.1:2379"}},
|
b: []url.URL{{Scheme: "http", Host: "10.0.10.1:2379"}},
|
||||||
expect: true,
|
expect: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
n: 2,
|
||||||
a: []url.URL{{Scheme: "http", Host: "example.com:2379"}},
|
a: []url.URL{{Scheme: "http", Host: "example.com:2379"}},
|
||||||
b: []url.URL{{Scheme: "https", Host: "10.0.10.1:2379"}},
|
b: []url.URL{{Scheme: "https", Host: "10.0.10.1:2379"}},
|
||||||
expect: false,
|
expect: false,
|
||||||
err: errors.New(`"http://10.0.10.1:2379"(resolved from "http://example.com:2379") != "https://10.0.10.1:2379"(resolved from "https://10.0.10.1:2379")`),
|
err: errors.New(`resolved urls: "http://10.0.10.1:2379" != "https://10.0.10.1:2379"`),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
n: 3,
|
||||||
a: []url.URL{{Scheme: "https", Host: "example.com:2379"}},
|
a: []url.URL{{Scheme: "https", Host: "example.com:2379"}},
|
||||||
b: []url.URL{{Scheme: "http", Host: "10.0.10.1:2379"}},
|
b: []url.URL{{Scheme: "http", Host: "10.0.10.1:2379"}},
|
||||||
expect: false,
|
expect: false,
|
||||||
err: errors.New(`"https://10.0.10.1:2379"(resolved from "https://example.com:2379") != "http://10.0.10.1:2379"(resolved from "http://10.0.10.1:2379")`),
|
err: errors.New(`resolved urls: "https://10.0.10.1:2379" != "http://10.0.10.1:2379"`),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
n: 4,
|
||||||
a: []url.URL{{Scheme: "unix", Host: "abc:2379"}},
|
a: []url.URL{{Scheme: "unix", Host: "abc:2379"}},
|
||||||
b: []url.URL{{Scheme: "unix", Host: "abc:2379"}},
|
b: []url.URL{{Scheme: "unix", Host: "abc:2379"}},
|
||||||
expect: true,
|
expect: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
n: 5,
|
||||||
a: []url.URL{{Scheme: "http", Host: "127.0.0.1:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
|
a: []url.URL{{Scheme: "http", Host: "127.0.0.1:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
|
||||||
b: []url.URL{{Scheme: "http", Host: "127.0.0.1:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
|
b: []url.URL{{Scheme: "http", Host: "127.0.0.1:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
|
||||||
expect: true,
|
expect: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
n: 6,
|
||||||
a: []url.URL{{Scheme: "http", Host: "example.com:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
|
a: []url.URL{{Scheme: "http", Host: "example.com:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
|
||||||
b: []url.URL{{Scheme: "http", Host: "example.com:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
|
b: []url.URL{{Scheme: "http", Host: "example.com:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
|
||||||
expect: true,
|
expect: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
n: 7,
|
||||||
a: []url.URL{{Scheme: "http", Host: "10.0.10.1:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
|
a: []url.URL{{Scheme: "http", Host: "10.0.10.1:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
|
||||||
b: []url.URL{{Scheme: "http", Host: "example.com:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
|
b: []url.URL{{Scheme: "http", Host: "example.com:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
|
||||||
expect: true,
|
expect: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
n: 8,
|
||||||
a: []url.URL{{Scheme: "http", Host: "127.0.0.1:2379"}},
|
a: []url.URL{{Scheme: "http", Host: "127.0.0.1:2379"}},
|
||||||
b: []url.URL{{Scheme: "http", Host: "127.0.0.1:2380"}},
|
b: []url.URL{{Scheme: "http", Host: "127.0.0.1:2380"}},
|
||||||
expect: false,
|
expect: false,
|
||||||
err: errors.New(`"http://127.0.0.1:2379"(resolved from "http://127.0.0.1:2379") != "http://127.0.0.1:2380"(resolved from "http://127.0.0.1:2380")`),
|
err: errors.New(`resolved urls: "http://127.0.0.1:2379" != "http://127.0.0.1:2380"`),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
n: 9,
|
||||||
a: []url.URL{{Scheme: "http", Host: "example.com:2380"}},
|
a: []url.URL{{Scheme: "http", Host: "example.com:2380"}},
|
||||||
b: []url.URL{{Scheme: "http", Host: "10.0.10.1:2379"}},
|
b: []url.URL{{Scheme: "http", Host: "10.0.10.1:2379"}},
|
||||||
expect: false,
|
expect: false,
|
||||||
err: errors.New(`"http://10.0.10.1:2380"(resolved from "http://example.com:2380") != "http://10.0.10.1:2379"(resolved from "http://10.0.10.1:2379")`),
|
err: errors.New(`resolved urls: "http://10.0.10.1:2380" != "http://10.0.10.1:2379"`),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
n: 10,
|
||||||
a: []url.URL{{Scheme: "http", Host: "127.0.0.1:2379"}},
|
a: []url.URL{{Scheme: "http", Host: "127.0.0.1:2379"}},
|
||||||
b: []url.URL{{Scheme: "http", Host: "10.0.0.1:2379"}},
|
b: []url.URL{{Scheme: "http", Host: "10.0.0.1:2379"}},
|
||||||
expect: false,
|
expect: false,
|
||||||
err: errors.New(`"http://127.0.0.1:2379"(resolved from "http://127.0.0.1:2379") != "http://10.0.0.1:2379"(resolved from "http://10.0.0.1:2379")`),
|
err: errors.New(`resolved urls: "http://127.0.0.1:2379" != "http://10.0.0.1:2379"`),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
n: 11,
|
||||||
a: []url.URL{{Scheme: "http", Host: "example.com:2379"}},
|
a: []url.URL{{Scheme: "http", Host: "example.com:2379"}},
|
||||||
b: []url.URL{{Scheme: "http", Host: "10.0.0.1:2379"}},
|
b: []url.URL{{Scheme: "http", Host: "10.0.0.1:2379"}},
|
||||||
expect: false,
|
expect: false,
|
||||||
err: errors.New(`"http://10.0.10.1:2379"(resolved from "http://example.com:2379") != "http://10.0.0.1:2379"(resolved from "http://10.0.0.1:2379")`),
|
err: errors.New(`resolved urls: "http://10.0.10.1:2379" != "http://10.0.0.1:2379"`),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
n: 12,
|
||||||
a: []url.URL{{Scheme: "http", Host: "127.0.0.1:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
|
a: []url.URL{{Scheme: "http", Host: "127.0.0.1:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
|
||||||
b: []url.URL{{Scheme: "http", Host: "127.0.0.1:2380"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
|
b: []url.URL{{Scheme: "http", Host: "127.0.0.1:2380"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
|
||||||
expect: false,
|
expect: false,
|
||||||
err: errors.New(`"http://127.0.0.1:2379"(resolved from "http://127.0.0.1:2379") != "http://127.0.0.1:2380"(resolved from "http://127.0.0.1:2380")`),
|
err: errors.New(`resolved urls: "http://127.0.0.1:2379" != "http://127.0.0.1:2380"`),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
n: 13,
|
||||||
a: []url.URL{{Scheme: "http", Host: "example.com:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
|
a: []url.URL{{Scheme: "http", Host: "example.com:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
|
||||||
b: []url.URL{{Scheme: "http", Host: "127.0.0.1:2380"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
|
b: []url.URL{{Scheme: "http", Host: "127.0.0.1:2380"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
|
||||||
expect: false,
|
expect: false,
|
||||||
err: errors.New(`"http://10.0.10.1:2379"(resolved from "http://example.com:2379") != "http://127.0.0.1:2380"(resolved from "http://127.0.0.1:2380")`),
|
err: errors.New(`resolved urls: "http://10.0.10.1:2379" != "http://127.0.0.1:2380"`),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
n: 14,
|
||||||
a: []url.URL{{Scheme: "http", Host: "127.0.0.1:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
|
a: []url.URL{{Scheme: "http", Host: "127.0.0.1:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
|
||||||
b: []url.URL{{Scheme: "http", Host: "10.0.0.1:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
|
b: []url.URL{{Scheme: "http", Host: "10.0.0.1:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
|
||||||
expect: false,
|
expect: false,
|
||||||
err: errors.New(`"http://127.0.0.1:2379"(resolved from "http://127.0.0.1:2379") != "http://10.0.0.1:2379"(resolved from "http://10.0.0.1:2379")`),
|
err: errors.New(`resolved urls: "http://127.0.0.1:2379" != "http://10.0.0.1:2379"`),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
n: 15,
|
||||||
a: []url.URL{{Scheme: "http", Host: "example.com:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
|
a: []url.URL{{Scheme: "http", Host: "example.com:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
|
||||||
b: []url.URL{{Scheme: "http", Host: "10.0.0.1:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
|
b: []url.URL{{Scheme: "http", Host: "10.0.0.1:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
|
||||||
expect: false,
|
expect: false,
|
||||||
err: errors.New(`"http://10.0.10.1:2379"(resolved from "http://example.com:2379") != "http://10.0.0.1:2379"(resolved from "http://10.0.0.1:2379")`),
|
err: errors.New(`resolved urls: "http://10.0.10.1:2379" != "http://10.0.0.1:2379"`),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
n: 16,
|
||||||
a: []url.URL{{Scheme: "http", Host: "10.0.0.1:2379"}},
|
a: []url.URL{{Scheme: "http", Host: "10.0.0.1:2379"}},
|
||||||
b: []url.URL{{Scheme: "http", Host: "10.0.0.1:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
|
b: []url.URL{{Scheme: "http", Host: "10.0.0.1:2379"}, {Scheme: "http", Host: "127.0.0.1:2380"}},
|
||||||
expect: false,
|
expect: false,
|
||||||
err: errors.New(`len(["http://10.0.0.1:2379"]) != len(["http://10.0.0.1:2379" "http://127.0.0.1:2380"])`),
|
err: errors.New(`len(["http://10.0.0.1:2379"]) != len(["http://10.0.0.1:2379" "http://127.0.0.1:2380"])`),
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
n: 17,
|
||||||
a: []url.URL{{Scheme: "http", Host: "first.com:2379"}, {Scheme: "http", Host: "second.com:2380"}},
|
a: []url.URL{{Scheme: "http", Host: "first.com:2379"}, {Scheme: "http", Host: "second.com:2380"}},
|
||||||
b: []url.URL{{Scheme: "http", Host: "10.0.11.1:2379"}, {Scheme: "http", Host: "10.0.11.2:2380"}},
|
b: []url.URL{{Scheme: "http", Host: "10.0.11.1:2379"}, {Scheme: "http", Host: "10.0.11.2:2380"}},
|
||||||
expect: true,
|
expect: true,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
|
n: 18,
|
||||||
a: []url.URL{{Scheme: "http", Host: "second.com:2380"}, {Scheme: "http", Host: "first.com:2379"}},
|
a: []url.URL{{Scheme: "http", Host: "second.com:2380"}, {Scheme: "http", Host: "first.com:2379"}},
|
||||||
b: []url.URL{{Scheme: "http", Host: "10.0.11.1:2379"}, {Scheme: "http", Host: "10.0.11.2:2380"}},
|
b: []url.URL{{Scheme: "http", Host: "10.0.11.1:2379"}, {Scheme: "http", Host: "10.0.11.2:2380"}},
|
||||||
expect: true,
|
expect: true,
|
||||||
@ -282,21 +309,48 @@ func TestURLsEqual(t *testing.T) {
|
|||||||
for i, test := range tests {
|
for i, test := range tests {
|
||||||
result, err := urlsEqual(context.TODO(), zap.NewExample(), test.a, test.b)
|
result, err := urlsEqual(context.TODO(), zap.NewExample(), test.a, test.b)
|
||||||
if result != test.expect {
|
if result != test.expect {
|
||||||
t.Errorf("#%d: a:%v b:%v, expected %v but %v", i, test.a, test.b, test.expect, result)
|
t.Errorf("idx=%d #%d: a:%v b:%v, expected %v but %v", i, test.n, test.a, test.b, test.expect, result)
|
||||||
}
|
}
|
||||||
if test.err != nil {
|
if test.err != nil {
|
||||||
if err.Error() != test.err.Error() {
|
if err.Error() != test.err.Error() {
|
||||||
t.Errorf("#%d: err expected %v but %v", i, test.err, err)
|
t.Errorf("idx=%d #%d: err expected %v but %v", i, test.n, test.err, err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
func TestURLStringsEqual(t *testing.T) {
|
func TestURLStringsEqual(t *testing.T) {
|
||||||
result, err := URLStringsEqual(context.TODO(), zap.NewExample(), []string{"http://127.0.0.1:8080"}, []string{"http://127.0.0.1:8080"})
|
defer func() { resolveTCPAddr = resolveTCPAddrDefault }()
|
||||||
if !result {
|
errOnResolve := func(ctx context.Context, addr string) (*net.TCPAddr, error) {
|
||||||
t.Errorf("unexpected result %v", result)
|
return nil, fmt.Errorf("unexpected attempt to resolve: %q", addr)
|
||||||
}
|
}
|
||||||
if err != nil {
|
cases := []struct {
|
||||||
t.Errorf("unexpected error %v", err)
|
urlsA []string
|
||||||
|
urlsB []string
|
||||||
|
resolver func(ctx context.Context, addr string) (*net.TCPAddr, error)
|
||||||
|
}{
|
||||||
|
{[]string{"http://127.0.0.1:8080"}, []string{"http://127.0.0.1:8080"}, resolveTCPAddrDefault},
|
||||||
|
{[]string{
|
||||||
|
"http://host1:8080",
|
||||||
|
"http://host2:8080",
|
||||||
|
}, []string{
|
||||||
|
"http://host1:8080",
|
||||||
|
"http://host2:8080",
|
||||||
|
}, errOnResolve},
|
||||||
|
{
|
||||||
|
urlsA: []string{"https://[c262:266f:fa53:0ee6:966e:e3f0:d68f:b046]:2380"},
|
||||||
|
urlsB: []string{"https://[c262:266f:fa53:ee6:966e:e3f0:d68f:b046]:2380"},
|
||||||
|
resolver: resolveTCPAddrDefault,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
for idx, c := range cases {
|
||||||
|
t.Logf("TestURLStringsEqual, case #%d", idx)
|
||||||
|
resolveTCPAddr = c.resolver
|
||||||
|
result, err := URLStringsEqual(context.TODO(), zap.NewExample(), c.urlsA, c.urlsB)
|
||||||
|
if !result {
|
||||||
|
t.Errorf("unexpected result %v", result)
|
||||||
|
}
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("unexpected error %v", err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,7 +24,7 @@ func UniqueStrings(slen uint, n int) (ss []string) {
|
|||||||
exist := make(map[string]struct{})
|
exist := make(map[string]struct{})
|
||||||
ss = make([]string, 0, n)
|
ss = make([]string, 0, n)
|
||||||
for len(ss) < n {
|
for len(ss) < n {
|
||||||
s := randString(slen)
|
s := RandString(slen)
|
||||||
if _, ok := exist[s]; !ok {
|
if _, ok := exist[s]; !ok {
|
||||||
ss = append(ss, s)
|
ss = append(ss, s)
|
||||||
exist[s] = struct{}{}
|
exist[s] = struct{}{}
|
||||||
@ -37,14 +37,14 @@ func UniqueStrings(slen uint, n int) (ss []string) {
|
|||||||
func RandomStrings(slen uint, n int) (ss []string) {
|
func RandomStrings(slen uint, n int) (ss []string) {
|
||||||
ss = make([]string, 0, n)
|
ss = make([]string, 0, n)
|
||||||
for i := 0; i < n; i++ {
|
for i := 0; i < n; i++ {
|
||||||
ss = append(ss, randString(slen))
|
ss = append(ss, RandString(slen))
|
||||||
}
|
}
|
||||||
return ss
|
return ss
|
||||||
}
|
}
|
||||||
|
|
||||||
const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
const chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
|
||||||
|
|
||||||
func randString(l uint) string {
|
func RandString(l uint) string {
|
||||||
rand.Seed(time.Now().UnixNano())
|
rand.Seed(time.Now().UnixNano())
|
||||||
s := make([]byte, l)
|
s := make([]byte, l)
|
||||||
for i := 0; i < int(l); i++ {
|
for i := 0; i < int(l); i++ {
|
||||||
|
@ -37,9 +37,11 @@ type Changer struct {
|
|||||||
// config is empty and initializes it with a copy of the incoming (=left)
|
// config is empty and initializes it with a copy of the incoming (=left)
|
||||||
// majority config. That is, it transitions from
|
// majority config. That is, it transitions from
|
||||||
//
|
//
|
||||||
// (1 2 3)&&()
|
// (1 2 3)&&()
|
||||||
|
//
|
||||||
// to
|
// to
|
||||||
// (1 2 3)&&(1 2 3).
|
//
|
||||||
|
// (1 2 3)&&(1 2 3).
|
||||||
//
|
//
|
||||||
// The supplied changes are then applied to the incoming majority config,
|
// The supplied changes are then applied to the incoming majority config,
|
||||||
// resulting in a joint configuration that in terms of the Raft thesis[1]
|
// resulting in a joint configuration that in terms of the Raft thesis[1]
|
||||||
|
107
raft/doc.go
107
raft/doc.go
@ -25,46 +25,46 @@ A simple example application, _raftexample_, is also available to help illustrat
|
|||||||
how to use this package in practice:
|
how to use this package in practice:
|
||||||
https://github.com/etcd-io/etcd/tree/main/contrib/raftexample
|
https://github.com/etcd-io/etcd/tree/main/contrib/raftexample
|
||||||
|
|
||||||
Usage
|
# Usage
|
||||||
|
|
||||||
The primary object in raft is a Node. You either start a Node from scratch
|
The primary object in raft is a Node. You either start a Node from scratch
|
||||||
using raft.StartNode or start a Node from some initial state using raft.RestartNode.
|
using raft.StartNode or start a Node from some initial state using raft.RestartNode.
|
||||||
|
|
||||||
To start a node from scratch:
|
To start a node from scratch:
|
||||||
|
|
||||||
storage := raft.NewMemoryStorage()
|
storage := raft.NewMemoryStorage()
|
||||||
c := &Config{
|
c := &Config{
|
||||||
ID: 0x01,
|
ID: 0x01,
|
||||||
ElectionTick: 10,
|
ElectionTick: 10,
|
||||||
HeartbeatTick: 1,
|
HeartbeatTick: 1,
|
||||||
Storage: storage,
|
Storage: storage,
|
||||||
MaxSizePerMsg: 4096,
|
MaxSizePerMsg: 4096,
|
||||||
MaxInflightMsgs: 256,
|
MaxInflightMsgs: 256,
|
||||||
}
|
}
|
||||||
n := raft.StartNode(c, []raft.Peer{{ID: 0x02}, {ID: 0x03}})
|
n := raft.StartNode(c, []raft.Peer{{ID: 0x02}, {ID: 0x03}})
|
||||||
|
|
||||||
To restart a node from previous state:
|
To restart a node from previous state:
|
||||||
|
|
||||||
storage := raft.NewMemoryStorage()
|
storage := raft.NewMemoryStorage()
|
||||||
|
|
||||||
// recover the in-memory storage from persistent
|
// recover the in-memory storage from persistent
|
||||||
// snapshot, state and entries.
|
// snapshot, state and entries.
|
||||||
storage.ApplySnapshot(snapshot)
|
storage.ApplySnapshot(snapshot)
|
||||||
storage.SetHardState(state)
|
storage.SetHardState(state)
|
||||||
storage.Append(entries)
|
storage.Append(entries)
|
||||||
|
|
||||||
c := &Config{
|
c := &Config{
|
||||||
ID: 0x01,
|
ID: 0x01,
|
||||||
ElectionTick: 10,
|
ElectionTick: 10,
|
||||||
HeartbeatTick: 1,
|
HeartbeatTick: 1,
|
||||||
Storage: storage,
|
Storage: storage,
|
||||||
MaxSizePerMsg: 4096,
|
MaxSizePerMsg: 4096,
|
||||||
MaxInflightMsgs: 256,
|
MaxInflightMsgs: 256,
|
||||||
}
|
}
|
||||||
|
|
||||||
// restart raft without peer information.
|
// restart raft without peer information.
|
||||||
// peer information is already included in the storage.
|
// peer information is already included in the storage.
|
||||||
n := raft.RestartNode(c)
|
n := raft.RestartNode(c)
|
||||||
|
|
||||||
Now that you are holding onto a Node you have a few responsibilities:
|
Now that you are holding onto a Node you have a few responsibilities:
|
||||||
|
|
||||||
@ -120,29 +120,29 @@ represented by an abstract "tick".
|
|||||||
|
|
||||||
The total state machine handling loop will look something like this:
|
The total state machine handling loop will look something like this:
|
||||||
|
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case <-s.Ticker:
|
case <-s.Ticker:
|
||||||
n.Tick()
|
n.Tick()
|
||||||
case rd := <-s.Node.Ready():
|
case rd := <-s.Node.Ready():
|
||||||
saveToStorage(rd.State, rd.Entries, rd.Snapshot)
|
saveToStorage(rd.State, rd.Entries, rd.Snapshot)
|
||||||
send(rd.Messages)
|
send(rd.Messages)
|
||||||
if !raft.IsEmptySnap(rd.Snapshot) {
|
if !raft.IsEmptySnap(rd.Snapshot) {
|
||||||
processSnapshot(rd.Snapshot)
|
processSnapshot(rd.Snapshot)
|
||||||
}
|
}
|
||||||
for _, entry := range rd.CommittedEntries {
|
for _, entry := range rd.CommittedEntries {
|
||||||
process(entry)
|
process(entry)
|
||||||
if entry.Type == raftpb.EntryConfChange {
|
if entry.Type == raftpb.EntryConfChange {
|
||||||
var cc raftpb.ConfChange
|
var cc raftpb.ConfChange
|
||||||
cc.Unmarshal(entry.Data)
|
cc.Unmarshal(entry.Data)
|
||||||
s.Node.ApplyConfChange(cc)
|
s.Node.ApplyConfChange(cc)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
s.Node.Advance()
|
s.Node.Advance()
|
||||||
case <-s.done:
|
case <-s.done:
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
To propose changes to the state machine from your node take your application
|
To propose changes to the state machine from your node take your application
|
||||||
data, serialize it into a byte slice and call:
|
data, serialize it into a byte slice and call:
|
||||||
@ -169,7 +169,7 @@ given ID MUST be used only once even if the old node has been removed.
|
|||||||
This means that for example IP addresses make poor node IDs since they
|
This means that for example IP addresses make poor node IDs since they
|
||||||
may be reused. Node IDs must be non-zero.
|
may be reused. Node IDs must be non-zero.
|
||||||
|
|
||||||
Implementation notes
|
# Implementation notes
|
||||||
|
|
||||||
This implementation is up to date with the final Raft thesis
|
This implementation is up to date with the final Raft thesis
|
||||||
(https://github.com/ongardie/dissertation/blob/master/stanford.pdf), although our
|
(https://github.com/ongardie/dissertation/blob/master/stanford.pdf), although our
|
||||||
@ -194,7 +194,7 @@ cannot be removed any more since the cluster cannot make progress.
|
|||||||
For this reason it is highly recommended to use three or more nodes in
|
For this reason it is highly recommended to use three or more nodes in
|
||||||
every cluster.
|
every cluster.
|
||||||
|
|
||||||
MessageType
|
# MessageType
|
||||||
|
|
||||||
Package raft sends and receives message in Protocol Buffer format (defined
|
Package raft sends and receives message in Protocol Buffer format (defined
|
||||||
in raftpb package). Each state (follower, candidate, leader) implements its
|
in raftpb package). Each state (follower, candidate, leader) implements its
|
||||||
@ -295,6 +295,5 @@ stale log entries:
|
|||||||
that the follower that sent this 'MsgUnreachable' is not reachable, often
|
that the follower that sent this 'MsgUnreachable' is not reachable, often
|
||||||
indicating 'MsgApp' is lost. When follower's progress state is replicate,
|
indicating 'MsgApp' is lost. When follower's progress state is replicate,
|
||||||
the leader sets it back to probe.
|
the leader sets it back to probe.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
package raft
|
package raft
|
||||||
|
13
raft/go.mod
13
raft/go.mod
@ -1,14 +1,17 @@
|
|||||||
module go.etcd.io/etcd/raft/v3
|
module go.etcd.io/etcd/raft/v3
|
||||||
|
|
||||||
go 1.16
|
go 1.19
|
||||||
|
|
||||||
require (
|
require (
|
||||||
github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054 // indirect
|
github.com/cockroachdb/datadriven v1.0.2
|
||||||
github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5
|
|
||||||
github.com/gogo/protobuf v1.3.2
|
github.com/gogo/protobuf v1.3.2
|
||||||
github.com/golang/protobuf v1.5.2
|
github.com/golang/protobuf v1.5.2
|
||||||
github.com/pkg/errors v0.9.1 // indirect
|
go.etcd.io/etcd/client/pkg/v3 v3.5.9
|
||||||
go.etcd.io/etcd/client/pkg/v3 v3.5.5
|
)
|
||||||
|
|
||||||
|
require (
|
||||||
|
github.com/pmezard/go-difflib v1.0.0 // indirect
|
||||||
|
google.golang.org/protobuf v1.26.0 // indirect
|
||||||
)
|
)
|
||||||
|
|
||||||
// Bad imports are sometimes causing attempts to pull that code.
|
// Bad imports are sometimes causing attempts to pull that code.
|
||||||
|
39
raft/go.sum
39
raft/go.sum
@ -1,19 +1,5 @@
|
|||||||
github.com/certifi/gocertifi v0.0.0-20191021191039-0944d244cd40/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
|
github.com/cockroachdb/datadriven v1.0.2 h1:H9MtNqVoVhvd9nCBwOyDjUEdZCREqbIdCJD93PBm/jA=
|
||||||
github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054 h1:uH66TXeswKn5PW5zdZ39xEwfS9an067BirqA+P4QaLI=
|
github.com/cockroachdb/datadriven v1.0.2/go.mod h1:a9RdTaap04u637JoCzcUoIcDmvwSUtcUFtT/C3kJlTU=
|
||||||
github.com/certifi/gocertifi v0.0.0-20200922220541-2c3bb06c6054/go.mod h1:sGbDF6GwGcLpkNXPUTkMRoywsNa/ol15pxFe6ERfguA=
|
|
||||||
github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5 h1:xD/lrqdvwsc+O2bjSSi3YqY73Ke3LAiSCx49aCesA0E=
|
|
||||||
github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo=
|
|
||||||
github.com/cockroachdb/errors v1.2.4 h1:Lap807SXTH5tri2TivECb/4abUkMZC9zRoLarvcKDqs=
|
|
||||||
github.com/cockroachdb/errors v1.2.4/go.mod h1:rQD95gz6FARkaKkQXUksEje/d9a6wBJoCr5oaCLELYA=
|
|
||||||
github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f h1:o/kfcElHqOiXqcou5a3rIlMc7oJbMQkeLk0VQJ7zgqY=
|
|
||||||
github.com/cockroachdb/logtags v0.0.0-20190617123548-eb05cc24525f/go.mod h1:i/u985jwjWRlyHXQbwatDASoW0RMlZ/3i9yJHE2xLkI=
|
|
||||||
github.com/coreos/go-systemd/v22 v22.3.2/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
|
|
||||||
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
|
||||||
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
|
|
||||||
github.com/getsentry/raven-go v0.2.0 h1:no+xWJRb5ZI7eE8TWgIq1jLulQiIoLG0IfYxv5JYMGs=
|
|
||||||
github.com/getsentry/raven-go v0.2.0/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ=
|
|
||||||
github.com/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
|
|
||||||
github.com/gogo/protobuf v1.3.1/go.mod h1:SlYgWuQ5SjCEi6WLHjHCa1yvBfUnHcTbrrZtXPKa29o=
|
|
||||||
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
|
||||||
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
|
||||||
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
|
||||||
@ -21,27 +7,12 @@ github.com/golang/protobuf v1.5.2 h1:ROPKBNFfQgOUMifHyP+KYbvpjbdoFNs+aK7DXlji0Tw
|
|||||||
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
github.com/golang/protobuf v1.5.2/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
|
||||||
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
|
||||||
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
|
||||||
github.com/kisielk/errcheck v1.2.0/go.mod h1:/BMXB+zMLi60iA8Vv6Ksmxu/1UDYcXs4uQLJ+jE2L00=
|
|
||||||
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
github.com/kisielk/errcheck v1.5.0/go.mod h1:pFxgyoBC7bSaBwPgfKdkLd5X25qrDl4LWUI2bnpBCr8=
|
||||||
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck=
|
||||||
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
|
|
||||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
|
||||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
|
||||||
github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
|
|
||||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
|
||||||
github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
|
||||||
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
|
|
||||||
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
|
||||||
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
|
||||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||||
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
|
|
||||||
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
|
|
||||||
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
|
|
||||||
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
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.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
|
||||||
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
|
|
||||||
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
|
|
||||||
go.uber.org/zap v1.17.0/go.mod h1:MXVU+bhUf/A7Xi2HNOnopQOrmycQ5Ih87HtOu4q5SSo=
|
|
||||||
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
|
||||||
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
|
||||||
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
|
||||||
@ -57,11 +28,9 @@ golang.org/x/sync v0.0.0-20201020160332-67f06af15bc9/go.mod h1:RxMgew5VJxzue5/jJ
|
|||||||
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||||
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
||||||
golang.org/x/sys v0.0.0-20210403161142-5e06dd20ab57/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
|
|
||||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||||
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
|
||||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||||
golang.org/x/tools v0.0.0-20181030221726-6c7e314b6563/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
|
||||||
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
|
||||||
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
|
||||||
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
golang.org/x/tools v0.0.0-20210106214847-113979e3529a/go.mod h1:emZCQorbCU4vsT4fOWvOPXz4eW1wZW4PmDk9uLelYpA=
|
||||||
@ -73,7 +42,3 @@ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8T
|
|||||||
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
|
||||||
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
|
google.golang.org/protobuf v1.26.0 h1:bxAC2xTBsZGibn2RTntX0oH50xLsqy1OxA9tTL3p/lk=
|
||||||
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
google.golang.org/protobuf v1.26.0/go.mod h1:9q0QmTI4eRPtz6boOQmLYwt+qCgq0jsYwAQnmE0givc=
|
||||||
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
|
|
||||||
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
|
|
||||||
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
|
||||||
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
|
|
||||||
|
@ -146,12 +146,14 @@ func TestAppend(t *testing.T) {
|
|||||||
|
|
||||||
// TestLogMaybeAppend ensures:
|
// TestLogMaybeAppend ensures:
|
||||||
// If the given (index, term) matches with the existing log:
|
// If the given (index, term) matches with the existing log:
|
||||||
// 1. If an existing entry conflicts with a new one (same index
|
// 1. If an existing entry conflicts with a new one (same index
|
||||||
// but different terms), delete the existing entry and all that
|
// but different terms), delete the existing entry and all that
|
||||||
// follow it
|
// follow it
|
||||||
// 2.Append any new entries not already in the log
|
// 2. Append any new entries not already in the log
|
||||||
|
//
|
||||||
// If the given (index, term) does not match with the existing log:
|
// If the given (index, term) does not match with the existing log:
|
||||||
// return false
|
//
|
||||||
|
// return false
|
||||||
func TestLogMaybeAppend(t *testing.T) {
|
func TestLogMaybeAppend(t *testing.T) {
|
||||||
previousEnts := []pb.Entry{{Index: 1, Term: 1}, {Index: 2, Term: 2}, {Index: 3, Term: 3}}
|
previousEnts := []pb.Entry{{Index: 1, Term: 1}, {Index: 2, Term: 2}, {Index: 3, Term: 3}}
|
||||||
lastindex := uint64(3)
|
lastindex := uint64(3)
|
||||||
@ -528,7 +530,7 @@ func TestStableToWithSnap(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//TestCompaction ensures that the number of log entries is correct after compactions.
|
// TestCompaction ensures that the number of log entries is correct after compactions.
|
||||||
func TestCompaction(t *testing.T) {
|
func TestCompaction(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
lastIndex uint64
|
lastIndex uint64
|
||||||
|
@ -76,7 +76,7 @@ func TestNodeStep(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Cancel and Stop should unblock Step()
|
// TestNodeStepUnblock should Cancel and Stop should unblock Step()
|
||||||
func TestNodeStepUnblock(t *testing.T) {
|
func TestNodeStepUnblock(t *testing.T) {
|
||||||
// a node without buffer to block step
|
// a node without buffer to block step
|
||||||
n := &node{
|
n := &node{
|
||||||
@ -959,14 +959,14 @@ func (s *ignoreSizeHintMemStorage) Entries(lo, hi uint64, maxSize uint64) ([]raf
|
|||||||
// Storage's Entries size limitation is slightly more permissive than Raft's
|
// Storage's Entries size limitation is slightly more permissive than Raft's
|
||||||
// internal one. The original bug was the following:
|
// internal one. The original bug was the following:
|
||||||
//
|
//
|
||||||
// - node learns that index 11 (or 100, doesn't matter) is committed
|
// - node learns that index 11 (or 100, doesn't matter) is committed
|
||||||
// - nextEnts returns index 1..10 in CommittedEntries due to size limiting. However,
|
// - nextEnts returns index 1..10 in CommittedEntries due to size limiting. However,
|
||||||
// index 10 already exceeds maxBytes, due to a user-provided impl of Entries.
|
// index 10 already exceeds maxBytes, due to a user-provided impl of Entries.
|
||||||
// - Commit index gets bumped to 10
|
// - Commit index gets bumped to 10
|
||||||
// - the node persists the HardState, but crashes before applying the entries
|
// - the node persists the HardState, but crashes before applying the entries
|
||||||
// - upon restart, the storage returns the same entries, but `slice` takes a different code path
|
// - upon restart, the storage returns the same entries, but `slice` takes a different code path
|
||||||
// (since it is now called with an upper bound of 10) and removes the last entry.
|
// (since it is now called with an upper bound of 10) and removes the last entry.
|
||||||
// - Raft emits a HardState with a regressing commit index.
|
// - Raft emits a HardState with a regressing commit index.
|
||||||
//
|
//
|
||||||
// A simpler version of this test would have the storage return a lot less entries than dictated
|
// A simpler version of this test would have the storage return a lot less entries than dictated
|
||||||
// by maxSize (for example, exactly one entry) after the restart, resulting in a larger regression.
|
// by maxSize (for example, exactly one entry) after the restart, resulting in a larger regression.
|
||||||
|
@ -1207,8 +1207,8 @@ func TestPastElectionTimeout(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ensure that the Step function ignores the message from old term and does not pass it to the
|
// TestStepIgnoreOldTermMsg to ensure that the Step function ignores the message
|
||||||
// actual stepX function.
|
// from old term and does not pass it to the actual stepX function.
|
||||||
func TestStepIgnoreOldTermMsg(t *testing.T) {
|
func TestStepIgnoreOldTermMsg(t *testing.T) {
|
||||||
called := false
|
called := false
|
||||||
fakeStep := func(r *raft, m pb.Message) error {
|
fakeStep := func(r *raft, m pb.Message) error {
|
||||||
@ -1225,10 +1225,10 @@ func TestStepIgnoreOldTermMsg(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TestHandleMsgApp ensures:
|
// TestHandleMsgApp ensures:
|
||||||
// 1. Reply false if log doesn’t contain an entry at prevLogIndex whose term matches prevLogTerm.
|
// 1. Reply false if log doesn’t contain an entry at prevLogIndex whose term matches prevLogTerm.
|
||||||
// 2. If an existing entry conflicts with a new one (same index but different terms),
|
// 2. If an existing entry conflicts with a new one (same index but different terms),
|
||||||
// delete the existing entry and all that follow it; append any new entries not already in the log.
|
// delete the existing entry and all that follow it; append any new entries not already in the log.
|
||||||
// 3. If leaderCommit > commitIndex, set commitIndex = min(leaderCommit, index of last new entry).
|
// 3. If leaderCommit > commitIndex, set commitIndex = min(leaderCommit, index of last new entry).
|
||||||
func TestHandleMsgApp(t *testing.T) {
|
func TestHandleMsgApp(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
m pb.Message
|
m pb.Message
|
||||||
@ -2479,7 +2479,7 @@ func TestLeaderAppResp(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// When the leader receives a heartbeat tick, it should
|
// TestBcastBeat is when the leader receives a heartbeat tick, it should
|
||||||
// send a MsgHeartbeat with m.Index = 0, m.LogTerm=0 and empty entries.
|
// send a MsgHeartbeat with m.Index = 0, m.LogTerm=0 and empty entries.
|
||||||
func TestBcastBeat(t *testing.T) {
|
func TestBcastBeat(t *testing.T) {
|
||||||
offset := uint64(1000)
|
offset := uint64(1000)
|
||||||
@ -2539,7 +2539,7 @@ func TestBcastBeat(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// tests the output of the state machine when receiving MsgBeat
|
// TestRecvMsgBeat tests the output of the state machine when receiving MsgBeat
|
||||||
func TestRecvMsgBeat(t *testing.T) {
|
func TestRecvMsgBeat(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
state StateType
|
state StateType
|
||||||
@ -2818,7 +2818,7 @@ func TestRestoreWithLearner(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tests if outgoing voter can receive and apply snapshot correctly.
|
// TestRestoreWithVotersOutgoing tests if outgoing voter can receive and apply snapshot correctly.
|
||||||
func TestRestoreWithVotersOutgoing(t *testing.T) {
|
func TestRestoreWithVotersOutgoing(t *testing.T) {
|
||||||
s := pb.Snapshot{
|
s := pb.Snapshot{
|
||||||
Metadata: pb.SnapshotMetadata{
|
Metadata: pb.SnapshotMetadata{
|
||||||
@ -4306,12 +4306,12 @@ func testConfChangeCheckBeforeCampaign(t *testing.T, v2 bool) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tests if unapplied ConfChange is checked before campaign.
|
// TestConfChangeCheckBeforeCampaign tests if unapplied ConfChange is checked before campaign.
|
||||||
func TestConfChangeCheckBeforeCampaign(t *testing.T) {
|
func TestConfChangeCheckBeforeCampaign(t *testing.T) {
|
||||||
testConfChangeCheckBeforeCampaign(t, false)
|
testConfChangeCheckBeforeCampaign(t, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tests if unapplied ConfChangeV2 is checked before campaign.
|
// TestConfChangeV2CheckBeforeCampaign tests if unapplied ConfChangeV2 is checked before campaign.
|
||||||
func TestConfChangeV2CheckBeforeCampaign(t *testing.T) {
|
func TestConfChangeV2CheckBeforeCampaign(t *testing.T) {
|
||||||
testConfChangeCheckBeforeCampaign(t, true)
|
testConfChangeCheckBeforeCampaign(t, true)
|
||||||
}
|
}
|
||||||
|
@ -36,22 +36,22 @@ type rawNodeAdapter struct {
|
|||||||
|
|
||||||
var _ Node = (*rawNodeAdapter)(nil)
|
var _ Node = (*rawNodeAdapter)(nil)
|
||||||
|
|
||||||
// Node specifies lead, which is pointless, can just be filled in.
|
// TransferLeadership is to test when node specifies lead, which is pointless, can just be filled in.
|
||||||
func (a *rawNodeAdapter) TransferLeadership(ctx context.Context, lead, transferee uint64) {
|
func (a *rawNodeAdapter) TransferLeadership(ctx context.Context, lead, transferee uint64) {
|
||||||
a.RawNode.TransferLeader(transferee)
|
a.RawNode.TransferLeader(transferee)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Node has a goroutine, RawNode doesn't need this.
|
// Stop when node has a goroutine, RawNode doesn't need this.
|
||||||
func (a *rawNodeAdapter) Stop() {}
|
func (a *rawNodeAdapter) Stop() {}
|
||||||
|
|
||||||
// RawNode returns a *Status.
|
// Status returns RawNode's status as *Status.
|
||||||
func (a *rawNodeAdapter) Status() Status { return a.RawNode.Status() }
|
func (a *rawNodeAdapter) Status() Status { return a.RawNode.Status() }
|
||||||
|
|
||||||
// RawNode takes a Ready. It doesn't really have to do that I think? It can hold on
|
// Advance is when RawNode takes a Ready. It doesn't really have to do that I think? It can hold on
|
||||||
// to it internally. But maybe that approach is frail.
|
// to it internally. But maybe that approach is frail.
|
||||||
func (a *rawNodeAdapter) Advance() { a.RawNode.Advance(Ready{}) }
|
func (a *rawNodeAdapter) Advance() { a.RawNode.Advance(Ready{}) }
|
||||||
|
|
||||||
// RawNode returns a Ready, not a chan of one.
|
// Ready when RawNode returns a Ready, not a chan of one.
|
||||||
func (a *rawNodeAdapter) Ready() <-chan Ready { return nil }
|
func (a *rawNodeAdapter) Ready() <-chan Ready { return nil }
|
||||||
|
|
||||||
// Node takes more contexts. Easy enough to fix.
|
// Node takes more contexts. Easy enough to fix.
|
||||||
@ -868,17 +868,17 @@ func TestRawNodeStatus(t *testing.T) {
|
|||||||
// TestNodeCommitPaginationAfterRestart. The anomaly here was even worse as the
|
// TestNodeCommitPaginationAfterRestart. The anomaly here was even worse as the
|
||||||
// Raft group would forget to apply entries:
|
// Raft group would forget to apply entries:
|
||||||
//
|
//
|
||||||
// - node learns that index 11 is committed
|
// - node learns that index 11 is committed
|
||||||
// - nextEnts returns index 1..10 in CommittedEntries (but index 10 already
|
// - nextEnts returns index 1..10 in CommittedEntries (but index 10 already
|
||||||
// exceeds maxBytes), which isn't noticed internally by Raft
|
// exceeds maxBytes), which isn't noticed internally by Raft
|
||||||
// - Commit index gets bumped to 10
|
// - Commit index gets bumped to 10
|
||||||
// - the node persists the HardState, but crashes before applying the entries
|
// - the node persists the HardState, but crashes before applying the entries
|
||||||
// - upon restart, the storage returns the same entries, but `slice` takes a
|
// - upon restart, the storage returns the same entries, but `slice` takes a
|
||||||
// different code path and removes the last entry.
|
// different code path and removes the last entry.
|
||||||
// - Raft does not emit a HardState, but when the app calls Advance(), it bumps
|
// - Raft does not emit a HardState, but when the app calls Advance(), it bumps
|
||||||
// its internal applied index cursor to 10 (when it should be 9)
|
// its internal applied index cursor to 10 (when it should be 9)
|
||||||
// - the next Ready asks the app to apply index 11 (omitting index 10), losing a
|
// - the next Ready asks the app to apply index 11 (omitting index 10), losing a
|
||||||
// write.
|
// write.
|
||||||
func TestRawNodeCommitPaginationAfterRestart(t *testing.T) {
|
func TestRawNodeCommitPaginationAfterRestart(t *testing.T) {
|
||||||
s := &ignoreSizeHintMemStorage{
|
s := &ignoreSizeHintMemStorage{
|
||||||
MemoryStorage: newTestMemoryStorage(withPeers(1)),
|
MemoryStorage: newTestMemoryStorage(withPeers(1)),
|
||||||
|
@ -1,19 +1,17 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
set -e
|
set -euo pipefail
|
||||||
|
|
||||||
source ./scripts/test_lib.sh
|
source ./scripts/test_lib.sh
|
||||||
|
|
||||||
VER=$1
|
VER=${1:-}
|
||||||
REPOSITORY="${REPOSITORY:-git@github.com:etcd-io/etcd.git}"
|
REPOSITORY="${REPOSITORY:-git@github.com:etcd-io/etcd.git}"
|
||||||
|
|
||||||
|
if [ -z "${VER}" ]; then
|
||||||
if [ -z "$1" ]; then
|
|
||||||
echo "Usage: ${0} VERSION" >> /dev/stderr
|
echo "Usage: ${0} VERSION" >> /dev/stderr
|
||||||
exit 255
|
exit 255
|
||||||
fi
|
fi
|
||||||
|
|
||||||
set -u
|
|
||||||
|
|
||||||
function setup_env {
|
function setup_env {
|
||||||
local ver=${1}
|
local ver=${1}
|
||||||
@ -25,9 +23,7 @@ function setup_env {
|
|||||||
|
|
||||||
pushd "${proj}" >/dev/null
|
pushd "${proj}" >/dev/null
|
||||||
run git fetch --all
|
run git fetch --all
|
||||||
git_assert_branch_in_sync || exit 2
|
|
||||||
run git checkout "${ver}"
|
run git checkout "${ver}"
|
||||||
git_assert_branch_in_sync || exit 2
|
|
||||||
popd >/dev/null
|
popd >/dev/null
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,7 +37,7 @@ function package {
|
|||||||
srcdir="${ccdir}"
|
srcdir="${ccdir}"
|
||||||
fi
|
fi
|
||||||
local ext=""
|
local ext=""
|
||||||
if [ "${GOOS}" == "windows" ]; then
|
if [ "${GOOS:-}" == "windows" ]; then
|
||||||
ext=".exe"
|
ext=".exe"
|
||||||
fi
|
fi
|
||||||
for bin in etcd etcdctl etcdutl; do
|
for bin in etcd etcdctl etcdutl; do
|
||||||
@ -63,7 +59,7 @@ function main {
|
|||||||
cd release
|
cd release
|
||||||
setup_env "${VER}" "${proj}"
|
setup_env "${VER}" "${proj}"
|
||||||
|
|
||||||
tarcmd=tar
|
local tarcmd=tar
|
||||||
if [[ $(go env GOOS) == "darwin" ]]; then
|
if [[ $(go env GOOS) == "darwin" ]]; then
|
||||||
echo "Please use linux machine for release builds."
|
echo "Please use linux machine for release builds."
|
||||||
exit 1
|
exit 1
|
||||||
@ -87,7 +83,7 @@ function main {
|
|||||||
export GOARCH=${TARGET_ARCH}
|
export GOARCH=${TARGET_ARCH}
|
||||||
|
|
||||||
pushd etcd >/dev/null
|
pushd etcd >/dev/null
|
||||||
GO_LDFLAGS="-s" ./build.sh
|
GO_LDFLAGS="-s -w" ./build.sh
|
||||||
popd >/dev/null
|
popd >/dev/null
|
||||||
|
|
||||||
TARGET="etcd-${VER}-${GOOS}-${GOARCH}"
|
TARGET="etcd-${VER}-${GOOS}-${GOARCH}"
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
set -e
|
set -euo pipefail
|
||||||
|
|
||||||
if [ "$#" -ne 1 ]; then
|
if [ "$#" -ne 1 ]; then
|
||||||
echo "Usage: $0 VERSION" >&2
|
echo "Usage: $0 VERSION" >&2
|
||||||
@ -11,7 +11,7 @@ ARCH=$(go env GOARCH)
|
|||||||
VERSION="${1}-${ARCH}"
|
VERSION="${1}-${ARCH}"
|
||||||
DOCKERFILE="Dockerfile-release.${ARCH}"
|
DOCKERFILE="Dockerfile-release.${ARCH}"
|
||||||
|
|
||||||
if [ -z "${BINARYDIR}" ]; then
|
if [ -z "${BINARYDIR:-}" ]; then
|
||||||
RELEASE="etcd-${1}"-$(go env GOOS)-$(go env GOARCH)
|
RELEASE="etcd-${1}"-$(go env GOOS)-$(go env GOARCH)
|
||||||
BINARYDIR="${RELEASE}"
|
BINARYDIR="${RELEASE}"
|
||||||
TARFILE="${RELEASE}.tar.gz"
|
TARFILE="${RELEASE}.tar.gz"
|
||||||
@ -34,9 +34,11 @@ cp "${BINARYDIR}"/etcd "${BINARYDIR}"/etcdctl "${BINARYDIR}"/etcdutl "${IMAGEDIR
|
|||||||
|
|
||||||
cat ./"${DOCKERFILE}" > "${IMAGEDIR}"/Dockerfile
|
cat ./"${DOCKERFILE}" > "${IMAGEDIR}"/Dockerfile
|
||||||
|
|
||||||
if [ -z "$TAG" ]; then
|
if [ -z "${TAG:-}" ]; then
|
||||||
docker build -t "gcr.io/etcd-development/etcd:${VERSION}" "${IMAGEDIR}"
|
# Fix incorrect image "Architecture" using buildkit
|
||||||
docker build -t "quay.io/coreos/etcd:${VERSION}" "${IMAGEDIR}"
|
# From https://stackoverflow.com/q/72144329/
|
||||||
|
DOCKER_BUILDKIT=1 docker build -t "gcr.io/etcd-development/etcd:${VERSION}" "${IMAGEDIR}"
|
||||||
|
DOCKER_BUILDKIT=1 docker build -t "quay.io/coreos/etcd:${VERSION}" "${IMAGEDIR}"
|
||||||
else
|
else
|
||||||
docker build -t "${TAG}:${VERSION}" "${IMAGEDIR}"
|
docker build -t "${TAG}:${VERSION}" "${IMAGEDIR}"
|
||||||
fi
|
fi
|
||||||
|
@ -3,11 +3,11 @@
|
|||||||
# Build all release binaries and images to directory ./release.
|
# Build all release binaries and images to directory ./release.
|
||||||
# Run from repository root.
|
# Run from repository root.
|
||||||
#
|
#
|
||||||
set -e
|
set -euo pipefail
|
||||||
|
|
||||||
source ./scripts/test_lib.sh
|
source ./scripts/test_lib.sh
|
||||||
|
|
||||||
VERSION=$1
|
VERSION=${1:-}
|
||||||
if [ -z "${VERSION}" ]; then
|
if [ -z "${VERSION}" ]; then
|
||||||
echo "Usage: ${0} VERSION" >> /dev/stderr
|
echo "Usage: ${0} VERSION" >> /dev/stderr
|
||||||
exit 255
|
exit 255
|
||||||
|
@ -41,6 +41,7 @@ help() {
|
|||||||
echo " flags:"
|
echo " flags:"
|
||||||
echo " --no-upload: skip gs://etcd binary artifact uploads."
|
echo " --no-upload: skip gs://etcd binary artifact uploads."
|
||||||
echo " --no-docker-push: skip docker image pushes."
|
echo " --no-docker-push: skip docker image pushes."
|
||||||
|
echo " --in-place: build binaries using current branch."
|
||||||
echo ""
|
echo ""
|
||||||
echo "One can perform a (dry-run) test release from any (uncommitted) branch using:"
|
echo "One can perform a (dry-run) test release from any (uncommitted) branch using:"
|
||||||
echo " DRY_RUN=true REPOSITORY=\`pwd\` BRANCH='local-branch-name' ./scripts/release 3.5.0-foobar.2"
|
echo " DRY_RUN=true REPOSITORY=\`pwd\` BRANCH='local-branch-name' ./scripts/release 3.5.0-foobar.2"
|
||||||
@ -54,8 +55,15 @@ main() {
|
|||||||
fi
|
fi
|
||||||
RELEASE_VERSION="v${VERSION}"
|
RELEASE_VERSION="v${VERSION}"
|
||||||
MINOR_VERSION=$(echo "${VERSION}" | cut -d. -f 1-2)
|
MINOR_VERSION=$(echo "${VERSION}" | cut -d. -f 1-2)
|
||||||
BRANCH=${BRANCH:-"release-${MINOR_VERSION}"}
|
|
||||||
REPOSITORY=${REPOSITORY:-"https://github.com/etcd-io/etcd.git"}
|
if [ "${IN_PLACE}" == 1 ]; then
|
||||||
|
# Trigger release in current branch
|
||||||
|
REPOSITORY=$(pwd)
|
||||||
|
BRANCH=$(git rev-parse --abbrev-ref HEAD)
|
||||||
|
else
|
||||||
|
REPOSITORY=${REPOSITORY:-"https://github.com/etcd-io/etcd.git"}
|
||||||
|
BRANCH=${BRANCH:-"release-${MINOR_VERSION}"}
|
||||||
|
fi
|
||||||
|
|
||||||
log_warning "DRY_RUN=${DRY_RUN}"
|
log_warning "DRY_RUN=${DRY_RUN}"
|
||||||
log_callout "RELEASE_VERSION=${RELEASE_VERSION}"
|
log_callout "RELEASE_VERSION=${RELEASE_VERSION}"
|
||||||
@ -78,19 +86,20 @@ main() {
|
|||||||
# Set up release directory.
|
# Set up release directory.
|
||||||
local reldir="/tmp/etcd-release-${VERSION}"
|
local reldir="/tmp/etcd-release-${VERSION}"
|
||||||
log_callout "Preparing temporary directory: ${reldir}"
|
log_callout "Preparing temporary directory: ${reldir}"
|
||||||
if [ ! -d "${reldir}/etcd" ]; then
|
if [ ! -d "${reldir}/etcd" ] && [ "${IN_PLACE}" == 0 ]; then
|
||||||
mkdir -p "${reldir}"
|
mkdir -p "${reldir}"
|
||||||
cd "${reldir}"
|
cd "${reldir}"
|
||||||
run git clone "${REPOSITORY}" --branch "${BRANCH}"
|
run git clone "${REPOSITORY}" --branch "${BRANCH}"
|
||||||
|
run cd "${reldir}/etcd" || exit 2
|
||||||
|
run git checkout "${BRANCH}" || exit 2
|
||||||
|
run git pull origin
|
||||||
|
|
||||||
|
git_assert_branch_in_sync || exit 2
|
||||||
fi
|
fi
|
||||||
run cd "${reldir}/etcd" || exit 2
|
|
||||||
# mark local directory as root for test_lib scripts executions
|
# mark local directory as root for test_lib scripts executions
|
||||||
set_root_dir
|
set_root_dir
|
||||||
|
|
||||||
run git checkout "${BRANCH}" || exit 2
|
|
||||||
run git pull origin
|
|
||||||
git_assert_branch_in_sync || exit 2
|
|
||||||
|
|
||||||
# If a release version tag already exists, use it.
|
# If a release version tag already exists, use it.
|
||||||
local remote_tag_exists
|
local remote_tag_exists
|
||||||
remote_tag_exists=$(run git ls-remote origin "refs/tags/${RELEASE_VERSION}" | grep -c "${RELEASE_VERSION}" || true)
|
remote_tag_exists=$(run git ls-remote origin "refs/tags/${RELEASE_VERSION}" | grep -c "${RELEASE_VERSION}" || true)
|
||||||
@ -101,15 +110,17 @@ main() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Check go version.
|
# Check go version.
|
||||||
|
log_callout "Check go version"
|
||||||
local go_version current_go_version
|
local go_version current_go_version
|
||||||
go_version="go$(grep go-version .github/workflows/tests.yaml | awk '{print $2}' | tr -d '"')"
|
go_version="go$(cat .go-version)"
|
||||||
current_go_version=$(go version | awk '{ print $3 }')
|
current_go_version=$(go version | awk '{ print $3 }')
|
||||||
if [[ "${current_go_version}" != "${go_version}" ]]; then
|
if [[ "${current_go_version}" != "${go_version}" ]]; then
|
||||||
log_error "Current go version is ${current_go_version}, but etcd ${RELEASE_VERSION} requires ${go_version} (see .travis.yml)."
|
log_error "Current go version is ${current_go_version}, but etcd ${RELEASE_VERSION} requires ${go_version} (see .go-version)."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# If the release tag does not already exist remotely, create it.
|
# If the release tag does not already exist remotely, create it.
|
||||||
|
log_callout "Create tag if not present"
|
||||||
if [ "${remote_tag_exists}" -eq 0 ]; then
|
if [ "${remote_tag_exists}" -eq 0 ]; then
|
||||||
# Bump version/version.go to release version.
|
# Bump version/version.go to release version.
|
||||||
local source_version
|
local source_version
|
||||||
@ -147,7 +158,7 @@ main() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Push the version change if it's not already been pushed.
|
# Push the version change if it's not already been pushed.
|
||||||
if [ "$DRY_RUN" != "true" ] && [ "$(git rev-list --count "origin/${BRANCH}..${BRANCH}")" -gt 0 ]; then
|
if [ "${DRY_RUN}" != "true" ] && [ "$(git rev-list --count "origin/${BRANCH}..${BRANCH}")" -gt 0 ]; then
|
||||||
read -p "Push version bump up to ${VERSION} to '$(git remote get-url origin)' [y/N]? " -r confirm
|
read -p "Push version bump up to ${VERSION} to '$(git remote get-url origin)' [y/N]? " -r confirm
|
||||||
[[ "${confirm,,}" == "y" ]] || exit 1
|
[[ "${confirm,,}" == "y" ]] || exit 1
|
||||||
maybe_run git push
|
maybe_run git push
|
||||||
@ -161,14 +172,23 @@ main() {
|
|||||||
REMOTE_REPO="origin" push_mod_tags_cmd
|
REMOTE_REPO="origin" push_mod_tags_cmd
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Verify the version tag is on the right branch
|
if [ "${IN_PLACE}" == 0 ]; then
|
||||||
local branch=$(git for-each-ref --contains "${RELEASE_VERSION}" --format="%(refname)" 'refs/heads' | cut -d '/' -f 3)
|
# Tried with `local branch=$(git branch -a --contains tags/"${RELEASE_VERSION}")`
|
||||||
if [ "${branch}" != "${BRANCH}" ]; then
|
# so as to work with both current branch and main/release-3.X.
|
||||||
log_error "Error: Git tag ${RELEASE_VERSION} should be on branch '${BRANCH}' but is on '${branch}'"
|
# But got error below on current branch mode,
|
||||||
exit 1
|
# Error: Git tag v3.6.99 should be on branch '* (HEAD detached at pull/14860/merge)' but is on '* (HEAD detached from pull/14860/merge)'
|
||||||
|
#
|
||||||
|
# Verify the version tag is on the right branch
|
||||||
|
# shellcheck disable=SC2155
|
||||||
|
local branch=$(git for-each-ref --contains "${RELEASE_VERSION}" --format="%(refname)" 'refs/heads' | cut -d '/' -f 3)
|
||||||
|
if [ "${branch}" != "${BRANCH}" ]; then
|
||||||
|
log_error "Error: Git tag ${RELEASE_VERSION} should be on branch '${BRANCH}' but is on '${branch}'"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
log_callout "Verify the latest commit has the version tag"
|
||||||
# Verify the latest commit has the version tag
|
# Verify the latest commit has the version tag
|
||||||
# shellcheck disable=SC2155
|
# shellcheck disable=SC2155
|
||||||
local tag="$(git describe --exact-match HEAD)"
|
local tag="$(git describe --exact-match HEAD)"
|
||||||
@ -177,6 +197,7 @@ main() {
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
log_callout "Verify the work space is clean"
|
||||||
# Verify the clean working tree
|
# Verify the clean working tree
|
||||||
# shellcheck disable=SC2155
|
# shellcheck disable=SC2155
|
||||||
local diff="$(git diff HEAD --stat)"
|
local diff="$(git diff HEAD --stat)"
|
||||||
@ -212,7 +233,7 @@ main() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Upload artifacts.
|
# Upload artifacts.
|
||||||
if [ "${NO_UPLOAD}" == 1 ]; then
|
if [ "${DRY_RUN}" == "true" ] || [ "${NO_UPLOAD}" == 1 ]; then
|
||||||
log_callout "Skipping artifact upload to gs://etcd. --no-upload flat is set."
|
log_callout "Skipping artifact upload to gs://etcd. --no-upload flat is set."
|
||||||
else
|
else
|
||||||
read -p "Upload etcd ${RELEASE_VERSION} release artifacts to gs://etcd [y/N]? " -r confirm
|
read -p "Upload etcd ${RELEASE_VERSION} release artifacts to gs://etcd [y/N]? " -r confirm
|
||||||
@ -224,7 +245,7 @@ main() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# Push images.
|
# Push images.
|
||||||
if [ "${NO_DOCKER_PUSH}" == 1 ]; then
|
if [ "${DRY_RUN}" == "true" ] || [ "${NO_DOCKER_PUSH}" == 1 ]; then
|
||||||
log_callout "Skipping docker push. --no-docker-push flat is set."
|
log_callout "Skipping docker push. --no-docker-push flat is set."
|
||||||
else
|
else
|
||||||
read -p "Publish etcd ${RELEASE_VERSION} docker images to quay.io [y/N]? " -r confirm
|
read -p "Publish etcd ${RELEASE_VERSION} docker images to quay.io [y/N]? " -r confirm
|
||||||
@ -303,6 +324,7 @@ main() {
|
|||||||
POSITIONAL=()
|
POSITIONAL=()
|
||||||
NO_UPLOAD=0
|
NO_UPLOAD=0
|
||||||
NO_DOCKER_PUSH=0
|
NO_DOCKER_PUSH=0
|
||||||
|
IN_PLACE=0
|
||||||
|
|
||||||
while test $# -gt 0; do
|
while test $# -gt 0; do
|
||||||
case "$1" in
|
case "$1" in
|
||||||
@ -311,6 +333,10 @@ while test $# -gt 0; do
|
|||||||
help
|
help
|
||||||
exit 0
|
exit 0
|
||||||
;;
|
;;
|
||||||
|
--in-place)
|
||||||
|
IN_PLACE=1
|
||||||
|
shift
|
||||||
|
;;
|
||||||
--no-upload)
|
--no-upload)
|
||||||
NO_UPLOAD=1
|
NO_UPLOAD=1
|
||||||
shift
|
shift
|
||||||
@ -332,4 +358,11 @@ if [[ ! $# -eq 1 ]]; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# Note that we shouldn't upload artifacts in --in-place mode, so it
|
||||||
|
# must be called with DRY_RUN=true
|
||||||
|
if [ "${DRY_RUN}" != "true" ] && [ "${IN_PLACE}" == 1 ]; then
|
||||||
|
log_error "--in-place should only be called with DRY_RUN=true"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
main "$1"
|
main "$1"
|
||||||
|
93
scripts/test_images.sh
Executable file
93
scripts/test_images.sh
Executable file
@ -0,0 +1,93 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
# http://redsymbol.net/articles/unofficial-bash-strict-mode/
|
||||||
|
set -euo pipefail
|
||||||
|
IFS=$'\n\t'
|
||||||
|
|
||||||
|
source ./scripts/test_lib.sh
|
||||||
|
|
||||||
|
function startContainer {
|
||||||
|
# run docker in the background
|
||||||
|
docker run -d --rm --name "${RUN_NAME}" "${IMAGE}"
|
||||||
|
|
||||||
|
# wait for etcd daemon to bootstrap
|
||||||
|
sleep 5
|
||||||
|
}
|
||||||
|
|
||||||
|
function runVersionCheck {
|
||||||
|
Out=$(docker run --rm "${IMAGE}" "${@}")
|
||||||
|
foundVersion=$(echo "$Out" | head -1 | rev | cut -d" " -f 1 | rev )
|
||||||
|
if [[ "${foundVersion}" != "${VERSION}" ]]; then
|
||||||
|
echo "error: Invalid Version. Got $foundVersion, expected $VERSION. Error: $Out"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
# Can't proceed without docker
|
||||||
|
if ! command -v docker >/dev/null; then
|
||||||
|
log_error "cannot find docker"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# You can't run darwin binaries in linux containers
|
||||||
|
if [[ $(go env GOOS) == "darwin" ]]; then
|
||||||
|
echo "Please use linux machine for release builds."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Pick defaults based on release workflow
|
||||||
|
ARCH=$(go env GOARCH)
|
||||||
|
REPOSITARY=${REPOSITARY:-"gcr.io/etcd-development/etcd"}
|
||||||
|
if [ -n "$VERSION" ]; then
|
||||||
|
# Expected Format: v3.6.99-amd64
|
||||||
|
TAG=v"${VERSION}"-"${ARCH}"
|
||||||
|
else
|
||||||
|
echo "Terminating test, VERSION not supplied"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
IMAGE=${IMAGE:-"${REPOSITARY}:${TAG}"}
|
||||||
|
|
||||||
|
# ETCD related values
|
||||||
|
RUN_NAME="test_etcd"
|
||||||
|
KEY="foo"
|
||||||
|
VALUE="bar"
|
||||||
|
|
||||||
|
if [[ "$(docker images -q "${IMAGE}" 2> /dev/null)" == "" ]]; then
|
||||||
|
echo "${IMAGE} not present locally"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Version check
|
||||||
|
runVersionCheck "/usr/local/bin/etcd" "--version"
|
||||||
|
runVersionCheck "/usr/local/bin/etcdctl" "version"
|
||||||
|
runVersionCheck "/usr/local/bin/etcdutl" "version"
|
||||||
|
|
||||||
|
startContainer
|
||||||
|
# stop container
|
||||||
|
trap 'docker stop "${RUN_NAME}"' EXIT
|
||||||
|
|
||||||
|
|
||||||
|
# Put/Get check
|
||||||
|
PUT=$(docker exec "${RUN_NAME}" /usr/local/bin/etcdctl put "${KEY}" "${VALUE}")
|
||||||
|
if [ "${PUT}" != "OK" ]; then
|
||||||
|
echo "Problem with Putting in etcd"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
GET=$(docker exec "${RUN_NAME}" /usr/local/bin/etcdctl get "$KEY" --print-value-only)
|
||||||
|
if [ "${GET}" != "${VALUE}" ]; then
|
||||||
|
echo "Problem with getting foo bar in etcd. Got ${GET}"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Succesfully tested etcd local image ${TAG}"
|
||||||
|
|
||||||
|
for TARGET_ARCH in "amd64" "arm64" "ppc64le" "s390x"; do
|
||||||
|
ARCH_TAG=v"${VERSION}"-"${TARGET_ARCH}"
|
||||||
|
IMG_ARCH=$(docker inspect --format '{{.Architecture}}' "${REPOSITARY}:${ARCH_TAG}")
|
||||||
|
if [ "${IMG_ARCH}" != "$TARGET_ARCH" ];then
|
||||||
|
echo "Incorrect docker image architecture"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "Correct Architecture ${ARCH_TAG}"
|
||||||
|
done
|
@ -1,5 +1,7 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
ROOT_MODULE="go.etcd.io/etcd"
|
ROOT_MODULE="go.etcd.io/etcd"
|
||||||
|
|
||||||
if [[ "$(go list)" != "${ROOT_MODULE}/v3" ]]; then
|
if [[ "$(go list)" != "${ROOT_MODULE}/v3" ]]; then
|
||||||
@ -71,7 +73,8 @@ function relativePath {
|
|||||||
local commonPart=$source
|
local commonPart=$source
|
||||||
local result=""
|
local result=""
|
||||||
|
|
||||||
while [[ "${target#$commonPart}" == "${target}" ]]; do
|
# Refer to https://www.shellcheck.net/wiki/SC2295
|
||||||
|
while [[ "${target#"$commonPart"}" == "${target}" ]]; do
|
||||||
# no match, means that candidate common part is not correct
|
# no match, means that candidate common part is not correct
|
||||||
# go up one level (reduce common part)
|
# go up one level (reduce common part)
|
||||||
commonPart="$(dirname "$commonPart")"
|
commonPart="$(dirname "$commonPart")"
|
||||||
@ -90,7 +93,8 @@ function relativePath {
|
|||||||
|
|
||||||
# since we now have identified the common part,
|
# since we now have identified the common part,
|
||||||
# compute the non-common part
|
# compute the non-common part
|
||||||
local forwardPart="${target#$commonPart}"
|
# Refer to https://www.shellcheck.net/wiki/SC2295
|
||||||
|
local forwardPart="${target#"$commonPart"}"
|
||||||
|
|
||||||
# and now stick all parts together
|
# and now stick all parts together
|
||||||
if [[ -n $result ]] && [[ -n $forwardPart ]]; then
|
if [[ -n $result ]] && [[ -n $forwardPart ]]; then
|
||||||
@ -105,10 +109,10 @@ function relativePath {
|
|||||||
|
|
||||||
#### Discovery of files/packages within a go module #####
|
#### Discovery of files/packages within a go module #####
|
||||||
|
|
||||||
# go_srcs_in_module [package]
|
# go_srcs_in_module
|
||||||
# returns list of all not-generated go sources in the current (dir) module.
|
# returns list of all not-generated go sources in the current (dir) module.
|
||||||
function go_srcs_in_module {
|
function go_srcs_in_module {
|
||||||
go fmt -n "$1" | grep -Eo "([^ ]*)$" | grep -vE "(\\_test.go|\\.pb\\.go|\\.pb\\.gw.go)"
|
go list -f "{{with \$c:=.}}{{range \$f:=\$c.GoFiles }}{{\$c.Dir}}/{{\$f}}{{\"\n\"}}{{end}}{{range \$f:=\$c.TestGoFiles }}{{\$c.Dir}}/{{\$f}}{{\"\n\"}}{{end}}{{range \$f:=\$c.XTestGoFiles }}{{\$c.Dir}}/{{\$f}}{{\"\n\"}}{{end}}{{end}}" ./... | grep -vE "(\\.pb\\.go|\\.pb\\.gw.go)"
|
||||||
}
|
}
|
||||||
|
|
||||||
# pkgs_in_module [optional:package_pattern]
|
# pkgs_in_module [optional:package_pattern]
|
||||||
@ -169,7 +173,7 @@ function module_dirs() {
|
|||||||
|
|
||||||
# maybe_run [cmd...] runs given command depending on the DRY_RUN flag.
|
# maybe_run [cmd...] runs given command depending on the DRY_RUN flag.
|
||||||
function maybe_run() {
|
function maybe_run() {
|
||||||
if ${DRY_RUN}; then
|
if ${DRY_RUN:-}; then
|
||||||
log_warning -e "# DRY_RUN:\\n % ${*}"
|
log_warning -e "# DRY_RUN:\\n % ${*}"
|
||||||
else
|
else
|
||||||
run "${@}"
|
run "${@}"
|
||||||
@ -241,7 +245,7 @@ function go_test {
|
|||||||
|
|
||||||
local goTestFlags=""
|
local goTestFlags=""
|
||||||
local goTestEnv=""
|
local goTestEnv=""
|
||||||
if [ "${VERBOSE}" == "1" ]; then
|
if [ "${VERBOSE:-}" == "1" ]; then
|
||||||
goTestFlags="-v"
|
goTestFlags="-v"
|
||||||
fi
|
fi
|
||||||
|
|
||||||
@ -308,16 +312,25 @@ fi
|
|||||||
|
|
||||||
# tool_get_bin [tool] - returns absolute path to a tool binary (or returns error)
|
# tool_get_bin [tool] - returns absolute path to a tool binary (or returns error)
|
||||||
function tool_get_bin {
|
function tool_get_bin {
|
||||||
tool_exists "gobin" "GO111MODULE=off go get github.com/myitcv/gobin" || return 2
|
|
||||||
|
|
||||||
local tool="$1"
|
local tool="$1"
|
||||||
|
local pkg_part="$1"
|
||||||
if [[ "$tool" == *"@"* ]]; then
|
if [[ "$tool" == *"@"* ]]; then
|
||||||
|
pkg_part=$(echo "${tool}" | cut -d'@' -f1)
|
||||||
# shellcheck disable=SC2086
|
# shellcheck disable=SC2086
|
||||||
run gobin ${GOBINARGS:-} -p "${tool}" || return 2
|
run go install ${GOBINARGS:-} "${tool}" || return 2
|
||||||
else
|
else
|
||||||
# shellcheck disable=SC2086
|
# shellcheck disable=SC2086
|
||||||
run_for_module ./tools/mod run gobin ${GOBINARGS:-} -p -m --mod=readonly "${tool}" || return 2
|
run_for_module ./tools/mod run go install ${GOBINARGS:-} "${tool}" || return 2
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
# remove the version suffix, such as removing "/v3" from "go.etcd.io/etcd/v3".
|
||||||
|
local cmd_base_name
|
||||||
|
cmd_base_name=$(basename "${pkg_part}")
|
||||||
|
if [[ ${cmd_base_name} =~ ^v[0-9]*$ ]]; then
|
||||||
|
pkg_part=$(dirname "${pkg_part}")
|
||||||
|
fi
|
||||||
|
|
||||||
|
run_for_module ./tools/mod go list -f '{{.Target}}' "${pkg_part}"
|
||||||
}
|
}
|
||||||
|
|
||||||
# tool_pkg_dir [pkg] - returns absolute path to a directory that stores given pkg.
|
# tool_pkg_dir [pkg] - returns absolute path to a directory that stores given pkg.
|
||||||
@ -354,14 +367,16 @@ function assert_no_git_modifications {
|
|||||||
# - no differencing commits in relation to the origin/$branch
|
# - no differencing commits in relation to the origin/$branch
|
||||||
function git_assert_branch_in_sync {
|
function git_assert_branch_in_sync {
|
||||||
local branch
|
local branch
|
||||||
branch=$(run git rev-parse --abbrev-ref HEAD)
|
|
||||||
# TODO: When git 2.22 popular, change to:
|
# TODO: When git 2.22 popular, change to:
|
||||||
# branch=$(git branch --show-current)
|
# branch=$(git branch --show-current)
|
||||||
|
branch=$(run git rev-parse --abbrev-ref HEAD)
|
||||||
|
log_callout "Verify the current branch '${branch}' is clean"
|
||||||
if [[ $(run git status --porcelain --untracked-files=no) ]]; then
|
if [[ $(run git status --porcelain --untracked-files=no) ]]; then
|
||||||
log_error "The workspace in '$(pwd)' for branch: ${branch} has uncommitted changes"
|
log_error "The workspace in '$(pwd)' for branch: ${branch} has uncommitted changes"
|
||||||
log_error "Consider cleaning up / renaming this directory or (cd $(pwd) && git reset --hard)"
|
log_error "Consider cleaning up / renaming this directory or (cd $(pwd) && git reset --hard)"
|
||||||
return 2
|
return 2
|
||||||
fi
|
fi
|
||||||
|
log_callout "Verify the current branch '${branch}' is in sync with the 'origin/${branch}'"
|
||||||
if [ -n "${branch}" ]; then
|
if [ -n "${branch}" ]; then
|
||||||
ref_local=$(run git rev-parse "${branch}")
|
ref_local=$(run git rev-parse "${branch}")
|
||||||
ref_origin=$(run git rev-parse "origin/${branch}")
|
ref_origin=$(run git rev-parse "origin/${branch}")
|
||||||
|
@ -21,7 +21,7 @@ import (
|
|||||||
"errors"
|
"errors"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
jwt "github.com/form3tech-oss/jwt-go"
|
"github.com/golang-jwt/jwt/v4"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -42,7 +42,7 @@ func (t *tokenJWT) info(ctx context.Context, token string, rev uint64) (*AuthInf
|
|||||||
// rev isn't used in JWT, it is only used in simple token
|
// rev isn't used in JWT, it is only used in simple token
|
||||||
var (
|
var (
|
||||||
username string
|
username string
|
||||||
revision uint64
|
revision float64
|
||||||
)
|
)
|
||||||
|
|
||||||
parsed, err := jwt.Parse(token, func(token *jwt.Token) (interface{}, error) {
|
parsed, err := jwt.Parse(token, func(token *jwt.Token) (interface{}, error) {
|
||||||
@ -74,10 +74,19 @@ func (t *tokenJWT) info(ctx context.Context, token string, rev uint64) (*AuthInf
|
|||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
username = claims["username"].(string)
|
username, ok = claims["username"].(string)
|
||||||
revision = uint64(claims["revision"].(float64))
|
if !ok {
|
||||||
|
t.lg.Warn("failed to obtain user claims from jwt token")
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
return &AuthInfo{Username: username, Revision: revision}, true
|
revision, ok = claims["revision"].(float64)
|
||||||
|
if !ok {
|
||||||
|
t.lg.Warn("failed to obtain revision claims from jwt token")
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
|
return &AuthInfo{Username: username, Revision: uint64(revision)}, true
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *tokenJWT) assign(ctx context.Context, username string, revision uint64) (string, error) {
|
func (t *tokenJWT) assign(ctx context.Context, username string, revision uint64) (string, error) {
|
||||||
|
@ -18,7 +18,10 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"testing"
|
"testing"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/golang-jwt/jwt/v4"
|
||||||
|
"github.com/stretchr/testify/require"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -202,3 +205,75 @@ func TestJWTBad(t *testing.T) {
|
|||||||
func testJWTOpts() string {
|
func testJWTOpts() string {
|
||||||
return fmt.Sprintf("%s,pub-key=%s,priv-key=%s,sign-method=RS256", tokenTypeJWT, jwtRSAPubKey, jwtRSAPrivKey)
|
return fmt.Sprintf("%s,pub-key=%s,priv-key=%s,sign-method=RS256", tokenTypeJWT, jwtRSAPubKey, jwtRSAPrivKey)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestJWTTokenWithMissingFields(t *testing.T) {
|
||||||
|
testCases := []struct {
|
||||||
|
name string
|
||||||
|
username string // An empty string means not present
|
||||||
|
revision uint64 // 0 means not present
|
||||||
|
expectValid bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "valid token",
|
||||||
|
username: "hello",
|
||||||
|
revision: 100,
|
||||||
|
expectValid: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "no username",
|
||||||
|
username: "",
|
||||||
|
revision: 100,
|
||||||
|
expectValid: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "no revision",
|
||||||
|
username: "hello",
|
||||||
|
revision: 0,
|
||||||
|
expectValid: false,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tc := range testCases {
|
||||||
|
tc := tc
|
||||||
|
optsMap := map[string]string{
|
||||||
|
"priv-key": jwtRSAPrivKey,
|
||||||
|
"sign-method": "RS256",
|
||||||
|
"ttl": "1h",
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Run(tc.name, func(t *testing.T) {
|
||||||
|
// prepare claims
|
||||||
|
claims := jwt.MapClaims{
|
||||||
|
"exp": time.Now().Add(time.Hour).Unix(),
|
||||||
|
}
|
||||||
|
if tc.username != "" {
|
||||||
|
claims["username"] = tc.username
|
||||||
|
}
|
||||||
|
if tc.revision != 0 {
|
||||||
|
claims["revision"] = tc.revision
|
||||||
|
}
|
||||||
|
|
||||||
|
// generate a JWT token with the given claims
|
||||||
|
var opts jwtOptions
|
||||||
|
err := opts.ParseWithDefaults(optsMap)
|
||||||
|
require.NoError(t, err)
|
||||||
|
key, err := opts.Key()
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
tk := jwt.NewWithClaims(opts.SignMethod, claims)
|
||||||
|
token, err := tk.SignedString(key)
|
||||||
|
require.NoError(t, err)
|
||||||
|
|
||||||
|
// verify the token
|
||||||
|
jwtProvider, err := newTokenProviderJWT(zap.NewNop(), optsMap)
|
||||||
|
require.NoError(t, err)
|
||||||
|
ai, ok := jwtProvider.info(context.TODO(), token, 123)
|
||||||
|
|
||||||
|
require.Equal(t, tc.expectValid, ok)
|
||||||
|
if ok {
|
||||||
|
require.Equal(t, tc.username, ai.Username)
|
||||||
|
require.Equal(t, tc.revision, ai.Revision)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -21,7 +21,7 @@ import (
|
|||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
jwt "github.com/form3tech-oss/jwt-go"
|
"github.com/golang-jwt/jwt/v4"
|
||||||
)
|
)
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -76,8 +76,10 @@ func checkKeyInterval(
|
|||||||
cachedPerms *unifiedRangePermissions,
|
cachedPerms *unifiedRangePermissions,
|
||||||
key, rangeEnd []byte,
|
key, rangeEnd []byte,
|
||||||
permtyp authpb.Permission_Type) bool {
|
permtyp authpb.Permission_Type) bool {
|
||||||
if len(rangeEnd) == 1 && rangeEnd[0] == 0 {
|
if isOpenEnded(rangeEnd) {
|
||||||
rangeEnd = nil
|
rangeEnd = nil
|
||||||
|
// nil rangeEnd will be converetd to []byte{}, the largest element of BytesAffineComparable,
|
||||||
|
// in NewBytesAffineInterval().
|
||||||
}
|
}
|
||||||
|
|
||||||
ivl := adt.NewBytesAffineInterval(key, rangeEnd)
|
ivl := adt.NewBytesAffineInterval(key, rangeEnd)
|
||||||
@ -153,3 +155,51 @@ type unifiedRangePermissions struct {
|
|||||||
readPerms adt.IntervalTree
|
readPerms adt.IntervalTree
|
||||||
writePerms adt.IntervalTree
|
writePerms adt.IntervalTree
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Constraints related to key range
|
||||||
|
// Assumptions:
|
||||||
|
// a1. key must be non-nil
|
||||||
|
// a2. []byte{} (in the case of string, "") is not a valid key of etcd
|
||||||
|
// For representing an open-ended range, BytesAffineComparable uses []byte{} as the largest element.
|
||||||
|
// a3. []byte{0x00} is the minimum valid etcd key
|
||||||
|
//
|
||||||
|
// Based on the above assumptions, key and rangeEnd must follow below rules:
|
||||||
|
// b1. for representing a single key point, rangeEnd should be nil or zero length byte array (in the case of string, "")
|
||||||
|
// Rule a2 guarantees that (X, []byte{}) for any X is not a valid range. So such ranges can be used for representing
|
||||||
|
// a single key permission.
|
||||||
|
//
|
||||||
|
// b2. key range with upper limit, like (X, Y), larger or equal to X and smaller than Y
|
||||||
|
//
|
||||||
|
// b3. key range with open-ended, like (X, <open ended>), is represented like (X, []byte{0x00})
|
||||||
|
// Because of rule a3, if we have (X, []byte{0x00}), such a range represents an empty range and makes no sense to have
|
||||||
|
// such a permission. So we use []byte{0x00} for representing an open-ended permission.
|
||||||
|
// Note that rangeEnd with []byte{0x00} will be converted into []byte{} before inserted into the interval tree
|
||||||
|
// (rule a2 ensures that this is the largest element).
|
||||||
|
// Special range like key = []byte{0x00} and rangeEnd = []byte{0x00} is treated as a range which matches with all keys.
|
||||||
|
//
|
||||||
|
// Treating a range whose rangeEnd with []byte{0x00} as an open-ended comes from the rules of Range() and Watch() API.
|
||||||
|
|
||||||
|
func isOpenEnded(rangeEnd []byte) bool { // check rule b3
|
||||||
|
return len(rangeEnd) == 1 && rangeEnd[0] == 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func isValidPermissionRange(key, rangeEnd []byte) bool {
|
||||||
|
if len(key) == 0 {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
if rangeEnd == nil || len(rangeEnd) == 0 { // ensure rule b1
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
begin := adt.BytesAffineComparable(key)
|
||||||
|
end := adt.BytesAffineComparable(rangeEnd)
|
||||||
|
if begin.Compare(end) == -1 { // rule b2
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
if isOpenEnded(rangeEnd) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
@ -45,6 +45,26 @@ func TestRangePermission(t *testing.T) {
|
|||||||
[]byte("a"), []byte("f"),
|
[]byte("a"), []byte("f"),
|
||||||
true,
|
true,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
[]adt.Interval{adt.NewBytesAffineInterval([]byte("a"), []byte("d")), adt.NewBytesAffineInterval([]byte("a"), []byte("b")), adt.NewBytesAffineInterval([]byte("c"), []byte("f"))},
|
||||||
|
[]byte("a"), []byte{},
|
||||||
|
false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
[]adt.Interval{adt.NewBytesAffineInterval([]byte("a"), []byte{})},
|
||||||
|
[]byte("a"), []byte{},
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
[]adt.Interval{adt.NewBytesAffineInterval([]byte{0x00}, []byte{})},
|
||||||
|
[]byte("a"), []byte{},
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
[]adt.Interval{adt.NewBytesAffineInterval([]byte{0x00}, []byte{})},
|
||||||
|
[]byte{0x00}, []byte{},
|
||||||
|
true,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, tt := range tests {
|
for i, tt := range tests {
|
||||||
@ -86,6 +106,16 @@ func TestKeyPermission(t *testing.T) {
|
|||||||
[]byte("f"),
|
[]byte("f"),
|
||||||
false,
|
false,
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
[]adt.Interval{adt.NewBytesAffineInterval([]byte("a"), []byte("d")), adt.NewBytesAffineInterval([]byte("a"), []byte("b")), adt.NewBytesAffineInterval([]byte("c"), []byte{})},
|
||||||
|
[]byte("f"),
|
||||||
|
true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
[]adt.Interval{adt.NewBytesAffineInterval([]byte("a"), []byte("d")), adt.NewBytesAffineInterval([]byte("a"), []byte("b")), adt.NewBytesAffineInterval([]byte{0x00}, []byte{})},
|
||||||
|
[]byte("f"),
|
||||||
|
true,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, tt := range tests {
|
for i, tt := range tests {
|
||||||
@ -100,3 +130,88 @@ func TestKeyPermission(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRangeCheck(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
key []byte
|
||||||
|
rangeEnd []byte
|
||||||
|
want bool
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "valid single key",
|
||||||
|
key: []byte("a"),
|
||||||
|
rangeEnd: []byte(""),
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "valid single key",
|
||||||
|
key: []byte("a"),
|
||||||
|
rangeEnd: nil,
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "valid key range, key < rangeEnd",
|
||||||
|
key: []byte("a"),
|
||||||
|
rangeEnd: []byte("b"),
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "invalid empty key range, key == rangeEnd",
|
||||||
|
key: []byte("a"),
|
||||||
|
rangeEnd: []byte("a"),
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "invalid empty key range, key > rangeEnd",
|
||||||
|
key: []byte("b"),
|
||||||
|
rangeEnd: []byte("a"),
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "invalid key, key must not be \"\"",
|
||||||
|
key: []byte(""),
|
||||||
|
rangeEnd: []byte("a"),
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "invalid key range, key must not be \"\"",
|
||||||
|
key: []byte(""),
|
||||||
|
rangeEnd: []byte(""),
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "invalid key range, key must not be \"\"",
|
||||||
|
key: []byte(""),
|
||||||
|
rangeEnd: []byte("\x00"),
|
||||||
|
want: false,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "valid single key (not useful in practice)",
|
||||||
|
key: []byte("\x00"),
|
||||||
|
rangeEnd: []byte(""),
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "valid key range, larger or equals to \"a\"",
|
||||||
|
key: []byte("a"),
|
||||||
|
rangeEnd: []byte("\x00"),
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "valid key range, which includes all keys",
|
||||||
|
key: []byte("\x00"),
|
||||||
|
rangeEnd: []byte("\x00"),
|
||||||
|
want: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
result := isValidPermissionRange(tt.key, tt.rangeEnd)
|
||||||
|
if result != tt.want {
|
||||||
|
t.Errorf("#%d: result=%t, want=%t", i, result, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -370,6 +370,7 @@ func (as *authStore) Recover(be backend.Backend) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
as.setRevision(getRevision(tx))
|
as.setRevision(getRevision(tx))
|
||||||
|
as.refreshRangePermCache(tx)
|
||||||
|
|
||||||
tx.Unlock()
|
tx.Unlock()
|
||||||
|
|
||||||
@ -478,7 +479,8 @@ func (as *authStore) UserChangePassword(r *pb.AuthUserChangePasswordRequest) (*p
|
|||||||
var password []byte
|
var password []byte
|
||||||
var err error
|
var err error
|
||||||
|
|
||||||
if !user.Options.NoPassword {
|
// Backward compatible with old versions of etcd, user options is nil
|
||||||
|
if user.Options == nil || !user.Options.NoPassword {
|
||||||
password, err = as.selectPassword(r.Password, r.HashedPassword)
|
password, err = as.selectPassword(r.Password, r.HashedPassword)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, ErrNoPasswordUser
|
return nil, ErrNoPasswordUser
|
||||||
@ -790,6 +792,9 @@ func (as *authStore) RoleGrantPermission(r *pb.AuthRoleGrantPermissionRequest) (
|
|||||||
if r.Perm == nil {
|
if r.Perm == nil {
|
||||||
return nil, ErrPermissionNotGiven
|
return nil, ErrPermissionNotGiven
|
||||||
}
|
}
|
||||||
|
if !isValidPermissionRange(r.Perm.Key, r.Perm.RangeEnd) {
|
||||||
|
return nil, ErrInvalidAuthMgmt
|
||||||
|
}
|
||||||
|
|
||||||
tx := as.be.BatchTx()
|
tx := as.be.BatchTx()
|
||||||
tx.LockInsideApply()
|
tx.LockInsideApply()
|
||||||
|
@ -17,6 +17,7 @@ package auth
|
|||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
"encoding/base64"
|
"encoding/base64"
|
||||||
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"reflect"
|
"reflect"
|
||||||
"strings"
|
"strings"
|
||||||
@ -74,7 +75,7 @@ func TestNewAuthStoreRevision(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestNewAuthStoreBryptCost ensures that NewAuthStore uses default when given bcrypt-cost is invalid
|
// TestNewAuthStoreBcryptCost ensures that NewAuthStore uses default when given bcrypt-cost is invalid
|
||||||
func TestNewAuthStoreBcryptCost(t *testing.T) {
|
func TestNewAuthStoreBcryptCost(t *testing.T) {
|
||||||
b, _ := betesting.NewDefaultTmpBackend(t)
|
b, _ := betesting.NewDefaultTmpBackend(t)
|
||||||
defer betesting.Close(t, b)
|
defer betesting.Close(t, b)
|
||||||
@ -124,6 +125,13 @@ func setupAuthStore(t *testing.T) (store *authStore, teardownfunc func(t *testin
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The UserAdd function cannot generate old etcd version user data (user's option is nil)
|
||||||
|
// add special users through the underlying interface
|
||||||
|
err = addUserWithNoOption(as)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
tearDown := func(_ *testing.T) {
|
tearDown := func(_ *testing.T) {
|
||||||
b.Close()
|
b.Close()
|
||||||
as.Close()
|
as.Close()
|
||||||
@ -131,6 +139,14 @@ func setupAuthStore(t *testing.T) (store *authStore, teardownfunc func(t *testin
|
|||||||
return as, tearDown
|
return as, tearDown
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func addUserWithNoOption(as *authStore) error {
|
||||||
|
_, err := as.UserAdd(&pb.AuthUserAddRequest{Name: "foo-no-user-options", Password: "bar"})
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
func enableAuthAndCreateRoot(as *authStore) error {
|
func enableAuthAndCreateRoot(as *authStore) error {
|
||||||
_, err := as.UserAdd(&pb.AuthUserAddRequest{Name: "root", HashedPassword: encodePassword("root"), Options: &authpb.UserAddOptions{NoPassword: false}})
|
_, err := as.UserAdd(&pb.AuthUserAddRequest{Name: "root", HashedPassword: encodePassword("root"), Options: &authpb.UserAddOptions{NoPassword: false}})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -189,6 +205,30 @@ func TestRecover(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRecoverWithEmptyRangePermCache(t *testing.T) {
|
||||||
|
as, tearDown := setupAuthStore(t)
|
||||||
|
defer as.Close()
|
||||||
|
defer tearDown(t)
|
||||||
|
|
||||||
|
as.enabled = false
|
||||||
|
as.rangePermCache = map[string]*unifiedRangePermissions{}
|
||||||
|
as.Recover(as.be)
|
||||||
|
|
||||||
|
if !as.IsAuthEnabled() {
|
||||||
|
t.Fatalf("expected auth enabled got disabled")
|
||||||
|
}
|
||||||
|
|
||||||
|
if len(as.rangePermCache) != 3 {
|
||||||
|
t.Fatalf("rangePermCache should have permission information for 3 users (\"root\" and \"foo\",\"foo-no-user-options\"), but has %d information", len(as.rangePermCache))
|
||||||
|
}
|
||||||
|
if _, ok := as.rangePermCache["root"]; !ok {
|
||||||
|
t.Fatal("user \"root\" should be created by setupAuthStore() but doesn't exist in rangePermCache")
|
||||||
|
}
|
||||||
|
if _, ok := as.rangePermCache["foo"]; !ok {
|
||||||
|
t.Fatal("user \"foo\" should be created by setupAuthStore() but doesn't exist in rangePermCache")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestCheckPassword(t *testing.T) {
|
func TestCheckPassword(t *testing.T) {
|
||||||
as, tearDown := setupAuthStore(t)
|
as, tearDown := setupAuthStore(t)
|
||||||
defer tearDown(t)
|
defer tearDown(t)
|
||||||
@ -310,6 +350,12 @@ func TestUserChangePassword(t *testing.T) {
|
|||||||
if err != ErrUserNotFound {
|
if err != ErrUserNotFound {
|
||||||
t.Fatalf("expected %v, got %v", ErrUserNotFound, err)
|
t.Fatalf("expected %v, got %v", ErrUserNotFound, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// change a user(user option is nil) password
|
||||||
|
_, err = as.UserChangePassword(&pb.AuthUserChangePasswordRequest{Name: "foo-no-user-options", HashedPassword: encodePassword("bar")})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestRoleAdd(t *testing.T) {
|
func TestRoleAdd(t *testing.T) {
|
||||||
@ -517,6 +563,144 @@ func TestRoleGrantPermission(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRoleGrantInvalidPermission(t *testing.T) {
|
||||||
|
as, tearDown := setupAuthStore(t)
|
||||||
|
defer tearDown(t)
|
||||||
|
|
||||||
|
_, err := as.RoleAdd(&pb.AuthRoleAddRequest{Name: "role-test-1"})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
perm *authpb.Permission
|
||||||
|
want error
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "valid range",
|
||||||
|
perm: &authpb.Permission{
|
||||||
|
PermType: authpb.WRITE,
|
||||||
|
Key: []byte("Keys"),
|
||||||
|
RangeEnd: []byte("RangeEnd"),
|
||||||
|
},
|
||||||
|
want: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "invalid range: nil key",
|
||||||
|
perm: &authpb.Permission{
|
||||||
|
PermType: authpb.WRITE,
|
||||||
|
Key: nil,
|
||||||
|
RangeEnd: []byte("RangeEnd"),
|
||||||
|
},
|
||||||
|
want: ErrInvalidAuthMgmt,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "valid range: single key",
|
||||||
|
perm: &authpb.Permission{
|
||||||
|
PermType: authpb.WRITE,
|
||||||
|
Key: []byte("Keys"),
|
||||||
|
RangeEnd: nil,
|
||||||
|
},
|
||||||
|
want: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "valid range: single key",
|
||||||
|
perm: &authpb.Permission{
|
||||||
|
PermType: authpb.WRITE,
|
||||||
|
Key: []byte("Keys"),
|
||||||
|
RangeEnd: []byte{},
|
||||||
|
},
|
||||||
|
want: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "invalid range: empty (Key == RangeEnd)",
|
||||||
|
perm: &authpb.Permission{
|
||||||
|
PermType: authpb.WRITE,
|
||||||
|
Key: []byte("a"),
|
||||||
|
RangeEnd: []byte("a"),
|
||||||
|
},
|
||||||
|
want: ErrInvalidAuthMgmt,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "invalid range: empty (Key > RangeEnd)",
|
||||||
|
perm: &authpb.Permission{
|
||||||
|
PermType: authpb.WRITE,
|
||||||
|
Key: []byte("b"),
|
||||||
|
RangeEnd: []byte("a"),
|
||||||
|
},
|
||||||
|
want: ErrInvalidAuthMgmt,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "invalid range: length of key is 0",
|
||||||
|
perm: &authpb.Permission{
|
||||||
|
PermType: authpb.WRITE,
|
||||||
|
Key: []byte(""),
|
||||||
|
RangeEnd: []byte("a"),
|
||||||
|
},
|
||||||
|
want: ErrInvalidAuthMgmt,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "invalid range: length of key is 0",
|
||||||
|
perm: &authpb.Permission{
|
||||||
|
PermType: authpb.WRITE,
|
||||||
|
Key: []byte(""),
|
||||||
|
RangeEnd: []byte(""),
|
||||||
|
},
|
||||||
|
want: ErrInvalidAuthMgmt,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "invalid range: length of key is 0",
|
||||||
|
perm: &authpb.Permission{
|
||||||
|
PermType: authpb.WRITE,
|
||||||
|
Key: []byte(""),
|
||||||
|
RangeEnd: []byte{0x00},
|
||||||
|
},
|
||||||
|
want: ErrInvalidAuthMgmt,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "valid range: single key permission for []byte{0x00}",
|
||||||
|
perm: &authpb.Permission{
|
||||||
|
PermType: authpb.WRITE,
|
||||||
|
Key: []byte{0x00},
|
||||||
|
RangeEnd: []byte(""),
|
||||||
|
},
|
||||||
|
want: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "valid range: \"a\" or larger keys",
|
||||||
|
perm: &authpb.Permission{
|
||||||
|
PermType: authpb.WRITE,
|
||||||
|
Key: []byte("a"),
|
||||||
|
RangeEnd: []byte{0x00},
|
||||||
|
},
|
||||||
|
want: nil,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "valid range: the entire keys",
|
||||||
|
perm: &authpb.Permission{
|
||||||
|
PermType: authpb.WRITE,
|
||||||
|
Key: []byte{0x00},
|
||||||
|
RangeEnd: []byte{0x00},
|
||||||
|
},
|
||||||
|
want: nil,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for i, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
_, err = as.RoleGrantPermission(&pb.AuthRoleGrantPermissionRequest{
|
||||||
|
Name: "role-test-1",
|
||||||
|
Perm: tt.perm,
|
||||||
|
})
|
||||||
|
|
||||||
|
if !errors.Is(err, tt.want) {
|
||||||
|
t.Errorf("#%d: result=%t, want=%t", i, err, tt.want)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestRoleRevokePermission(t *testing.T) {
|
func TestRoleRevokePermission(t *testing.T) {
|
||||||
as, tearDown := setupAuthStore(t)
|
as, tearDown := setupAuthStore(t)
|
||||||
defer tearDown(t)
|
defer tearDown(t)
|
||||||
@ -742,7 +926,7 @@ func TestIsAuthEnabled(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// TestAuthRevisionRace ensures that access to authStore.revision is thread-safe.
|
// TestAuthInfoFromCtxRace ensures that access to authStore.revision is thread-safe.
|
||||||
func TestAuthInfoFromCtxRace(t *testing.T) {
|
func TestAuthInfoFromCtxRace(t *testing.T) {
|
||||||
b, _ := betesting.NewDefaultTmpBackend(t)
|
b, _ := betesting.NewDefaultTmpBackend(t)
|
||||||
defer betesting.Close(t, b)
|
defer betesting.Close(t, b)
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
package embed
|
package embed
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/tls"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
"math"
|
"math"
|
||||||
@ -204,12 +205,12 @@ type Config struct {
|
|||||||
// streams that each client can open at a time.
|
// streams that each client can open at a time.
|
||||||
MaxConcurrentStreams uint32 `json:"max-concurrent-streams"`
|
MaxConcurrentStreams uint32 `json:"max-concurrent-streams"`
|
||||||
|
|
||||||
LPUrls, LCUrls []url.URL
|
ListenPeerUrls, ListenClientUrls, ListenClientHttpUrls []url.URL
|
||||||
APUrls, ACUrls []url.URL
|
AdvertisePeerUrls, AdvertiseClientUrls []url.URL
|
||||||
ClientTLSInfo transport.TLSInfo
|
ClientTLSInfo transport.TLSInfo
|
||||||
ClientAutoTLS bool
|
ClientAutoTLS bool
|
||||||
PeerTLSInfo transport.TLSInfo
|
PeerTLSInfo transport.TLSInfo
|
||||||
PeerAutoTLS bool
|
PeerAutoTLS bool
|
||||||
// SelfSignedCertValidity specifies the validity period of the client and peer certificates
|
// SelfSignedCertValidity specifies the validity period of the client and peer certificates
|
||||||
// that are automatically generated by etcd when you specify ClientAutoTLS and PeerAutoTLS,
|
// that are automatically generated by etcd when you specify ClientAutoTLS and PeerAutoTLS,
|
||||||
// the unit is year, and the default is 1
|
// the unit is year, and the default is 1
|
||||||
@ -220,6 +221,11 @@ type Config struct {
|
|||||||
// Note that cipher suites are prioritized in the given order.
|
// Note that cipher suites are prioritized in the given order.
|
||||||
CipherSuites []string `json:"cipher-suites"`
|
CipherSuites []string `json:"cipher-suites"`
|
||||||
|
|
||||||
|
// TlsMinVersion is the minimum accepted TLS version between client/server and peers.
|
||||||
|
TlsMinVersion string `json:"tls-min-version"`
|
||||||
|
// TlsMaxVersion is the maximum accepted TLS version between client/server and peers.
|
||||||
|
TlsMaxVersion string `json:"tls-max-version"`
|
||||||
|
|
||||||
ClusterState string `json:"initial-cluster-state"`
|
ClusterState string `json:"initial-cluster-state"`
|
||||||
DNSCluster string `json:"discovery-srv"`
|
DNSCluster string `json:"discovery-srv"`
|
||||||
DNSClusterServiceName string `json:"discovery-srv-name"`
|
DNSClusterServiceName string `json:"discovery-srv-name"`
|
||||||
@ -417,10 +423,11 @@ type configYAML struct {
|
|||||||
|
|
||||||
// configJSON has file options that are translated into Config options
|
// configJSON has file options that are translated into Config options
|
||||||
type configJSON struct {
|
type configJSON struct {
|
||||||
LPUrlsJSON string `json:"listen-peer-urls"`
|
ListenPeerUrls string `json:"listen-peer-urls"`
|
||||||
LCUrlsJSON string `json:"listen-client-urls"`
|
ListenClientUrls string `json:"listen-client-urls"`
|
||||||
APUrlsJSON string `json:"initial-advertise-peer-urls"`
|
ListenClientHttpUrls string `json:"listen-client-http-urls"`
|
||||||
ACUrlsJSON string `json:"advertise-client-urls"`
|
AdvertisePeerUrls string `json:"initial-advertise-peer-urls"`
|
||||||
|
AdvertiseClientUrls string `json:"advertise-client-urls"`
|
||||||
|
|
||||||
CORSJSON string `json:"cors"`
|
CORSJSON string `json:"cors"`
|
||||||
HostWhitelistJSON string `json:"host-whitelist"`
|
HostWhitelistJSON string `json:"host-whitelist"`
|
||||||
@ -469,10 +476,10 @@ func NewConfig() *Config {
|
|||||||
ElectionMs: 1000,
|
ElectionMs: 1000,
|
||||||
InitialElectionTickAdvance: true,
|
InitialElectionTickAdvance: true,
|
||||||
|
|
||||||
LPUrls: []url.URL{*lpurl},
|
ListenPeerUrls: []url.URL{*lpurl},
|
||||||
LCUrls: []url.URL{*lcurl},
|
ListenClientUrls: []url.URL{*lcurl},
|
||||||
APUrls: []url.URL{*apurl},
|
AdvertisePeerUrls: []url.URL{*apurl},
|
||||||
ACUrls: []url.URL{*acurl},
|
AdvertiseClientUrls: []url.URL{*acurl},
|
||||||
|
|
||||||
ClusterState: ClusterStateFlagNew,
|
ClusterState: ClusterStateFlagNew,
|
||||||
InitialClusterToken: "etcd-cluster",
|
InitialClusterToken: "etcd-cluster",
|
||||||
@ -533,40 +540,49 @@ func (cfg *configYAML) configFromFile(path string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.LPUrlsJSON != "" {
|
if cfg.configJSON.ListenPeerUrls != "" {
|
||||||
u, err := types.NewURLs(strings.Split(cfg.LPUrlsJSON, ","))
|
u, err := types.NewURLs(strings.Split(cfg.configJSON.ListenPeerUrls, ","))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "unexpected error setting up listen-peer-urls: %v\n", err)
|
fmt.Fprintf(os.Stderr, "unexpected error setting up listen-peer-urls: %v\n", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
cfg.LPUrls = []url.URL(u)
|
cfg.Config.ListenPeerUrls = u
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.LCUrlsJSON != "" {
|
if cfg.configJSON.ListenClientUrls != "" {
|
||||||
u, err := types.NewURLs(strings.Split(cfg.LCUrlsJSON, ","))
|
u, err := types.NewURLs(strings.Split(cfg.configJSON.ListenClientUrls, ","))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "unexpected error setting up listen-client-urls: %v\n", err)
|
fmt.Fprintf(os.Stderr, "unexpected error setting up listen-client-urls: %v\n", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
cfg.LCUrls = []url.URL(u)
|
cfg.Config.ListenClientUrls = u
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.APUrlsJSON != "" {
|
if cfg.configJSON.ListenClientHttpUrls != "" {
|
||||||
u, err := types.NewURLs(strings.Split(cfg.APUrlsJSON, ","))
|
u, err := types.NewURLs(strings.Split(cfg.configJSON.ListenClientHttpUrls, ","))
|
||||||
|
if err != nil {
|
||||||
|
fmt.Fprintf(os.Stderr, "unexpected error setting up listen-client-http-urls: %v\n", err)
|
||||||
|
os.Exit(1)
|
||||||
|
}
|
||||||
|
cfg.Config.ListenClientHttpUrls = u
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg.configJSON.AdvertisePeerUrls != "" {
|
||||||
|
u, err := types.NewURLs(strings.Split(cfg.configJSON.AdvertisePeerUrls, ","))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "unexpected error setting up initial-advertise-peer-urls: %v\n", err)
|
fmt.Fprintf(os.Stderr, "unexpected error setting up initial-advertise-peer-urls: %v\n", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
cfg.APUrls = []url.URL(u)
|
cfg.Config.AdvertisePeerUrls = u
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.ACUrlsJSON != "" {
|
if cfg.configJSON.AdvertiseClientUrls != "" {
|
||||||
u, err := types.NewURLs(strings.Split(cfg.ACUrlsJSON, ","))
|
u, err := types.NewURLs(strings.Split(cfg.configJSON.AdvertiseClientUrls, ","))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
fmt.Fprintf(os.Stderr, "unexpected error setting up advertise-peer-urls: %v\n", err)
|
fmt.Fprintf(os.Stderr, "unexpected error setting up advertise-peer-urls: %v\n", err)
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
cfg.ACUrls = []url.URL(u)
|
cfg.Config.AdvertiseClientUrls = u
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.ListenMetricsUrlsJSON != "" {
|
if cfg.ListenMetricsUrlsJSON != "" {
|
||||||
@ -619,39 +635,52 @@ func updateCipherSuites(tls *transport.TLSInfo, ss []string) error {
|
|||||||
return fmt.Errorf("TLSInfo.CipherSuites is already specified (given %v)", ss)
|
return fmt.Errorf("TLSInfo.CipherSuites is already specified (given %v)", ss)
|
||||||
}
|
}
|
||||||
if len(ss) > 0 {
|
if len(ss) > 0 {
|
||||||
cs := make([]uint16, len(ss))
|
cs, err := tlsutil.GetCipherSuites(ss)
|
||||||
for i, s := range ss {
|
if err != nil {
|
||||||
var ok bool
|
return err
|
||||||
cs[i], ok = tlsutil.GetCipherSuite(s)
|
|
||||||
if !ok {
|
|
||||||
return fmt.Errorf("unexpected TLS cipher suite %q", s)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
tls.CipherSuites = cs
|
tls.CipherSuites = cs
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func updateMinMaxVersions(info *transport.TLSInfo, min, max string) {
|
||||||
|
// Validate() has been called to check the user input, so it should never fail.
|
||||||
|
var err error
|
||||||
|
if info.MinVersion, err = tlsutil.GetTLSVersion(min); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
if info.MaxVersion, err = tlsutil.GetTLSVersion(max); err != nil {
|
||||||
|
panic(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Validate ensures that '*embed.Config' fields are properly configured.
|
// Validate ensures that '*embed.Config' fields are properly configured.
|
||||||
func (cfg *Config) Validate() error {
|
func (cfg *Config) Validate() error {
|
||||||
if err := cfg.setupLogging(); err != nil {
|
if err := cfg.setupLogging(); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := checkBindURLs(cfg.LPUrls); err != nil {
|
if err := checkBindURLs(cfg.ListenPeerUrls); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := checkBindURLs(cfg.LCUrls); err != nil {
|
if err := checkBindURLs(cfg.ListenClientUrls); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
if err := checkBindURLs(cfg.ListenClientHttpUrls); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
if len(cfg.ListenClientHttpUrls) == 0 {
|
||||||
|
cfg.logger.Warn("Running http and grpc server on single port. This is not recommended for production.")
|
||||||
|
}
|
||||||
if err := checkBindURLs(cfg.ListenMetricsUrls); err != nil {
|
if err := checkBindURLs(cfg.ListenMetricsUrls); err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
if err := checkHostURLs(cfg.APUrls); err != nil {
|
if err := checkHostURLs(cfg.AdvertisePeerUrls); err != nil {
|
||||||
addrs := cfg.getAPURLs()
|
addrs := cfg.getAdvertisePeerUrls()
|
||||||
return fmt.Errorf(`--initial-advertise-peer-urls %q must be "host:port" (%v)`, strings.Join(addrs, ","), err)
|
return fmt.Errorf(`--initial-advertise-peer-urls %q must be "host:port" (%v)`, strings.Join(addrs, ","), err)
|
||||||
}
|
}
|
||||||
if err := checkHostURLs(cfg.ACUrls); err != nil {
|
if err := checkHostURLs(cfg.AdvertiseClientUrls); err != nil {
|
||||||
addrs := cfg.getACURLs()
|
addrs := cfg.getAdvertiseClientUrls()
|
||||||
return fmt.Errorf(`--advertise-client-urls %q must be "host:port" (%v)`, strings.Join(addrs, ","), err)
|
return fmt.Errorf(`--advertise-client-urls %q must be "host:port" (%v)`, strings.Join(addrs, ","), err)
|
||||||
}
|
}
|
||||||
// Check if conflicting flags are passed.
|
// Check if conflicting flags are passed.
|
||||||
@ -684,7 +713,7 @@ func (cfg *Config) Validate() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// check this last since proxying in etcdmain may make this OK
|
// check this last since proxying in etcdmain may make this OK
|
||||||
if cfg.LCUrls != nil && cfg.ACUrls == nil {
|
if cfg.ListenClientUrls != nil && cfg.AdvertiseClientUrls == nil {
|
||||||
return ErrUnsetAdvertiseClientURLsFlag
|
return ErrUnsetAdvertiseClientURLsFlag
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -707,6 +736,25 @@ func (cfg *Config) Validate() error {
|
|||||||
return fmt.Errorf("--experimental-compact-hash-check-time must be >0 (set to %v)", cfg.ExperimentalCompactHashCheckTime)
|
return fmt.Errorf("--experimental-compact-hash-check-time must be >0 (set to %v)", cfg.ExperimentalCompactHashCheckTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
minVersion, err := tlsutil.GetTLSVersion(cfg.TlsMinVersion)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
maxVersion, err := tlsutil.GetTLSVersion(cfg.TlsMaxVersion)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
// maxVersion == 0 means that Go selects the highest available version.
|
||||||
|
if maxVersion != 0 && minVersion > maxVersion {
|
||||||
|
return fmt.Errorf("min version (%s) is greater than max version (%s)", cfg.TlsMinVersion, cfg.TlsMaxVersion)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if user attempted to configure ciphers for TLS1.3 only: Go does not support that currently.
|
||||||
|
if minVersion == tls.VersionTLS13 && len(cfg.CipherSuites) > 0 {
|
||||||
|
return fmt.Errorf("cipher suites cannot be configured when only TLS1.3 is enabled")
|
||||||
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -718,7 +766,7 @@ func (cfg *Config) PeerURLsMapAndToken(which string) (urlsmap types.URLsMap, tok
|
|||||||
urlsmap = types.URLsMap{}
|
urlsmap = types.URLsMap{}
|
||||||
// If using discovery, generate a temporary cluster based on
|
// If using discovery, generate a temporary cluster based on
|
||||||
// self's advertised peer URLs
|
// self's advertised peer URLs
|
||||||
urlsmap[cfg.Name] = cfg.APUrls
|
urlsmap[cfg.Name] = cfg.AdvertisePeerUrls
|
||||||
token = cfg.Durl
|
token = cfg.Durl
|
||||||
|
|
||||||
case cfg.DNSCluster != "":
|
case cfg.DNSCluster != "":
|
||||||
@ -772,7 +820,7 @@ func (cfg *Config) GetDNSClusterNames() ([]string, error) {
|
|||||||
|
|
||||||
// Use both etcd-server-ssl and etcd-server for discovery.
|
// Use both etcd-server-ssl and etcd-server for discovery.
|
||||||
// Combine the results if both are available.
|
// Combine the results if both are available.
|
||||||
clusterStrs, cerr = getCluster("https", "etcd-server-ssl"+serviceNameSuffix, cfg.Name, cfg.DNSCluster, cfg.APUrls)
|
clusterStrs, cerr = getCluster("https", "etcd-server-ssl"+serviceNameSuffix, cfg.Name, cfg.DNSCluster, cfg.AdvertisePeerUrls)
|
||||||
if cerr != nil {
|
if cerr != nil {
|
||||||
clusterStrs = make([]string, 0)
|
clusterStrs = make([]string, 0)
|
||||||
}
|
}
|
||||||
@ -782,12 +830,12 @@ func (cfg *Config) GetDNSClusterNames() ([]string, error) {
|
|||||||
zap.String("service-name", "etcd-server-ssl"+serviceNameSuffix),
|
zap.String("service-name", "etcd-server-ssl"+serviceNameSuffix),
|
||||||
zap.String("server-name", cfg.Name),
|
zap.String("server-name", cfg.Name),
|
||||||
zap.String("discovery-srv", cfg.DNSCluster),
|
zap.String("discovery-srv", cfg.DNSCluster),
|
||||||
zap.Strings("advertise-peer-urls", cfg.getAPURLs()),
|
zap.Strings("advertise-peer-urls", cfg.getAdvertisePeerUrls()),
|
||||||
zap.Strings("found-cluster", clusterStrs),
|
zap.Strings("found-cluster", clusterStrs),
|
||||||
zap.Error(cerr),
|
zap.Error(cerr),
|
||||||
)
|
)
|
||||||
|
|
||||||
defaultHTTPClusterStrs, httpCerr := getCluster("http", "etcd-server"+serviceNameSuffix, cfg.Name, cfg.DNSCluster, cfg.APUrls)
|
defaultHTTPClusterStrs, httpCerr := getCluster("http", "etcd-server"+serviceNameSuffix, cfg.Name, cfg.DNSCluster, cfg.AdvertisePeerUrls)
|
||||||
if httpCerr == nil {
|
if httpCerr == nil {
|
||||||
clusterStrs = append(clusterStrs, defaultHTTPClusterStrs...)
|
clusterStrs = append(clusterStrs, defaultHTTPClusterStrs...)
|
||||||
}
|
}
|
||||||
@ -797,7 +845,7 @@ func (cfg *Config) GetDNSClusterNames() ([]string, error) {
|
|||||||
zap.String("service-name", "etcd-server"+serviceNameSuffix),
|
zap.String("service-name", "etcd-server"+serviceNameSuffix),
|
||||||
zap.String("server-name", cfg.Name),
|
zap.String("server-name", cfg.Name),
|
||||||
zap.String("discovery-srv", cfg.DNSCluster),
|
zap.String("discovery-srv", cfg.DNSCluster),
|
||||||
zap.Strings("advertise-peer-urls", cfg.getAPURLs()),
|
zap.Strings("advertise-peer-urls", cfg.getAdvertisePeerUrls()),
|
||||||
zap.Strings("found-cluster", clusterStrs),
|
zap.Strings("found-cluster", clusterStrs),
|
||||||
zap.Error(httpCerr),
|
zap.Error(httpCerr),
|
||||||
)
|
)
|
||||||
@ -806,15 +854,15 @@ func (cfg *Config) GetDNSClusterNames() ([]string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (cfg Config) InitialClusterFromName(name string) (ret string) {
|
func (cfg Config) InitialClusterFromName(name string) (ret string) {
|
||||||
if len(cfg.APUrls) == 0 {
|
if len(cfg.AdvertisePeerUrls) == 0 {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
n := name
|
n := name
|
||||||
if name == "" {
|
if name == "" {
|
||||||
n = DefaultName
|
n = DefaultName
|
||||||
}
|
}
|
||||||
for i := range cfg.APUrls {
|
for i := range cfg.AdvertisePeerUrls {
|
||||||
ret = ret + "," + n + "=" + cfg.APUrls[i].String()
|
ret = ret + "," + n + "=" + cfg.AdvertisePeerUrls[i].String()
|
||||||
}
|
}
|
||||||
return ret[1:]
|
return ret[1:]
|
||||||
}
|
}
|
||||||
@ -830,11 +878,11 @@ func (cfg Config) V2DeprecationEffective() config.V2DeprecationEnum {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (cfg Config) defaultPeerHost() bool {
|
func (cfg Config) defaultPeerHost() bool {
|
||||||
return len(cfg.APUrls) == 1 && cfg.APUrls[0].String() == DefaultInitialAdvertisePeerURLs
|
return len(cfg.AdvertisePeerUrls) == 1 && cfg.AdvertisePeerUrls[0].String() == DefaultInitialAdvertisePeerURLs
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg Config) defaultClientHost() bool {
|
func (cfg Config) defaultClientHost() bool {
|
||||||
return len(cfg.ACUrls) == 1 && cfg.ACUrls[0].String() == DefaultAdvertiseClientURLs
|
return len(cfg.AdvertiseClientUrls) == 1 && cfg.AdvertiseClientUrls[0].String() == DefaultAdvertiseClientURLs
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *Config) ClientSelfCert() (err error) {
|
func (cfg *Config) ClientSelfCert() (err error) {
|
||||||
@ -845,9 +893,12 @@ func (cfg *Config) ClientSelfCert() (err error) {
|
|||||||
cfg.logger.Warn("ignoring client auto TLS since certs given")
|
cfg.logger.Warn("ignoring client auto TLS since certs given")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
chosts := make([]string, len(cfg.LCUrls))
|
chosts := make([]string, 0, len(cfg.ListenClientUrls)+len(cfg.ListenClientHttpUrls))
|
||||||
for i, u := range cfg.LCUrls {
|
for _, u := range cfg.ListenClientUrls {
|
||||||
chosts[i] = u.Host
|
chosts = append(chosts, u.Host)
|
||||||
|
}
|
||||||
|
for _, u := range cfg.ListenClientHttpUrls {
|
||||||
|
chosts = append(chosts, u.Host)
|
||||||
}
|
}
|
||||||
cfg.ClientTLSInfo, err = transport.SelfCert(cfg.logger, filepath.Join(cfg.Dir, "fixtures", "client"), chosts, cfg.SelfSignedCertValidity)
|
cfg.ClientTLSInfo, err = transport.SelfCert(cfg.logger, filepath.Join(cfg.Dir, "fixtures", "client"), chosts, cfg.SelfSignedCertValidity)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -864,8 +915,8 @@ func (cfg *Config) PeerSelfCert() (err error) {
|
|||||||
cfg.logger.Warn("ignoring peer auto TLS since certs given")
|
cfg.logger.Warn("ignoring peer auto TLS since certs given")
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
phosts := make([]string, len(cfg.LPUrls))
|
phosts := make([]string, len(cfg.ListenPeerUrls))
|
||||||
for i, u := range cfg.LPUrls {
|
for i, u := range cfg.ListenPeerUrls {
|
||||||
phosts[i] = u.Host
|
phosts[i] = u.Host
|
||||||
}
|
}
|
||||||
cfg.PeerTLSInfo, err = transport.SelfCert(cfg.logger, filepath.Join(cfg.Dir, "fixtures", "peer"), phosts, cfg.SelfSignedCertValidity)
|
cfg.PeerTLSInfo, err = transport.SelfCert(cfg.logger, filepath.Join(cfg.Dir, "fixtures", "peer"), phosts, cfg.SelfSignedCertValidity)
|
||||||
@ -893,9 +944,9 @@ func (cfg *Config) UpdateDefaultClusterFromName(defaultInitialCluster string) (s
|
|||||||
}
|
}
|
||||||
|
|
||||||
used := false
|
used := false
|
||||||
pip, pport := cfg.LPUrls[0].Hostname(), cfg.LPUrls[0].Port()
|
pip, pport := cfg.ListenPeerUrls[0].Hostname(), cfg.ListenPeerUrls[0].Port()
|
||||||
if cfg.defaultPeerHost() && pip == "0.0.0.0" {
|
if cfg.defaultPeerHost() && pip == "0.0.0.0" {
|
||||||
cfg.APUrls[0] = url.URL{Scheme: cfg.APUrls[0].Scheme, Host: fmt.Sprintf("%s:%s", defaultHostname, pport)}
|
cfg.AdvertisePeerUrls[0] = url.URL{Scheme: cfg.AdvertisePeerUrls[0].Scheme, Host: fmt.Sprintf("%s:%s", defaultHostname, pport)}
|
||||||
used = true
|
used = true
|
||||||
}
|
}
|
||||||
// update 'initial-cluster' when only the name is specified (e.g. 'etcd --name=abc')
|
// update 'initial-cluster' when only the name is specified (e.g. 'etcd --name=abc')
|
||||||
@ -903,9 +954,9 @@ func (cfg *Config) UpdateDefaultClusterFromName(defaultInitialCluster string) (s
|
|||||||
cfg.InitialCluster = cfg.InitialClusterFromName(cfg.Name)
|
cfg.InitialCluster = cfg.InitialClusterFromName(cfg.Name)
|
||||||
}
|
}
|
||||||
|
|
||||||
cip, cport := cfg.LCUrls[0].Hostname(), cfg.LCUrls[0].Port()
|
cip, cport := cfg.ListenClientUrls[0].Hostname(), cfg.ListenClientUrls[0].Port()
|
||||||
if cfg.defaultClientHost() && cip == "0.0.0.0" {
|
if cfg.defaultClientHost() && cip == "0.0.0.0" {
|
||||||
cfg.ACUrls[0] = url.URL{Scheme: cfg.ACUrls[0].Scheme, Host: fmt.Sprintf("%s:%s", defaultHostname, cport)}
|
cfg.AdvertiseClientUrls[0] = url.URL{Scheme: cfg.AdvertiseClientUrls[0].Scheme, Host: fmt.Sprintf("%s:%s", defaultHostname, cport)}
|
||||||
used = true
|
used = true
|
||||||
}
|
}
|
||||||
dhost := defaultHostname
|
dhost := defaultHostname
|
||||||
@ -950,34 +1001,42 @@ func checkHostURLs(urls []url.URL) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *Config) getAPURLs() (ss []string) {
|
func (cfg *Config) getAdvertisePeerUrls() (ss []string) {
|
||||||
ss = make([]string, len(cfg.APUrls))
|
ss = make([]string, len(cfg.AdvertisePeerUrls))
|
||||||
for i := range cfg.APUrls {
|
for i := range cfg.AdvertisePeerUrls {
|
||||||
ss[i] = cfg.APUrls[i].String()
|
ss[i] = cfg.AdvertisePeerUrls[i].String()
|
||||||
}
|
}
|
||||||
return ss
|
return ss
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *Config) getLPURLs() (ss []string) {
|
func (cfg *Config) getListenPeerUrls() (ss []string) {
|
||||||
ss = make([]string, len(cfg.LPUrls))
|
ss = make([]string, len(cfg.ListenPeerUrls))
|
||||||
for i := range cfg.LPUrls {
|
for i := range cfg.ListenPeerUrls {
|
||||||
ss[i] = cfg.LPUrls[i].String()
|
ss[i] = cfg.ListenPeerUrls[i].String()
|
||||||
}
|
}
|
||||||
return ss
|
return ss
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *Config) getACURLs() (ss []string) {
|
func (cfg *Config) getAdvertiseClientUrls() (ss []string) {
|
||||||
ss = make([]string, len(cfg.ACUrls))
|
ss = make([]string, len(cfg.AdvertiseClientUrls))
|
||||||
for i := range cfg.ACUrls {
|
for i := range cfg.AdvertiseClientUrls {
|
||||||
ss[i] = cfg.ACUrls[i].String()
|
ss[i] = cfg.AdvertiseClientUrls[i].String()
|
||||||
}
|
}
|
||||||
return ss
|
return ss
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cfg *Config) getLCURLs() (ss []string) {
|
func (cfg *Config) getListenClientUrls() (ss []string) {
|
||||||
ss = make([]string, len(cfg.LCUrls))
|
ss = make([]string, len(cfg.ListenClientUrls))
|
||||||
for i := range cfg.LCUrls {
|
for i := range cfg.ListenClientUrls {
|
||||||
ss[i] = cfg.LCUrls[i].String()
|
ss[i] = cfg.ListenClientUrls[i].String()
|
||||||
|
}
|
||||||
|
return ss
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cfg *Config) getListenClientHttpUrls() (ss []string) {
|
||||||
|
ss = make([]string, len(cfg.ListenClientHttpUrls))
|
||||||
|
for i := range cfg.ListenClientHttpUrls {
|
||||||
|
ss[i] = cfg.ListenClientHttpUrls[i].String()
|
||||||
}
|
}
|
||||||
return ss
|
return ss
|
||||||
}
|
}
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
package embed
|
package embed
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"crypto/tls"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
@ -24,6 +25,7 @@ import (
|
|||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
"github.com/stretchr/testify/assert"
|
||||||
"go.etcd.io/etcd/client/pkg/v3/srv"
|
"go.etcd.io/etcd/client/pkg/v3/srv"
|
||||||
"go.etcd.io/etcd/client/pkg/v3/transport"
|
"go.etcd.io/etcd/client/pkg/v3/transport"
|
||||||
"go.etcd.io/etcd/client/pkg/v3/types"
|
"go.etcd.io/etcd/client/pkg/v3/types"
|
||||||
@ -84,12 +86,12 @@ func TestConfigFileOtherFields(t *testing.T) {
|
|||||||
func TestUpdateDefaultClusterFromName(t *testing.T) {
|
func TestUpdateDefaultClusterFromName(t *testing.T) {
|
||||||
cfg := NewConfig()
|
cfg := NewConfig()
|
||||||
defaultInitialCluster := cfg.InitialCluster
|
defaultInitialCluster := cfg.InitialCluster
|
||||||
oldscheme := cfg.APUrls[0].Scheme
|
oldscheme := cfg.AdvertisePeerUrls[0].Scheme
|
||||||
origpeer := cfg.APUrls[0].String()
|
origpeer := cfg.AdvertisePeerUrls[0].String()
|
||||||
origadvc := cfg.ACUrls[0].String()
|
origadvc := cfg.AdvertiseClientUrls[0].String()
|
||||||
|
|
||||||
cfg.Name = "abc"
|
cfg.Name = "abc"
|
||||||
lpport := cfg.LPUrls[0].Port()
|
lpport := cfg.ListenPeerUrls[0].Port()
|
||||||
|
|
||||||
// in case of 'etcd --name=abc'
|
// in case of 'etcd --name=abc'
|
||||||
exp := fmt.Sprintf("%s=%s://localhost:%s", cfg.Name, oldscheme, lpport)
|
exp := fmt.Sprintf("%s=%s://localhost:%s", cfg.Name, oldscheme, lpport)
|
||||||
@ -98,12 +100,12 @@ func TestUpdateDefaultClusterFromName(t *testing.T) {
|
|||||||
t.Fatalf("initial-cluster expected %q, got %q", exp, cfg.InitialCluster)
|
t.Fatalf("initial-cluster expected %q, got %q", exp, cfg.InitialCluster)
|
||||||
}
|
}
|
||||||
// advertise peer URL should not be affected
|
// advertise peer URL should not be affected
|
||||||
if origpeer != cfg.APUrls[0].String() {
|
if origpeer != cfg.AdvertisePeerUrls[0].String() {
|
||||||
t.Fatalf("advertise peer url expected %q, got %q", origadvc, cfg.APUrls[0].String())
|
t.Fatalf("advertise peer url expected %q, got %q", origadvc, cfg.AdvertisePeerUrls[0].String())
|
||||||
}
|
}
|
||||||
// advertise client URL should not be affected
|
// advertise client URL should not be affected
|
||||||
if origadvc != cfg.ACUrls[0].String() {
|
if origadvc != cfg.AdvertiseClientUrls[0].String() {
|
||||||
t.Fatalf("advertise client url expected %q, got %q", origadvc, cfg.ACUrls[0].String())
|
t.Fatalf("advertise client url expected %q, got %q", origadvc, cfg.AdvertiseClientUrls[0].String())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,17 +118,17 @@ func TestUpdateDefaultClusterFromNameOverwrite(t *testing.T) {
|
|||||||
|
|
||||||
cfg := NewConfig()
|
cfg := NewConfig()
|
||||||
defaultInitialCluster := cfg.InitialCluster
|
defaultInitialCluster := cfg.InitialCluster
|
||||||
oldscheme := cfg.APUrls[0].Scheme
|
oldscheme := cfg.AdvertisePeerUrls[0].Scheme
|
||||||
origadvc := cfg.ACUrls[0].String()
|
origadvc := cfg.AdvertiseClientUrls[0].String()
|
||||||
|
|
||||||
cfg.Name = "abc"
|
cfg.Name = "abc"
|
||||||
lpport := cfg.LPUrls[0].Port()
|
lpport := cfg.ListenPeerUrls[0].Port()
|
||||||
cfg.LPUrls[0] = url.URL{Scheme: cfg.LPUrls[0].Scheme, Host: fmt.Sprintf("0.0.0.0:%s", lpport)}
|
cfg.ListenPeerUrls[0] = url.URL{Scheme: cfg.ListenPeerUrls[0].Scheme, Host: fmt.Sprintf("0.0.0.0:%s", lpport)}
|
||||||
dhost, _ := cfg.UpdateDefaultClusterFromName(defaultInitialCluster)
|
dhost, _ := cfg.UpdateDefaultClusterFromName(defaultInitialCluster)
|
||||||
if dhost != defaultHostname {
|
if dhost != defaultHostname {
|
||||||
t.Fatalf("expected default host %q, got %q", defaultHostname, dhost)
|
t.Fatalf("expected default host %q, got %q", defaultHostname, dhost)
|
||||||
}
|
}
|
||||||
aphost, apport := cfg.APUrls[0].Hostname(), cfg.APUrls[0].Port()
|
aphost, apport := cfg.AdvertisePeerUrls[0].Hostname(), cfg.AdvertisePeerUrls[0].Port()
|
||||||
if apport != lpport {
|
if apport != lpport {
|
||||||
t.Fatalf("advertise peer url got different port %s, expected %s", apport, lpport)
|
t.Fatalf("advertise peer url got different port %s, expected %s", apport, lpport)
|
||||||
}
|
}
|
||||||
@ -139,8 +141,8 @@ func TestUpdateDefaultClusterFromNameOverwrite(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// advertise client URL should not be affected
|
// advertise client URL should not be affected
|
||||||
if origadvc != cfg.ACUrls[0].String() {
|
if origadvc != cfg.AdvertiseClientUrls[0].String() {
|
||||||
t.Fatalf("advertise-client-url expected %q, got %q", origadvc, cfg.ACUrls[0].String())
|
t.Fatalf("advertise-client-url expected %q, got %q", origadvc, cfg.AdvertiseClientUrls[0].String())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -274,7 +276,7 @@ func TestPeerURLsMapAndTokenFromSRV(t *testing.T) {
|
|||||||
cfg.InitialCluster = ""
|
cfg.InitialCluster = ""
|
||||||
cfg.InitialClusterToken = ""
|
cfg.InitialClusterToken = ""
|
||||||
cfg.DNSCluster = "example.com"
|
cfg.DNSCluster = "example.com"
|
||||||
cfg.APUrls = types.MustNewURLs(tt.apurls)
|
cfg.AdvertisePeerUrls = types.MustNewURLs(tt.apurls)
|
||||||
|
|
||||||
if err := cfg.Validate(); err != nil {
|
if err := cfg.Validate(); err != nil {
|
||||||
t.Errorf("#%d: failed to validate test Config: %v", i, err)
|
t.Errorf("#%d: failed to validate test Config: %v", i, err)
|
||||||
@ -422,3 +424,80 @@ func TestLogRotation(t *testing.T) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestTLSVersionMinMax(t *testing.T) {
|
||||||
|
tests := []struct {
|
||||||
|
name string
|
||||||
|
givenTLSMinVersion string
|
||||||
|
givenTLSMaxVersion string
|
||||||
|
givenCipherSuites []string
|
||||||
|
expectError bool
|
||||||
|
expectedMinTLSVersion uint16
|
||||||
|
expectedMaxTLSVersion uint16
|
||||||
|
}{
|
||||||
|
{
|
||||||
|
name: "Minimum TLS version is set",
|
||||||
|
givenTLSMinVersion: "TLS1.3",
|
||||||
|
expectedMinTLSVersion: tls.VersionTLS13,
|
||||||
|
expectedMaxTLSVersion: 0,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Maximum TLS version is set",
|
||||||
|
givenTLSMaxVersion: "TLS1.2",
|
||||||
|
expectedMinTLSVersion: 0,
|
||||||
|
expectedMaxTLSVersion: tls.VersionTLS12,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Minimum and Maximum TLS versions are set",
|
||||||
|
givenTLSMinVersion: "TLS1.3",
|
||||||
|
givenTLSMaxVersion: "TLS1.3",
|
||||||
|
expectedMinTLSVersion: tls.VersionTLS13,
|
||||||
|
expectedMaxTLSVersion: tls.VersionTLS13,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Minimum and Maximum TLS versions are set in reverse order",
|
||||||
|
givenTLSMinVersion: "TLS1.3",
|
||||||
|
givenTLSMaxVersion: "TLS1.2",
|
||||||
|
expectError: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Invalid minimum TLS version",
|
||||||
|
givenTLSMinVersion: "invalid version",
|
||||||
|
expectError: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Invalid maximum TLS version",
|
||||||
|
givenTLSMaxVersion: "invalid version",
|
||||||
|
expectError: true,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "Cipher suites configured for TLS 1.3",
|
||||||
|
givenTLSMinVersion: "TLS1.3",
|
||||||
|
givenCipherSuites: []string{"TLS_AES_128_GCM_SHA256"},
|
||||||
|
expectError: true,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
cfg := NewConfig()
|
||||||
|
cfg.TlsMinVersion = tt.givenTLSMinVersion
|
||||||
|
cfg.TlsMaxVersion = tt.givenTLSMaxVersion
|
||||||
|
cfg.CipherSuites = tt.givenCipherSuites
|
||||||
|
|
||||||
|
err := cfg.Validate()
|
||||||
|
if err != nil {
|
||||||
|
assert.True(t, tt.expectError, "Validate() returned error while expecting success: %v", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
updateMinMaxVersions(&cfg.PeerTLSInfo, cfg.TlsMinVersion, cfg.TlsMaxVersion)
|
||||||
|
updateMinMaxVersions(&cfg.ClientTLSInfo, cfg.TlsMinVersion, cfg.TlsMaxVersion)
|
||||||
|
|
||||||
|
assert.Equal(t, tt.expectedMinTLSVersion, cfg.PeerTLSInfo.MinVersion)
|
||||||
|
assert.Equal(t, tt.expectedMaxTLSVersion, cfg.PeerTLSInfo.MaxVersion)
|
||||||
|
assert.Equal(t, tt.expectedMinTLSVersion, cfg.ClientTLSInfo.MinVersion)
|
||||||
|
assert.Equal(t, tt.expectedMaxTLSVersion, cfg.ClientTLSInfo.MaxVersion)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -20,6 +20,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
defaultLog "log"
|
defaultLog "log"
|
||||||
|
"math"
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
@ -32,6 +33,7 @@ import (
|
|||||||
"go.etcd.io/etcd/api/v3/version"
|
"go.etcd.io/etcd/api/v3/version"
|
||||||
"go.etcd.io/etcd/client/pkg/v3/transport"
|
"go.etcd.io/etcd/client/pkg/v3/transport"
|
||||||
"go.etcd.io/etcd/client/pkg/v3/types"
|
"go.etcd.io/etcd/client/pkg/v3/types"
|
||||||
|
"go.etcd.io/etcd/client/v3/credentials"
|
||||||
"go.etcd.io/etcd/pkg/v3/debugutil"
|
"go.etcd.io/etcd/pkg/v3/debugutil"
|
||||||
runtimeutil "go.etcd.io/etcd/pkg/v3/runtime"
|
runtimeutil "go.etcd.io/etcd/pkg/v3/runtime"
|
||||||
"go.etcd.io/etcd/server/v3/config"
|
"go.etcd.io/etcd/server/v3/config"
|
||||||
@ -48,6 +50,7 @@ import (
|
|||||||
"github.com/soheilhy/cmux"
|
"github.com/soheilhy/cmux"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
|
"google.golang.org/grpc/credentials/insecure"
|
||||||
"google.golang.org/grpc/keepalive"
|
"google.golang.org/grpc/keepalive"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -123,7 +126,7 @@ func StartEtcd(inCfg *Config) (e *Etcd, err error) {
|
|||||||
}
|
}
|
||||||
e.cfg.logger.Info(
|
e.cfg.logger.Info(
|
||||||
"configuring peer listeners",
|
"configuring peer listeners",
|
||||||
zap.Strings("listen-peer-urls", e.cfg.getLPURLs()),
|
zap.Strings("listen-peer-urls", e.cfg.getListenPeerUrls()),
|
||||||
)
|
)
|
||||||
if e.Peers, err = configurePeerListeners(cfg); err != nil {
|
if e.Peers, err = configurePeerListeners(cfg); err != nil {
|
||||||
return e, err
|
return e, err
|
||||||
@ -131,7 +134,7 @@ func StartEtcd(inCfg *Config) (e *Etcd, err error) {
|
|||||||
|
|
||||||
e.cfg.logger.Info(
|
e.cfg.logger.Info(
|
||||||
"configuring client listeners",
|
"configuring client listeners",
|
||||||
zap.Strings("listen-client-urls", e.cfg.getLCURLs()),
|
zap.Strings("listen-client-urls", e.cfg.getListenClientUrls()),
|
||||||
)
|
)
|
||||||
if e.sctxs, err = configureClientListeners(cfg); err != nil {
|
if e.sctxs, err = configureClientListeners(cfg); err != nil {
|
||||||
return e, err
|
return e, err
|
||||||
@ -167,8 +170,8 @@ func StartEtcd(inCfg *Config) (e *Etcd, err error) {
|
|||||||
|
|
||||||
srvcfg := config.ServerConfig{
|
srvcfg := config.ServerConfig{
|
||||||
Name: cfg.Name,
|
Name: cfg.Name,
|
||||||
ClientURLs: cfg.ACUrls,
|
ClientURLs: cfg.AdvertiseClientUrls,
|
||||||
PeerURLs: cfg.APUrls,
|
PeerURLs: cfg.AdvertisePeerUrls,
|
||||||
DataDir: cfg.Dir,
|
DataDir: cfg.Dir,
|
||||||
DedicatedWALDir: cfg.WalDir,
|
DedicatedWALDir: cfg.WalDir,
|
||||||
SnapshotCount: cfg.SnapshotCount,
|
SnapshotCount: cfg.SnapshotCount,
|
||||||
@ -275,10 +278,10 @@ func StartEtcd(inCfg *Config) (e *Etcd, err error) {
|
|||||||
e.cfg.logger.Info(
|
e.cfg.logger.Info(
|
||||||
"now serving peer/client/metrics",
|
"now serving peer/client/metrics",
|
||||||
zap.String("local-member-id", e.Server.ID().String()),
|
zap.String("local-member-id", e.Server.ID().String()),
|
||||||
zap.Strings("initial-advertise-peer-urls", e.cfg.getAPURLs()),
|
zap.Strings("initial-advertise-peer-urls", e.cfg.getAdvertisePeerUrls()),
|
||||||
zap.Strings("listen-peer-urls", e.cfg.getLPURLs()),
|
zap.Strings("listen-peer-urls", e.cfg.getListenPeerUrls()),
|
||||||
zap.Strings("advertise-client-urls", e.cfg.getACURLs()),
|
zap.Strings("advertise-client-urls", e.cfg.getAdvertiseClientUrls()),
|
||||||
zap.Strings("listen-client-urls", e.cfg.getLCURLs()),
|
zap.Strings("listen-client-urls", e.cfg.getListenClientUrls()),
|
||||||
zap.Strings("listen-metrics-urls", e.cfg.getMetricsURLs()),
|
zap.Strings("listen-metrics-urls", e.cfg.getMetricsURLs()),
|
||||||
)
|
)
|
||||||
serving = true
|
serving = true
|
||||||
@ -323,11 +326,13 @@ func print(lg *zap.Logger, ec Config, sc config.ServerConfig, memberInitialized
|
|||||||
zap.String("election-timeout", fmt.Sprintf("%v", time.Duration(sc.ElectionTicks*int(sc.TickMs))*time.Millisecond)),
|
zap.String("election-timeout", fmt.Sprintf("%v", time.Duration(sc.ElectionTicks*int(sc.TickMs))*time.Millisecond)),
|
||||||
zap.Bool("initial-election-tick-advance", sc.InitialElectionTickAdvance),
|
zap.Bool("initial-election-tick-advance", sc.InitialElectionTickAdvance),
|
||||||
zap.Uint64("snapshot-count", sc.SnapshotCount),
|
zap.Uint64("snapshot-count", sc.SnapshotCount),
|
||||||
|
zap.Uint("max-wals", sc.MaxWALFiles),
|
||||||
|
zap.Uint("max-snapshots", sc.MaxSnapFiles),
|
||||||
zap.Uint64("snapshot-catchup-entries", sc.SnapshotCatchUpEntries),
|
zap.Uint64("snapshot-catchup-entries", sc.SnapshotCatchUpEntries),
|
||||||
zap.Strings("initial-advertise-peer-urls", ec.getAPURLs()),
|
zap.Strings("initial-advertise-peer-urls", ec.getAdvertisePeerUrls()),
|
||||||
zap.Strings("listen-peer-urls", ec.getLPURLs()),
|
zap.Strings("listen-peer-urls", ec.getListenPeerUrls()),
|
||||||
zap.Strings("advertise-client-urls", ec.getACURLs()),
|
zap.Strings("advertise-client-urls", ec.getAdvertiseClientUrls()),
|
||||||
zap.Strings("listen-client-urls", ec.getLCURLs()),
|
zap.Strings("listen-client-urls", ec.getListenClientUrls()),
|
||||||
zap.Strings("listen-metrics-urls", ec.getMetricsURLs()),
|
zap.Strings("listen-metrics-urls", ec.getMetricsURLs()),
|
||||||
zap.Strings("cors", cors),
|
zap.Strings("cors", cors),
|
||||||
zap.Strings("host-whitelist", hss),
|
zap.Strings("host-whitelist", hss),
|
||||||
@ -364,8 +369,8 @@ func (e *Etcd) Close() {
|
|||||||
fields := []zap.Field{
|
fields := []zap.Field{
|
||||||
zap.String("name", e.cfg.Name),
|
zap.String("name", e.cfg.Name),
|
||||||
zap.String("data-dir", e.cfg.Dir),
|
zap.String("data-dir", e.cfg.Dir),
|
||||||
zap.Strings("advertise-peer-urls", e.cfg.getAPURLs()),
|
zap.Strings("advertise-peer-urls", e.cfg.getAdvertisePeerUrls()),
|
||||||
zap.Strings("advertise-client-urls", e.cfg.getACURLs()),
|
zap.Strings("advertise-client-urls", e.cfg.getAdvertiseClientUrls()),
|
||||||
}
|
}
|
||||||
lg := e.GetLogger()
|
lg := e.GetLogger()
|
||||||
lg.Info("closing etcd server", fields...)
|
lg.Info("closing etcd server", fields...)
|
||||||
@ -435,11 +440,16 @@ func (e *Etcd) Close() {
|
|||||||
|
|
||||||
func stopServers(ctx context.Context, ss *servers) {
|
func stopServers(ctx context.Context, ss *servers) {
|
||||||
// first, close the http.Server
|
// first, close the http.Server
|
||||||
ss.http.Shutdown(ctx)
|
if ss.http != nil {
|
||||||
// do not grpc.Server.GracefulStop with TLS enabled etcd server
|
ss.http.Shutdown(ctx)
|
||||||
|
}
|
||||||
|
if ss.grpc == nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
// do not grpc.Server.GracefulStop when grpc runs under http server
|
||||||
// See https://github.com/grpc/grpc-go/issues/1384#issuecomment-317124531
|
// See https://github.com/grpc/grpc-go/issues/1384#issuecomment-317124531
|
||||||
// and https://github.com/etcd-io/etcd/issues/8916
|
// and https://github.com/etcd-io/etcd/issues/8916
|
||||||
if ss.secure {
|
if ss.secure && ss.http != nil {
|
||||||
ss.grpc.Stop()
|
ss.grpc.Stop()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -478,6 +488,9 @@ func configurePeerListeners(cfg *Config) (peers []*peerListener, err error) {
|
|||||||
if err = cfg.PeerSelfCert(); err != nil {
|
if err = cfg.PeerSelfCert(); err != nil {
|
||||||
cfg.logger.Fatal("failed to get peer self-signed certs", zap.Error(err))
|
cfg.logger.Fatal("failed to get peer self-signed certs", zap.Error(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateMinMaxVersions(&cfg.PeerTLSInfo, cfg.TlsMinVersion, cfg.TlsMaxVersion)
|
||||||
|
|
||||||
if !cfg.PeerTLSInfo.Empty() {
|
if !cfg.PeerTLSInfo.Empty() {
|
||||||
cfg.logger.Info(
|
cfg.logger.Info(
|
||||||
"starting with peer TLS",
|
"starting with peer TLS",
|
||||||
@ -486,7 +499,7 @@ func configurePeerListeners(cfg *Config) (peers []*peerListener, err error) {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
peers = make([]*peerListener, len(cfg.LPUrls))
|
peers = make([]*peerListener, len(cfg.ListenPeerUrls))
|
||||||
defer func() {
|
defer func() {
|
||||||
if err == nil {
|
if err == nil {
|
||||||
return
|
return
|
||||||
@ -495,7 +508,7 @@ func configurePeerListeners(cfg *Config) (peers []*peerListener, err error) {
|
|||||||
if peers[i] != nil && peers[i].close != nil {
|
if peers[i] != nil && peers[i].close != nil {
|
||||||
cfg.logger.Warn(
|
cfg.logger.Warn(
|
||||||
"closing peer listener",
|
"closing peer listener",
|
||||||
zap.String("address", cfg.LPUrls[i].String()),
|
zap.String("address", cfg.ListenPeerUrls[i].String()),
|
||||||
zap.Error(err),
|
zap.Error(err),
|
||||||
)
|
)
|
||||||
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
|
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
|
||||||
@ -505,7 +518,7 @@ func configurePeerListeners(cfg *Config) (peers []*peerListener, err error) {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
for i, u := range cfg.LPUrls {
|
for i, u := range cfg.ListenPeerUrls {
|
||||||
if u.Scheme == "http" {
|
if u.Scheme == "http" {
|
||||||
if !cfg.PeerTLSInfo.Empty() {
|
if !cfg.PeerTLSInfo.Empty() {
|
||||||
cfg.logger.Warn("scheme is HTTP while key and cert files are present; ignoring key and cert files", zap.String("peer-url", u.String()))
|
cfg.logger.Warn("scheme is HTTP while key and cert files are present; ignoring key and cert files", zap.String("peer-url", u.String()))
|
||||||
@ -598,13 +611,15 @@ func configureClientListeners(cfg *Config) (sctxs map[string]*serveCtx, err erro
|
|||||||
if err = cfg.ClientSelfCert(); err != nil {
|
if err = cfg.ClientSelfCert(); err != nil {
|
||||||
cfg.logger.Fatal("failed to get client self-signed certs", zap.Error(err))
|
cfg.logger.Fatal("failed to get client self-signed certs", zap.Error(err))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateMinMaxVersions(&cfg.ClientTLSInfo, cfg.TlsMinVersion, cfg.TlsMaxVersion)
|
||||||
|
|
||||||
if cfg.EnablePprof {
|
if cfg.EnablePprof {
|
||||||
cfg.logger.Info("pprof is enabled", zap.String("path", debugutil.HTTPPrefixPProf))
|
cfg.logger.Info("pprof is enabled", zap.String("path", debugutil.HTTPPrefixPProf))
|
||||||
}
|
}
|
||||||
|
|
||||||
sctxs = make(map[string]*serveCtx)
|
sctxs = make(map[string]*serveCtx)
|
||||||
for _, u := range cfg.LCUrls {
|
for _, u := range append(cfg.ListenClientUrls, cfg.ListenClientHttpUrls...) {
|
||||||
sctx := newServeCtx(cfg.logger)
|
|
||||||
if u.Scheme == "http" || u.Scheme == "unix" {
|
if u.Scheme == "http" || u.Scheme == "unix" {
|
||||||
if !cfg.ClientTLSInfo.Empty() {
|
if !cfg.ClientTLSInfo.Empty() {
|
||||||
cfg.logger.Warn("scheme is HTTP while key and cert files are present; ignoring key and cert files", zap.String("client-url", u.String()))
|
cfg.logger.Warn("scheme is HTTP while key and cert files are present; ignoring key and cert files", zap.String("client-url", u.String()))
|
||||||
@ -616,24 +631,41 @@ func configureClientListeners(cfg *Config) (sctxs map[string]*serveCtx, err erro
|
|||||||
if (u.Scheme == "https" || u.Scheme == "unixs") && cfg.ClientTLSInfo.Empty() {
|
if (u.Scheme == "https" || u.Scheme == "unixs") && cfg.ClientTLSInfo.Empty() {
|
||||||
return nil, fmt.Errorf("TLS key/cert (--cert-file, --key-file) must be provided for client url %s with HTTPS scheme", u.String())
|
return nil, fmt.Errorf("TLS key/cert (--cert-file, --key-file) must be provided for client url %s with HTTPS scheme", u.String())
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
network := "tcp"
|
for _, u := range cfg.ListenClientUrls {
|
||||||
addr := u.Host
|
addr, secure, network := resolveUrl(u)
|
||||||
if u.Scheme == "unix" || u.Scheme == "unixs" {
|
sctx := sctxs[addr]
|
||||||
network = "unix"
|
if sctx == nil {
|
||||||
addr = u.Host + u.Path
|
sctx = newServeCtx(cfg.logger)
|
||||||
|
sctxs[addr] = sctx
|
||||||
}
|
}
|
||||||
|
sctx.secure = sctx.secure || secure
|
||||||
|
sctx.insecure = sctx.insecure || !secure
|
||||||
|
sctx.scheme = u.Scheme
|
||||||
|
sctx.addr = addr
|
||||||
sctx.network = network
|
sctx.network = network
|
||||||
|
}
|
||||||
|
for _, u := range cfg.ListenClientHttpUrls {
|
||||||
|
addr, secure, network := resolveUrl(u)
|
||||||
|
|
||||||
sctx.secure = u.Scheme == "https" || u.Scheme == "unixs"
|
sctx := sctxs[addr]
|
||||||
sctx.insecure = !sctx.secure
|
if sctx == nil {
|
||||||
if oldctx := sctxs[addr]; oldctx != nil {
|
sctx = newServeCtx(cfg.logger)
|
||||||
oldctx.secure = oldctx.secure || sctx.secure
|
sctxs[addr] = sctx
|
||||||
oldctx.insecure = oldctx.insecure || sctx.insecure
|
} else if !sctx.httpOnly {
|
||||||
continue
|
return nil, fmt.Errorf("cannot bind both --client-listen-urls and --client-listen-http-urls on the same url %s", u.String())
|
||||||
}
|
}
|
||||||
|
sctx.secure = sctx.secure || secure
|
||||||
|
sctx.insecure = sctx.insecure || !secure
|
||||||
|
sctx.scheme = u.Scheme
|
||||||
|
sctx.addr = addr
|
||||||
|
sctx.network = network
|
||||||
|
sctx.httpOnly = true
|
||||||
|
}
|
||||||
|
|
||||||
if sctx.l, err = transport.NewListenerWithOpts(addr, u.Scheme,
|
for _, sctx := range sctxs {
|
||||||
|
if sctx.l, err = transport.NewListenerWithOpts(sctx.addr, sctx.scheme,
|
||||||
transport.WithSocketOpts(&cfg.SocketOpts),
|
transport.WithSocketOpts(&cfg.SocketOpts),
|
||||||
transport.WithSkipTLSInfoCheck(true),
|
transport.WithSkipTLSInfoCheck(true),
|
||||||
); err != nil {
|
); err != nil {
|
||||||
@ -641,7 +673,6 @@ func configureClientListeners(cfg *Config) (sctxs map[string]*serveCtx, err erro
|
|||||||
}
|
}
|
||||||
// net.Listener will rewrite ipv4 0.0.0.0 to ipv6 [::], breaking
|
// net.Listener will rewrite ipv4 0.0.0.0 to ipv6 [::], breaking
|
||||||
// hosts that disable ipv6. So, use the address given by the user.
|
// hosts that disable ipv6. So, use the address given by the user.
|
||||||
sctx.addr = addr
|
|
||||||
|
|
||||||
if fdLimit, fderr := runtimeutil.FDLimit(); fderr == nil {
|
if fdLimit, fderr := runtimeutil.FDLimit(); fderr == nil {
|
||||||
if fdLimit <= reservedInternalFDNum {
|
if fdLimit <= reservedInternalFDNum {
|
||||||
@ -654,17 +685,17 @@ func configureClientListeners(cfg *Config) (sctxs map[string]*serveCtx, err erro
|
|||||||
sctx.l = transport.LimitListener(sctx.l, int(fdLimit-reservedInternalFDNum))
|
sctx.l = transport.LimitListener(sctx.l, int(fdLimit-reservedInternalFDNum))
|
||||||
}
|
}
|
||||||
|
|
||||||
defer func(u url.URL) {
|
defer func(sctx *serveCtx) {
|
||||||
if err == nil {
|
if err == nil || sctx.l == nil {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
sctx.l.Close()
|
sctx.l.Close()
|
||||||
cfg.logger.Warn(
|
cfg.logger.Warn(
|
||||||
"closing peer listener",
|
"closing peer listener",
|
||||||
zap.String("address", u.Host),
|
zap.String("address", sctx.addr),
|
||||||
zap.Error(err),
|
zap.Error(err),
|
||||||
)
|
)
|
||||||
}(u)
|
}(sctx)
|
||||||
for k := range cfg.UserHandlers {
|
for k := range cfg.UserHandlers {
|
||||||
sctx.userHandlers[k] = cfg.UserHandlers[k]
|
sctx.userHandlers[k] = cfg.UserHandlers[k]
|
||||||
}
|
}
|
||||||
@ -675,11 +706,21 @@ func configureClientListeners(cfg *Config) (sctxs map[string]*serveCtx, err erro
|
|||||||
if cfg.LogLevel == "debug" {
|
if cfg.LogLevel == "debug" {
|
||||||
sctx.registerTrace()
|
sctx.registerTrace()
|
||||||
}
|
}
|
||||||
sctxs[addr] = sctx
|
|
||||||
}
|
}
|
||||||
return sctxs, nil
|
return sctxs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func resolveUrl(u url.URL) (addr string, secure bool, network string) {
|
||||||
|
addr = u.Host
|
||||||
|
network = "tcp"
|
||||||
|
if u.Scheme == "unix" || u.Scheme == "unixs" {
|
||||||
|
addr = u.Host + u.Path
|
||||||
|
network = "unix"
|
||||||
|
}
|
||||||
|
secure = u.Scheme == "https" || u.Scheme == "unixs"
|
||||||
|
return addr, secure, network
|
||||||
|
}
|
||||||
|
|
||||||
func (e *Etcd) serveClients() (err error) {
|
func (e *Etcd) serveClients() (err error) {
|
||||||
if !e.cfg.ClientTLSInfo.Empty() {
|
if !e.cfg.ClientTLSInfo.Empty() {
|
||||||
e.cfg.logger.Info(
|
e.cfg.logger.Info(
|
||||||
@ -725,15 +766,69 @@ func (e *Etcd) serveClients() (err error) {
|
|||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
splitHttp := false
|
||||||
|
for _, sctx := range e.sctxs {
|
||||||
|
if sctx.httpOnly {
|
||||||
|
splitHttp = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// start client servers in each goroutine
|
// start client servers in each goroutine
|
||||||
for _, sctx := range e.sctxs {
|
for _, sctx := range e.sctxs {
|
||||||
go func(s *serveCtx) {
|
go func(s *serveCtx) {
|
||||||
e.errHandler(s.serve(e.Server, &e.cfg.ClientTLSInfo, h, e.errHandler, gopts...))
|
e.errHandler(s.serve(e.Server, &e.cfg.ClientTLSInfo, h, e.errHandler, e.grpcGatewayDial(splitHttp), splitHttp, gopts...))
|
||||||
}(sctx)
|
}(sctx)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (e *Etcd) grpcGatewayDial(splitHttp bool) (grpcDial func(ctx context.Context) (*grpc.ClientConn, error)) {
|
||||||
|
if !e.cfg.EnableGRPCGateway {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
sctx := e.pickGrpcGatewayServeContext(splitHttp)
|
||||||
|
addr := sctx.addr
|
||||||
|
if network := sctx.network; network == "unix" {
|
||||||
|
// explicitly define unix network for gRPC socket support
|
||||||
|
addr = fmt.Sprintf("%s://%s", network, addr)
|
||||||
|
}
|
||||||
|
|
||||||
|
opts := []grpc.DialOption{grpc.WithDefaultCallOptions(grpc.MaxCallRecvMsgSize(math.MaxInt32))}
|
||||||
|
if sctx.secure {
|
||||||
|
tlscfg, tlsErr := e.cfg.ClientTLSInfo.ServerConfig()
|
||||||
|
if tlsErr != nil {
|
||||||
|
return func(ctx context.Context) (*grpc.ClientConn, error) {
|
||||||
|
return nil, tlsErr
|
||||||
|
}
|
||||||
|
}
|
||||||
|
dtls := tlscfg.Clone()
|
||||||
|
// trust local server
|
||||||
|
dtls.InsecureSkipVerify = true
|
||||||
|
bundle := credentials.NewBundle(credentials.Config{TLSConfig: dtls})
|
||||||
|
opts = append(opts, grpc.WithTransportCredentials(bundle.TransportCredentials()))
|
||||||
|
} else {
|
||||||
|
opts = append(opts, grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||||
|
}
|
||||||
|
|
||||||
|
return func(ctx context.Context) (*grpc.ClientConn, error) {
|
||||||
|
conn, err := grpc.DialContext(ctx, addr, opts...)
|
||||||
|
if err != nil {
|
||||||
|
sctx.lg.Error("grpc gateway failed to dial", zap.String("addr", addr), zap.Error(err))
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return conn, err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (e *Etcd) pickGrpcGatewayServeContext(splitHttp bool) *serveCtx {
|
||||||
|
for _, sctx := range e.sctxs {
|
||||||
|
if !splitHttp || !sctx.httpOnly {
|
||||||
|
return sctx
|
||||||
|
}
|
||||||
|
}
|
||||||
|
panic("Expect at least one context able to serve grpc")
|
||||||
|
}
|
||||||
|
|
||||||
func (e *Etcd) serveMetrics() (err error) {
|
func (e *Etcd) serveMetrics() (err error) {
|
||||||
if e.cfg.Metrics == "extensive" {
|
if e.cfg.Metrics == "extensive" {
|
||||||
grpc_prometheus.EnableHandlingTimeHistogram()
|
grpc_prometheus.EnableHandlingTimeHistogram()
|
||||||
|
@ -19,14 +19,12 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
defaultLog "log"
|
defaultLog "log"
|
||||||
"math"
|
|
||||||
"net"
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
etcdservergw "go.etcd.io/etcd/api/v3/etcdserverpb/gw"
|
etcdservergw "go.etcd.io/etcd/api/v3/etcdserverpb/gw"
|
||||||
"go.etcd.io/etcd/client/pkg/v3/transport"
|
"go.etcd.io/etcd/client/pkg/v3/transport"
|
||||||
"go.etcd.io/etcd/client/v3/credentials"
|
|
||||||
"go.etcd.io/etcd/pkg/v3/debugutil"
|
"go.etcd.io/etcd/pkg/v3/debugutil"
|
||||||
"go.etcd.io/etcd/pkg/v3/httputil"
|
"go.etcd.io/etcd/pkg/v3/httputil"
|
||||||
"go.etcd.io/etcd/server/v3/config"
|
"go.etcd.io/etcd/server/v3/config"
|
||||||
@ -50,12 +48,15 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type serveCtx struct {
|
type serveCtx struct {
|
||||||
lg *zap.Logger
|
lg *zap.Logger
|
||||||
l net.Listener
|
l net.Listener
|
||||||
|
|
||||||
|
scheme string
|
||||||
addr string
|
addr string
|
||||||
network string
|
network string
|
||||||
secure bool
|
secure bool
|
||||||
insecure bool
|
insecure bool
|
||||||
|
httpOnly bool
|
||||||
|
|
||||||
ctx context.Context
|
ctx context.Context
|
||||||
cancel context.CancelFunc
|
cancel context.CancelFunc
|
||||||
@ -93,6 +94,8 @@ func (sctx *serveCtx) serve(
|
|||||||
tlsinfo *transport.TLSInfo,
|
tlsinfo *transport.TLSInfo,
|
||||||
handler http.Handler,
|
handler http.Handler,
|
||||||
errHandler func(error),
|
errHandler func(error),
|
||||||
|
grpcDialForRestGatewayBackends func(ctx context.Context) (*grpc.ClientConn, error),
|
||||||
|
splitHttp bool,
|
||||||
gopts ...grpc.ServerOption) (err error) {
|
gopts ...grpc.ServerOption) (err error) {
|
||||||
logger := defaultLog.New(ioutil.Discard, "etcdhttp", 0)
|
logger := defaultLog.New(ioutil.Discard, "etcdhttp", 0)
|
||||||
<-s.ReadyNotify()
|
<-s.ReadyNotify()
|
||||||
@ -100,115 +103,166 @@ func (sctx *serveCtx) serve(
|
|||||||
sctx.lg.Info("ready to serve client requests")
|
sctx.lg.Info("ready to serve client requests")
|
||||||
|
|
||||||
m := cmux.New(sctx.l)
|
m := cmux.New(sctx.l)
|
||||||
|
var server func() error
|
||||||
|
onlyGRPC := splitHttp && !sctx.httpOnly
|
||||||
|
onlyHttp := splitHttp && sctx.httpOnly
|
||||||
|
grpcEnabled := !onlyHttp
|
||||||
|
httpEnabled := !onlyGRPC
|
||||||
|
|
||||||
v3c := v3client.New(s)
|
v3c := v3client.New(s)
|
||||||
servElection := v3election.NewElectionServer(v3c)
|
servElection := v3election.NewElectionServer(v3c)
|
||||||
servLock := v3lock.NewLockServer(v3c)
|
servLock := v3lock.NewLockServer(v3c)
|
||||||
|
|
||||||
var gs *grpc.Server
|
// Make sure serversC is closed even if we prematurely exit the function.
|
||||||
defer func() {
|
defer close(sctx.serversC)
|
||||||
if err != nil && gs != nil {
|
var gwmux *gw.ServeMux
|
||||||
gs.Stop()
|
if s.Cfg.EnableGRPCGateway {
|
||||||
|
// GRPC gateway connects to grpc server via connection provided by grpc dial.
|
||||||
|
gwmux, err = sctx.registerGateway(grpcDialForRestGatewayBackends)
|
||||||
|
if err != nil {
|
||||||
|
sctx.lg.Error("registerGateway failed", zap.Error(err))
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
}()
|
}
|
||||||
|
var traffic string
|
||||||
|
switch {
|
||||||
|
case onlyGRPC:
|
||||||
|
traffic = "grpc"
|
||||||
|
case onlyHttp:
|
||||||
|
traffic = "http"
|
||||||
|
default:
|
||||||
|
traffic = "grpc+http"
|
||||||
|
}
|
||||||
|
|
||||||
if sctx.insecure {
|
if sctx.insecure {
|
||||||
gs = v3rpc.Server(s, nil, nil, gopts...)
|
var gs *grpc.Server
|
||||||
v3electionpb.RegisterElectionServer(gs, servElection)
|
var srv *http.Server
|
||||||
v3lockpb.RegisterLockServer(gs, servLock)
|
if httpEnabled {
|
||||||
if sctx.serviceRegister != nil {
|
httpmux := sctx.createMux(gwmux, handler)
|
||||||
sctx.serviceRegister(gs)
|
srv = &http.Server{
|
||||||
}
|
Handler: createAccessController(sctx.lg, s, httpmux),
|
||||||
grpcl := m.Match(cmux.HTTP2())
|
ErrorLog: logger, // do not log user error
|
||||||
go func() { errHandler(gs.Serve(grpcl)) }()
|
}
|
||||||
|
if err := configureHttpServer(srv, s.Cfg); err != nil {
|
||||||
var gwmux *gw.ServeMux
|
sctx.lg.Error("Configure http server failed", zap.Error(err))
|
||||||
if s.Cfg.EnableGRPCGateway {
|
|
||||||
gwmux, err = sctx.registerGateway([]grpc.DialOption{grpc.WithInsecure()})
|
|
||||||
if err != nil {
|
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if grpcEnabled {
|
||||||
httpmux := sctx.createMux(gwmux, handler)
|
gs = v3rpc.Server(s, nil, nil, gopts...)
|
||||||
|
v3electionpb.RegisterElectionServer(gs, servElection)
|
||||||
srvhttp := &http.Server{
|
v3lockpb.RegisterLockServer(gs, servLock)
|
||||||
Handler: createAccessController(sctx.lg, s, httpmux),
|
if sctx.serviceRegister != nil {
|
||||||
ErrorLog: logger, // do not log user error
|
sctx.serviceRegister(gs)
|
||||||
|
}
|
||||||
|
defer func(gs *grpc.Server) {
|
||||||
|
if err != nil {
|
||||||
|
sctx.lg.Warn("stopping insecure grpc server due to error", zap.Error(err))
|
||||||
|
gs.Stop()
|
||||||
|
sctx.lg.Warn("stopped insecure grpc server due to error", zap.Error(err))
|
||||||
|
}
|
||||||
|
}(gs)
|
||||||
}
|
}
|
||||||
if err := configureHttpServer(srvhttp, s.Cfg); err != nil {
|
if onlyGRPC {
|
||||||
sctx.lg.Error("Configure http server failed", zap.Error(err))
|
server = func() error {
|
||||||
return err
|
return gs.Serve(sctx.l)
|
||||||
}
|
}
|
||||||
httpl := m.Match(cmux.HTTP1())
|
} else {
|
||||||
go func() { errHandler(srvhttp.Serve(httpl)) }()
|
server = m.Serve
|
||||||
|
|
||||||
sctx.serversC <- &servers{grpc: gs, http: srvhttp}
|
httpl := m.Match(cmux.HTTP1())
|
||||||
|
go func(srvhttp *http.Server, tlsLis net.Listener) {
|
||||||
|
errHandler(srvhttp.Serve(tlsLis))
|
||||||
|
}(srv, httpl)
|
||||||
|
|
||||||
|
if grpcEnabled {
|
||||||
|
grpcl := m.Match(cmux.HTTP2())
|
||||||
|
go func(gs *grpc.Server, l net.Listener) {
|
||||||
|
errHandler(gs.Serve(l))
|
||||||
|
}(gs, grpcl)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sctx.serversC <- &servers{grpc: gs, http: srv}
|
||||||
sctx.lg.Info(
|
sctx.lg.Info(
|
||||||
"serving client traffic insecurely; this is strongly discouraged!",
|
"serving client traffic insecurely; this is strongly discouraged!",
|
||||||
|
zap.String("traffic", traffic),
|
||||||
zap.String("address", sctx.l.Addr().String()),
|
zap.String("address", sctx.l.Addr().String()),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
if sctx.secure {
|
if sctx.secure {
|
||||||
|
var gs *grpc.Server
|
||||||
|
var srv *http.Server
|
||||||
|
|
||||||
tlscfg, tlsErr := tlsinfo.ServerConfig()
|
tlscfg, tlsErr := tlsinfo.ServerConfig()
|
||||||
if tlsErr != nil {
|
if tlsErr != nil {
|
||||||
return tlsErr
|
return tlsErr
|
||||||
}
|
}
|
||||||
gs = v3rpc.Server(s, tlscfg, nil, gopts...)
|
|
||||||
v3electionpb.RegisterElectionServer(gs, servElection)
|
|
||||||
v3lockpb.RegisterLockServer(gs, servLock)
|
|
||||||
if sctx.serviceRegister != nil {
|
|
||||||
sctx.serviceRegister(gs)
|
|
||||||
}
|
|
||||||
handler = grpcHandlerFunc(gs, handler)
|
|
||||||
|
|
||||||
var gwmux *gw.ServeMux
|
if grpcEnabled {
|
||||||
if s.Cfg.EnableGRPCGateway {
|
gs = v3rpc.Server(s, tlscfg, nil, gopts...)
|
||||||
dtls := tlscfg.Clone()
|
v3electionpb.RegisterElectionServer(gs, servElection)
|
||||||
// trust local server
|
v3lockpb.RegisterLockServer(gs, servLock)
|
||||||
dtls.InsecureSkipVerify = true
|
if sctx.serviceRegister != nil {
|
||||||
bundle := credentials.NewBundle(credentials.Config{TLSConfig: dtls})
|
sctx.serviceRegister(gs)
|
||||||
opts := []grpc.DialOption{grpc.WithTransportCredentials(bundle.TransportCredentials())}
|
}
|
||||||
gwmux, err = sctx.registerGateway(opts)
|
defer func(gs *grpc.Server) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
sctx.lg.Warn("stopping secure grpc server due to error", zap.Error(err))
|
||||||
|
gs.Stop()
|
||||||
|
sctx.lg.Warn("stopped secure grpc server due to error", zap.Error(err))
|
||||||
|
}
|
||||||
|
}(gs)
|
||||||
|
}
|
||||||
|
if httpEnabled {
|
||||||
|
if grpcEnabled {
|
||||||
|
handler = grpcHandlerFunc(gs, handler)
|
||||||
|
}
|
||||||
|
httpmux := sctx.createMux(gwmux, handler)
|
||||||
|
|
||||||
|
srv = &http.Server{
|
||||||
|
Handler: createAccessController(sctx.lg, s, httpmux),
|
||||||
|
TLSConfig: tlscfg,
|
||||||
|
ErrorLog: logger, // do not log user error
|
||||||
|
}
|
||||||
|
if err := configureHttpServer(srv, s.Cfg); err != nil {
|
||||||
|
sctx.lg.Error("Configure https server failed", zap.Error(err))
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
var tlsl net.Listener
|
if onlyGRPC {
|
||||||
tlsl, err = transport.NewTLSListener(m.Match(cmux.Any()), tlsinfo)
|
server = func() error { return gs.Serve(sctx.l) }
|
||||||
if err != nil {
|
} else {
|
||||||
return err
|
server = m.Serve
|
||||||
}
|
|
||||||
// TODO: add debug flag; enable logging when debug flag is set
|
|
||||||
httpmux := sctx.createMux(gwmux, handler)
|
|
||||||
|
|
||||||
srv := &http.Server{
|
tlsl, err := transport.NewTLSListener(m.Match(cmux.Any()), tlsinfo)
|
||||||
Handler: createAccessController(sctx.lg, s, httpmux),
|
if err != nil {
|
||||||
TLSConfig: tlscfg,
|
return err
|
||||||
ErrorLog: logger, // do not log user error
|
}
|
||||||
|
go func(srvhttp *http.Server, tlsl net.Listener) {
|
||||||
|
errHandler(srvhttp.Serve(tlsl))
|
||||||
|
}(srv, tlsl)
|
||||||
}
|
}
|
||||||
if err := configureHttpServer(srv, s.Cfg); err != nil {
|
|
||||||
sctx.lg.Error("Configure https server failed", zap.Error(err))
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
go func() { errHandler(srv.Serve(tlsl)) }()
|
|
||||||
|
|
||||||
sctx.serversC <- &servers{secure: true, grpc: gs, http: srv}
|
sctx.serversC <- &servers{secure: true, grpc: gs, http: srv}
|
||||||
sctx.lg.Info(
|
sctx.lg.Info(
|
||||||
"serving client traffic securely",
|
"serving client traffic securely",
|
||||||
|
zap.String("traffic", traffic),
|
||||||
zap.String("address", sctx.l.Addr().String()),
|
zap.String("address", sctx.l.Addr().String()),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
close(sctx.serversC)
|
return server()
|
||||||
return m.Serve()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func configureHttpServer(srv *http.Server, cfg config.ServerConfig) error {
|
func configureHttpServer(srv *http.Server, cfg config.ServerConfig) error {
|
||||||
// todo (ahrtr): should we support configuring other parameters in the future as well?
|
// todo (ahrtr): should we support configuring other parameters in the future as well?
|
||||||
return http2.ConfigureServer(srv, &http2.Server{
|
return http2.ConfigureServer(srv, &http2.Server{
|
||||||
MaxConcurrentStreams: cfg.MaxConcurrentStreams,
|
MaxConcurrentStreams: cfg.MaxConcurrentStreams,
|
||||||
|
// Override to avoid using priority scheduler which is affected by https://github.com/golang/go/issues/58804.
|
||||||
|
NewWriteScheduler: http2.NewRandomWriteScheduler,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -231,20 +285,10 @@ func grpcHandlerFunc(grpcServer *grpc.Server, otherHandler http.Handler) http.Ha
|
|||||||
|
|
||||||
type registerHandlerFunc func(context.Context, *gw.ServeMux, *grpc.ClientConn) error
|
type registerHandlerFunc func(context.Context, *gw.ServeMux, *grpc.ClientConn) error
|
||||||
|
|
||||||
func (sctx *serveCtx) registerGateway(opts []grpc.DialOption) (*gw.ServeMux, error) {
|
func (sctx *serveCtx) registerGateway(dial func(ctx context.Context) (*grpc.ClientConn, error)) (*gw.ServeMux, error) {
|
||||||
ctx := sctx.ctx
|
ctx := sctx.ctx
|
||||||
|
|
||||||
addr := sctx.addr
|
conn, err := dial(ctx)
|
||||||
if network := sctx.network; network == "unix" {
|
|
||||||
// explicitly define unix network for gRPC socket support
|
|
||||||
addr = fmt.Sprintf("%s://%s", network, addr)
|
|
||||||
}
|
|
||||||
|
|
||||||
opts = append(opts, grpc.WithDefaultCallOptions([]grpc.CallOption{
|
|
||||||
grpc.MaxCallRecvMsgSize(math.MaxInt32),
|
|
||||||
}...))
|
|
||||||
|
|
||||||
conn, err := grpc.DialContext(ctx, addr, opts...)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -279,6 +323,18 @@ func (sctx *serveCtx) registerGateway(opts []grpc.DialOption) (*gw.ServeMux, err
|
|||||||
return gwmux, nil
|
return gwmux, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type wsProxyZapLogger struct {
|
||||||
|
*zap.Logger
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w wsProxyZapLogger) Warnln(i ...interface{}) {
|
||||||
|
w.Warn(fmt.Sprint(i...))
|
||||||
|
}
|
||||||
|
|
||||||
|
func (w wsProxyZapLogger) Debugln(i ...interface{}) {
|
||||||
|
w.Debug(fmt.Sprint(i...))
|
||||||
|
}
|
||||||
|
|
||||||
func (sctx *serveCtx) createMux(gwmux *gw.ServeMux, handler http.Handler) *http.ServeMux {
|
func (sctx *serveCtx) createMux(gwmux *gw.ServeMux, handler http.Handler) *http.ServeMux {
|
||||||
httpmux := http.NewServeMux()
|
httpmux := http.NewServeMux()
|
||||||
for path, h := range sctx.userHandlers {
|
for path, h := range sctx.userHandlers {
|
||||||
@ -298,6 +354,7 @@ func (sctx *serveCtx) createMux(gwmux *gw.ServeMux, handler http.Handler) *http.
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
wsproxy.WithMaxRespBodyBufferSize(0x7fffffff),
|
wsproxy.WithMaxRespBodyBufferSize(0x7fffffff),
|
||||||
|
wsproxy.WithLogger(wsProxyZapLogger{sctx.lg}),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -38,8 +38,8 @@ func TestStartEtcdWrongToken(t *testing.T) {
|
|||||||
urls := newEmbedURLs(2)
|
urls := newEmbedURLs(2)
|
||||||
curls := []url.URL{urls[0]}
|
curls := []url.URL{urls[0]}
|
||||||
purls := []url.URL{urls[1]}
|
purls := []url.URL{urls[1]}
|
||||||
cfg.LCUrls, cfg.ACUrls = curls, curls
|
cfg.ListenClientUrls, cfg.AdvertiseClientUrls = curls, curls
|
||||||
cfg.LPUrls, cfg.APUrls = purls, purls
|
cfg.ListenPeerUrls, cfg.AdvertisePeerUrls = purls, purls
|
||||||
cfg.InitialCluster = ""
|
cfg.InitialCluster = ""
|
||||||
for i := range purls {
|
for i := range purls {
|
||||||
cfg.InitialCluster += ",default=" + purls[i].String()
|
cfg.InitialCluster += ",default=" + purls[i].String()
|
||||||
|
@ -26,6 +26,7 @@ import (
|
|||||||
|
|
||||||
"go.etcd.io/etcd/api/v3/version"
|
"go.etcd.io/etcd/api/v3/version"
|
||||||
"go.etcd.io/etcd/client/pkg/v3/logutil"
|
"go.etcd.io/etcd/client/pkg/v3/logutil"
|
||||||
|
"go.etcd.io/etcd/client/pkg/v3/tlsutil"
|
||||||
"go.etcd.io/etcd/pkg/v3/flags"
|
"go.etcd.io/etcd/pkg/v3/flags"
|
||||||
cconfig "go.etcd.io/etcd/server/v3/config"
|
cconfig "go.etcd.io/etcd/server/v3/config"
|
||||||
"go.etcd.io/etcd/server/v3/embed"
|
"go.etcd.io/etcd/server/v3/embed"
|
||||||
@ -145,7 +146,11 @@ func newConfig() *config {
|
|||||||
)
|
)
|
||||||
fs.Var(
|
fs.Var(
|
||||||
flags.NewUniqueURLsWithExceptions(embed.DefaultListenClientURLs, ""), "listen-client-urls",
|
flags.NewUniqueURLsWithExceptions(embed.DefaultListenClientURLs, ""), "listen-client-urls",
|
||||||
"List of URLs to listen on for client traffic.",
|
"List of URLs to listen on for client grpc traffic and http as long as --listen-client-http-urls is not specified.",
|
||||||
|
)
|
||||||
|
fs.Var(
|
||||||
|
flags.NewUniqueURLsWithExceptions("", ""), "listen-client-http-urls",
|
||||||
|
"List of URLs to listen on for http only client traffic. Enabling this flag removes http services from --listen-client-urls.",
|
||||||
)
|
)
|
||||||
fs.Var(
|
fs.Var(
|
||||||
flags.NewUniqueURLsWithExceptions("", ""),
|
flags.NewUniqueURLsWithExceptions("", ""),
|
||||||
@ -196,7 +201,7 @@ func newConfig() *config {
|
|||||||
fs.StringVar(&cfg.ec.DNSClusterServiceName, "discovery-srv-name", cfg.ec.DNSClusterServiceName, "Service name to query when using DNS discovery.")
|
fs.StringVar(&cfg.ec.DNSClusterServiceName, "discovery-srv-name", cfg.ec.DNSClusterServiceName, "Service name to query when using DNS discovery.")
|
||||||
fs.StringVar(&cfg.ec.InitialCluster, "initial-cluster", cfg.ec.InitialCluster, "Initial cluster configuration for bootstrapping.")
|
fs.StringVar(&cfg.ec.InitialCluster, "initial-cluster", cfg.ec.InitialCluster, "Initial cluster configuration for bootstrapping.")
|
||||||
fs.StringVar(&cfg.ec.InitialClusterToken, "initial-cluster-token", cfg.ec.InitialClusterToken, "Initial cluster token for the etcd cluster during bootstrap.")
|
fs.StringVar(&cfg.ec.InitialClusterToken, "initial-cluster-token", cfg.ec.InitialClusterToken, "Initial cluster token for the etcd cluster during bootstrap.")
|
||||||
fs.Var(cfg.cf.clusterState, "initial-cluster-state", "Initial cluster state ('new' or 'existing').")
|
fs.Var(cfg.cf.clusterState, "initial-cluster-state", "Initial cluster state ('new' when bootstrapping a new cluster or 'existing' when adding new members to an existing cluster). After successful initialization (bootstrapping or adding), flag is ignored on restarts.")
|
||||||
|
|
||||||
fs.BoolVar(&cfg.ec.StrictReconfigCheck, "strict-reconfig-check", cfg.ec.StrictReconfigCheck, "Reject reconfiguration requests that would cause quorum loss.")
|
fs.BoolVar(&cfg.ec.StrictReconfigCheck, "strict-reconfig-check", cfg.ec.StrictReconfigCheck, "Reject reconfiguration requests that would cause quorum loss.")
|
||||||
|
|
||||||
@ -237,6 +242,8 @@ func newConfig() *config {
|
|||||||
fs.StringVar(&cfg.ec.PeerTLSInfo.AllowedHostname, "peer-cert-allowed-hostname", "", "Allowed TLS hostname for inter peer authentication.")
|
fs.StringVar(&cfg.ec.PeerTLSInfo.AllowedHostname, "peer-cert-allowed-hostname", "", "Allowed TLS hostname for inter peer authentication.")
|
||||||
fs.Var(flags.NewStringsValue(""), "cipher-suites", "Comma-separated list of supported TLS cipher suites between client/server and peers (empty will be auto-populated by Go).")
|
fs.Var(flags.NewStringsValue(""), "cipher-suites", "Comma-separated list of supported TLS cipher suites between client/server and peers (empty will be auto-populated by Go).")
|
||||||
fs.BoolVar(&cfg.ec.PeerTLSInfo.SkipClientSANVerify, "experimental-peer-skip-client-san-verification", false, "Skip verification of SAN field in client certificate for peer connections.")
|
fs.BoolVar(&cfg.ec.PeerTLSInfo.SkipClientSANVerify, "experimental-peer-skip-client-san-verification", false, "Skip verification of SAN field in client certificate for peer connections.")
|
||||||
|
fs.StringVar(&cfg.ec.TlsMinVersion, "tls-min-version", string(tlsutil.TLSVersion12), "Minimum TLS version supported by etcd. Possible values: TLS1.2, TLS1.3.")
|
||||||
|
fs.StringVar(&cfg.ec.TlsMaxVersion, "tls-max-version", string(tlsutil.TLSVersionDefault), "Maximum TLS version supported by etcd. Possible values: TLS1.2, TLS1.3 (empty defers to Go).")
|
||||||
|
|
||||||
fs.Var(
|
fs.Var(
|
||||||
flags.NewUniqueURLsWithExceptions("*", "*"),
|
flags.NewUniqueURLsWithExceptions("*", "*"),
|
||||||
@ -389,10 +396,11 @@ func (cfg *config) configFromCmdLine() error {
|
|||||||
lg.Info(fmt.Sprintf("raft-write-timeout increased to minimum value: %v", rafthttp.DefaultConnWriteTimeout))
|
lg.Info(fmt.Sprintf("raft-write-timeout increased to minimum value: %v", rafthttp.DefaultConnWriteTimeout))
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg.ec.LPUrls = flags.UniqueURLsFromFlag(cfg.cf.flagSet, "listen-peer-urls")
|
cfg.ec.ListenPeerUrls = flags.UniqueURLsFromFlag(cfg.cf.flagSet, "listen-peer-urls")
|
||||||
cfg.ec.APUrls = flags.UniqueURLsFromFlag(cfg.cf.flagSet, "initial-advertise-peer-urls")
|
cfg.ec.AdvertisePeerUrls = flags.UniqueURLsFromFlag(cfg.cf.flagSet, "initial-advertise-peer-urls")
|
||||||
cfg.ec.LCUrls = flags.UniqueURLsFromFlag(cfg.cf.flagSet, "listen-client-urls")
|
cfg.ec.ListenClientUrls = flags.UniqueURLsFromFlag(cfg.cf.flagSet, "listen-client-urls")
|
||||||
cfg.ec.ACUrls = flags.UniqueURLsFromFlag(cfg.cf.flagSet, "advertise-client-urls")
|
cfg.ec.ListenClientHttpUrls = flags.UniqueURLsFromFlag(cfg.cf.flagSet, "listen-client-http-urls")
|
||||||
|
cfg.ec.AdvertiseClientUrls = flags.UniqueURLsFromFlag(cfg.cf.flagSet, "advertise-client-urls")
|
||||||
cfg.ec.ListenMetricsUrls = flags.UniqueURLsFromFlag(cfg.cf.flagSet, "listen-metrics-urls")
|
cfg.ec.ListenMetricsUrls = flags.UniqueURLsFromFlag(cfg.cf.flagSet, "listen-metrics-urls")
|
||||||
|
|
||||||
cfg.ec.CORS = flags.UniqueURLsMapFromFlag(cfg.cf.flagSet, "cors")
|
cfg.ec.CORS = flags.UniqueURLsMapFromFlag(cfg.cf.flagSet, "cors")
|
||||||
@ -413,7 +421,7 @@ func (cfg *config) configFromCmdLine() error {
|
|||||||
// disable default advertise-client-urls if lcurls is set
|
// disable default advertise-client-urls if lcurls is set
|
||||||
missingAC := flags.IsSet(cfg.cf.flagSet, "listen-client-urls") && !flags.IsSet(cfg.cf.flagSet, "advertise-client-urls")
|
missingAC := flags.IsSet(cfg.cf.flagSet, "listen-client-urls") && !flags.IsSet(cfg.cf.flagSet, "advertise-client-urls")
|
||||||
if !cfg.mayBeProxy() && missingAC {
|
if !cfg.mayBeProxy() && missingAC {
|
||||||
cfg.ec.ACUrls = nil
|
cfg.ec.AdvertiseClientUrls = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// disable default initial-cluster if discovery is set
|
// disable default initial-cluster if discovery is set
|
||||||
|
@ -36,6 +36,7 @@ func TestConfigParsingMemberFlags(t *testing.T) {
|
|||||||
"-snapshot-count=10",
|
"-snapshot-count=10",
|
||||||
"-listen-peer-urls=http://localhost:8000,https://localhost:8001",
|
"-listen-peer-urls=http://localhost:8000,https://localhost:8001",
|
||||||
"-listen-client-urls=http://localhost:7000,https://localhost:7001",
|
"-listen-client-urls=http://localhost:7000,https://localhost:7001",
|
||||||
|
"-listen-client-http-urls=http://localhost:7002,https://localhost:7003",
|
||||||
// it should be set if -listen-client-urls is set
|
// it should be set if -listen-client-urls is set
|
||||||
"-advertise-client-urls=http://localhost:7000,https://localhost:7001",
|
"-advertise-client-urls=http://localhost:7000,https://localhost:7001",
|
||||||
}
|
}
|
||||||
@ -51,14 +52,15 @@ func TestConfigParsingMemberFlags(t *testing.T) {
|
|||||||
|
|
||||||
func TestConfigFileMemberFields(t *testing.T) {
|
func TestConfigFileMemberFields(t *testing.T) {
|
||||||
yc := struct {
|
yc := struct {
|
||||||
Dir string `json:"data-dir"`
|
Dir string `json:"data-dir"`
|
||||||
MaxSnapFiles uint `json:"max-snapshots"`
|
MaxSnapFiles uint `json:"max-snapshots"`
|
||||||
MaxWalFiles uint `json:"max-wals"`
|
MaxWalFiles uint `json:"max-wals"`
|
||||||
Name string `json:"name"`
|
Name string `json:"name"`
|
||||||
SnapshotCount uint64 `json:"snapshot-count"`
|
SnapshotCount uint64 `json:"snapshot-count"`
|
||||||
LPUrls string `json:"listen-peer-urls"`
|
ListenPeerUrls string `json:"listen-peer-urls"`
|
||||||
LCUrls string `json:"listen-client-urls"`
|
ListenClientUrls string `json:"listen-client-urls"`
|
||||||
AcurlsCfgFile string `json:"advertise-client-urls"`
|
ListenClientHttpUrls string `json:"listen-client-http-urls"`
|
||||||
|
AdvertiseClientUrls string `json:"advertise-client-urls"`
|
||||||
}{
|
}{
|
||||||
"testdir",
|
"testdir",
|
||||||
10,
|
10,
|
||||||
@ -67,6 +69,7 @@ func TestConfigFileMemberFields(t *testing.T) {
|
|||||||
10,
|
10,
|
||||||
"http://localhost:8000,https://localhost:8001",
|
"http://localhost:8000,https://localhost:8001",
|
||||||
"http://localhost:7000,https://localhost:7001",
|
"http://localhost:7000,https://localhost:7001",
|
||||||
|
"http://localhost:7002,https://localhost:7003",
|
||||||
"http://localhost:7000,https://localhost:7001",
|
"http://localhost:7000,https://localhost:7001",
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -513,13 +516,14 @@ func mustCreateCfgFile(t *testing.T, b []byte) *os.File {
|
|||||||
|
|
||||||
func validateMemberFlags(t *testing.T, cfg *config) {
|
func validateMemberFlags(t *testing.T, cfg *config) {
|
||||||
wcfg := &embed.Config{
|
wcfg := &embed.Config{
|
||||||
Dir: "testdir",
|
Dir: "testdir",
|
||||||
LPUrls: []url.URL{{Scheme: "http", Host: "localhost:8000"}, {Scheme: "https", Host: "localhost:8001"}},
|
ListenPeerUrls: []url.URL{{Scheme: "http", Host: "localhost:8000"}, {Scheme: "https", Host: "localhost:8001"}},
|
||||||
LCUrls: []url.URL{{Scheme: "http", Host: "localhost:7000"}, {Scheme: "https", Host: "localhost:7001"}},
|
ListenClientUrls: []url.URL{{Scheme: "http", Host: "localhost:7000"}, {Scheme: "https", Host: "localhost:7001"}},
|
||||||
MaxSnapFiles: 10,
|
ListenClientHttpUrls: []url.URL{{Scheme: "http", Host: "localhost:7002"}, {Scheme: "https", Host: "localhost:7003"}},
|
||||||
MaxWalFiles: 10,
|
MaxSnapFiles: 10,
|
||||||
Name: "testname",
|
MaxWalFiles: 10,
|
||||||
SnapshotCount: 10,
|
Name: "testname",
|
||||||
|
SnapshotCount: 10,
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.ec.Dir != wcfg.Dir {
|
if cfg.ec.Dir != wcfg.Dir {
|
||||||
@ -537,18 +541,21 @@ func validateMemberFlags(t *testing.T, cfg *config) {
|
|||||||
if cfg.ec.SnapshotCount != wcfg.SnapshotCount {
|
if cfg.ec.SnapshotCount != wcfg.SnapshotCount {
|
||||||
t.Errorf("snapcount = %v, want %v", cfg.ec.SnapshotCount, wcfg.SnapshotCount)
|
t.Errorf("snapcount = %v, want %v", cfg.ec.SnapshotCount, wcfg.SnapshotCount)
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(cfg.ec.LPUrls, wcfg.LPUrls) {
|
if !reflect.DeepEqual(cfg.ec.ListenPeerUrls, wcfg.ListenPeerUrls) {
|
||||||
t.Errorf("listen-peer-urls = %v, want %v", cfg.ec.LPUrls, wcfg.LPUrls)
|
t.Errorf("listen-peer-urls = %v, want %v", cfg.ec.ListenPeerUrls, wcfg.ListenPeerUrls)
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(cfg.ec.LCUrls, wcfg.LCUrls) {
|
if !reflect.DeepEqual(cfg.ec.ListenClientUrls, wcfg.ListenClientUrls) {
|
||||||
t.Errorf("listen-client-urls = %v, want %v", cfg.ec.LCUrls, wcfg.LCUrls)
|
t.Errorf("listen-client-urls = %v, want %v", cfg.ec.ListenClientUrls, wcfg.ListenClientUrls)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(cfg.ec.ListenClientHttpUrls, wcfg.ListenClientHttpUrls) {
|
||||||
|
t.Errorf("listen-client-http-urls = %v, want %v", cfg.ec.ListenClientHttpUrls, wcfg.ListenClientHttpUrls)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func validateClusteringFlags(t *testing.T, cfg *config) {
|
func validateClusteringFlags(t *testing.T, cfg *config) {
|
||||||
wcfg := newConfig()
|
wcfg := newConfig()
|
||||||
wcfg.ec.APUrls = []url.URL{{Scheme: "http", Host: "localhost:8000"}, {Scheme: "https", Host: "localhost:8001"}}
|
wcfg.ec.AdvertisePeerUrls = []url.URL{{Scheme: "http", Host: "localhost:8000"}, {Scheme: "https", Host: "localhost:8001"}}
|
||||||
wcfg.ec.ACUrls = []url.URL{{Scheme: "http", Host: "localhost:7000"}, {Scheme: "https", Host: "localhost:7001"}}
|
wcfg.ec.AdvertiseClientUrls = []url.URL{{Scheme: "http", Host: "localhost:7000"}, {Scheme: "https", Host: "localhost:7001"}}
|
||||||
wcfg.ec.ClusterState = embed.ClusterStateFlagExisting
|
wcfg.ec.ClusterState = embed.ClusterStateFlagExisting
|
||||||
wcfg.cf.fallback.Set(fallbackFlagExit)
|
wcfg.cf.fallback.Set(fallbackFlagExit)
|
||||||
wcfg.ec.InitialCluster = "0=http://localhost:8000"
|
wcfg.ec.InitialCluster = "0=http://localhost:8000"
|
||||||
@ -566,11 +573,11 @@ func validateClusteringFlags(t *testing.T, cfg *config) {
|
|||||||
if cfg.ec.InitialClusterToken != wcfg.ec.InitialClusterToken {
|
if cfg.ec.InitialClusterToken != wcfg.ec.InitialClusterToken {
|
||||||
t.Errorf("initialClusterToken = %v, want %v", cfg.ec.InitialClusterToken, wcfg.ec.InitialClusterToken)
|
t.Errorf("initialClusterToken = %v, want %v", cfg.ec.InitialClusterToken, wcfg.ec.InitialClusterToken)
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(cfg.ec.APUrls, wcfg.ec.APUrls) {
|
if !reflect.DeepEqual(cfg.ec.AdvertisePeerUrls, wcfg.ec.AdvertisePeerUrls) {
|
||||||
t.Errorf("initial-advertise-peer-urls = %v, want %v", cfg.ec.APUrls, wcfg.ec.APUrls)
|
t.Errorf("initial-advertise-peer-urls = %v, want %v", cfg.ec.AdvertisePeerUrls, wcfg.ec.AdvertisePeerUrls)
|
||||||
}
|
}
|
||||||
if !reflect.DeepEqual(cfg.ec.ACUrls, wcfg.ec.ACUrls) {
|
if !reflect.DeepEqual(cfg.ec.AdvertiseClientUrls, wcfg.ec.AdvertiseClientUrls) {
|
||||||
t.Errorf("advertise-client-urls = %v, want %v", cfg.ec.ACUrls, wcfg.ec.ACUrls)
|
t.Errorf("advertise-client-urls = %v, want %v", cfg.ec.AdvertiseClientUrls, wcfg.ec.AdvertiseClientUrls)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -193,7 +193,7 @@ func startEtcdOrProxyV2(args []string) {
|
|||||||
if cfg.ec.InitialCluster == cfg.ec.InitialClusterFromName(cfg.ec.Name) {
|
if cfg.ec.InitialCluster == cfg.ec.InitialClusterFromName(cfg.ec.Name) {
|
||||||
lg.Warn("forgot to set --initial-cluster?")
|
lg.Warn("forgot to set --initial-cluster?")
|
||||||
}
|
}
|
||||||
if types.URLs(cfg.ec.APUrls).String() == embed.DefaultInitialAdvertisePeerURLs {
|
if types.URLs(cfg.ec.AdvertisePeerUrls).String() == embed.DefaultInitialAdvertisePeerURLs {
|
||||||
lg.Warn("forgot to set --initial-advertise-peer-urls?")
|
lg.Warn("forgot to set --initial-advertise-peer-urls?")
|
||||||
}
|
}
|
||||||
if cfg.ec.InitialCluster == cfg.ec.InitialClusterFromName(cfg.ec.Name) && len(cfg.ec.Durl) == 0 {
|
if cfg.ec.InitialCluster == cfg.ec.InitialClusterFromName(cfg.ec.Name) && len(cfg.ec.Durl) == 0 {
|
||||||
@ -276,7 +276,7 @@ func startProxy(cfg *config) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cfg.ec.Dir = filepath.Join(cfg.ec.Dir, "proxy")
|
cfg.ec.Dir = filepath.Join(cfg.ec.Dir, "proxy")
|
||||||
err = fileutil.TouchDirAll(cfg.ec.Dir)
|
err = fileutil.TouchDirAll(lg, cfg.ec.Dir)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
@ -389,11 +389,11 @@ func startProxy(cfg *config) error {
|
|||||||
|
|
||||||
// setup self signed certs when serving https
|
// setup self signed certs when serving https
|
||||||
cHosts, cTLS := []string{}, false
|
cHosts, cTLS := []string{}, false
|
||||||
for _, u := range cfg.ec.LCUrls {
|
for _, u := range cfg.ec.ListenClientUrls {
|
||||||
cHosts = append(cHosts, u.Host)
|
cHosts = append(cHosts, u.Host)
|
||||||
cTLS = cTLS || u.Scheme == "https"
|
cTLS = cTLS || u.Scheme == "https"
|
||||||
}
|
}
|
||||||
for _, u := range cfg.ec.ACUrls {
|
for _, u := range cfg.ec.AdvertiseClientUrls {
|
||||||
cHosts = append(cHosts, u.Host)
|
cHosts = append(cHosts, u.Host)
|
||||||
cTLS = cTLS || u.Scheme == "https"
|
cTLS = cTLS || u.Scheme == "https"
|
||||||
}
|
}
|
||||||
@ -406,7 +406,7 @@ func startProxy(cfg *config) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Start a proxy server goroutine for each listen address
|
// Start a proxy server goroutine for each listen address
|
||||||
for _, u := range cfg.ec.LCUrls {
|
for _, u := range cfg.ec.ListenClientUrls {
|
||||||
l, err := transport.NewListener(u.Host, u.Scheme, &listenerTLS)
|
l, err := transport.NewListener(u.Host, u.Scheme, &listenerTLS)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -31,6 +31,7 @@ import (
|
|||||||
|
|
||||||
pb "go.etcd.io/etcd/api/v3/etcdserverpb"
|
pb "go.etcd.io/etcd/api/v3/etcdserverpb"
|
||||||
"go.etcd.io/etcd/client/pkg/v3/logutil"
|
"go.etcd.io/etcd/client/pkg/v3/logutil"
|
||||||
|
"go.etcd.io/etcd/client/pkg/v3/tlsutil"
|
||||||
"go.etcd.io/etcd/client/pkg/v3/transport"
|
"go.etcd.io/etcd/client/pkg/v3/transport"
|
||||||
clientv3 "go.etcd.io/etcd/client/v3"
|
clientv3 "go.etcd.io/etcd/client/v3"
|
||||||
"go.etcd.io/etcd/client/v3/leasing"
|
"go.etcd.io/etcd/client/v3/leasing"
|
||||||
@ -41,12 +42,12 @@ import (
|
|||||||
"go.etcd.io/etcd/server/v3/etcdserver/api/v3election/v3electionpb"
|
"go.etcd.io/etcd/server/v3/etcdserver/api/v3election/v3electionpb"
|
||||||
"go.etcd.io/etcd/server/v3/etcdserver/api/v3lock/v3lockpb"
|
"go.etcd.io/etcd/server/v3/etcdserver/api/v3lock/v3lockpb"
|
||||||
"go.etcd.io/etcd/server/v3/proxy/grpcproxy"
|
"go.etcd.io/etcd/server/v3/proxy/grpcproxy"
|
||||||
"go.uber.org/zap/zapgrpc"
|
|
||||||
|
|
||||||
grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus"
|
grpc_prometheus "github.com/grpc-ecosystem/go-grpc-prometheus"
|
||||||
"github.com/soheilhy/cmux"
|
"github.com/soheilhy/cmux"
|
||||||
"github.com/spf13/cobra"
|
"github.com/spf13/cobra"
|
||||||
"go.uber.org/zap"
|
"go.uber.org/zap"
|
||||||
|
"go.uber.org/zap/zapgrpc"
|
||||||
"golang.org/x/net/http2"
|
"golang.org/x/net/http2"
|
||||||
"google.golang.org/grpc"
|
"google.golang.org/grpc"
|
||||||
"google.golang.org/grpc/grpclog"
|
"google.golang.org/grpc/grpclog"
|
||||||
@ -74,12 +75,13 @@ var (
|
|||||||
|
|
||||||
// tls for clients connecting to proxy
|
// tls for clients connecting to proxy
|
||||||
|
|
||||||
grpcProxyListenCA string
|
grpcProxyListenCA string
|
||||||
grpcProxyListenCert string
|
grpcProxyListenCert string
|
||||||
grpcProxyListenKey string
|
grpcProxyListenKey string
|
||||||
grpcProxyListenAutoTLS bool
|
grpcProxyListenCipherSuites []string
|
||||||
grpcProxyListenCRL string
|
grpcProxyListenAutoTLS bool
|
||||||
selfSignedCertValidity uint
|
grpcProxyListenCRL string
|
||||||
|
selfSignedCertValidity uint
|
||||||
|
|
||||||
grpcProxyAdvertiseClientURL string
|
grpcProxyAdvertiseClientURL string
|
||||||
grpcProxyResolverPrefix string
|
grpcProxyResolverPrefix string
|
||||||
@ -154,6 +156,7 @@ func newGRPCProxyStartCommand() *cobra.Command {
|
|||||||
cmd.Flags().StringVar(&grpcProxyListenCert, "cert-file", "", "identify secure connections to the proxy using this TLS certificate file")
|
cmd.Flags().StringVar(&grpcProxyListenCert, "cert-file", "", "identify secure connections to the proxy using this TLS certificate file")
|
||||||
cmd.Flags().StringVar(&grpcProxyListenKey, "key-file", "", "identify secure connections to the proxy using this TLS key file")
|
cmd.Flags().StringVar(&grpcProxyListenKey, "key-file", "", "identify secure connections to the proxy using this TLS key file")
|
||||||
cmd.Flags().StringVar(&grpcProxyListenCA, "trusted-ca-file", "", "verify certificates of TLS-enabled secure proxy using this CA bundle")
|
cmd.Flags().StringVar(&grpcProxyListenCA, "trusted-ca-file", "", "verify certificates of TLS-enabled secure proxy using this CA bundle")
|
||||||
|
cmd.Flags().StringSliceVar(&grpcProxyListenCipherSuites, "listen-cipher-suites", grpcProxyListenCipherSuites, "Comma-separated list of supported TLS cipher suites between client/proxy (empty will be auto-populated by Go).")
|
||||||
cmd.Flags().BoolVar(&grpcProxyListenAutoTLS, "auto-tls", false, "proxy TLS using generated certificates")
|
cmd.Flags().BoolVar(&grpcProxyListenAutoTLS, "auto-tls", false, "proxy TLS using generated certificates")
|
||||||
cmd.Flags().StringVar(&grpcProxyListenCRL, "client-crl-file", "", "proxy client certificate revocation list file.")
|
cmd.Flags().StringVar(&grpcProxyListenCRL, "client-crl-file", "", "proxy client certificate revocation list file.")
|
||||||
cmd.Flags().UintVar(&selfSignedCertValidity, "self-signed-cert-validity", 1, "The validity period of the proxy certificates, unit is year")
|
cmd.Flags().UintVar(&selfSignedCertValidity, "self-signed-cert-validity", 1, "The validity period of the proxy certificates, unit is year")
|
||||||
@ -187,21 +190,28 @@ func startGRPCProxy(cmd *cobra.Command, args []string) {
|
|||||||
// The proxy itself (ListenCert) can have not-empty CN.
|
// The proxy itself (ListenCert) can have not-empty CN.
|
||||||
// The empty CN is required for grpcProxyCert.
|
// The empty CN is required for grpcProxyCert.
|
||||||
// Please see https://github.com/etcd-io/etcd/issues/11970#issuecomment-687875315 for more context.
|
// Please see https://github.com/etcd-io/etcd/issues/11970#issuecomment-687875315 for more context.
|
||||||
tlsinfo := newTLS(grpcProxyListenCA, grpcProxyListenCert, grpcProxyListenKey, false)
|
tlsInfo := newTLS(grpcProxyListenCA, grpcProxyListenCert, grpcProxyListenKey, false)
|
||||||
|
if len(grpcProxyListenCipherSuites) > 0 {
|
||||||
if tlsinfo == nil && grpcProxyListenAutoTLS {
|
cs, err := tlsutil.GetCipherSuites(grpcProxyListenCipherSuites)
|
||||||
|
if err != nil {
|
||||||
|
log.Fatal(err)
|
||||||
|
}
|
||||||
|
tlsInfo.CipherSuites = cs
|
||||||
|
}
|
||||||
|
if tlsInfo == nil && grpcProxyListenAutoTLS {
|
||||||
host := []string{"https://" + grpcProxyListenAddr}
|
host := []string{"https://" + grpcProxyListenAddr}
|
||||||
dir := filepath.Join(grpcProxyDataDir, "fixtures", "proxy")
|
dir := filepath.Join(grpcProxyDataDir, "fixtures", "proxy")
|
||||||
autoTLS, err := transport.SelfCert(lg, dir, host, selfSignedCertValidity)
|
autoTLS, err := transport.SelfCert(lg, dir, host, selfSignedCertValidity)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
tlsinfo = &autoTLS
|
tlsInfo = &autoTLS
|
||||||
}
|
}
|
||||||
if tlsinfo != nil {
|
|
||||||
lg.Info("gRPC proxy server TLS", zap.String("tls-info", fmt.Sprintf("%+v", tlsinfo)))
|
if tlsInfo != nil {
|
||||||
|
lg.Info("gRPC proxy server TLS", zap.String("tls-info", fmt.Sprintf("%+v", tlsInfo)))
|
||||||
}
|
}
|
||||||
m := mustListenCMux(lg, tlsinfo)
|
m := mustListenCMux(lg, tlsInfo)
|
||||||
grpcl := m.Match(cmux.HTTP2())
|
grpcl := m.Match(cmux.HTTP2())
|
||||||
defer func() {
|
defer func() {
|
||||||
grpcl.Close()
|
grpcl.Close()
|
||||||
@ -214,11 +224,11 @@ func startGRPCProxy(cmd *cobra.Command, args []string) {
|
|||||||
// TODO: The mechanism should be refactored to use internal connection.
|
// TODO: The mechanism should be refactored to use internal connection.
|
||||||
var proxyClient *clientv3.Client
|
var proxyClient *clientv3.Client
|
||||||
if grpcProxyAdvertiseClientURL != "" {
|
if grpcProxyAdvertiseClientURL != "" {
|
||||||
proxyClient = mustNewProxyClient(lg, tlsinfo)
|
proxyClient = mustNewProxyClient(lg, tlsInfo)
|
||||||
}
|
}
|
||||||
httpClient := mustNewHTTPClient(lg)
|
httpClient := mustNewHTTPClient(lg)
|
||||||
|
|
||||||
srvhttp, httpl := mustHTTPListener(lg, m, tlsinfo, client, proxyClient)
|
srvhttp, httpl := mustHTTPListener(lg, m, tlsInfo, client, proxyClient)
|
||||||
|
|
||||||
if err := http2.ConfigureServer(srvhttp, &http2.Server{
|
if err := http2.ConfigureServer(srvhttp, &http2.Server{
|
||||||
MaxConcurrentStreams: maxConcurrentStreams,
|
MaxConcurrentStreams: maxConcurrentStreams,
|
||||||
@ -231,7 +241,7 @@ func startGRPCProxy(cmd *cobra.Command, args []string) {
|
|||||||
go func() { errc <- srvhttp.Serve(httpl) }()
|
go func() { errc <- srvhttp.Serve(httpl) }()
|
||||||
go func() { errc <- m.Serve() }()
|
go func() { errc <- m.Serve() }()
|
||||||
if len(grpcProxyMetricsListenAddr) > 0 {
|
if len(grpcProxyMetricsListenAddr) > 0 {
|
||||||
mhttpl := mustMetricsListener(lg, tlsinfo)
|
mhttpl := mustMetricsListener(lg, tlsInfo)
|
||||||
go func() {
|
go func() {
|
||||||
mux := http.NewServeMux()
|
mux := http.NewServeMux()
|
||||||
grpcproxy.HandleMetrics(mux, httpClient, client.Endpoints())
|
grpcproxy.HandleMetrics(mux, httpClient, client.Endpoints())
|
||||||
|
@ -63,7 +63,9 @@ Member:
|
|||||||
--listen-peer-urls 'http://localhost:2380'
|
--listen-peer-urls 'http://localhost:2380'
|
||||||
List of URLs to listen on for peer traffic.
|
List of URLs to listen on for peer traffic.
|
||||||
--listen-client-urls 'http://localhost:2379'
|
--listen-client-urls 'http://localhost:2379'
|
||||||
List of URLs to listen on for client traffic.
|
List of URLs to listen on for client grpc traffic and http as long as --listen-client-http-urls is not specified.
|
||||||
|
--listen-client-http-urls ''
|
||||||
|
List of URLs to listen on for http only client traffic. Enabling this flag removes http services from --listen-client-urls.
|
||||||
--max-snapshots '` + strconv.Itoa(embed.DefaultMaxSnapshots) + `'
|
--max-snapshots '` + strconv.Itoa(embed.DefaultMaxSnapshots) + `'
|
||||||
Maximum number of snapshot files to retain (0 is unlimited).
|
Maximum number of snapshot files to retain (0 is unlimited).
|
||||||
--max-wals '` + strconv.Itoa(embed.DefaultMaxWALs) + `'
|
--max-wals '` + strconv.Itoa(embed.DefaultMaxWALs) + `'
|
||||||
@ -99,7 +101,8 @@ Clustering:
|
|||||||
--initial-cluster 'default=http://localhost:2380'
|
--initial-cluster 'default=http://localhost:2380'
|
||||||
Initial cluster configuration for bootstrapping.
|
Initial cluster configuration for bootstrapping.
|
||||||
--initial-cluster-state 'new'
|
--initial-cluster-state 'new'
|
||||||
Initial cluster state ('new' or 'existing').
|
Initial cluster state ('new' when bootstrapping a new cluster or 'existing' when adding new members to an existing cluster).
|
||||||
|
After successful initialization (bootstrapping or adding), flag is ignored on restarts.
|
||||||
--initial-cluster-token 'etcd-cluster'
|
--initial-cluster-token 'etcd-cluster'
|
||||||
Initial cluster token for the etcd cluster during bootstrap.
|
Initial cluster token for the etcd cluster during bootstrap.
|
||||||
Specifying this can protect you from unintended cross-cluster interaction when running multiple clusters.
|
Specifying this can protect you from unintended cross-cluster interaction when running multiple clusters.
|
||||||
@ -174,6 +177,10 @@ Security:
|
|||||||
Comma-separated whitelist of origins for CORS, or cross-origin resource sharing, (empty or * means allow all).
|
Comma-separated whitelist of origins for CORS, or cross-origin resource sharing, (empty or * means allow all).
|
||||||
--host-whitelist '*'
|
--host-whitelist '*'
|
||||||
Acceptable hostnames from HTTP client requests, if server is not secure (empty or * means allow all).
|
Acceptable hostnames from HTTP client requests, if server is not secure (empty or * means allow all).
|
||||||
|
--tls-min-version 'TLS1.2'
|
||||||
|
Minimum TLS version supported by etcd. Possible values: TLS1.2, TLS1.3.
|
||||||
|
--tls-max-version ''
|
||||||
|
Maximum TLS version supported by etcd. Possible values: TLS1.2, TLS1.3 (empty will be auto-populated by Go).
|
||||||
|
|
||||||
Auth:
|
Auth:
|
||||||
--auth-token 'simple'
|
--auth-token 'simple'
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user