Compare commits

..

1 Commits

Author SHA1 Message Date
dependabot[bot]
44685ac824
build(deps): bump google.golang.org/grpc in /tools/mod
Bumps [google.golang.org/grpc](https://github.com/grpc/grpc-go) from 1.60.1 to 1.61.0.
- [Release notes](https://github.com/grpc/grpc-go/releases)
- [Commits](https://github.com/grpc/grpc-go/compare/v1.60.1...v1.61.0)

---
updated-dependencies:
- dependency-name: google.golang.org/grpc
  dependency-type: indirect
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-29 17:42:31 +00:00
837 changed files with 19517 additions and 33892 deletions

View File

@ -2,21 +2,23 @@
// README at: https://github.com/devcontainers/templates/tree/main/src/go
{
"name": "Go",
// Or use a Dockerfile or Docker Compose file. More info: https://containers.dev/guide/dockerfile
"image": "mcr.microsoft.com/devcontainers/go:1.24-bookworm",
"image": "mcr.microsoft.com/devcontainers/go:1.21-bookworm",
// Features to add to the dev container. More info: https://containers.dev/features.
"features": {
"ghcr.io/devcontainers/features/docker-in-docker:2": {},
"ghcr.io/devcontainers/features/github-cli:1": {},
"ghcr.io/devcontainers/features/kubectl-helm-minikube:1": {}
"ghcr.io/devcontainers/features/docker-in-docker:2": {},
"ghcr.io/devcontainers/features/github-cli:1": {},
"ghcr.io/devcontainers/features/kubectl-helm-minikube:1": {}
},
// Use 'forwardPorts' to make a list of ports inside the container available locally.
"forwardPorts": [
2379,
2380
],
"forwardPorts": [2379, 2380],
// Use 'postCreateCommand' to run commands after the container is created.
"postCreateCommand": "make build"
// Configure tool-specific properties.
// "customizations": {},
}
}

View File

@ -10,7 +10,7 @@ body:
label: Bug report criteria
description: Please confirm this bug report meets the following criteria.
options:
- label: This bug report is not security related, security issues should be disclosed privately via [etcd maintainers](mailto:etcd-maintainers@googlegroups.com).
- label: This bug report is not security related, security issues should be disclosed privately via security@etcd.io.
- label: This is not a support request or question, support requests or questions should be raised in the etcd [discussion forums](https://github.com/etcd-io/etcd/discussions).
- label: You have read the etcd [bug reporting guidelines](https://github.com/etcd-io/etcd/blob/main/Documentation/contributor-guide/reporting_bugs.md).
- label: Existing open issues along with etcd [frequently asked questions](https://etcd.io/docs/latest/faq) have been checked and this is not a duplicate.

View File

@ -0,0 +1,31 @@
---
name: Membership nomination
description: Nominate new etcd members
labels:
- area/community
body:
- type: textarea
id: feature
attributes:
label: Who would you like to nominate?
validations:
required: true
- id: requirements
type: checkboxes
attributes:
label: Requirements
options:
- label: I have reviewed the [community membership guidelines](https://github.com/etcd-io/etcd/blob/main/Documentation/contributor-guide/community-membership.md)
required: true
- label: The members are actively contributing to 1 or more etcd subprojects
required: true
- label: The members are being sponsored by two current reviewers or a current maintainer.
required: true
- type: textarea
id: rationale
attributes:
label: How do the new members meet the regular active contribution requirements?
validations:
required: true

View File

@ -8,7 +8,7 @@ body:
- type: textarea
id: workflows
attributes:
label: Which Github Action / Prow Jobs are flaking?
label: Which github workflows are flaking?
validations:
required: true
@ -22,7 +22,7 @@ body:
- type: input
id: link
attributes:
label: Github Action / Prow Job link
label: Github Action link
- type: textarea
id: reason

4
.github/OWNERS vendored
View File

@ -1,4 +0,0 @@
# See the OWNERS docs at https://go.k8s.io/owners
approvers:
- ivanvc # Ivan Valdes <ivan@vald.es>

View File

@ -18,21 +18,9 @@ updates:
schedule:
interval: weekly
allow:
- dependency-type: direct
- dependency-type: all
- package-ecosystem: docker
directory: /
schedule:
interval: weekly
- package-ecosystem: docker
directory: /
target-branch: "release-3.4"
schedule:
interval: monthly
- package-ecosystem: docker
directory: /
target-branch: "release-3.5"
schedule:
interval: monthly

View File

@ -1,4 +0,0 @@
# See the OWNERS docs at https://go.k8s.io/owners
labels:
- github_actions

67
.github/workflows/build.yaml vendored Normal file
View File

@ -0,0 +1,67 @@
---
name: Build
on: [push, pull_request]
permissions: read-all
jobs:
build:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
target:
- linux-amd64
- linux-386
- darwin-amd64
- darwin-arm64
- windows-amd64
- linux-arm
- linux-arm64
- linux-ppc64le
- linux-s390x
steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- id: goversion
run: echo "goversion=$(cat .go-version)" >> "$GITHUB_OUTPUT"
- uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0
with:
go-version: ${{ steps.goversion.outputs.goversion }}
- env:
TARGET: ${{ matrix.target }}
run: |
set -euo pipefail
echo "${TARGET}"
case "${TARGET}" in
linux-amd64)
GOOS=linux GOARCH=amd64 make build
;;
linux-386)
GOOS=linux GOARCH=386 make build
;;
darwin-amd64)
GOOS=darwin GOARCH=amd64 make build
;;
darwin-arm64)
GOOS=darwin GOARCH=arm64 make build
;;
windows-amd64)
GOOS=windows GOARCH=amd64 make build
;;
linux-arm)
GOOS=linux GOARCH=arm make build
;;
linux-arm64)
GOOS=linux GOARCH=arm64 make build
;;
linux-ppc64le)
GOOS=linux GOARCH=ppc64le make build
;;
linux-s390x)
GOOS=linux GOARCH=s390x make build
;;
*)
echo "Failed to find target"
exit 1
;;
esac

View File

@ -37,10 +37,10 @@ jobs:
language: ['go']
steps:
- name: Checkout repository
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@6bb031afdd8eb862ea3fc1848194185e076637e5 # v3.28.11
uses: github/codeql-action/init@0b21cf2492b6b02c465a3e5d7c473717ad7721ba # v3.23.1
with:
# If you wish to specify custom queries, you can do so here or in a config file.
# By default, queries listed here will override any specified in a config file.
@ -50,6 +50,6 @@ jobs:
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@6bb031afdd8eb862ea3fc1848194185e076637e5 # v3.28.11
uses: github/codeql-action/autobuild@0b21cf2492b6b02c465a3e5d7c473717ad7721ba # v3.23.1
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@6bb031afdd8eb862ea3fc1848194185e076637e5 # v3.28.11
uses: github/codeql-action/analyze@0b21cf2492b6b02c465a3e5d7c473717ad7721ba # v3.23.1

18
.github/workflows/contrib.yaml vendored Normal file
View File

@ -0,0 +1,18 @@
---
name: Test contrib/mixin
on: [push, pull_request]
permissions: read-all
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- id: goversion
run: echo "goversion=$(cat .go-version)" >> "$GITHUB_OUTPUT"
- uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0
with:
go-version: ${{ steps.goversion.outputs.goversion }}
- run: |
set -euo pipefail
make -C contrib/mixin tools test

32
.github/workflows/coverage.yaml vendored Normal file
View File

@ -0,0 +1,32 @@
---
name: Coverage
on: [push]
permissions: read-all
jobs:
coverage:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
target:
- linux-amd64-coverage
steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- id: goversion
run: echo "goversion=$(cat .go-version)" >> "$GITHUB_OUTPUT"
- uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0
with:
go-version: ${{ steps.goversion.outputs.goversion }}
- env:
TARGET: ${{ matrix.target }}
run: |
mkdir "${TARGET}"
case "${TARGET}" in
linux-amd64-coverage)
GOARCH=amd64 ./scripts/codecov_upload.sh
;;
*)
echo "Failed to find target"
exit 1
;;
esac

37
.github/workflows/e2e-arm64.yaml vendored Normal file
View File

@ -0,0 +1,37 @@
---
name: E2E-Arm64
on: [push, pull_request]
permissions: read-all
jobs:
test:
# this is to prevent the job to run at forked projects
if: github.repository == 'etcd-io/etcd'
runs-on: actuated-arm64-8cpu-8gb
strategy:
fail-fast: false
matrix:
target:
- linux-arm64-e2e
steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- id: goversion
run: echo "goversion=$(cat .go-version)" >> "$GITHUB_OUTPUT"
- uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0
with:
go-version: ${{ steps.goversion.outputs.goversion }}
- env:
TARGET: ${{ matrix.target }}
run: |
set -euo pipefail
go clean -testcache
echo "${TARGET}"
case "${TARGET}" in
linux-arm64-e2e)
GOOS=linux GOARCH=arm64 CPU=4 EXPECT_DEBUG=true make test-e2e-release
;;
*)
echo "Failed to find target"
exit 1
;;
esac

40
.github/workflows/e2e.yaml vendored Normal file
View File

@ -0,0 +1,40 @@
---
name: E2E
on: [push, pull_request]
permissions: read-all
jobs:
test:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
target:
- linux-amd64-e2e
- linux-386-e2e
steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- id: goversion
run: echo "goversion=$(cat .go-version)" >> "$GITHUB_OUTPUT"
- uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0
with:
go-version: ${{ steps.goversion.outputs.goversion }}
- env:
TARGET: ${{ matrix.target }}
run: |
set -euo pipefail
go clean -testcache
echo "${TARGET}"
case "${TARGET}" in
linux-amd64-e2e)
make gofail-enable
VERBOSE=1 GOOS=linux GOARCH=amd64 CPU=4 EXPECT_DEBUG=true make test-e2e-release
;;
linux-386-e2e)
VERBOSE=1 GOOS=linux GOARCH=386 CPU=4 EXPECT_DEBUG=true make test-e2e
;;
*)
echo "Failed to find target"
exit 1
;;
esac

26
.github/workflows/fuzzing.yaml vendored Normal file
View File

@ -0,0 +1,26 @@
---
name: Fuzzing v3rpc
on: [push, pull_request]
permissions: read-all
jobs:
fuzzing:
runs-on: ubuntu-latest
strategy:
fail-fast: false
env:
TARGET_PATH: ./server/etcdserver/api/v3rpc
steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- id: goversion
run: echo "goversion=$(cat .go-version)" >> "$GITHUB_OUTPUT"
- uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0
with:
go-version: ${{ steps.goversion.outputs.goversion }}
- run: |
set -euo pipefail
GOARCH=amd64 CPU=4 make fuzz
- uses: actions/upload-artifact@694cdabd8bdb0f10b2cea11669e1bf5453eed0a6 # v4.2.0
if: failure()
with:
path: "${{env.TARGET_PATH}}/testdata/fuzz/**/*"

View File

@ -1,6 +1,5 @@
---
name: Approve GitHub Workflows
permissions: read-all
on:
pull_request_target:

19
.github/workflows/govuln.yaml vendored Normal file
View File

@ -0,0 +1,19 @@
---
name: Go Vulnerability Checker
on: [push, pull_request]
permissions: read-all
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- id: goversion
run: echo "goversion=$(cat .go-version)" >> "$GITHUB_OUTPUT"
- uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0
with:
go-version: ${{ steps.goversion.outputs.goversion }}
- run: date
- run: |
set -euo pipefail
go install golang.org/x/vuln/cmd/govulncheck@latest && govulncheck ./...

38
.github/workflows/grpcproxy.yaml vendored Normal file
View File

@ -0,0 +1,38 @@
---
name: grpcProxy-tests
on: [push, pull_request]
permissions: read-all
jobs:
test:
runs-on: ubuntu-latest
strategy:
fail-fast: false
matrix:
target:
- linux-amd64-grpcproxy-integration
- linux-amd64-grpcproxy-e2e
steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- id: goversion
run: echo "goversion=$(cat .go-version)" >> "$GITHUB_OUTPUT"
- uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0
with:
go-version: ${{ steps.goversion.outputs.goversion }}
- env:
TARGET: ${{ matrix.target }}
run: |
set -euo pipefail
echo "${TARGET}"
case "${TARGET}" in
linux-amd64-grpcproxy-integration)
GOOS=linux GOARCH=amd64 CPU=4 make test-grpcproxy-integration
;;
linux-amd64-grpcproxy-e2e)
GOOS=linux GOARCH=amd64 CPU=4 make test-grpcproxy-e2e
;;
*)
echo "Failed to find target"
exit 1
;;
esac

View File

@ -0,0 +1,23 @@
---
name: Measure Test Flakiness
on:
schedule:
- cron: "0 0 * * 0" # run every Sunday at midnight
permissions: read-all
jobs:
measure-test-flakiness:
name: Measure Test Flakiness
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
./scripts/measure-test-flakiness.sh
make bin/etcd-test-analyzer
bin/etcd-test-analyzer run -token $GITHUB_TOKEN -max-age=168h -workflow Tests -branch main

View File

@ -1,26 +0,0 @@
---
name: Measure TestGrid Flakiness
on:
schedule:
- cron: "0 0 * * *" # run every day at midnight
permissions: read-all
jobs:
measure-testgrid-flakiness:
name: Measure TestGrid Flakiness
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
- id: goversion
run: echo "goversion=$(cat .go-version)" >> "$GITHUB_OUTPUT"
- uses: actions/setup-go@f111f3307d8850f501ac008e886eec1fd1932a34 # v5.3.0
with:
go-version: ${{ steps.goversion.outputs.goversion }}
- env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
set -euo pipefail
./scripts/measure-testgrid-flakiness.sh

34
.github/workflows/release.yaml vendored Normal file
View File

@ -0,0 +1,34 @@
---
name: Release
on: [push, pull_request]
permissions: read-all
jobs:
main:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- id: goversion
run: echo "goversion=$(cat .go-version)" >> "$GITHUB_OUTPUT"
- uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0
with:
go-version: ${{ steps.goversion.outputs.goversion }}
- name: release
run: |
set -euo pipefail
git config --global user.email "github-action@etcd.io"
git config --global user.name "Github Action"
gpg --batch --gen-key <<EOF
%no-protection
Key-Type: 1
Key-Length: 2048
Subkey-Type: 1
Subkey-Length: 2048
Name-Real: Github Action
Name-Email: github-action@etcd.io
Expire-Date: 0
EOF
DRY_RUN=true ./scripts/release.sh --no-upload --no-docker-push --in-place 3.6.99
- name: test-image
run: |
VERSION=3.6.99 ./scripts/test_images.sh

View File

@ -0,0 +1,64 @@
---
name: Robustness Nightly
permissions: read-all
on:
# schedules always run against the main branch, hence we have to create separate jobs
# with individual checkout actions for each of the active release branches
schedule:
- cron: '25 9 * * *' # runs every day at 09:25 UTC
# workflow_dispatch enables manual testing of this job by maintainers
workflow_dispatch:
jobs:
main:
# GHA has a maximum amount of 6h execution time, we try to get done within 3h
uses: ./.github/workflows/robustness-template.yaml
with:
etcdBranch: main
count: 150
testTimeout: 200m
artifactName: main
runs-on: "['ubuntu-latest-8-cores']"
scenario: TestRobustnessExploratory
lazyfsEnabled: true
main-arm64:
uses: ./.github/workflows/robustness-template.yaml
with:
etcdBranch: main
count: 150
testTimeout: 200m
artifactName: main-arm64
runs-on: "['actuated-arm64-8cpu-8gb']"
scenario: TestRobustnessExploratory
lazyfsEnabled: false
release-35:
uses: ./.github/workflows/robustness-template.yaml
with:
etcdBranch: release-3.5
count: 150
testTimeout: 200m
artifactName: release-35
runs-on: "['ubuntu-latest-8-cores']"
scenario: TestRobustnessExploratory
lazyfsEnabled: true
release-35-arm64:
uses: ./.github/workflows/robustness-template.yaml
with:
etcdBranch: release-3.5
count: 150
testTimeout: 200m
artifactName: release-35-arm64
runs-on: "['actuated-arm64-8cpu-8gb']"
scenario: TestRobustnessExploratory
lazyfsEnabled: false
release-34:
uses: ./.github/workflows/robustness-template.yaml
with:
etcdBranch: release-3.4
count: 150
testTimeout: 200m
artifactName: release-34
runs-on: "['ubuntu-latest-8-cores']"
scenario: TestRobustnessExploratory
lazyfsEnabled: true

View File

@ -0,0 +1,78 @@
---
name: Reusable Robustness Workflow
on:
workflow_call:
inputs:
etcdBranch:
required: true
type: string
count:
required: true
type: number
testTimeout:
required: false
type: string
default: '30m'
artifactName:
required: true
type: string
runs-on:
required: false
type: string
default: "['ubuntu-latest']"
scenario:
required: true
type: string
lazyfsEnabled:
required: true
type: boolean
permissions: read-all
jobs:
test:
timeout-minutes: 210
runs-on: ${{ fromJson(inputs.runs-on) }}
steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- id: goversion
run: echo "goversion=$(cat .go-version)" >> "$GITHUB_OUTPUT"
- uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0
with:
go-version: ${{ steps.goversion.outputs.goversion }}
- name: install-lazyfs
if: ${{ inputs.lazyfsEnabled }}
run: |
sudo apt update && sudo apt-get --yes install cmake libfuse3-dev libfuse3-3 fuse3
sudo sed -i 's/#user_allow_other/user_allow_other/g' /etc/fuse.conf
make install-lazyfs
- name: test-robustness
env:
ETCD_BRANCH: "${{ inputs.etcdBranch }}"
run: |
set -euo pipefail
go clean -testcache
# Use --failfast to avoid overriding report generated by failed test
GO_TEST_FLAGS="-v --count ${{ inputs.count }} --timeout ${{ inputs.testTimeout }} --failfast --run ${{ inputs.scenario }}"
case "${ETCD_BRANCH}" in
release-3.5)
EXPECT_DEBUG=true GO_TEST_FLAGS=${GO_TEST_FLAGS} RESULTS_DIR=/tmp/results make test-robustness-release-3.5
;;
release-3.4)
EXPECT_DEBUG=true GO_TEST_FLAGS=${GO_TEST_FLAGS} RESULTS_DIR=/tmp/results make test-robustness-release-3.4
;;
main)
make gofail-enable
make build
EXPECT_DEBUG=true GO_TEST_FLAGS=${GO_TEST_FLAGS} RESULTS_DIR=/tmp/results make test-robustness
;;
*)
echo "Failed to find target ${ETCD_BRANCH}"
exit 1
;;
esac
- uses: actions/upload-artifact@694cdabd8bdb0f10b2cea11669e1bf5453eed0a6 # v4.2.0
if: always()
with:
name: ${{ inputs.artifactName }}
path: /tmp/results/*

25
.github/workflows/robustness.yaml vendored Normal file
View File

@ -0,0 +1,25 @@
---
name: Robustness
on: [push, pull_request]
permissions: read-all
jobs:
main:
uses: ./.github/workflows/robustness-template.yaml
with:
etcdBranch: main
count: 12
testTimeout: 30m
artifactName: main
runs-on: "['ubuntu-latest-8-cores']"
scenario: TestRobustness
lazyfsEnabled: true
main-arm64:
uses: ./.github/workflows/robustness-template.yaml
with:
etcdBranch: main
count: 12
testTimeout: 30m
artifactName: main-arm64
runs-on: "['actuated-arm64-8cpu-8gb']"
scenario: TestRobustness
lazyfsEnabled: false

View File

@ -23,12 +23,12 @@ jobs:
steps:
- name: "Checkout code"
uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
with:
persist-credentials: false
- name: "Run analysis"
uses: ossf/scorecard-action@f49aabe0b5af0936a0987cfb85d86b75731b0186 # v2.4.1
uses: ossf/scorecard-action@0864cf19026789058feabb7e87baa5f140aac736 # v2.3.1
with:
results_file: results.sarif
results_format: sarif
@ -42,7 +42,7 @@ jobs:
# Upload the results as artifacts (optional). Commenting out will disable uploads of run results in SARIF
# format to the repository Actions tab.
- name: "Upload artifact"
uses: actions/upload-artifact@4cec3d8aa04e39d1a68397de0c4cd6fb9dce8ec1 # v4.6.1
uses: actions/upload-artifact@694cdabd8bdb0f10b2cea11669e1bf5453eed0a6 # v4.2.0
with:
name: SARIF file
path: results.sarif
@ -50,6 +50,6 @@ jobs:
# Upload the results to GitHub's code scanning dashboard.
- name: "Upload to code-scanning"
uses: github/codeql-action/upload-sarif@6bb031afdd8eb862ea3fc1848194185e076637e5 # v3.28.11
uses: github/codeql-action/upload-sarif@0b21cf2492b6b02c465a3e5d7c473717ad7721ba # v3.23.1
with:
sarif_file: results.sarif

51
.github/workflows/static-analysis.yaml vendored Normal file
View File

@ -0,0 +1,51 @@
---
name: Static Analysis
on: [push, pull_request]
permissions: read-all
jobs:
run:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- id: goversion
run: echo "goversion=$(cat .go-version)" >> "$GITHUB_OUTPUT"
- uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0
with:
go-version: ${{ steps.goversion.outputs.goversion }}
- id: golangci_lint_version
run: echo "golangci_lint_version=$(cd tools/mod && go list -m -f {{.Version}} github.com/golangci/golangci-lint)" >> "$GITHUB_OUTPUT"
- name: golangci-lint
uses: golangci/golangci-lint-action@3a919529898de77ec3da873e3063ca4b10e7f5cc # v3.7.0
with:
version: ${{ steps.golangci_lint_version.outputs.golangci_lint_version }}
args: --config tools/.golangci.yaml
- name: protoc
uses: arduino/setup-protoc@149f6c87b92550901b26acd1632e11c3662e381f # v1.3.0
with:
version: '3.20.3'
repo-token: ${{ secrets.GITHUB_TOKEN }}
- uses: actions-rs/toolchain@v1
with:
toolchain: stable
- run: |
set -euo pipefail
cargo install marker --version 0.9.0
- run: |
set -euo pipefail
make verify
- run: |
set -euo pipefail
make fix
DIFF=$(git status --porcelain)
if [ -n "$DIFF" ]; then
echo "These files were modified:"
echo
echo "$DIFF"
echo
exit 1
fi

73
.github/workflows/tests-template.yaml vendored Normal file
View File

@ -0,0 +1,73 @@
---
name: Reusable Tests Workflow
on:
workflow_call:
inputs:
arch:
required: true
type: string
runs-on:
required: true
type: string
permissions: read-all
jobs:
test:
runs-on: ${{ inputs.runs-on }}
# this is to prevent arm64 jobs from running at forked projects
if: inputs.arch == 'amd64' || github.repository == 'etcd-io/etcd'
strategy:
fail-fast: false
matrix:
target:
- linux-${{ inputs.arch }}-integration-1-cpu
- linux-${{ inputs.arch }}-integration-2-cpu
- linux-${{ inputs.arch }}-integration-4-cpu
- linux-${{ inputs.arch }}-unit-4-cpu
- linux-386-unit-1-cpu
steps:
- uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
- id: goversion
run: echo "goversion=$(cat .go-version)" >> "$GITHUB_OUTPUT"
- uses: actions/setup-go@0c52d547c9bc32b1aa3301fd7a9cb496313a4491 # v5.0.0
with:
go-version: ${{ steps.goversion.outputs.goversion }}
- env:
TARGET: ${{ matrix.target }}
run: |
set -euo pipefail
go clean -testcache
mkdir "${TARGET}"
export JUNIT_REPORT_DIR=$(realpath ${TARGET})
case "${TARGET}" in
linux-${{ inputs.arch }}-integration-1-cpu)
make gofail-enable
GOOS=linux GOARCH=${{ inputs.arch }} CPU=1 make test-integration
;;
linux-${{ inputs.arch }}-integration-2-cpu)
make gofail-enable
GOOS=linux GOARCH=${{ inputs.arch }} CPU=2 make test-integration
;;
linux-${{ inputs.arch }}-integration-4-cpu)
make gofail-enable
GOOS=linux GOARCH=${{ inputs.arch }} CPU=4 make test-integration
;;
linux-${{ inputs.arch }}-unit-4-cpu)
GOOS=linux GOARCH=${{ inputs.arch }} CPU=4 GO_TEST_FLAGS='-p=2' make test-unit
;;
linux-386-unit-1-cpu)
# skip running single-threaded 386 unit tests only if arch is arm64
if [ "${{ inputs.arch }}" == "arm64" ]; then exit; fi
GOOS=linux GOARCH=386 CPU=1 GO_TEST_FLAGS='-p=4' make test-unit
;;
*)
echo "Failed to find target"
exit 1
;;
esac
- uses: actions/upload-artifact@694cdabd8bdb0f10b2cea11669e1bf5453eed0a6 # v4.2.0
if: always()
with:
name: "${{ matrix.target }}"
path: ./**/junit_*.xml

15
.github/workflows/tests.yaml vendored Normal file
View File

@ -0,0 +1,15 @@
---
name: Tests
on: [push, pull_request]
permissions: read-all
jobs:
amd64:
uses: ./.github/workflows/tests-template.yaml
with:
arch: amd64
runs-on: ubuntu-latest
arm64:
uses: ./.github/workflows/tests-template.yaml
with:
arch: arm64
runs-on: actuated-arm64-8cpu-8gb

View File

@ -1,44 +0,0 @@
---
name: Verify released binary assets
permissions: read-all
on:
release:
types: [published]
jobs:
verify-assets:
name: Verify released binary assets
runs-on: ubuntu-latest
steps:
- name: Verify binary assets
env:
GH_TOKEN: ${{ github.token }}
RELEASE: ${{ github.event.release.tag_name }}
REPOSITORY: ${{ github.repository }}
run: |
mkdir github-assets
pushd github-assets
gh --repo "${REPOSITORY}" release download "${RELEASE}"
test_assets() {
if [ "$(wc -l <SHA256SUMS)" != "$(find . -name 'etcd-*' | wc -l)" ]; then
echo "::error:: Invalid number of assets"
exit 1
fi
sha256sum -c SHA256SUMS
}
test_assets
popd
mkdir google-assets
for file in github-assets/*; do
file=$(basename "${file}")
echo "Downloading ${file} from Google..."
curl "https://storage.googleapis.com/etcd/${RELEASE}/${file}" \
--fail \
-o "google-assets/${file}"
done
pushd google-assets
test_assets

View File

@ -1 +1 @@
1.24.1
1.21.6

View File

@ -212,7 +212,7 @@ At [Branch][branch], we use kubernetes heavily as our core microservice platform
## Baidu Waimai
- *Application*: SkyDNS, Kubernetes, UDC, CMDB and other distributed systems
- *Launched*: April 2016
- *Launched*: April. 2016
- *Cluster Size*: 3 clusters of 5 members
- *Order of Data Size*: several gigabytes
- *Operator*: Baidu Waimai Operations Department
@ -248,13 +248,3 @@ At [Branch][branch], we use kubernetes heavily as our core microservice platform
- *Operator*: Trasnwarp Operating System
- *Environment*: Bare Metal, Container
- *Backups*: backup scripts
## Cyberfusion
- *Application*: cluster configuration management
- *Launched*: February 2023
- *Cluster Size*: single cluster, 3 nodes
- *Order of Data Size*: kilobytes
- *Operator*: Cyberfusion
- *Environment*: Debian on VMs
- *Backups*: periodic `etcdctl snapshot save` + rotation in cron. More about our setup: https://cyberfusion.io/articles/building-hosting-infrastructure-in-2024-configuration-management-part-1

View File

@ -4,118 +4,13 @@ Previous change logs can be found at [CHANGELOG-3.3](https://github.com/etcd-io/
<hr>
## v3.4.37 (TBC)
### Dependencies
- Bump [golang.org/x/net to v0.36.0 to address CVE-2025-22870](https://github.com/etcd-io/etcd/pull/19529).
- Compile binaries using [go 1.23.7](https://github.com/etcd-io/etcd/pull/19533)
<hr>
## v3.4.36 (2025-02-25)
### etcd server
- [Avoid deadlock in etcd.Close when stopping during bootstrapping](https://github.com/etcd-io/etcd/pull/19166)
- Fix [missing delete event on watch opened on same revision as compaction request](https://github.com/etcd-io/etcd/pull/19251)
### Package `clientv3`
- Fix [runtime panic that occurs when KeepAlive is called with a Context implemented by an uncomparable type](https://github.com/etcd-io/etcd/pull/18936)
### Dependencies
- Compile binaries using [go 1.23.6](https://github.com/etcd-io/etcd/pull/19429)
- Bump golang.org/x/crypto to v0.35.0 to address [CVE-2024-45337](https://github.com/etcd-io/etcd/pull/19197) and [CVE-2025-22869](https://github.com/etcd-io/etcd/pull/19477).
- Bump golang.org/x/net to v0.34.0 to address [CVE-2024-45338](https://github.com/etcd-io/etcd/pull/19197).
<hr>
## v3.4.35 (2024-11-12)
### etcd server
- Fix [watchserver related goroutine leakage](https://github.com/etcd-io/etcd/pull/18785)
- Fix [panicking occurred due to improper error handling during defragmentation](https://github.com/etcd-io/etcd/pull/18843)
- Fix [close temp file(s) in case an error happens during defragmentation](https://github.com/etcd-io/etcd/pull/18855)
### Dependencies
- Compile binaries using [go 1.22.9](https://github.com/etcd-io/etcd/pull/18850).
<hr>
## v3.4.34 (2024-09-11)
### etcd server
- Fix [performance regression issue caused by the `ensureLeadership` in lease renew](https://github.com/etcd-io/etcd/pull/18440).
- [Keep the tombstone during compaction if it happens to be the compaction revision](https://github.com/etcd-io/etcd/pull/18475)
### Package clientv3
- [Print gRPC metadata in guaranteed order using the official go fmt pkg](https://github.com/etcd-io/etcd/pull/18311).
### Dependencies
- Compile binaries using [go 1.22.7](https://github.com/etcd-io/etcd/pull/18549).
- Upgrade [bbolt to 1.3.11](https://github.com/etcd-io/etcd/pull/18488).
<hr>
## v3.4.33 (2024-06-13)
### etcd grpc-proxy
- Fix [Memberlist results not updated when proxy node down](https://github.com/etcd-io/etcd/pull/17896).
### Dependencies
- Compile binaries using go [1.21.11](https://github.com/etcd-io/etcd/pull/18130).
- Upgrade [bbolt to 1.3.10](https://github.com/etcd-io/etcd/pull/17945).
<hr>
## v3.4.32 (2024-04-25)
### etcd server
- Fix [LeaseTimeToLive returns error if leader changed](https://github.com/etcd-io/etcd/pull/17705).
- Fix [ignore raft messages if member id mismatch](https://github.com/etcd-io/etcd/pull/17814).
- Update [the compaction log when bootstrap](https://github.com/etcd-io/etcd/pull/17831).
- [Allow new server to join 3.5 cluster if `next-cluster-version-compatible=true`](https://github.com/etcd-io/etcd/pull/17665)
- [Allow updating the cluster version when downgrading from 3.5](https://github.com/etcd-io/etcd/pull/17821).
- Fix [Revision decreasing after panic during compaction](https://github.com/etcd-io/etcd/pull/17864)
### Package `clientv3`
- Add [requests retry when receiving ErrGPRCNotSupportedForLearner and endpoints > 1](https://github.com/etcd-io/etcd/pull/17692).
- Fix [initialization for epMu in client context](https://github.com/etcd-io/etcd/pull/17714).
### Dependencies
- Compile binaries using [go 1.21.9](https://github.com/etcd-io/etcd/pull/17709).
<hr>
## v3.4.31 (2024-03-21)
### etcd server
- Add [mvcc: print backend database size and size in use in compaction logs](https://github.com/etcd-io/etcd/pull/17436).
- Fix leases wrongly revoked by the leader by [ignoring old leader's leases revoking request](https://github.com/etcd-io/etcd/pull/17465).
- Fix [no progress notification being sent for watch that doesn't get any events](https://github.com/etcd-io/etcd/pull/17567).
- Fix [watch event loss after compaction](https://github.com/etcd-io/etcd/pull/17610).
- Add `next-cluster-version-compatible` flag to [allow downgrade from 3.5](https://github.com/etcd-io/etcd/pull/17330).
### Package `clientv3`
- Add [client backoff and retry config options](https://github.com/etcd-io/etcd/pull/17369).
### Dependencies
- Upgrade [bbolt to 1.3.9](https://github.com/etcd-io/etcd/pull/17484).
- Compile binaries using [go 1.21.8](https://github.com/etcd-io/etcd/pull/17538).
- Upgrade [google.golang.org/protobuf to v1.33.0 to address CVE-2024-24786](https://github.com/etcd-io/etcd/pull/17554).
- Upgrade github.com/sirupsen/logrus to v1.9.3 to address [PRISMA-2023-0056](https://github.com/etcd-io/etcd/pull/17580).
### Others
- [Make CGO_ENABLED configurable](https://github.com/etcd-io/etcd/pull/17422).
<hr>
## v3.4.30 (2024-01-31)
## v3.4.30 (tbd)
### etcd server
- Fix [nil pointer panicking due to using the wrong log library](https://github.com/etcd-io/etcd/pull/17270)
### Dependencies
- Compile binaries using go [1.20.13](https://github.com/etcd-io/etcd/pull/17276).
- Upgrade [golang.org/x/crypto to v0.17+ to address CVE-2023-48795](https://github.com/etcd-io/etcd/pull/17347).
<hr>

View File

@ -1,180 +1,22 @@
Previous change logs can be found at [CHANGELOG-3.4](https://github.com/etcd-io/etcd/blob/main/CHANGELOG/CHANGELOG-3.4.md).
<hr>
## v3.5.21 (TBC)
<hr>
## v3.5.20 (2025-03-21)
## v3.5.12 (tbd)
### etcd server
- Fix [grpcproxy can get stuck in and endless loop causing high CPU usage](https://github.com/etcd-io/etcd/pull/19562)
- Fix [the learner promotion changes not being persisted into v3store (bbolt)](https://github.com/etcd-io/etcd/pull/19563)
- Update [the RLock in Demoted method for read-only access to expiry](https://github.com/etcd-io/etcd/pull/19445)
### etcdctl
- Fix [command `etcdctl member promote` doesn't support json output](https://github.com/etcd-io/etcd/pull/19602)
<hr>
## v3.5.19 (2025-03-05)
### etcd server
- Backport [add learner status check to readyz endpoint](https://github.com/etcd-io/etcd/pull/19280).
- Fix [performance regression due to uncertain compaction sleep interval](https://github.com/etcd-io/etcd/pull/19405).
### `tools/benchmark`
- Backport [add mixed read-write performance evaluation scripts](https://github.com/etcd-io/etcd/pull/19275).
### Dependencies
- Compile binaries using [go 1.23.7](https://github.com/etcd-io/etcd/pull/19528).
- Bump [golang.org/x/crypto to v0.35.0 to address CVE-2025-22869](https://github.com/etcd-io/etcd/pull/19478).
- Bump [golang.org/x/net to v0.36.0 to address CVE-2025-22870](https://github.com/etcd-io/etcd/pull/19530).
<hr>
## v3.5.18 (2025-01-24)
### etcd server
- Avoid deadlock in etcd.Close when stopping during bootstrapping, see https://github.com/etcd-io/etcd/pull/19167 and https://github.com/etcd-io/etcd/pull/19258.
- [Print warning messages if any of the deprecated v2store related flags is set](https://github.com/etcd-io/etcd/pull/18999)
- Fix [missing delete event on watch opened on same revision as compaction request](https://github.com/etcd-io/etcd/pull/19249)
### Package `clientv3`
- Fix [runtime panic that occurs when KeepAlive is called with a Context implemented by an uncomparable type](https://github.com/etcd-io/etcd/pull/18937)
### etcdutl v3
- Add [command `etcdutl check v2store` to offline check whether v2store contains custom content](https://github.com/etcd-io/etcd/pull/19113)
### etcd grpc-proxy
- Add [`tls min/max version to grpc proxy`](https://github.com/etcd-io/etcd/pull/18829) to support setting TLS min and max version.
### Dependencies
- Bump [golang-jwt/jwt to 4.5.1 to address GO-2024-3250](https://github.com/etcd-io/etcd/pull/18899).
- Compile binaries using [go 1.22.11](https://github.com/etcd-io/etcd/pull/19211).
- Bump [golang.org/x/crypto to 0.32.0 to address CVE-2024-45337](https://github.com/etcd-io/etcd/pull/19154).
- Bump [golang.org/x/net to 0.34.0 to address CVE-2024-45338](https://github.com/etcd-io/etcd/pull/19158).
<hr>
## v3.5.17 (2024-11-12)
### etcd server
- Fix [watchserver related goroutine leakage](https://github.com/etcd-io/etcd/pull/18784)
- Fix [risk of a partial write txn being applied](https://github.com/etcd-io/etcd/pull/18799)
- Fix [panicking occurred due to improper error handling during defragmentation](https://github.com/etcd-io/etcd/pull/18842)
- Fix [close temp file(s) in case an error happens during defragmentation](https://github.com/etcd-io/etcd/pull/18854)
### Dependencies
- Compile binaries using [go 1.22.9](https://github.com/etcd-io/etcd/pull/18849).
<hr>
## v3.5.16 (2024-09-10)
### etcd server
- Fix [performance regression issue caused by the `ensureLeadership` in lease renew](https://github.com/etcd-io/etcd/pull/18439).
- [Keep the tombstone during compaction if it happens to be the compaction revision](https://github.com/etcd-io/etcd/pull/18474)
- Add [`etcd --experimental-compaction-sleep-interval`](https://github.com/etcd-io/etcd/pull/18514) flag to control the sleep interval between each compaction batch.
### Dependencies
- Compile binaries using [go 1.22.7](https://github.com/etcd-io/etcd/pull/18550).
- Upgrade [bbolt to v1.3.11](https://github.com/etcd-io/etcd/pull/18489).
<hr>
## v3.5.15 (2024-07-19)
### etcd server
- Fix [add prometheus metric registration for metric `etcd_disk_wal_write_duration_seconds`](https://github.com/etcd-io/etcd/pull/18174).
- Add [Support multiple values for allowed client and peer TLS identities](https://github.com/etcd-io/etcd/pull/18160)
- Fix [noisy logs from simple auth token expiration by reducing log level to debug](https://github.com/etcd-io/etcd/pull/18245)
- [Differentiate the warning message for rejected client and peer connections](https://github.com/etcd-io/etcd/pull/18319)
### Package clientv3
- [Print gRPC metadata in guaranteed order using the official go fmt pkg](https://github.com/etcd-io/etcd/pull/18312).
### Dependencies
- Compile binaries using [go 1.21.12](https://github.com/etcd-io/etcd/pull/18271).
- [Fully address CVE-2023-45288 and fix govulncheck CI check](https://github.com/etcd-io/etcd/pull/18170)
## v3.5.14 (2024-05-29)
### etcd server
- Fix [LeaseTimeToLive returns error if leader changed](https://github.com/etcd-io/etcd/pull/17704).
- Add [metrics `etcd_disk_wal_write_duration_seconds`](https://github.com/etcd-io/etcd/pull/17616).
- Fix [ignore raft messages if member id mismatch](https://github.com/etcd-io/etcd/pull/17813).
- Update [the compaction log when bootstrap](https://github.com/etcd-io/etcd/pull/17830).
- Fix [Revision decreasing after panic during compaction](https://github.com/etcd-io/etcd/pull/17865)
- Add [`etcd --experimental-stop-grpc-service-on-defrag`](https://github.com/etcd-io/etcd/pull/17914) to enable client failover on defrag.
- Add [support for `AllowedCN` and `AllowedHostname` through config file](https://github.com/etcd-io/etcd/pull/18063)
### etcdutl v3
- Add [`--initial-memory-map-size` to `snapshot restore` to avoid memory allocation issues](https://github.com/etcd-io/etcd/pull/17977)
### Package `clientv3`
- Add [requests retry when receiving ErrGPRCNotSupportedForLearner and endpoints > 1](https://github.com/etcd-io/etcd/pull/17641).
- Fix [initialization for mu in client context](https://github.com/etcd-io/etcd/pull/17699).
### Dependencies
- Compile binaries using [go 1.21.10](https://github.com/etcd-io/etcd/pull/17980).
- Upgrade [bbolt to v1.3.10](https://github.com/etcd-io/etcd/pull/17943).
<hr>
## v3.5.13 (2024-03-29)
### etcd server
- Fix leases wrongly revoked by the leader by [ignoring old leader's leases revoking request](https://github.com/etcd-io/etcd/pull/17425).
- Fix [no progress notification being sent for watch that doesn't get any events](https://github.com/etcd-io/etcd/pull/17566).
- Fix [watch event loss after compaction](https://github.com/etcd-io/etcd/pull/17612).
### Package `clientv3`
- Add [client backoff and retry config options](https://github.com/etcd-io/etcd/pull/17363).
- [Ignore SetKeepAlivePeriod errors on OpenBSD](https://github.com/etcd-io/etcd/pull/17387).
- [Support unix/unixs socket in client or peer URLs](https://github.com/etcd-io/etcd/pull/15940)
### gRPC Proxy
- Add [three flags (see below) for grpc-proxy](https://github.com/etcd-io/etcd/pull/17447)
- `--dial-keepalive-time`
- `--dial-keepalive-timeout`
- `--permit-without-stream`
### Dependencies
- Upgrade [bbolt to v1.3.9](https://github.com/etcd-io/etcd/pull/17483).
- Compile binaries using [go 1.21.8](https://github.com/etcd-io/etcd/pull/17537).
- Upgrade [google.golang.org/protobuf to v1.33.0 to address CVE-2024-24786](https://github.com/etcd-io/etcd/pull/17553).
- Upgrade github.com/sirupsen/logrus to v1.9.3 to address [PRISMA-2023-0056](https://github.com/etcd-io/etcd/pull/17482).
### Others
- [Make CGO_ENABLED configurable](https://github.com/etcd-io/etcd/pull/17421).
<hr>
## v3.5.12 (2024-01-31)
### etcd server
- Fix [not validating database consistent index, and panicking on nil backend](https://github.com/etcd-io/etcd/pull/17151)
- Document [`experimental-enable-lease-checkpoint-persist` flag in etcd help](https://github.com/etcd-io/etcd/pull/17190)
- Fix [needlessly flocking snapshot files when deleting](https://github.com/etcd-io/etcd/pull/17206)
- Add [digest for etcd base image](https://github.com/etcd-io/etcd/pull/17205)
- Fix [delete inconsistencies in read buffer](https://github.com/etcd-io/etcd/pull/17230)
- Add [mvcc: print backend database size and size in use in compaction logs](https://github.com/etcd-io/etcd/pull/17291)
- [Add livez/readyz HTTP endpoints](https://github.com/etcd-io/etcd/pull/17039)
### Dependencies
- Compile binaries using [go 1.20.13](https://github.com/etcd-io/etcd/pull/17275)
- Upgrade [golang.org/x/crypto to v0.17+ to address CVE-2023-48795](https://github.com/etcd-io/etcd/pull/17346)
## v3.5.11 (2023-12-07)
### etcd server
- Fix distributed tracing by ensuring `--experimental-distributed-tracing-sampling-rate` configuration option is available to [set tracing sample rate](https://github.com/etcd-io/etcd/pull/16951).
- Fix [url redirects while checking peer urls during new member addition](https://github.com/etcd-io/etcd/pull/16986)
- Add [livez/readyz HTTP endpoints](https://github.com/etcd-io/etcd/pull/17039)
### Dependencies
- Compile binaries using [go 1.20.12](https://github.com/etcd-io/etcd/pull/17077)

View File

@ -6,49 +6,6 @@ Previous change logs can be found at [CHANGELOG-3.5](https://github.com/etcd-io/
## v3.6.0 (TBD)
<hr>
## v3.6.0-rc.3 (TBD)
### etcd server
- [Auto sync members in v3store for the issues which have already been affected by #19557](https://github.com/etcd-io/etcd/pull/19636).
<hr>
## v3.6.0-rc.2 (2025-03-05)
### etcd server
- Add [Prometheus metric to query server feature gates](https://github.com/etcd-io/etcd/pull/19495).
### Dependencies
- Compile binaries using [go 1.23.7](https://github.com/etcd-io/etcd/pull/19527).
- Bump [golang.org/x/net to v0.36.0 to address CVE-2025-22870](https://github.com/etcd-io/etcd/pull/19531).
- Bump [github.com/grpc-ecosystem/grpc-gateway/v2 to v2.26.3 to fix the issue of etcdserver crashing on receiving REST watch stream requests](https://github.com/etcd-io/etcd/pull/19522).
<hr>
## v3.6.0-rc.1 (2025-02-25)
### etcdctl v3
- Add [`DowngradeInfo` in result of endpoint status](https://github.com/etcd-io/etcd/pull/19471)
### etcd server
- Add [`DowngradeInfo` to endpoint status response](https://github.com/etcd-io/etcd/pull/19471)
### Dependencies
- Bump [golang.org/x/crypto to v0.35.0 to address CVE-2025-22869](https://github.com/etcd-io/etcd/pull/19480).
<hr>
## v3.6.0-rc.0 (2025-02-13)
See [code changes](https://github.com/etcd-io/etcd/compare/v3.5.0...v3.6.0).
### Breaking Changes
@ -66,7 +23,7 @@ See [code changes](https://github.com/etcd-io/etcd/compare/v3.5.0...v3.6.0).
- Removed [etcdctl snapshot status](https://github.com/etcd-io/etcd/pull/13809).
- Removed [etcdctl snapshot restore](https://github.com/etcd-io/etcd/pull/13809).
- Removed [etcdutl snapshot save](https://github.com/etcd-io/etcd/pull/13809).
- Removed [NewZapCoreLoggerBuilder in server/embed](https://github.com/etcd-io/etcd/pull/19404)
### etcdctl v3
@ -77,16 +34,13 @@ See [code changes](https://github.com/etcd-io/etcd/compare/v3.5.0...v3.6.0).
- Add [`--max-txn-ops`](https://github.com/etcd-io/etcd/pull/14340) flag to make-mirror command.
- Add [`--consistency`](https://github.com/etcd-io/etcd/pull/15261) flag to member list command.
- Display [field `hash_revision`](https://github.com/etcd-io/etcd/pull/14812) for `etcdctl endpoint hash` command.
- Add [`--max-request-bytes` and `--max-recv-bytes`](https://github.com/etcd-io/etcd/pull/18718) global flags.
### etcdutl v3
- Add command to generate [shell completion](https://github.com/etcd-io/etcd/pull/13142).
- Add `migrate` command for downgrading/upgrading etcd data dir files.
- Add [optional --bump-revision and --mark-compacted flag to etcdutl snapshot restore operation](https://github.com/etcd-io/etcd/pull/16029).
- Add [hashkv](https://github.com/etcd-io/etcd/pull/15965) command to print hash of keys and values up to given revision
- Removed [legacy etcdutl backup](https://github.com/etcd-io/etcd/pull/16662)
- [Count the number of keys from users perspective](https://github.com/etcd-io/etcd/pull/19344)
### Package `clientv3`
@ -120,16 +74,12 @@ See [code changes](https://github.com/etcd-io/etcd/compare/v3.5.0...v3.6.0).
- Add [`etcd --experimental-snapshot-catch-up-entries`](https://github.com/etcd-io/etcd/pull/15033) flag to configure number of entries for a slow follower to catch up after compacting the raft storage entries and defaults to 5k.
- Decreased [`--snapshot-count` default value from 100,000 to 10,000](https://github.com/etcd-io/etcd/pull/15408)
- Add [`etcd --tls-min-version --tls-max-version`](https://github.com/etcd-io/etcd/pull/15156) to enable support for TLS 1.3.
- Add [quota to endpoint status response](https://github.com/etcd-io/etcd/pull/17877)
- Add [feature gate `SetMemberLocalAddr`](https://github.com/etcd-io/etcd/pull/19413) to [enable using the first specified and non-loopback local address from initial-advertise-peer-urls as the local address when communicating with a peer]((https://github.com/etcd-io/etcd/pull/17661))
- Add [Support multiple values for allowed client and peer TLS identities](https://github.com/etcd-io/etcd/pull/18015)
- Add [`embed.Config.GRPCAdditionalServerOptions`](https://github.com/etcd-io/etcd/pull/14066) to support updating the default internal gRPC configuration for embedded use cases.
- Add [`etcd --experimental-stop-grpc-service-on-defrag`](https://github.com/etcd-io/etcd/pull/16278) to enable client failover on defrag.
### etcd grpc-proxy
- Add [`etcd grpc-proxy start --endpoints-auto-sync-interval`](https://github.com/etcd-io/etcd/pull/14354) flag to enable and configure interval of auto sync of endpoints with server.
- Add [`etcd grpc-proxy start --listen-cipher-suites`](https://github.com/etcd-io/etcd/pull/14308) flag to support adding configurable cipher list.
- Add [`tls min/max version to grpc proxy`](https://github.com/etcd-io/etcd/pull/18816) to support setting TLS min and max version.
### tools/benchmark
@ -141,16 +91,14 @@ See [List of metrics](https://etcd.io/docs/latest/metrics/) for all metrics per
- Add [`etcd_disk_defrag_inflight`](https://github.com/etcd-io/etcd/pull/13371).
- Add [`etcd_debugging_server_alarms`](https://github.com/etcd-io/etcd/pull/14276).
- Add [`etcd_server_range_duration_seconds`](https://github.com/etcd-io/etcd/pull/17983).
### Go
- Require [Go 1.23+](https://github.com/etcd-io/etcd/pull/16594).
- Compile with [Go 1.23+](https://go.dev/doc/devel/release#go1.21.minor). Please refer to [gc-guide](https://go.dev/doc/gc-guide) to configure `GOGC` and `GOMEMLIMIT` properly.
- Require [Go 1.21+](https://github.com/etcd-io/etcd/pull/16594).
- Compile with [Go 1.21+](https://go.dev/doc/devel/release#go1.21.minor). Please refer to [gc-guide](https://go.dev/doc/gc-guide) to configure `GOGC` and `GOMEMLIMIT` properly.
### Other
- Use Distroless as base image to make the image less vulnerable and reduce image size.
- [Upgrade grpc-gateway from v1 to v2](https://github.com/etcd-io/etcd/pull/16595).
- [Switch from grpc-ecosystem/go-grpc-prometheus to grpc-ecosystem/go-grpc-middleware/providers/prometheus](https://github.com/etcd-io/etcd/pull/19195).
<hr>

View File

@ -1,11 +0,0 @@
Previous change logs can be found at [CHANGELOG-3.6](https://github.com/etcd-io/etcd/blob/main/CHANGELOG/CHANGELOG-3.6.md).
<hr>
## v3.7.0 (TBD)
### Deprecations
- Deprecated [UsageFunc in pkg/cobrautl](https://github.com/etcd-io/etcd/pull/18356).

View File

@ -1,42 +1,41 @@
# How to contribute
etcd is Apache 2.0 licensed and accepts contributions via GitHub pull requests.
This document outlines the basics of contributing to etcd.
This document outlines basics of contributing to etcd.
This is a rough outline of what a contributor's workflow looks like:
* [Find something to work on](#Find-something-to-work-on)
* [Check for flaky tests](#Check-for-flaky-tests)
* [Set up development environment](#Set-up-development-environment)
* [Setup development environment](#Setup-development-environment)
* [Implement your change](#Implement-your-change)
* [Commit your change](#Commit-your-change)
* [Create a pull request](#Create-a-pull-request)
* [Get your pull request reviewed](#Get-your-pull-request-reviewed)
If you have any questions, please reach out using one of the methods listed in [contact].
If you have any questions about, please reach out using one of the methods listed in [contact].
[contact]: ./README.md#Contact
## Learn more about etcd
Before making a change please look through the resources below to learn more about etcd and tools used for development.
Before making a change please look through resources below to learn more about etcd and tools used for development.
* Please learn about [Git](https://github.com/git-guides) version control system used in etcd.
* Read the [etcd learning resources](https://etcd.io/docs/v3.5/learning/)
* Read the [etcd community membership](/Documentation/contributor-guide/community-membership.md)
* Watch [etcd deep dive](https://www.youtube.com/watch?v=D2pm6ufIt98&t=927s)
* Watch [etcd code walkthrough](https://www.youtube.com/watch?v=H3XaSF6wF7w)
* Watch [etcd code walk through](https://www.youtube.com/watch?v=H3XaSF6wF7w)
## Find something to work on
All the work in the etcd project is tracked in [GitHub issue tracker].
All the work in etcd project is tracked in [github issue tracker].
Issues should be properly labeled making it easy to find something for you.
Depending on your interest and experience you should check different labels:
* If you are just starting, check issues labeled with [good first issue].
* When you feel more comfortable in your contributions, check out [help wanted].
* Advanced contributors can try to help with issues labeled [priority/important] covering the most relevant work at the time.
* When you feel more conformable in your contributions, checkout [help wanted].
* Advanced contributors can try to help with issues labeled [priority/important] covering most relevant work at the time.
If any of the aforementioned labels don't have unassigned issues, please [contact] one of the [maintainers] asking to triage more issues.
If any of aforementioned labels don't have unassigned issues, please [contact] one of the [maintainers] asking to triage more issues.
[github issue tracker]: https://github.com/etcd-io/etcd/issues
[good first issue]: https://github.com/search?type=issues&q=org%3Aetcd-io+state%3Aopen++label%3A%22good+first+issue%22
@ -44,68 +43,29 @@ If any of the aforementioned labels don't have unassigned issues, please [contac
[maintainers]: https://github.com/etcd-io/etcd/blob/main/OWNERS
[priority/important]: https://github.com/search?type=issues&q=org%3Aetcd-io+state%3Aopen++label%3A%22priority%2Fimportant%22
### Check for flaky tests
The project could always use some help to deflake tests. [These](https://github.com/etcd-io/etcd/issues?q=is%3Aissue+is%3Aopen+label%3Atype%2Fflake) are the currently open flaky test issues.
For more, because etcd uses Kubernetes' prow infrastructure to run CI jobs, the past test results can be viewed at [testgrid](https://testgrid.k8s.io/sig-etcd).
| Tests | Status |
| ----- | ------ |
| periodics e2e-amd64 | [![sig-etcd-periodics/ci-etcd-e2e-amd64](https://testgrid.k8s.io/q/summary/sig-etcd-periodics/ci-etcd-e2e-amd64/tests_status?style=svg)](https://testgrid.k8s.io/q/summary/sig-etcd-periodics/ci-etcd-e2e-amd64) |
| presubmit build | [![sig-etcd-presubmits/pull-etcd-build](https://testgrid.k8s.io/q/summary/sig-etcd-presubmits/pull-etcd-build/tests_status?style=svg)](https://testgrid.k8s.io/q/summary/sig-etcd-presubmits/pull-etcd-build) |
| presubmit e2e-amd64 | [![sig-etcd-presubmits/pull-etcd-e2e-amd64](https://testgrid.k8s.io/q/summary/sig-etcd-presubmits/pull-etcd-e2e-amd64/tests_status?style=svg)](https://testgrid.k8s.io/q/summary/sig-etcd-presubmits/pull-etcd-e2e-amd64) |
| presubmit unit-test | [![sig-etcd-presubmits/pull-etcd-unit-test](https://testgrid.k8s.io/q/summary/sig-etcd-presubmits/pull-etcd-unit-test/tests_status?style=svg)](https://testgrid.k8s.io/q/summary/sig-etcd-presubmits/pull-etcd-unit-test) |
| presubmit verify | [![sig-etcd-presubmits/pull-etcd-verify](https://testgrid.k8s.io/q/summary/sig-etcd-presubmits/pull-etcd-verify/tests_status?style=svg)](https://testgrid.k8s.io/q/summary/sig-etcd-presubmits/pull-etcd-verify) |
| postsubmit build | [![sig-etcd-postsubmits/post-etcd-build](https://testgrid.k8s.io/q/summary/sig-etcd-postsubmits/post-etcd-build/tests_status?style=svg)](https://testgrid.k8s.io/q/summary/sig-etcd-postsubmits/post-etcd-build) |
If you find any flaky tests on testgrid, please
1. Check [existing issues](https://github.com/etcd-io/etcd/issues?q=is%3Aissue+is%3Aopen+label%3Atype%2Fflake) to see if an issue has already been opened for this test. If not, open an issue with the `type/flake` label.
2. Try to reproduce the flaky test on your machine via [`stress`](https://pkg.go.dev/golang.org/x/tools/cmd/stress), for example, to reproduce the failure of `TestPeriodicSkipRevNotChange`:
```bash
# install the stress utility
go install golang.org/x/tools/cmd/stress@latest
cd server/etcdserver/api/v3compactor
# compile the test
go test -v -c -count 1
# run the compiled test file using stress
stress -p=8 ./v3compactor.test -test.run “^TestPeriodicSkipRevNotChange$”
```
3. Fix it.
## Set up development environment
## Setup development environment
The etcd project supports two options for development:
1. Manually set up the local environment.
2. Automatically set up [devcontainer](https://containers.dev).
1. Manually setup local environment.
2. Automatically setup [devcontainer](https://containers.dev).
For both options, the only supported architecture is `linux-amd64`. Bug reports for other environments will generally be ignored. Supporting new environments requires the introduction of proper tests and maintainer support that is currently lacking in the etcd project.
For both options the only supported architecture is `linux-amd64`. Bug reports for other environments will generally be ignored. Supporting new environments requires introduction of proper tests and maintainer support that is currently lacking in the etcd project.
If you would like etcd to support your preferred environment you can [file an issue].
### Option 1 - Manually set up the local environment
### Option 1 - Manually setup local environment
This is the original etcd development environment, is most supported, and is backward compatible for the development of older etcd versions.
This is the original etcd development environment, is most supported and is backwards compatible for development of older etcd versions.
Follow the steps below to set up the environment:
Follow the steps below to setup the environment:
- [Clone the repository](https://docs.github.com/en/repositories/creating-and-managing-repositories/cloning-a-repository)
- Install Go by following [installation](https://go.dev/doc/install). Please check the minimal go version in [go.mod file](./go.mod#L3).
- Install Go by following [installation](https://go.dev/doc/install). Please check minimal go version in [go.mod file](./go.mod#L3).
- Install build tools:
- [`make`](https://www.gnu.org/software/make/): For Debian-based distributions
you can run `sudo apt-get install build-essential`
- [`protoc`](https://protobuf.dev/): You can download it for your os. Use
version
[`v3.20.3`](https://github.com/protocolbuffers/protobuf/releases/tag/v3.20.3).
- [`yamllint`](https://www.yamllint.com/): For Debian-based distribution you
can run `sudo apt-get install yamllint`
- [`jq`](https://jqlang.github.io/jq/): For Debian-based distribution you can
run `sudo apt-get install jq`
- [`xz`](https://tukaani.org/xz/): For Debian-based distribution you can run
`sudo apt-get install xz-utils`
- `make`: For debian based distributions you can run `sudo apt-get install build-essential`
- `protoc`: You can download for your os. Use version [`v3.20.3`](https://github.com/protocolbuffers/protobuf/releases/tag/v3.20.3).
- `yamllint`: For debian based distribution you can run `sudo apt-get install yamllint`
- Verify that everything is installed by running `make build`
Note: `make build` runs with `-v`. Other build flags can be added through env `GO_BUILD_FLAGS`, **if required**. Eg.,
@ -113,17 +73,17 @@ Note: `make build` runs with `-v`. Other build flags can be added through env `G
GO_BUILD_FLAGS="-buildmode=pie" make build
```
### Option 2 - Automatically set up devcontainer
### Option 2 - Automatically setup devcontainer
This is a more recently added environment that aims to make it faster for new contributors to get started with etcd. This option is supported for etcd versions 3.6 onwards.
This is a more recently added environmnent that aims to make it faster for new contributors to get started with etcd. This option is supported for etcd versions 3.6 onwards.
This option can be [used locally](https://code.visualstudio.com/docs/devcontainers/tutorial) on a system running Visual Studio Code and Docker, or in a remote cloud-based [Codespaces](https://github.com/features/codespaces) environment.
This option can be [used locally](https://code.visualstudio.com/docs/devcontainers/tutorial) on a system running Visual Studio Code and Docker, or in a remote cloud based [Codespaces](https://github.com/features/codespaces) environment.
To get started, create a codespace for this repository by clicking this 👇
[![Open in GitHub Codespaces](https://github.com/codespaces/badge.svg)](https://github.com/codespaces/new?hide_repo_select=true&ref=main&repo=11225014)
A codespace will open in a web-based version of Visual Studio Code. The [dev container](.devcontainer/devcontainer.json) is fully configured with the software needed for this project.
A codespace will open in a web-based version of Visual Studio Code. The [dev container](.devcontainer/devcontainer.json) is fully configured with software needed for this project.
**Note**: Dev containers is an open spec which is supported by [GitHub Codespaces](https://github.com/codespaces) and [other tools](https://containers.dev/supporting).
@ -131,31 +91,30 @@ A codespace will open in a web-based version of Visual Studio Code. The [dev con
## Implement your change
etcd code should follow the coding style suggested by the Golang community.
See the [style doc](https://go.dev/wiki/CodeReviewComments) for details.
etcd code should follow coding style suggested by the Golang community.
See the [style doc](https://github.com/golang/go/wiki/CodeReviewComments) for details.
Please ensure that your change passes static analysis (requires
[golangci-lint](https://golangci-lint.run/welcome/install/)):
Please ensure that your change passes static analysis (requires [golangci-lint](https://golangci-lint.run/usage/install/)):
- `make verify` to verify if all checks pass.
- `make verify-*` to verify a single check, for example, `make verify-bom` to verify if `bill-of-materials.json` file is up-to-date.
- `make verify-*` to verify a single check, for example `make verify-bom` to verify if bill-of-materials.json file is up-to-date.
- `make fix` to fix all checks.
- `make fix-*` to fix a single check, for example, `make fix-bom` to update `bill-of-materials.json`.
- `make fix-*` to fix a single checks, for example `make fix-bom` to update bill-of-materials.json.
Please ensure that your change passes tests.
- `make test-unit` to run unit tests.
- `make test-integration` to run integration tests.
- `make test-e2e` to run e2e tests.
All changes are expected to come with a unit test.
All changes are expected to come with unit test.
All new features are expected to have either e2e or integration tests.
## Commit your change
etcd follows a rough convention for commit messages:
* First line:
* Should start with the name of the package (for example `etcdserver`, `etcdctl`) followed by the `:` character.
* Should start name of package (for example `etcdserver`, `etcdctl`) followed by `:` character.
* Describe the `what` behind the change
* Optionally, the author might provide the `why` behind the change in the main commit message body.
* Optionally author might provide the `why` behind the change in the main commit message body.
* Last line should be `Signed-off-by: firstname lastname <email@example.com>` (can be automatically generate by providing `--signoff` to git commit command).
Example of commit message:
@ -173,9 +132,9 @@ Signed-off-by: FirstName LastName <github@github.com>
## Create a pull request
Please follow the [making a pull request](https://docs.github.com/en/get-started/quickstart/contributing-to-projects#making-a-pull-request) guide.
Please follow [making a pull request](https://docs.github.com/en/get-started/quickstart/contributing-to-projects#making-a-pull-request) guide.
If you are still working on the pull request, you can convert it to a draft by clicking `Convert to draft` link just below the list of reviewers.
If you are still working on the pull request, you can convert it to draft by clicking `Convert to draft` link just below list of reviewers.
Multiple small PRs are preferred over single large ones (>500 lines of code).
@ -186,12 +145,11 @@ releases.
## Get your pull request reviewed
Before requesting review please ensure that all GitHub and Prow checks are successful. In some cases your pull request may have the label `needs-ok-to-test`. If so an `etcd-io` organisation member will leave a comment on your pull request with `/ok-to-test` to trigger all checks to be run.
Before requesting review please ensure that all GitHub checks were successful.
It might happen that some unrelated tests on your PR are failing, due to their flakiness.
In such cases please [file an issue] to deflake the problematic test and ask one of [maintainers] to rerun the tests.
If all checks were successful feel free to reach out for review from people that were involved in the original discussion or [maintainers].
Depending on the complexity of the PR it might require between 1 and 2 maintainers to approve your change before merging.
Depending on complexity of the PR it might require between 1 and 2 maintainers to approve your change before merging.
Thanks for contributing!

View File

@ -1,5 +1,5 @@
ARG ARCH=amd64
FROM --platform=linux/${ARCH} gcr.io/distroless/static-debian12@sha256:3f2b64ef97bd285e36132c684e6b2ae8f2723293d09aae046196cca64251acac
FROM --platform=linux/${ARCH} gcr.io/distroless/static-debian12@sha256:4a2c1a51ae5e10ec4758a0f981be3ce5d6ac55445828463fce8dff3a355e0b75
ADD etcd /usr/local/bin/
ADD etcdctl /usr/local/bin/

View File

@ -1,4 +0,0 @@
# See the OWNERS docs at https://go.k8s.io/owners
labels:
- area/documentation

View File

@ -3,7 +3,7 @@
## Guide
* New development occurs on the [main branch][main].
* The main branch should always have a green build!
* Main branch should always have a green build!
* Backwards-compatible bug fixes should target the main branch and subsequently be ported to stable branches.
* Once the main branch is ready for release, it will be tagged and become the new stable branch.
@ -15,12 +15,13 @@ The `main` branch is our development branch. All new features land here first.
To try new and experimental features, pull `main` and play with it. Note that `main` may not be stable because new features may introduce bugs.
Before the release of the next stable version, feature PRs will be frozen. A [release manager](./release.md#release-management) will be assigned to the major/minor version and will lead the etcd community in testing, bug-fix, and documentation of the release for one to two weeks.
Before the release of the next stable version, feature PRs will be frozen. A [release manager](./release.md#release-management) will be assigned to major/minor version and will lead the etcd community in test, bug-fix and documentation of the release for one to two weeks.
### Stable branches
All branches with the prefix `release-` are considered _stable_ branches.
All branches with prefix `release-` are considered _stable_ branches.
After every minor release ([semver.org](https://semver.org/)), we will have a new stable branch for that release, managed by a [patch release manager](./release.md#release-management). We will keep fixing the backward-compatible bugs for the latest two stable releases. A _patch_ release to each supported release branch, incorporating any bug fixes, will be once every two weeks, given any patches.
After every minor release ([semver.org](https://semver.org/)), we will have a new stable branch for that release, managed by a [patch release manager](./release.md#release-management). We will keep fixing the backwards-compatible bugs for the latest two stable releases. A _patch_ release to each supported release branch, incorporating any bug fixes, will be once every two weeks, given any patches.
[main]: https://github.com/etcd-io/etcd/tree/main

View File

@ -24,7 +24,7 @@ below.
## Member
Members are continuously active contributors to the community. They can have
Members are continuously active contributors in the community. They can have
issues and PRs assigned to them. Members are expected to remain active
contributors to the community.
@ -38,12 +38,12 @@ contributors to the community.
- Filing or commenting on issues on GitHub
- Contributing to community discussions (e.g. meetings, Slack, email discussion
forums, Stack Overflow)
- Subscribed to [etcd-dev@googlegroups.com](https://groups.google.com/g/etcd-dev)
- Subscribed to etcd-dev@googlegroups.com
- Have read the [contributor guide]
- Sponsored by two active maintainers or reviewers.
- Sponsors must be from multiple member companies to demonstrate integration across the community.
- Sponsored by one active maintainer or two reviewers.
- Sponsors must be from multiple member companies to demonstrate integration across community.
- With no objections from other maintainers
- Open a [membership nomination] issue against the `kubernetes/org` repo
- Open a [membership nomination] issue against the etcd-io/etcd repo
- Ensure your sponsors are @mentioned on the issue
- Make sure that the list of contributions included is representative of your work on the project.
- Members can be removed by a supermajority of the maintainers or can resign by notifying
@ -54,11 +54,11 @@ contributors to the community.
- Responsive to issues and PRs assigned to them
- Granted "triage access" to etcd project
- Active owner of code they have contributed (unless ownership is explicitly transferred)
- Code is well-tested
- Code is well tested
- Tests consistently pass
- Addresses bugs or issues discovered after code is accepted
**Note:** Members who frequently contribute code are expected to proactively
**Note:** members who frequently contribute code are expected to proactively
perform code reviews and work towards becoming a *reviewer*.
## Reviewers
@ -78,7 +78,7 @@ maintainership.
- Reviewed or contributed at least 20 substantial PRs to the codebase.
- Knowledgeable about the codebase.
- Sponsored by two active maintainers.
- Sponsors must be from multiple member companies to demonstrate integration across the community.
- Sponsors must be from multiple member companies to demonstrate integration across community.
- With no objections from other maintainers
- Reviewers can be removed by a supermajority of the maintainers or can resign by notifying
the maintainers.
@ -96,8 +96,8 @@ maintainership.
## Maintainers
Maintainers are first and foremost contributors who have shown they
are committed to the long-term success of a project. Maintainership is about building
Maintainers are first and foremost contributors that have shown they
are committed to the long term success of a project. Maintainership is about building
trust with the current maintainers and being a person that they can
depend on to make decisions in the best interest of the project in a consistent manner.
@ -109,20 +109,20 @@ depend on to make decisions in the best interest of the project in a consistent
- Deep understanding of the technical domain of the project
- Sustained contributions to design and direction by doing all of:
- Authoring and reviewing proposals
- Initiating, contributing, and resolving discussions (emails, GitHub issues, meetings)
- Identifying subtle or complex issues in the designs and implementation of PRs
- Directly contributed to the project through implementation and/or review
- Initiating, contributing and resolving discussions (emails, GitHub issues, meetings)
- Identifying subtle or complex issues in designs and implementation PRs
- Directly contributed to the project through implementation and / or review
- Sponsored by two active maintainers and elected by supermajority
- Sponsors must be from multiple member companies to demonstrate integration across the community.
- Sponsors must be from multiple member companies to demonstrate integration across community.
- To become a maintainer send an email with your candidacy to etcd-maintainers-private@googlegroups.com
- Ensure your sponsors are @mentioned in the email
- Ensure your sponsors are @mentioned on the email
- Include a list of contributions representative of your work on the project.
- Existing maintainers vote will privately and respond to the email with either acceptance or feedback for suggested improvement.
- Existing maintainers vote will privately and respond to the email with either acceptance or with feedback for suggested improvement.
- With your membership approved you are expected to:
- Open a PR and add an entry to the [OWNERS] file
- Subscribe to etcd-maintainers@googlegroups.com and etcd-maintainers-private@googlegroups.com
- Request to join [etcd-maintainer teams of etcd organization of GitHub](https://github.com/orgs/etcd-io/teams/maintainers-etcd)
- Request to join the private slack channel for etcd maintainers on [kubernetes slack](http://slack.kubernetes.io/)
- Request to join to [etcd-maintainer teams of etcd organization of GitHub](https://github.com/orgs/etcd-io/teams/maintainers-etcd)
- Request to join to the private slack channel for etcd maintainers on [kubernetes slack](http://slack.kubernetes.io/)
- Request access to etcd-development GCP project where we publish releases
- Request access to passwords shared between maintainers
@ -133,26 +133,26 @@ depend on to make decisions in the best interest of the project in a consistent
- Define milestones and releases
- Mentor and guide reviewers, and contributors to the project.
- Participate when called upon in the [security disclosure and release process]
- Ensure the continued health of the project
- Ensure continued health of the project
- Adequate test coverage to confidently release
- Tests are passing reliably (i.e. not flaky) and are fixed when they fail
- Ensure a healthy process for discussion and decision-making is in place.
- Ensure a healthy process for discussion and decision making is in place.
- Work with other maintainers to maintain the project's overall health and success holistically
### Retiring
Life priorities, interests, and passions can change. Maintainers can retire and
move to [emeritus maintainers]. If a maintainer needs to step down, they should
inform other maintainers and, if possible, help find someone to pick up the related
work. At the very least, ensure the related work can be continued. Afterward,
they can remove themselves from the list of existing maintainers.
inform other maintainers, if possible, help find someone to pick up the related
work. At the very least, ensure the related work can be continued. Afterward
they can remove themselves from list of existing maintainers.
If a maintainer has not been performing their duties for 12 months,
they can be removed by other maintainers. In that case, the inactive maintainer will
be first notified via an email. If the situation doesn't improve, they will be
If a maintainer has not been performing their duties for period of 12 months,
they can be removed by other maintainers. In that case inactive maintainer will
be first notified via an email. If situation doesn't improve, they will be
removed. If an emeritus maintainer wants to regain an active role, they can do
so by renewing their contributions. Active maintainers should welcome such a move.
Retiring other maintainers or regaining the status should require the approval
Retiring of other maintainers or regaining the status should require approval
of at least two active maintainers.
## Acknowledgements
@ -161,9 +161,8 @@ Contributor roles and responsibilities were written based on [Kubernetes communi
[OWNERS]: /OWNERS
[contributor guide]: /CONTRIBUTING.md
[membership nomination]: https://github.com/kubernetes/org/issues/new?assignees=&labels=area%2Fgithub-membership&projects=&template=membership.yml&title=REQUEST%3A+New+membership+for+%3Cyour-GH-handle%3E
[membership nomination]:https://github.com/etcd-io/etcd/issues/new?assignees=&labels=area%2Fcommunity&template=membership-request.yml
[Kubernetes community membership]: https://github.com/kubernetes/community/blob/master/community-membership.md
[emeritus maintainers]: /README.md#etcd-emeritus-maintainers
[security disclosure and release process]: /security/README.md
[two-factor authentication]: https://docs.github.com/en/authentication/securing-your-account-with-two-factor-authentication-2fa/about-two-factor-authentication

View File

@ -12,19 +12,18 @@
- [Rotation worksheet](#rotation-worksheet)
- **[Stable branches](#stable-branches)**
- **[Golang versions](#golang-versions)**
- **[Core dependencies mappings](#core-dependencies-mappings)**
## Main branch
The dependabot is enabled & [configured](https://github.com/etcd-io/etcd/blob/main/.github/dependabot.yml) to
manage dependencies for etcd `main` branch. But dependabot doesn't work well for multi-module repository like `etcd`,
see [dependabot-core/issues/6678](https://github.com/dependabot/dependabot-core/issues/6678).
Usually, human intervention is required each time when dependabot automatically opens some PRs to bump dependencies.
Please see the guidance below.
Usually human intervention is required each time when dependabot automatically opens some PRs to bump dependencies.
Please see guidance below.
### Dependencies used in workflows
The PRs that automatically bump dependencies (see examples below) used in workflows are fine and can be approved & merged directly as long as all checks are successful.
The PRs which automatically bump dependencies (see examples below) used in workflows are fine, and can be approved & merged directly as long as all checks are successful.
- [build(deps): bump github/codeql-action from 2.2.11 to 2.2.12](https://github.com/etcd-io/etcd/pull/15736)
- [build(deps): bump actions/checkout from 3.5.0 to 3.5.2](https://github.com/etcd-io/etcd/pull/15735)
@ -34,7 +33,7 @@ The PRs that automatically bump dependencies (see examples below) used in workfl
When multiple etcd modules depend on the same package, please bump the package version for all the modules in the correct order. The rule is simple:
if module A depends on module B, then bump the dependency for module B before module A. If the two modules do not depend on each other, then
it doesn't matter to bump which module first. For example, multiple modules depend on `github.com/spf13/cobra`, so we need to bump the dependency
it doesn't matter to bump which module first. For example, multiple modules depend on `github.com/spf13/cobra`, we need to bump the dependency
in the following order,
- go.etcd.io/etcd/pkg/v3
@ -50,7 +49,7 @@ Note the module `go.etcd.io/etcd/tools/v3` doesn't depend on any other modules,
### Steps to bump a dependency
Use the `github.com/spf13/cobra` as an example, follow the steps below to bump it from 1.6.1 to 1.7.0 for module `go.etcd.io/etcd/etcdctl/v3`,
Use the `github.com/spf13/cobra` as an example, follow steps below to bump it from 1.6.1 to 1.7.0 for module `go.etcd.io/etcd/etcdctl/v3`,
```bash
cd ${ETCD_ROOT_DIR}/etcdctl
@ -72,26 +71,11 @@ Please close the related PRs which were automatically opened by dependabot.
When you bump multiple dependencies in one PR, it's recommended to create a separate commit for each dependency. But it isn't a must; for example,
you can get all dependencies bumping for the module `go.etcd.io/etcd/tools/v3` included in one commit.
#### Troubleshooting
In an event of bumping the version of protoc, protoc plugins or grpc-gateway, it might change `*.proto` file which can result in the following error:
```bash
[0;31mFAIL: 'genproto' FAILED at Wed Jul 31 07:09:08 UTC 2024
make: *** [Makefile:134: verify-genproto] Error 255
```
To fix the above error, run the following script from the root of etcd repository:
```bash
./scripts/genproto.sh
```
### Indirect dependencies
Usually, we don't bump a dependency if all modules just indirectly depend on it, such as `github.com/go-logr/logr`.
Usually we don't bump a dependency if all modules just indirectly depend on it, such as `github.com/go-logr/logr`.
If an indirect dependency (e.g. `D1`) causes any CVE or bugs that affect etcd, usually the module (e.g. `M1`, not part of etcd, but used by etcd)
If an indirect dependency (e.g. `D1`) causes any CVE or bugs which affect etcd, usually the module (e.g. `M1`, not part of etcd, but used by etcd)
which depends on it should bump the dependency (`D1`), and then etcd just needs to bump `M1`. However, if the module (`M1`) somehow doesn't
bump the problematic dependency, then etcd can still bump it (`D1`) directly following the same steps above. But as a long-term solution, etcd should
try to remove the dependency on such module (`M1`) that lack maintenance.
@ -99,7 +83,7 @@ try to remove the dependency on such module (`M1`) that lack maintenance.
For mixed cases, in which some modules directly while others indirectly depend on a dependency, we have multiple options,
- Bump the dependency for all modules, no matter it's direct or indirect dependency.
- Bump the dependency only for modules that directly depend on it.
- Bump the dependency only for modules which directly depend on it.
We should try to follow the first way, and temporarily fall back to the second one if we run into any issue on the first way. Eventually we
should fix the issue and ensure all modules depend on the same version of the dependency.
@ -113,50 +97,32 @@ Please refer to [build(deps): bump arduino/setup-protoc from 1.3.0 to 2.0.0](htt
### Rotation worksheet
The dependabot scheduling interval is weekly; it means dependabot will automatically raise a bunch of PRs per week.
Usually, human intervention is required each time. We have a [rotation worksheet](https://docs.google.com/spreadsheets/d/1jodHIO7Dk2VWTs1IRnfMFaRktS9IH8XRyifOnPdSY8I/edit#gid=1394774387),
Usually human intervention is required each time. We have a [rotation worksheet](https://docs.google.com/spreadsheets/d/1jodHIO7Dk2VWTs1IRnfMFaRktS9IH8XRyifOnPdSY8I/edit#gid=1394774387),
and everyone is welcome to participate; you just need to register your name in the worksheet.
## Stable branches
Usually, we don't proactively bump dependencies for stable releases unless there are any CVEs or bugs that affect etcd.
Usually we don't proactively bump dependencies for stable releases unless there are any CVEs or bugs that affect etcd.
If we have to do it, then follow the same guidance above. Note that there is no `./scripts/fix.sh` in release-3.4, so no need to
execute it for 3.4.
## Golang versions
The etcd project aims to maintain a development branch that is on the latest [Go version](https://go.dev/dl), ideally, this will align with the Go version in use for Kubernetes project development. For an example of how to update etcd to a new minor release of Go refer to issue <https://github.com/etcd-io/etcd/issues/16393> and the linked pull requests.
The etcd project aims to maintain a development branch that is on the latest [Go version](https://go.dev/dl), ideally this will align with the Go version in use for Kubernetes project development. For an example on how to update etcd to a new minor release of Go refer to issue <https://github.com/etcd-io/etcd/issues/16393> and the linked pull requests.
Suggested steps for performing a minor version upgrade for the etcd development branch:
1. Carefully review new Go version release notes and potentially related blog posts for any deprecations, performance impacts, or other considerations.
2. Create a GitHub issue to signal intent to upgrade and invite discussion, for example, <https://github.com/etcd-io/etcd/issues/16393>.
3. Complete the upgrade locally in your development environment by editing `.go-version` and running `make fix`.
1. Carefully review new Go version release notes and potentially related blog for any deprecations, performance impacts or other considerations.
2. Create a github issue to signal intent to upgrade and invite discussion, example <https://github.com/etcd-io/etcd/issues/16393>.
3. Complete the upgrade locally in your development environment.
4. Run performance benchmarks locally to compare before and after.
5. Raise a pull request for the changes, for example, <https://github.com/etcd-io/etcd/pull/16394>.
5. Raise a pull request for the changes, example <https://github.com/etcd-io/etcd/pull/16394>.
Stable etcd release branches will be maintained to stay on the latest patch release of a supported Go version. Upgrading minor versions will be completed before the minor version in use currently is no longer supported. Refer to the [Go release policy](https://go.dev/doc/devel/release).
Stable etcd release branches will be maintained to stay on the latest patch release of a supported Go version, however upgrading minor versions will be avoided unless the minor version in use is now out of support. Refer to the [Go release policy](https://go.dev/doc/devel/release).
For an example of how to update etcd to a new patch release of Go refer to issue <https://github.com/etcd-io/etcd/issues/16343> and the linked pull requests.
References:
- <https://github.com/kubernetes/sig-release/blob/master/release-engineering/handbooks/go.md>
## Core dependencies mappings
[bbolt](https://github.com/etcd-io/bbolt) and [raft](https://github.com/etcd-io/raft) are two core dependencies of etcd.
Both etcd 3.4.x and 3.5.x depend on bbolt 1.3.x, and etcd 3.6.x (`main` branch) depends on bbolt 1.4.x.
raft is included in the etcd repository for release-3.4 and release-3.5 branches, so etcd 3.4.x and 3.5.x do not depend on any
external raft module. We moved raft into [a separate repository](https://github.com/etcd-io/raft) starting from 3.6 (`main` branch), and the first raft
release will be v3.6.0, so etcd 3.6.x will depend on raft 3.6.x.
Please see the table below:
| etcd versions | bbolt versions | raft versions |
|---------------|----------------|---------------|
| 3.4.x | v1.3.x | N/A |
| 3.5.x | v1.3.x | N/A |
| 3.6.x | v1.4.x | v3.6.x |

View File

@ -4,84 +4,80 @@ This document provides an overview of etcd features and general development guid
## Overview
The etcd features fall into three stages: Alpha, Beta, and GA.
The etcd features fall into three stages, experimental, stable, and unsafe.
### Alpha
### Experimental
Any new feature is usually added as an Alpha feature. An Alpha feature is characterized as below:
Any new feature is usually added as an experimental feature. An experimental feature is characterized as below:
- Might be buggy due to a lack of user testing. Enabling the feature may not work as expected.
- Disabled by default.
- Disabled by default when added initially.
- Support for such a feature may be dropped at any time without notice
- Feature-related issues may be given lower priorities.
- It can be removed in the next minor or major release without following the feature deprecation policy unless it graduates to a more stable stage.
- Feature related issues may be given lower priorities.
- It can be removed in the next minor or major release without following the feature deprecation policy unless it graduates to the stable future.
### Beta
### Stable
A Beta feature is characterized as below:
A stable feature is characterized as below:
- Supported as part of the supported releases of etcd.
- Enabled by default.
- May be enabled by default.
- Discontinuation of support must follow the feature deprecation policy.
### GA
### Unsafe
A GA feature is characterized as below:
- Supported as part of the supported releases of etcd.
- Always enabled; you cannot disable it. The corresponding feature gate is no longer needed.
- Discontinuation of support must follow the feature deprecation policy.
Unsafe features are rare and listed under the `Unsafe feature:` section in the etcd usage documentation. By default, they are disabled. They should be used with caution following documentation. An unsafe feature can be removed in the next minor or major release without following feature deprecation policy.
## Development Guidelines
### Adding a new feature
Any new enhancements to the etcd are typically added as an Alpha feature.
etcd follows the Kubernetes [KEP process](https://github.com/kubernetes/enhancements/blob/master/keps/sig-architecture/0000-kep-process/README.md) for new enhancements. The general development requirements are listed below. They can be somewhat flexible depending on the scope of the feature and review discussions and will evolve over time.
- Open a [KEP](https://github.com/kubernetes/enhancements/issues) issue
Any new enhancements to the etcd are typically added as an experimental feature. The general development requirements are listed below. They can be somewhat flexible depending on the scope of the feature and review discussions, and will evolve over time.
- Open an issue
- It must provide a clear need for the proposed feature.
- It should list development work items as checkboxes. There must be one work item towards future graduation to Beta.
- Label the issue with `/sig etcd`.
- Keep the issue open for tracking purposes until a decision is made on graduation.
- Open a [KEP](https://github.com/kubernetes/enhancements) Pull Request (PR).
- The KEP template can be simplified for etcd.
- It must provide clear graduation criteria for each stage.
- The KEP doc should reside in [keps/sig-etcd](https://github.com/kubernetes/enhancements/tree/master/keps/sig-etcd/)
- Open Pull Requests (PRs) in [etcd](https://github.com/etcd-io/etcd)
- Provide unit tests. Integration tests are also recommended as possible.
- Provide robust e2e test coverage. If the feature being added is complicated or quickly needed, maintainers can decide to go with e2e tests for basic coverage initially and have robust coverage added at a later time before the feature graduation to the stable feature.
- It should list development work items as checkboxes. There must be one work item towards future graduation to the stable future.
- Label the issue with `type/feature` and `experimental`.
- Keep the issue open for tracking purpose until a decision is made on graduation.
- Open a Pull Request (PR)
- Provide unit tests. Integreation tests are also recommended as possible.
- Provide robust e2e test coverage. If the feature being added is complicated or quickly needed, maintainers can decide to go with e2e tests for basic coverage initially and have robust coverage added at the later time before feature graduation to the stable feature.
- Provide logs for proper debugging.
- Provide metrics and benchmarks as needed.
- Add an Alpha [feature gate](https://etcd.io/docs/v3.6/feature-gates/).
- Any code changes or configuration flags related to the implementation of the feature must be gated with the feature gate e.g. `if cfg.ServerFeatureGate.Enabled(features.FeatureName)`.
- The Feature should be disabled by default.
- Any configuration flags related to the implementation of the feature must be prefixed with `experimental` e.g. `--experimental-feature-name`.
- Add a CHANGELOG entry.
- At least two maintainers must approve the KEP and related code changes.
- At least two maintainers must approve feature requirements and related code changes.
### Graduating a feature to the next stage
### Graduating an Experimental feature to Stable
It is important that features don't get stuck in one stage. They should be revisited and moved to the next stage once they meet the graduation criteria listed in the KEP. A feature should stay at one stage for at least one release before being promoted.
It is important that experimental features don't get stuck in that stage. They should be revisited and moved to the stable stage following the graduation steps as described here.
#### Locate graduation candidate
Decide if an experimental feature is ready for graduation to the stable stage.
- Find the issue that was used to enable the experimental feature initially. One way to find such issues is to search for issues with `type/feature` and `experimental` labels.
- Fix any known open issues against the feature.
- Make sure the feature was enabled for at least one previous release. Check the PR(s) reference from the issue to see when the feature related code changes were merged.
#### Provide implementation
If a feature is found ready for graduation to the next stage, open a Pull Request (PR) with the following changes.
- Update the feature `PreRelease` stage in `server/features/etcd_features.go`.
- Update the status in the original KEP issue.
If an experimental feature is found ready for graduation to the stable stage, open a Pull Request (PR) with the following changes.
- Add robust e2e tests if not already provided.
- Add a new stable feature flag identical to the experimental feature flag but without the `--experimental` prefix.
- Deprecate the experimental feature following the [feature deprecation policy](#Deprecating-a-feature).
- Implementation must ensure that both the graduated and deprecated experimental feature flags work as expected. Note that both these flags will co-exist for the timeframe described in the feature deprecation policy.
- Enable the graduated feature by default if needed.
At least two maintainers must approve the work. Patch releases should not be considered for graduation.
### Deprecating a feature
#### Alpha
Alpha features can be removed without going through the deprecation process.
- Remove the feature gate in `server/features/etcd_features.go`, and clean up all relevant code.
- Close the original KEP issue with reasons to drop the feature.
#### Experimental
An experimental feature deprecates when it graduates to the stable stage.
- Add a deprecation message in the documentation of the experimental feature with a recommendation to use related stable feature. e.g. `DEPRECATED. Use <feature-name> instead.`
- Add a `deprecated` label in the issue that was initially used to enable the experimental feature.
#### Beta and GA
As the project evolves, a Beta/GA feature may sometimes need to be deprecated and removed. Such a situation should be handled using the steps below:
#### Stable
As the project evolves, a stable feature may sometimes need to be deprecated and removed. Such a situation should be handled using the steps below:
- Create an issue for tracking purpose.
- Add a deprecation message in the feature usage documentation before a planned release for feature deprecation. e.g. `To be deprecated in <release>.`. If a new feature replaces the `To be deprecated` feature, then also provide a message saying so. e.g. `Use <feature-name> instead.`.
- Deprecate the feature in the planned release with a message as part of the feature usage documentation. e.g. `DEPRECATED`. If a new feature replaces the deprecated feature, then also provide a message saying so. e.g. `DEPRECATED. Use <feature-name> instead.`.
- Add a `deprecated` label in the related issue.
- A Beta/GA feature can only be deprecated after at least 2 minor or major releases.
- Update original KEP issue if it has not been closed or create a new etcd issue with reasons and steps to deprecate the feature.
- Add the feature deprecation documentation in the release notes and feature gates documentation of the next minor/major release.
- In the next minor/major release, set the feature gate to `{Default: false, PreRelease: featuregate.Deprecated, LockedToDefault: false}` in `server/features/etcd_features.go`. Deprecated feature gates must respond with a warning when used.
- If the feature has GAed, and the original gated codes has been cleaned up, add the disablement codes back with the feature gate.
- In the minor/major release after the next, set the feature gate to `{Default: false, PreRelease: featuregate.Deprecated, LockedToDefault: true}` in `server/features/etcd_features.go`, and start cleaning the code.
At least two maintainers must approve the work. Patch releases should not be considered for deprecation.
Remove the deprecated feature in the following release. Close any related issue(s). At least two maintainers must approve the work. Patch releases should not be considered for deprecation.

View File

@ -1,4 +1,4 @@
# Set up the local cluster
# Set up local cluster
For testing and development deployments, the quickest and easiest way is to configure a local cluster. For a production deployment, refer to the [clustering][clustering] section.
@ -28,7 +28,7 @@ Use `etcdctl` to interact with the running cluster:
OK
```
If OK is printed, storing the key-value pair is successful.
If OK is printed, storing key-value pair is successful.
2. Retrieve the value of `foo`:
@ -69,7 +69,7 @@ Use `etcdctl` to interact with the running cluster:
```
$ etcdctl --write-out=table --endpoints=localhost:2379 member list
```
The list of etcd members is displayed as follows:
The list of etcd members are displayed as follows:
```
+------------------+---------+--------+------------------------+------------------------+
@ -88,7 +88,7 @@ Use `etcdctl` to interact with the running cluster:
OK
```
If OK is printed, storing the key-value pair is successful.
If OK is printed, storing key-value pair is successful.
### Testing fault tolerance
@ -144,7 +144,7 @@ To exercise etcd's fault tolerance, kill a member and attempt to retrieve the ke
hello
```
Restarting the member re-establishs the connection. `etcdctl` will now be able to retrieve the key successfully. To learn more about interacting with etcd, read [interacting with etcd section][interacting].
Restarting the member re-establish the connection. `etcdctl` will now be able to retrieve the key successfully. To learn more about interacting with etcd, read [interacting with etcd section][interacting].
[clustering]: https://etcd.io/docs/latest/op-guide/clustering/
[interacting]: https://etcd.io/docs/latest/dev-guide/interacting_v3/

View File

@ -7,14 +7,14 @@ etcd uses the [zap][zap] library for logging application output categorized into
* Send a normal message to a remote peer
* Write a log entry to disk
* Info: Normal, working log information, everything is fine, but helpful notices for auditing or common operations. Should rather not be logged more frequently than once per a few seconds in a normal server's operation.
* Info: Normal, working log information, everything is fine, but helpful notices for auditing or common operations. Should rather not be logged more frequently than once per a few seconds in normal server's operation.
* Examples:
* Startup configuration
* Start to do a snapshot
* Start to do snapshot
* Warning: (Hopefully) Temporary conditions that may cause errors, but may work fine. A replica disappearing (that may reconnect) is a warning.
* Examples:
* Failure to send a raft message to a remote peer
* Failure to send raft message to a remote peer
* Failure to receive heartbeat message within the configured election timeout
* Error: Data has been lost, a request has failed for a bad reason, or a required resource has been lost.

View File

@ -5,17 +5,17 @@ The etcd project (since version 3.5) is organized into multiple
![modules graph](modules.svg)
There are the following modules:
There are following modules:
- **go.etcd.io/etcd/api/v3** - contains API definitions
(like protos & proto-generated libraries) that defines communication protocol
between etcd clients and servers.
between etcd clients and server.
- **go.etcd.io/etcd/pkg/v3** - a collection of utility packages used by etcd
- **go.etcd.io/etcd/pkg/v3** - collection of utility packages used by etcd
without being specific to etcd itself. A package belongs here
only if it could possibly be moved out into its own repository in the future.
Please avoid adding here code that has a lot of dependencies on its own, as
they automatically become dependencies of the client library
they automatically becoming dependencies of the client library
(that we want to keep lightweight).
- **go.etcd.io/etcd/client/v3** - client library used to contact etcd over
@ -26,14 +26,14 @@ There are the following modules:
https://github.com/etcd-io/raft.
- **go.etcd.io/etcd/server/v3** - etcd implementation.
The code in this package is internal to etcd and should not be consumed
The code in this package is etcd internal and should not be consumed
by external projects. The package layout and API can change within the minor versions.
- **go.etcd.io/etcd/etcdctl/v3** - a command line tool to access and manage etcd.
- **go.etcd.io/etcd/tests/v3** - a module that contains all integration tests of etcd.
Notice: All unit tests (fast and not requiring cross-module dependencies)
should be kept in the local modules of the code under the test.
Notice: All unit-tests (fast and not requiring cross-module dependencies)
should be kept in the local modules to the code under the test.
- **go.etcd.io/bbolt** - implementation of persistent b-tree.
Hosted in a separate repository: https://github.com/etcd-io/bbolt.
@ -44,7 +44,7 @@ There are the following modules:
1. All etcd modules should be released in the same versions, e.g.
`go.etcd.io/etcd/client/v3@v3.5.10` must depend on `go.etcd.io/etcd/api/v3@v3.5.10`.
The consistent updating of versions can be performed using:
The consistent updating of versions can by performed using:
```shell script
% DRY_RUN=false TARGET_VERSION="v3.5.10" ./scripts/release_mod.sh update_versions
```
@ -76,7 +76,7 @@ There are the following modules:
### Future
As a North Star, we would like to evaluate etcd modules towards the following model:
As a North Star, we would like to evaluate etcd modules towards following model:
![modules graph](modules-future.svg)

View File

@ -6,126 +6,70 @@ The procedure includes some manual steps for sanity checking, but it can probabl
## Release management
Under the leadership of **James Blair** [@jmhbnz](https://github.com/jmhbnz) and **Ivan Valdes Castillo** [@ivanvc](https://github.com/ivanvc), the following pool of release candidates manages the release of each etcd major/minor version as well as manages patches
to each stable release branch. They are responsible for communicating the timelines and status of each release and
for ensuring the stability of the release branch.
etcd community members are assigned to manage the release each etcd major/minor version as well as manage patches
and to each stable release branch. The managers are responsible for communicating the timelines and status of each
release and for ensuring the stability of the release branch.
- Benjamin Wang [@ahrtr](https://github.com/ahrtr)
- Fu Wei [@fuweid](https://github.com/fuweid)
- James Blair [@jmhbnz](https://github.com/jmhbnz)
- Ivan Valdes Castillo [@ivanvc](https://github.com/ivanvc)
- Marek Siarkowicz [@serathius](https://github.com/serathius)
- Sahdev Zala [@spzala](https://github.com/spzala)
- Siyuan Zhang [@siyuanfoundation](https://github.com/siyuanfoundation)
- Wenjia Zhang [@wenjiaswe](https://github.com/wenjiaswe)
| Releases | Manager |
|------------------------|-------------------------------------------------------------|
| 3.4 patch (post 3.4.0) | Benjamin Wang [@ahrtr](https://github.com/ahrtr) |
| 3.5 patch (post 3.5.0) | Marek Siarkowicz [@serathius](https://github.com/serathius) |
All release version numbers follow the format of [semantic versioning 2.0.0](http://semver.org/).
All releases version numbers follow the format of [semantic versioning 2.0.0](http://semver.org/).
### Major, minor version release, or its pre-release
- Ensure the relevant [milestone](https://github.com/etcd-io/etcd/milestones) on GitHub is complete. All referenced issues should be closed or moved elsewhere.
- Ensure the latest [upgrade documentation](https://etcd.io/docs/next/upgrades) is available.
- Ensure the relevant milestone on GitHub is complete. All referenced issues should be closed, or moved elsewhere.
- Ensure the latest upgrade documentation is available.
- Bump [hardcoded MinClusterVerion in the repository](https://github.com/etcd-io/etcd/blob/v3.4.15/version/version.go#L29), if necessary.
- Add feature capability maps for the new version, if necessary.
### Patch version release
- To request a backport, developers submit cherry-pick PRs targeting the release branch. The commits should not include merge commits. The commits should be restricted to bug fixes and security patches.
- The cherrypick PRs should target the appropriate release branch (`base:release-<major>-<minor>`). The k8s infra cherry pick robot `/cherrypick <branch>` PR chatops command may be used to automatically generate cherrypick PRs.
- The release patch manager reviews the cherrypick PRs. Please discuss carefully what is backported to the patch release. Each patch release should be strictly better than its predecessor.
- To request a backport, devlopers submit cherrypick PRs targeting the release branch. The commits should not include merge commits. The commits should be restricted to bug fixes and security patches.
- The cherrypick PRs should target the appropriate release branch (`base:release-<major>-<minor>`). `hack/patch/cherrypick.sh` may be used to automatically generate cherrypick PRs.
- The release patch manager reviews the cherrypick PRs. Please discuss carefully what is backported to the patch release. Each patch release should be strictly better than it's predecessor.
- The release patch manager will cherry-pick these commits starting from the oldest one into stable branch.
## Write a release note
## Write release note
- Write an introduction for the new release. For example, what major bug we fix, what new features we introduce, or what performance improvement we make.
- Put `[GH XXXX]` at the head of the change line to reference the Pull Request that introduces the change. Moreover, add a link on it to jump to the Pull Request.
- Find PRs with the `release-note` label and explain them in the `NEWS` file, as a straightforward summary of changes for end-users.
- Write introduction for the new release. For example, what major bug we fix, what new features we introduce or what performance improvement we make.
- Put `[GH XXXX]` at the head of change line to reference Pull Request that introduces the change. Moreover, add a link on it to jump to the Pull Request.
- Find PRs with `release-note` label and explain them in `NEWS` file, as a straightforward summary of changes for end-users.
## Patch release criteria
## Build and push the release artifacts
The etcd project aims to release a new patch version if any of the following conditions are met:
- Ensure `docker` is available.
- Fixed one or more major CVEs (>=7.5).
- Fixed one or more critical bugs.
- Fixed three or more major bugs.
- Fixed five or more minor bugs.
Run release script in root directory:
## Release guide
### Prerequisites
There are some prerequisites, which should be done before the release process. These are one-time operations,
which don't need to be executed before releasing each version.
1. Generate a GPG key and add it to your GitHub account. Refer to the links on [settings](https://github.com/settings/keys).
2. Ensure you have a Linux machine, on which the git, Golang, and docker have been installed.
- Ensure the Golang version matches the version defined in `.go-version` file.
- Ensure non-privileged users can run docker commands, refer to the [Linux postinstall](https://docs.docker.com/engine/install/linux-postinstall/).
- Ensure there is at least 5GB of free space on your Linux machine.
3. Install gsutil, refer to [gsutil_install](https://cloud.google.com/storage/docs/gsutil_install). When asked about cloud project to use, pick `etcd-development`.
4. Authenticate the image registry, refer to [Authentication methods](https://cloud.google.com/container-registry/docs/advanced-authentication).
- `gcloud auth login`
- `gcloud auth configure-docker`
5. Install gh, refer to [GitHub's documentation](https://github.com/cli/cli#installation). Ensure that running
`gh auth login` succeeds for the GitHub account you use to contribute to etcd,
and that `gh auth status` has a clean exit and doesn't show any issues.
### Release steps
1. Raise an issue to publish the release plan, e.g. [issues/17350](https://github.com/etcd-io/etcd/issues/17350).
2. Raise a `kubernetes/org` pull request to ensure members of the release team are added to the [release github team](https://github.com/orgs/etcd-io/teams/release-etcd).
3. Verify you can pass the authentication to the image registries,
- `docker login gcr.io`
- `docker login quay.io`
- If the release person doesn't have access to 1password, one of the owners (@ahrtr, @ivanvc, @jmhbnz, @serathius) needs to share the password with them per [this guide](https://support.1password.com/share-items/). See rough steps below,
- [Sign in](https://team-etcd.1password.com/home) to your account on 1password.com.
- Click `Your Vault Items` on the right side.
- Select `Password of quay.io`.
- Click `Share` on the top right, and set expiration as `1 hour` and only available to the release person using his/her email.
- Click `Copy Link` then send the link to the release person via slack or email.
4. Clone the etcd repository and checkout the target branch,
- `git clone --branch release-3.X git@github.com:etcd-io/etcd.git`
5. Run the release script under the repository's root directory, replacing `${VERSION}` with a value without the `v` prefix, i.e. `3.5.13`.
- `DRY_RUN=false ./scripts/release.sh ${VERSION}`
- **NOTE:** When doing a pre-release (i.e., a version from the main branch, 3.6.0-alpha.2), you will need to explicitly set the branch to main:
```
DRY_RUN=false BRANCH=main ./scripts/release.sh ${VERSION}
```
It generates all release binaries under the directory `/tmp/etcd-release-${VERSION}/etcd/release/` and images. Binaries are pushed to the Google Cloud bucket
under project `etcd-development`, and images are pushed to `quay.io` and `gcr.io`.
6. Publish the release page on GitHub
- Open the **draft** release URL shown by the release script
- Click the pen button at the top right to edit the release
- Review that it looks correct, reviewing that the bottom checkboxes are checked depending on the
release version (v3.4 no checkboxes, v3.5 has the set as latest release checkbox checked,
v3.6 has the set as pre-release checkbox checked)
- Then, publish the release
7. Announce to the etcd-dev googlegroup
Follow the format of previous release emails sent to etcd-dev@googlegroups.com, see an example below. After sending out the email, ask one of the mailing list maintainers to approve the email from the pending list. Additionally, label the release email as `Release`.
```text
Hello,
etcd v3.4.30 is now public!
https://github.com/etcd-io/etcd/releases/tag/v3.4.30
Thanks to everyone who contributed to the release!
etcd team
```
DRY_RUN=false ./scripts/release.sh ${VERSION}
```
8. Update the changelog to reflect the correct release date.
9. Paste the release link to the issue raised in Step 1 and close the issue.
10. Raise a follow-up `kubernetes/org` pull request to return the GitHub release team to empty, least privilege state.
11. Crease a new stable branch through `git push origin release-${VERSION_MAJOR}.${VERSION_MINOR}` if this is a new major or minor stable release.
12. Re-generate a new password for quay.io if needed (e.g. shared to a contributor who isn't in the release team, and we should rotate the password at least once every 3 months).
It generates all release binaries and images under directory ./release.
Binaries are pushed to gcr.io and images are pushed to quay.io and gcr.io.
#### Release known issues
## Publish release page in GitHub
1. Timeouts pushing binaries - If binaries fail to fully upload to Google Cloud storage, the script must be re-run using the same command. Any artifacts that are already pushed will be overwritten to ensure they are correct. The storage bucket does not use object versioning so incorrect files cannot remain.
- Set release title as the version name.
- Follow the format of previous release pages.
- Attach the generated binaries and signatures.
- Select whether it is a pre-release.
- Publish the release!
2. Timeouts pushing images - It is rare, although possible for connection timeouts to occur when publishing etcd release images to `quay.io` or `gcr.io`. If this occurs, it is known to be safe to rerun the release script command appending the `--no-upload` flag, and image uploads will gracefully resume.
## Announce to the etcd-dev Googlegroup
3. GPG vs SSH signing - The release scripts assume that git tags will be signed with a GPG key. Since 2022 GitHub has supported [signing commits and tags using ssh](https://github.blog/changelog/2022-08-23-ssh-commit-verification-now-supported). Until further release script updates are completed you will need to disable this feature in your `~/.gitconfig` and revert to signing via GPG to perform etcd releases.
- Follow the format of [previous release emails](https://groups.google.com/g/etcd-dev).
- Make sure to include a list of authors that contributed since the previous release - something like the following might be handy:
```
git log ...${PREV_VERSION} --pretty=format:"%an" | sort | uniq | tr '\n' ',' | sed -e 's#,#, #g' -e 's#, $##'
```
- Send email to etcd-dev@googlegroups.com
## Post release
- Create new stable branch through `git push origin ${VERSION_MAJOR}.${VERSION_MINOR}` if this is a major stable release. This assumes `origin` corresponds to "https://github.com/etcd-io/etcd".
- Bump [hardcoded Version in the repository](https://github.com/etcd-io/etcd/blob/v3.4.15/version/version.go#L30) to the version `${VERSION}+git`.

View File

@ -4,13 +4,13 @@ If any part of the etcd project has bugs or documentation mistakes, please let u
To make the bug report accurate and easy to understand, please try to create bug reports that are:
- Specific. Include as many details as possible: which version, what environment, what configuration, etc. If the bug is related to running the etcd server, please attach the etcd log (the starting log with the etcd configuration is especially important).
- Specific. Include as much details as possible: which version, what environment, what configuration, etc. If the bug is related to running the etcd server, please attach the etcd log (the starting log with etcd configuration is especially important).
- Reproducible. Include the steps to reproduce the problem. We understand some issues might be hard to reproduce, please include the steps that might lead to the problem. If possible, please attach the affected etcd data dir and stack trace to the bug report.
- Reproducible. Include the steps to reproduce the problem. We understand some issues might be hard to reproduce, please includes the steps that might lead to the problem. If possible, please attach the affected etcd data dir and stack strace to the bug report.
- Isolated. Please try to isolate and reproduce the bug with minimum dependencies. It would significantly slow down the speed to fix a bug if too many dependencies are involved in a bug report. Debugging external systems that rely on etcd is out of scope, but we are happy to provide guidance in the right direction or help with using etcd itself.
- Unique. Do not duplicate existing bug reports.
- Unique. Do not duplicate existing bug report.
- Scoped. One bug per report. Do not follow up with another bug inside one report.
@ -26,7 +26,7 @@ We might ask for further information to locate a bug. A duplicated bug report wi
$ kill -QUIT $PID
```
### How to get the etcd version
### How to get etcd version
``` bash
$ etcd --version
@ -39,7 +39,7 @@ $ sudo systemctl cat etcd2
$ sudo journalctl -u etcd2
```
Due to an upstream systemd bug, journald may miss the last few log lines when its processes exit. If journalctl says etcd stopped without a fatal or panic message, try `sudo journalctl -f -t etcd2` to get the full log.
Due to an upstream systemd bug, journald may miss the last few log lines when its processes exit. If journalctl says etcd stopped without fatal or panic message, try `sudo journalctl -f -t etcd2` to get full log.
[etcd-issue]: https://github.com/etcd-io/etcd/issues/new
[filing-good-bugs]: http://fantasai.inkedblade.net/style/talks/filing-good-bugs/

View File

@ -1,9 +1,9 @@
# Roadmap
etcd uses GitHub milestones to track all tasks in each major or minor release. The `roadmap.md` file only records the
most important tasks for each release. The list is based on the current maintainer capacity that may shift over time.
Proposed milestones are what we think we can deliver with the people we have. If we have more support on the important
stuff, we could pick up more items from the backlog. Note that etcd will continue to mainly focus on technical debt over
most important tasks for each release. The list is based on current maintainers capacity that may shift over time.
Proposed milestones is what we think we can deliver with people we have. If we have more support on the important
stuff, we could pick up more items from backlog. Note that etcd will continue to mainly focus on technical debt over
the next few major or minor releases.
Each item has an assigned priority. Refer to [priority definitions](https://github.com/etcd-io/etcd/blob/main/Documentation/contributor-guide/triage_issues.md#step-5---prioritise-the-issue).
@ -18,7 +18,7 @@ For a full list of tasks in `v3.6.0`, please see [milestone etcd-v3.6](https://g
| [StoreV2 deprecation](https://github.com/etcd-io/etcd/issues/12913) | priority/important-soon | In progress | This task will be covered in both 3.6 and 3.7. |
| [Release raft 3.6.0](https://github.com/etcd-io/raft/issues/89) | priority/important-soon | Not started | etcd 3.6.0 will depends on raft 3.6.0 |
| [Release bbolt 1.4.0](https://github.com/etcd-io/bbolt/issues/553) | priority/important-soon | Not started | etcd 3.6.0 will depends on bbolt 1.4.0 |
| [Support /livez and /readyz endpoints](https://github.com/etcd-io/etcd/issues/16007) | priority/important-longterm | In progress | It provides clearer APIs, and can also work around the stalled writes issue |
| [Support /livez and /readyz endpoints](https://github.com/etcd-io/etcd/issues/16007) | priority/important-longterm | In progress | It provides clearer APIs, and can also workaround the stalled writes issue |
| [Bump gRPC](https://github.com/etcd-io/etcd/issues/16290) | priority/important-longterm | Completed | It isn't guaranteed to be resolved in 3.6, and might be postponed to 3.7 depending on the effort and risk. |
| [Deprecate grpc-gateway or bump it](https://github.com/etcd-io/etcd/issues/14499) | priority/important-longterm | Completed | It isn't guaranteed to be resolved in 3.6, and might be postponed to 3.7 depending on the effort and risk. |
| [bbolt: Add logger into bbolt](https://github.com/etcd-io/bbolt/issues/509) | priority/important-longterm | Completed | It's important to diagnose bbolt issues |
@ -33,7 +33,7 @@ For a full list of tasks in `v3.7.0`, please see [milestone etcd-v3.7](https://g
|-------------------------------------------------------------------------------------------------------------------|----------|-----------------------------------------------------------------------------------|
| [StoreV2 deprecation](https://github.com/etcd-io/etcd/issues/12913) | P0 | Finish the remaining tasks 3.7. |
| [Refactor lease: Lease might be revoked by mistake by old leader](https://github.com/etcd-io/etcd/issues/15247) | P1 | to be investigated & discussed |
| [Integrate raft's new feature (async write) into etcd](https://github.com/etcd-io/etcd/issues/16291) | P1 | It should improve the performance |
| [Integrate raft's new feature (async write) into etcd](https://github.com/etcd-io/etcd/issues/16291) | P1 | It should can improve the performance |
| [bbolt: Support customizing the bbolt rebalance threshold](https://github.com/etcd-io/bbolt/issues/422) | P2 | It may get rid of etcd's defragmentation. Both bbolt and etcd need to be changed. |
| [Evaluate and (graduate or deprecate/remove) experimental features](https://github.com/etcd-io/etcd/issues/16292) | P2 | Finish the remaining tasks 3.7. |

View File

@ -4,19 +4,19 @@
Speed up issue management.
The `etcd` issues are listed at <https://github.com/etcd-io/etcd/issues> and are identified with labels. For example, an issue that is identified as a bug will be set to the label `type/bug`.
The `etcd` issues are listed at <https://github.com/etcd-io/etcd/issues> and are identified with labels. For example, an issue that is identified as a bug will be set to label `type/bug`.
The etcd project uses labels to indicate common attributes such as `area`, `type`, and `priority` of incoming issues.
The etcd project uses labels to indicate common attributes such as `area`, `type` and `priority` of incoming issues.
New issues will often start without any labels, but typically `etcd` maintainers, reviewers, and members will add labels by following these triage guidelines. The detailed list of labels can be found at <https://github.com/etcd-io/etcd/labels>.
New issues will often start out without any labels, but typically `etcd` maintainers, reviewers and members will add labels by following these triage guidelines. The detailed list of labels can be found at <https://github.com/etcd-io/etcd/labels>.
## Scope
This document serves as the primary guidelines for triaging incoming issues in `etcd`.
All contributors are encouraged and welcome to help manage issues which will help reduce the burden on project maintainers, though the work and responsibilities discussed in this document are created with `etcd` project reviewers and members in mind as these individuals will have triage access to the etcd project which is a requirement for actions like applying labels or closing issues.
All contributors are encouraged and welcome to help manage issues which will help reduce burden on project maintainers, though the work and responsibilities discussed in this document are created with `etcd` project reviewers and members in mind as these individuals will have triage access to the etcd project which is a requirement for actions like applying labels or closing issues.
Refer to [etcd community membership](https://github.com/etcd-io/etcd/blob/main/Documentation/contributor-guide/community-membership.md) for guidance on becoming an etcd project member or reviewer.
Refer to [etcd community membership](https://github.com/etcd-io/etcd/blob/main/Documentation/contributor-guide/community-membership.md) for guidance on becoming and etcd project member or reviewer.
## Step 1 - Find an issue to triage
@ -34,33 +34,33 @@ Before we start adding labels or trying to work out a priority, our first triage
### Issues that don't belong to etcd
Sometimes issues are reported that belong to other projects that `etcd` use. For example, `grpc` or `golang` issues. Such issues should be addressed by asking the reporter to open issues in the appropriate other projects.
Sometime issues are reported that actually belongs to other projects that `etcd` use. For example, `grpc` or `golang` issues. Such issues should be addressed by asking reporter to open issues in appropriate other project.
These issues can generally be closed unless a maintainer and issue reporter see a need to keep it open for tracking purposes. If you have triage permissions please close it, alternatively mention the @etcd-io/members group to request a member with triage access to close the issue.
These issues can generally be closed unless a maintainer and issue reporter see a need to keep it open for tracking purpose. If you have triage permissions please close it, alternatively mention the @etcd-io/members group to request a member with triage access close the issue.
### Duplicate issues
If an issue is a duplicate, add a comment stating so along with a reference for the original issue and if you have triage permissions please close it, alternatively mention the @etcd-io/members group to request a member with triage access close the issue.
## Step 3 - Apply the appropriate type of label
## Step 3 - Apply the appropriate type label
Adding a `type` label to an issue helps create visibility on the health of the project and helps contributors identify potential priorities, i.e. addressing existing bugs or test flakes before implementing new features.
### Support requests
As a general rule, the focus for etcd support is to address common themes in a broad way that helps all users, i.e. through channels like known issues, frequently asked questions, and high-quality documentation. To make the best use of project members time we should avoid providing 1:1 support if a broad approach is available.
As a general rule the focus for etcd support is to address common themes in a broad way that helps all users, i.e. through channels like known issues, frequently asked questions and high quality documentation. To make the best use of project members time we should avoid providing 1:1 support if a broad approach is available.
Some people mistakenly use our GitHub bug report or feature request templates to file support requests. Usually, they are asking for help operating or configuring some aspect of etcd. Support requests for etcd should instead be raised as [discussions](https://github.com/etcd-io/etcd/discussions).
Some people mistakenly use our GitHub bug report or feature request templates to file support requests. Usually they are asking for help operating or configuring some aspect of etcd. Support requests for etcd should instead be raised as [discussions](https://github.com/etcd-io/etcd/discussions).
Common types of support requests are:
1. Questions about configuring or operating existing well-documented etcd features, for example, <https://github.com/etcd-io/etcd/issues/15945>. Note - If an existing feature is not well documented please apply the `area/documentation` label and propose documentation improvements that would prevent future users from stumbling on the problem again.
1. Questions about configuring or operating existing well documented etcd features, for example <https://github.com/etcd-io/etcd/issues/15945>. Note - If an existing feature is not well documented please apply the `area/documentation` label and propose documentation improvements that would prevent future users from stumbling on the problem again.
2. Bug reports or questions about unsupported versions of etcd, for example <https://github.com/etcd-io/etcd/issues/15796>. When responding to these issues please refer to our [supported versions documentation](https://etcd.io/docs/latest/op-guide/versioning) and encourage the reporter to upgrade to a recent patch release of a supported version as soon as possible. We should limit the effort supporting users that do not make the effort to run a supported version of etcd or ensure their version is patched.
2. Bug reports or questions about unspported versions of etcd, for example <https://github.com/etcd-io/etcd/issues/15796>. When responding to these issues please refer to our [supported versions documentation](https://etcd.io/docs/latest/op-guide/versioning) and encourage the reporter to upgrade to a recent patch release of a supported version as soon as possible. We should limit the effort supporting users that do not make the effort to run a supported version of etcd or ensure their version is patched.
3. Bug reports that do not provide a complete list of steps to reproduce the issue and/or contributors are not able to reproduce the issue, for example, <https://github.com/etcd-io/etcd/issues/15740>. We should limit the effort we put into reproducing issues ourselves and motivate users to provide the necessary information to accept the bug report.
3. Bug reports that do not provide a complete list of steps to reproduce issue and/or contributors are not able to reproduce the issue, for example <https://github.com/etcd-io/etcd/issues/15740>. We should limit the effort we put into reproducing issues ourselves and motivate users to provide necessary information to accept the bug report.
4. General questions that are filed using feature request or bug report issue templates, for example, <https://github.com/etcd-io/etcd/issues/15914>. Note - These types of requests may surface good additions to our [frequently asked questions](https://etcd.io/docs/v3.5/faq).
4. General questions that are filed using feature request or bug report issue templates, for example <https://github.com/etcd-io/etcd/issues/15914>. Note - These types of requests may surface good additions to our [frequently asked questions](https://etcd.io/docs/v3.5/faq).
If you identify that an issue is a support request please:
@ -70,7 +70,7 @@ If you identify that an issue is a support request please:
> Thank you for your question, this support issue will be moved to our [Discussion Forums](https://github.com/etcd-io/etcd/discussions).
>
> We are trying to consolidate the channels to which questions for help/support are posted so that we can improve our efficiency in responding to your requests, and make it easier for you to find answers to frequently asked questions and how to address common use cases.
> We are trying to consolidate the channels to which questions for help/support are posted so that we can improve our efficiency in responding to your requests, and to make it easier for you to find answers to frequently asked questions and how to address common use cases.
>
> We regularly see messages posted in multiple forums, with the full response thread only in one place or, worse, spread across multiple forums. Also, the large volume of support issues on GitHub is making it difficult for us to use issues to identify real bugs.
>
@ -83,23 +83,23 @@ If you identify that an issue is a support request please:
>
> The etcd team
3. Finally, click `Convert to discussion` on the right-hand panel, selecting the appropriate discussion category.
3. Finally, click `Convert to discussion` on the right hand panel, selecting the appropriate discussion category.
### Bug reports
If an issue has been raised as a bug it should already have the `type/bug` label, however, if this is missing for an issue you determine to be a bug please add the label manually.
If an issue has been raised as a bug it should already have the `type/bug` label, however if this is missing for an issue you determine to be a bug please add the label manually.
The next step is to validate if the issue is indeed a bug. If not, add a comment with the findings and close the trivial issue. For non-trivial issues, wait to hear back from the issue reporter and see if there is any objection. If the issue reporter does not reply in 30 days, close the issue.
The next step is to validate if the issue is indeed a bug. If not, add a comment with findings and close trivial issue. For non-trivial issue, wait to hear back from issue reporter and see if there is any objection. If issue reporter does not reply in 30 days, close the issue.
If the problem can not be reproduced or requires more information, leave a comment for the issue reporter as soon as possible while the issue is fresh for the issue reporter.
If the problem can not be reproduced or requires more information, leave a comment for the issue reporter as soon as possible while the issue will be fresh for the issue reporter.
### Feature requests
New feature requests should be created via the etcd feature request template and in theory already have the `type/feature` label, however, if this is missing for an issue you determine to be a feature please add the label manually.
New feature requests should be created via the etcd feature request template and in theory already have the `type/feature` label, however if this is missing for an issue you determine to be a feature please add the label manually.
### Test flakes
Test flakes are a specific type of bug that the etcd project tracks separately as these are a priority to address. These should be created via the test flake template and in theory already have the `type/flake` label, however, if this is missing for an issue you determine to be related to a flaking test please add the label manually.
Test flakes are a specific type of bug that the etcd project tracks separately as these are a priority to address. These should be created via the test flake template and in theory already have the `type/flake` label, however if this is missing for an issue you determine to be related to a flaking test please add the label manually.
## Step 4 - Define the areas impacted
@ -121,9 +121,9 @@ Below is a brief summary of the area labels in active use by the etcd project al
| area/auth | |
| area/etcdctl | |
| area/etcdutl | |
| area/contrib | Not to be confused with `area/community` this label is specifically used for issues relating to community-maintained scripts or files in the `contrib/` directory which aren't part of the core etcd project. |
| area/contrib | Not to be confused with `area/community` this label is specifically used for issues relating to community maintained scripts or files in the `contrib/` directory which aren't part of the core etcd project. |
| area/documentation | |
| area/tooling | Generally used in relation to the third party / external utilities or tools that are used in various stages of the etcd build, test, or release process, for example, tooling to create sboms. |
| area/tooling | Generally used in relation to the third party / external utilities or tools that are used in various stages of the etcd build, test or release process, for example tooling to create sboms. |
| area/testing | |
| area/robustness-testing | |
@ -131,11 +131,11 @@ Below is a brief summary of the area labels in active use by the etcd project al
If an issue lacks a priority label it has not been formally prioritized yet.
Adding a `priority` label helps the etcd project understand what is important and should be worked on now, and conversely, what is not as important and is on the project backlog.
Adding a `priority` label helps the etcd project understand what is important and should be worked on now, and conversely what is not as important and is on the project backlog.
|Priority label|What it means|Examples|
|---|---|---|
| `priority/critical-urgent` | Maintainers are responsible for making sure that these issues (in their area) are being actively worked on—i.e., drop what you're doing. The stuff is burning. These should be fixed before the next release. | user-visible critical bugs in core features <br> broken builds on tier1 supported platforms <br> tests and critical security issues |
| `priority/critical-urgent` | Maintainers are responsible for making sure that these issues (in their area) are being actively worked on—i.e., drop what you're doing. Stuff is burning. These should be fixed before the next release. | user-visible critical bugs in core features <br> broken builds on tier1 supported platforms <br> tests and critical security issues |
| `priority/important-soon` | Must be staffed and worked on either currently or very soon—ideally in time for the next release. | |
| `priority/important-longterm` | Important over the long term, but may not be currently staffed and/or may require multiple releases to complete. | |
| `priority/backlog` | General agreement that this is a nice-to-have, but no one's available to work on it anytime soon. Community contributions would be most welcome in the meantime, though it might take a while to get them reviewed if reviewers are fully occupied with higher-priority issues—for example, immediately before a release.| |
@ -179,11 +179,11 @@ Once initial triage has been completed, issues need to be re-evaluated over time
### Track important issues
If an issue is at risk of being closed by the stale bot in the future, but is an important issue for the etcd project, then please apply the `stage/tracked` label and remove any `stale` labels that exist. This will ensure the project does not lose sight of the issue.
If an issue is at risk of being closed by stale bot in future, but is an important issuefor the etcd project, then please apply the `stage/tracked` label and remove any `stale` labels that exist. This will ensure the project does not lose sight of the issue.
### Close incomplete issues
Issues that lack enough information from the issue reporter should be closed if the issue reporter does not provide information in 30 days. Issues can always be re-opened at a later date if new information is provided.
Issues that lack enough information from the issue reporter should be closed if issue reporter do not provide information in 30 days. Issues can always be re-opened at a later date if new information is provided.
### Check for incomplete work

View File

@ -5,27 +5,23 @@
Speed up PR management.
The `etcd` PRs are listed at https://github.com/etcd-io/etcd/pulls
A PR can have various labels, milestones, reviewers, etc. The detailed list of labels can be found at
A PR can have various labels, milestone, reviewer etc. The detailed list of labels can be found at
https://github.com/kubernetes/kubernetes/labels
Following are a few example searches on PR for convenience:
Following are few example searches on PR for convenience:
* [Open PRS for milestone etcd-v3.6](https://github.com/etcd-io/etcd/pulls?utf8=%E2%9C%93&q=is%3Apr+is%3Aopen+milestone%3Aetcd-v3.6)
* [PRs under investigation](https://github.com/etcd-io/etcd/labels/Investigating)
## Scope
These guidelines serve as a primary document for managing PRs in `etcd`. Everyone is welcome to help manage PRs but the work and responsibilities discussed in this document are created with `etcd` maintainers and active contributors in mind.
## Ensure tests are run
The etcd project use Kubernetes Prow and GitHub Actions to run tests. To ensure all required tests run if a pull request is ready for testing and still has the `needs-ok-to-test` label then please comment on the pull request `/ok-to-test`.
These guidelines serves as a primary document for managing PRs in `etcd`. Everyone is welcome to help manage PRs but the work and responsibilities discussed in this document is created with `etcd` maintainers and active contributors in mind.
## Handle inactive PRs
Poke PR owner if review comments are not addressed in 15 days. If the PR owner does not reply in 90 days, update the PR with a new commit if possible. If not, inactive PR should be closed after 180 days.
Poke PR owner if review comments are not addressed in 15 days. If PR owner does not reply in 90 days, update the PR with a new commit if possible. If not, inactive PR should be closed after 180 days.
## Poke reviewer if needed
Reviewers are responsive in a timely fashion, but considering everyone is busy, give them some time after requesting a review if a quick response is not provided. If the response is not provided in 10 days, feel free to contact them via adding a comment in the PR or sending an email or message on Slack.
Reviewers are responsive in a timely fashion, but considering everyone is busy, give them some time after requesting review if quick response is not provided. If response is not provided in 10 days, feel free to contact them via adding a comment in the PR or sending an email or message on the Slack.
## Verify important labels are in place

View File

@ -2135,19 +2135,6 @@
}
}
},
"etcdserverpbDowngradeInfo": {
"type": "object",
"properties": {
"enabled": {
"type": "boolean",
"description": "enabled indicates whether the cluster is enabled to downgrade."
},
"targetVersion": {
"type": "string",
"description": "targetVersion is the target downgrade version."
}
}
},
"etcdserverpbDowngradeRequest": {
"type": "object",
"properties": {
@ -2702,7 +2689,7 @@
"count": {
"type": "string",
"format": "int64",
"description": "count is set to the actual number of keys within the range when requested.\nUnlike Kvs, it is unaffected by limits and filters (e.g., Min/Max, Create/Modify, Revisions)\nand reflects the full count within the specified range."
"description": "count is set to the number of keys within the range when requested."
}
}
},
@ -2847,16 +2834,7 @@
},
"storageVersion": {
"type": "string",
"description": "storageVersion is the version of the db file. It might be updated with delay in relationship to the target cluster version."
},
"dbSizeQuota": {
"type": "string",
"format": "int64",
"title": "dbSizeQuota is the configured etcd storage quota in bytes (the value passed to etcd instance by flag --quota-backend-bytes)"
},
"downgradeInfo": {
"$ref": "#/definitions/etcdserverpbDowngradeInfo",
"description": "downgradeInfo indicates if there is downgrade process."
"description": "storageVersion is the version of the db file. It might be get updated with delay in relationship to the target cluster version."
}
}
},
@ -2999,7 +2977,7 @@
},
"canceled": {
"type": "boolean",
"description": "canceled is set to true if the response is for a cancel watch request\nor if the start_revision has already been compacted.\nNo further events will be sent to the canceled watcher."
"description": "canceled is set to true if the response is for a cancel watch request.\nNo further events will be sent to the canceled watcher."
},
"compact_revision": {
"type": "string",

View File

@ -318,7 +318,7 @@
"name": {
"type": "string",
"format": "byte",
"description": "name is the election identifier that corresponds to the leadership key."
"description": "name is the election identifier that correponds to the leadership key."
},
"key": {
"type": "string",

View File

@ -0,0 +1,17 @@
# etcd arm64 test infrastructure
The infrastructure to build for arm64 is provided by [Equinix Metal](https://www.equinix.com/) via the [CNCF Community Infrastructure Lab](https://github.com/cncf/cluster/issues).
Previously, several maintainers were responsible for managing two bare-metal machines with a self-hosted runner installed. This was a manual process, and side effects could be left over from previous builds.
As part of a joint program between Ampere and the CNCF, [actuated.dev](https://actuated.dev) is providing managed Arm64 builds.
To use the new infrastructure, add the following to your workflow:
```yaml
runs-on: actuated-arm64-8cpu-8gb
```
The vCPUs and RAM are customizable, i.e. `actuated-arm64-8cpu-16gb` or `actuated-arm64-8cpu-32gb`.
For urgent support, contact @alexellis or the [actuated team](https://actuated.dev).

View File

@ -1,29 +1,25 @@
REPOSITORY_ROOT := $(shell git rev-parse --show-toplevel)
.PHONY: all
all: build
include $(REPOSITORY_ROOT)/tests/robustness/Makefile
include tests/robustness/makefile.mk
.PHONY: build
build:
GO_BUILD_FLAGS="${GO_BUILD_FLAGS} -v -mod=readonly" ./scripts/build.sh
PLATFORMS=linux-amd64 linux-386 linux-arm linux-arm64 linux-ppc64le linux-s390x darwin-amd64 darwin-arm64 windows-amd64 windows-arm64
.PHONY: build-all
build-all:
@for platform in $(PLATFORMS); do \
$(MAKE) build-$${platform}; \
done
.PHONY: build-%
build-%:
GOOS=$$(echo $* | cut -d- -f 1) GOARCH=$$(echo $* | cut -d- -f 2) GO_BUILD_FLAGS="${GO_BUILD_FLAGS} -v -mod=readonly" ./scripts/build.sh
.PHONY: tools
tools:
GO_BUILD_FLAGS="${GO_BUILD_FLAGS} -v -mod=readonly" ./scripts/build_tools.sh
TEMP_TEST_ANALYZER_DIR=/tmp/etcd-test-analyzer
TEST_ANALYZER_BIN=${PWD}/bin
bin/etcd-test-analyzer: $(TEMP_TEST_ANALYZER_DIR)/*
make -C ${TEMP_TEST_ANALYZER_DIR} build
mkdir -p ${TEST_ANALYZER_BIN}
install ${TEMP_TEST_ANALYZER_DIR}/bin/etcd-test-analyzer ${TEST_ANALYZER_BIN}
${TEST_ANALYZER_BIN}/etcd-test-analyzer -h
$(TEMP_TEST_ANALYZER_DIR)/*:
git clone "https://github.com/endocrimes/etcd-test-analyzer.git" ${TEMP_TEST_ANALYZER_DIR}
# Tests
GO_TEST_FLAGS?=
@ -60,27 +56,17 @@ test-e2e-release: build
test-robustness:
PASSES="robustness" ./scripts/test.sh $(GO_TEST_FLAGS)
.PHONY: test-coverage
test-coverage:
COVERDIR=covdir PASSES="build cov" ./scripts/test.sh $(GO_TEST_FLAGS)
.PHONY: upload-coverage-report
upload-coverage-report: test-coverage
COVERDIR=covdir ./scripts/codecov_upload.sh
.PHONY: fuzz
fuzz:
./scripts/fuzzing.sh
# Static analysis
.PHONY: verify
verify: verify-gofmt verify-bom verify-lint verify-dep verify-shellcheck verify-goword \
verify-govet verify-license-header verify-mod-tidy \
verify-shellws verify-proto-annotations verify-genproto verify-yamllint \
verify-govet-shadow verify-markdown-marker verify-go-versions
.PHONY: fix
fix: fix-bom fix-lint fix-yamllint sync-toolchain-directive
verify: verify-gofmt verify-bom verify-lint verify-dep verify-shellcheck verify-goword \
verify-govet verify-license-header verify-receiver-name verify-mod-tidy \
verify-shellws verify-proto-annotations verify-genproto verify-yamllint \
verify-govet-shadow verify-markdown-marker
fix: fix-bom fix-lint fix-yamllint
./scripts/fix.sh
.PHONY: verify-gofmt
@ -123,6 +109,10 @@ verify-govet:
verify-license-header:
PASSES="license_header" ./scripts/test.sh
.PHONY: verify-receiver-name
verify-receiver-name:
PASSES="receiver_name" ./scripts/test.sh
.PHONY: verify-mod-tidy
verify-mod-tidy:
PASSES="mod_tidy" ./scripts/test.sh
@ -143,11 +133,9 @@ verify-genproto:
verify-yamllint:
ifeq (, $(shell which yamllint))
@echo "Installing yamllint..."
tmpdir=$$(mktemp -d); \
trap "rm -rf $$tmpdir" EXIT; \
python3 -m venv $$tmpdir; \
$$tmpdir/bin/python3 -m pip install yamllint; \
$$tmpdir/bin/yamllint --config-file tools/.yamllint .
python3 -m venv bin/python
bin/python/bin/python3 -m pip install yamllint
./bin/python/bin/yamllint --config-file tools/.yamllint .
else
@echo "yamllint already installed..."
yamllint --config-file tools/.yamllint .
@ -170,13 +158,6 @@ ifeq (, $(shell which yamlfmt))
endif
yamlfmt -conf tools/.yamlfmt .
.PHONY: run-govulncheck
run-govulncheck:
ifeq (, $(shell which govulncheck))
$(shell go install golang.org/x/vuln/cmd/govulncheck@latest)
endif
PASSES="govuln" ./scripts/test.sh
# Tools
GOLANGCI_LINT_VERSION = $(shell cd tools/mod && go list -m -f {{.Version}} github.com/golangci/golangci-lint)
@ -197,7 +178,7 @@ bin/lazyfs:
cp /tmp/lazyfs/lazyfs/build/lazyfs ./bin/lazyfs
# Cleanup
.PHONY: clean
clean:
rm -f ./codecov
rm -rf ./covdir
@ -212,15 +193,3 @@ clean:
rm -rf ./tests/e2e/default.proxy
rm -rf ./bin/shellcheck*
find ./ -name "127.0.0.1:*" -o -name "localhost:*" -o -name "*.log" -o -name "agent-*" -o -name "*.coverprofile" -o -name "testname-proxy-*" -delete
.PHONY: verify-go-versions
verify-go-versions:
./scripts/verify_go_versions.sh
.PHONY: sync-toolchain-directive
sync-toolchain-directive:
./scripts/sync_go_toolchain_directive.sh
.PHONY: markdown-diff-lint
markdown-diff-lint:
./scripts/markdown_diff_lint.sh

15
OWNERS
View File

@ -1,12 +1,11 @@
# See the OWNERS docs at https://go.k8s.io/owners
approvers:
- ahrtr # Benjamin Wang <benjamin.ahrtr@gmail.com> <benjamin.wang@broadcom.com>
- fuweid # Wei Fu <fuweid89@gmail.com>
- jmhbnz # James Blair <jablair@redhat.com> <mail@jamesblair.net>
- serathius # Marek Siarkowicz <siarkowicz@google.com> <marek.siarkowicz@gmail.com>
- spzala # Sahdev Zala <spzala@us.ibm.com>
- wenjiaswe # Wenjia Zhang <wenjiazhang@google.com> <wenjia.swe@gmail.com>
- ahrtr # Benjamin Wang <wachao@vmware.com> <benjamin.ahrtr@gmail.com>
- mitake # Hitoshi Mitake <h.mitake@gmail.com>
- serathius # Marek Siarkowicz <siarkowicz@google.com> <marek.siarkowicz@gmail.com>
- spzala # Sahdev Zala <spzala@us.ibm.com>
- wenjiaswe # Wenjia Zhang <wenjiazhang@google.com> <wenjia.swe@gmail.com>
reviewers:
- ivanvc # Ivan Valdes <ivan@vald.es>
- siyuanfoundation # Siyuan Zhang <sizhang@google.com> <physicsbug@gmail.com>
- jmhbnz # James Blair <jablair@redhat.com> <mail@jamesblair.net>
- fuweid # Wei Fu <fuweid89@gmail.com>

View File

@ -8,15 +8,12 @@
[![Godoc](http://img.shields.io/badge/go-documentation-blue.svg?style=flat-square)](https://godoc.org/github.com/etcd-io/etcd)
[![Releases](https://img.shields.io/github/release/etcd-io/etcd/all.svg?style=flat-square)](https://github.com/etcd-io/etcd/releases)
[![LICENSE](https://img.shields.io/github/license/etcd-io/etcd.svg?style=flat-square)](https://github.com/etcd-io/etcd/blob/main/LICENSE)
[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/etcd-io/etcd/badge)](https://scorecard.dev/viewer/?uri=github.com/etcd-io/etcd)
[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/etcd-io/etcd/badge)](https://api.securityscorecards.dev/projects/github.com/etcd-io/etcd)
<a href="https://actuated.dev/"><img alt="Arm CI sponsored by Actuated" src="https://docs.actuated.dev/images/actuated-badge.png" width="120px"></img></a>
**Note**: The `main` branch may be in an *unstable or even broken state* during development. For stable versions, see [releases][github-release].
<picture>
<source media="(prefers-color-scheme: dark)" srcset="https://raw.githubusercontent.com/cncf/artwork/9870640f123303a355611065195c43ac3f27aa19/projects/etcd/horizontal/white/etcd-horizontal-white.png">
<source media="(prefers-color-scheme: light)" srcset="logos/etcd-horizontal-color.svg">
<img alt="etcd logo" src="logos/etcd-horizontal-color.svg" width=269 />
</picture>
![etcd Logo](logos/etcd-horizontal-color.svg)
etcd is a distributed reliable key-value store for the most critical data of a distributed system, with a focus on being:
@ -144,21 +141,18 @@ Now it's time to dig into the full etcd API and other guides.
### Community meetings
etcd contributors and maintainers meet every week at `11:00` AM (USA Pacific) on Thursday and meetings alternate between community meetings and issue triage meetings. Meeting agendas are recorded in a [shared Google doc][shared-meeting-notes] and everyone is welcome to suggest additional topics or other agendas.
etcd contributors and maintainers meet every week at 11:00 AM (USA Pacific) on Thursday and meetings alternate between community meetings and issue triage meetings. An initial agenda will be posted to the [shared Google docs][shared-meeting-notes] a day before each meeting, and everyone is welcome to suggest additional topics or other agendas.
Issue triage meetings are aimed at getting through our backlog of PRs and Issues. Triage meetings are open to any contributor; you don't have to be a reviewer or approver to help out! They can also be a good way to get started contributing.
The meeting lead role is rotated for each meeting between etcd maintainers or sig-etcd leads and is recorded in a [shared Google sheet][shared-rotation-sheet].
Meeting recordings are uploaded to official etcd [YouTube channel].
Meeting recordings are uploaded to the official etcd [YouTube channel].
Get calendar invitation by joining [etcd-dev](https://groups.google.com/g/etcd-dev) mailing group.
Get calendar invitations by joining [etcd-dev](https://groups.google.com/g/etcd-dev) mailing group.
Join the CNCF-funded Zoom channel: [zoom.us/my/cncfetcdproject](https://zoom.us/my/cncfetcdproject)
Join CNCF-funded Zoom channel: [zoom.us/my/cncfetcdproject](https://zoom.us/my/cncfetcdproject)
[shared-meeting-notes]: https://docs.google.com/document/d/16XEGyPBisZvmmoIHSZzv__LoyOeluC5a4x353CX0SIM/edit
[shared-rotation-sheet]: https://docs.google.com/spreadsheets/d/1jodHIO7Dk2VWTs1IRnfMFaRktS9IH8XRyifOnPdSY8I/edit
[YouTube channel]: https://www.youtube.com/@etcdio
[YouTube channel]: https://www.youtube.com/channel/UC7tUWR24I5AR9NMsG-NYBlg
## Contributing
@ -198,7 +192,6 @@ These emeritus maintainers dedicated a part of their career to etcd and reviewed
* Ben Darnell
* Sam Batschelet
* Piotr Tabor
* Hitoshi Mitake
### License

File diff suppressed because it is too large Load Diff

View File

@ -105,7 +105,6 @@ type InternalRaftRequest struct {
ClusterVersionSet *membershippb.ClusterVersionSetRequest `protobuf:"bytes,1300,opt,name=cluster_version_set,json=clusterVersionSet,proto3" json:"cluster_version_set,omitempty"`
ClusterMemberAttrSet *membershippb.ClusterMemberAttrSetRequest `protobuf:"bytes,1301,opt,name=cluster_member_attr_set,json=clusterMemberAttrSet,proto3" json:"cluster_member_attr_set,omitempty"`
DowngradeInfoSet *membershippb.DowngradeInfoSetRequest `protobuf:"bytes,1302,opt,name=downgrade_info_set,json=downgradeInfoSet,proto3" json:"downgrade_info_set,omitempty"`
DowngradeVersionTest *DowngradeVersionTestRequest `protobuf:"bytes,9900,opt,name=downgrade_version_test,json=downgradeVersionTest,proto3" json:"downgrade_version_test,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
@ -239,76 +238,74 @@ func init() {
func init() { proto.RegisterFile("raft_internal.proto", fileDescriptor_b4c9a9be0cfca103) }
var fileDescriptor_b4c9a9be0cfca103 = []byte{
// 1101 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x56, 0xcb, 0x72, 0x1b, 0x45,
0x14, 0x8d, 0x6c, 0xc7, 0xb6, 0x5a, 0xb6, 0xe3, 0xb4, 0x9d, 0xa4, 0xb1, 0xab, 0x8c, 0xe3, 0x90,
0x60, 0x20, 0xc8, 0xc1, 0x06, 0xaa, 0x60, 0x03, 0x8a, 0xe5, 0x72, 0x4c, 0x25, 0x29, 0xd7, 0xc4,
0x50, 0x29, 0x28, 0x6a, 0x68, 0xcd, 0x5c, 0x4b, 0x13, 0x8f, 0x66, 0x86, 0xee, 0x96, 0xe2, 0x6c,
0x59, 0xb2, 0x06, 0x8a, 0x8f, 0x60, 0xc1, 0x2b, 0xff, 0x90, 0x05, 0x8f, 0x00, 0x3f, 0x00, 0x66,
0xc3, 0x1e, 0xd8, 0xa7, 0xfa, 0x31, 0x2f, 0xa9, 0xe5, 0xdd, 0xe8, 0xde, 0x73, 0xcf, 0x39, 0xdd,
0x7d, 0xbb, 0x75, 0xd1, 0x02, 0xa3, 0x87, 0xc2, 0x0d, 0x22, 0x01, 0x2c, 0xa2, 0x61, 0x3d, 0x61,
0xb1, 0x88, 0xf1, 0x0c, 0x08, 0xcf, 0xe7, 0xc0, 0xfa, 0xc0, 0x92, 0xd6, 0xd2, 0x62, 0x3b, 0x6e,
0xc7, 0x2a, 0xb1, 0x21, 0xbf, 0x34, 0x66, 0x69, 0x3e, 0xc7, 0x98, 0x48, 0x95, 0x25, 0x9e, 0xf9,
0x5c, 0x95, 0xc9, 0x0d, 0x9a, 0x04, 0x1b, 0x7d, 0x60, 0x3c, 0x88, 0xa3, 0xa4, 0x95, 0x7e, 0x19,
0xc4, 0xb5, 0x0c, 0xd1, 0x85, 0x6e, 0x0b, 0x18, 0xef, 0x04, 0x49, 0xd2, 0x2a, 0xfc, 0xd0, 0xb8,
0x35, 0x86, 0x66, 0x1d, 0xf8, 0xb4, 0x07, 0x5c, 0xdc, 0x02, 0xea, 0x03, 0xc3, 0x73, 0x68, 0x6c,
0xaf, 0x49, 0x2a, 0xab, 0x95, 0xf5, 0x09, 0x67, 0x6c, 0xaf, 0x89, 0x97, 0xd0, 0x74, 0x8f, 0x4b,
0xf3, 0x5d, 0x20, 0x63, 0xab, 0x95, 0xf5, 0xaa, 0x93, 0xfd, 0xc6, 0xd7, 0xd1, 0x2c, 0xed, 0x89,
0x8e, 0xcb, 0xa0, 0x1f, 0x48, 0x6d, 0x32, 0x2e, 0xcb, 0x6e, 0x4e, 0x7d, 0xfe, 0x98, 0x8c, 0x6f,
0xd5, 0x5f, 0x73, 0x66, 0x64, 0xd6, 0x31, 0xc9, 0xb7, 0xa7, 0x3e, 0x53, 0xe1, 0x1b, 0x6b, 0x8f,
0x17, 0xd0, 0xc2, 0x9e, 0xd9, 0x11, 0x87, 0x1e, 0x0a, 0x63, 0x00, 0x6f, 0xa1, 0xc9, 0x8e, 0x32,
0x41, 0xfc, 0xd5, 0xca, 0x7a, 0x6d, 0x73, 0xb9, 0x5e, 0xdc, 0xa7, 0x7a, 0xc9, 0xa7, 0x63, 0xa0,
0x43, 0x7e, 0xaf, 0xa2, 0xb1, 0xfe, 0xa6, 0x72, 0x5a, 0xdb, 0xbc, 0x60, 0x25, 0x70, 0xc6, 0xfa,
0x9b, 0xf8, 0x06, 0x3a, 0xcb, 0x68, 0xd4, 0x06, 0x65, 0xb9, 0xb6, 0xb9, 0x34, 0x80, 0x94, 0xa9,
0x14, 0xae, 0x81, 0xf8, 0x65, 0x34, 0x9e, 0xf4, 0x04, 0x99, 0x50, 0x78, 0x52, 0xc6, 0xef, 0xf7,
0xd2, 0x45, 0x38, 0x12, 0x84, 0xb7, 0xd1, 0x8c, 0x0f, 0x21, 0x08, 0x70, 0xb5, 0xc8, 0x59, 0x55,
0xb4, 0x5a, 0x2e, 0x6a, 0x2a, 0x44, 0x49, 0xaa, 0xe6, 0xe7, 0x31, 0x29, 0x28, 0x8e, 0x23, 0x32,
0x69, 0x13, 0x3c, 0x38, 0x8e, 0x32, 0x41, 0x71, 0x1c, 0xe1, 0x77, 0x10, 0xf2, 0xe2, 0x6e, 0x42,
0x3d, 0x21, 0x8f, 0x61, 0x4a, 0x95, 0x3c, 0x5f, 0x2e, 0xd9, 0xce, 0xf2, 0x69, 0x65, 0xa1, 0x04,
0xbf, 0x8b, 0x6a, 0x21, 0x50, 0x0e, 0x6e, 0x9b, 0xd1, 0x48, 0x90, 0x69, 0x1b, 0xc3, 0x6d, 0x09,
0xd8, 0x95, 0xf9, 0x8c, 0x21, 0xcc, 0x42, 0x72, 0xcd, 0x9a, 0x81, 0x41, 0x3f, 0x3e, 0x02, 0x52,
0xb5, 0xad, 0x59, 0x51, 0x38, 0x0a, 0x90, 0xad, 0x39, 0xcc, 0x63, 0xf2, 0x58, 0x68, 0x48, 0x59,
0x97, 0x20, 0xdb, 0xb1, 0x34, 0x64, 0x2a, 0x3b, 0x16, 0x05, 0xc4, 0xf7, 0xd1, 0xbc, 0x96, 0xf5,
0x3a, 0xe0, 0x1d, 0x25, 0x71, 0x10, 0x09, 0x52, 0x53, 0xc5, 0x2f, 0x58, 0xa4, 0xb7, 0x33, 0x90,
0xa1, 0x49, 0x9b, 0xf5, 0x75, 0xe7, 0x5c, 0x58, 0x06, 0xe0, 0x06, 0xaa, 0xa9, 0xee, 0x86, 0x88,
0xb6, 0x42, 0x20, 0xff, 0x58, 0x77, 0xb5, 0xd1, 0x13, 0x9d, 0x1d, 0x05, 0xc8, 0xf6, 0x84, 0x66,
0x21, 0xdc, 0x44, 0xea, 0x0a, 0xb8, 0x7e, 0xc0, 0x15, 0xc7, 0xbf, 0x53, 0xb6, 0x4d, 0x91, 0x1c,
0x4d, 0x8d, 0xc8, 0x36, 0x85, 0xe6, 0x31, 0xfc, 0x9e, 0x31, 0xc2, 0x05, 0x15, 0x3d, 0x4e, 0xfe,
0x1f, 0x69, 0xe4, 0x9e, 0x02, 0x0c, 0xac, 0xec, 0x0d, 0xed, 0x48, 0xe7, 0xf0, 0x5d, 0xed, 0x08,
0x22, 0x11, 0x78, 0x54, 0x00, 0xf9, 0x4f, 0x93, 0xbd, 0x54, 0x26, 0x4b, 0x6f, 0x67, 0xa3, 0x00,
0x4d, 0xad, 0x95, 0xea, 0xf1, 0x8e, 0x79, 0x02, 0xe4, 0x9b, 0xe0, 0x52, 0xdf, 0x27, 0x3f, 0x4d,
0x8f, 0x5a, 0xe2, 0xfb, 0x1c, 0x58, 0xc3, 0xf7, 0x4b, 0x4b, 0x34, 0x31, 0x7c, 0x17, 0xcd, 0xe7,
0x34, 0xfa, 0x12, 0x90, 0x9f, 0x35, 0xd3, 0x15, 0x3b, 0x93, 0xb9, 0x3d, 0x86, 0x6c, 0x8e, 0x96,
0xc2, 0x65, 0x5b, 0x6d, 0x10, 0xe4, 0x97, 0x53, 0x6d, 0xed, 0x82, 0x18, 0xb2, 0xb5, 0x0b, 0x02,
0xb7, 0xd1, 0x73, 0x39, 0x8d, 0xd7, 0x91, 0xd7, 0xd2, 0x4d, 0x28, 0xe7, 0x0f, 0x63, 0xe6, 0x93,
0x5f, 0x35, 0xe5, 0x2b, 0x76, 0xca, 0x6d, 0x85, 0xde, 0x37, 0xe0, 0x94, 0xfd, 0x22, 0xb5, 0xa6,
0xf1, 0x7d, 0xb4, 0x58, 0xf0, 0x2b, 0xef, 0x93, 0xcb, 0xe2, 0x10, 0xc8, 0x53, 0xad, 0x71, 0x6d,
0x84, 0x6d, 0x75, 0x17, 0xe3, 0xbc, 0x6d, 0xce, 0xd3, 0xc1, 0x0c, 0xfe, 0x08, 0x5d, 0xc8, 0x99,
0xf5, 0xd5, 0xd4, 0xd4, 0xbf, 0x69, 0xea, 0x17, 0xed, 0xd4, 0xe6, 0x8e, 0x16, 0xb8, 0x31, 0x1d,
0x4a, 0xe1, 0x5b, 0x68, 0x2e, 0x27, 0x0f, 0x03, 0x2e, 0xc8, 0xef, 0x9a, 0xf5, 0xb2, 0x9d, 0xf5,
0x76, 0xc0, 0x45, 0xa9, 0x8f, 0xd2, 0x60, 0xc6, 0x24, 0xad, 0x69, 0xa6, 0x3f, 0x46, 0x32, 0x49,
0xe9, 0x21, 0xa6, 0x34, 0x98, 0x1d, 0xbd, 0x62, 0x92, 0x1d, 0xf9, 0x6d, 0x75, 0xd4, 0xd1, 0xcb,
0x9a, 0xc1, 0x8e, 0x34, 0xb1, 0xac, 0x23, 0x15, 0x8d, 0xe9, 0xc8, 0xef, 0xaa, 0xa3, 0x3a, 0x52,
0x56, 0x59, 0x3a, 0x32, 0x0f, 0x97, 0x6d, 0xc9, 0x8e, 0xfc, 0xfe, 0x54, 0x5b, 0x83, 0x1d, 0x69,
0x62, 0xf8, 0x01, 0x5a, 0x2a, 0xd0, 0xa8, 0x46, 0x49, 0x80, 0x75, 0x03, 0xae, 0xfe, 0x7f, 0x7f,
0xd0, 0x9c, 0xd7, 0x47, 0x70, 0x4a, 0xf8, 0x7e, 0x86, 0x4e, 0xf9, 0x2f, 0x51, 0x7b, 0x1e, 0x77,
0xd1, 0x72, 0xae, 0x65, 0x5a, 0xa7, 0x20, 0xf6, 0xa3, 0x16, 0x7b, 0xd5, 0x2e, 0xa6, 0xbb, 0x64,
0x58, 0x8d, 0xd0, 0x11, 0x00, 0xfc, 0x09, 0x5a, 0xf0, 0xc2, 0x1e, 0x17, 0xc0, 0x5c, 0x33, 0xcb,
0xb8, 0x1c, 0x04, 0xf9, 0x02, 0x99, 0x2b, 0x50, 0x1c, 0x64, 0xea, 0xdb, 0x1a, 0xf9, 0x81, 0x06,
0xde, 0x03, 0x31, 0xf4, 0xea, 0x9d, 0xf7, 0x06, 0x21, 0xf8, 0x01, 0xba, 0x94, 0x2a, 0x68, 0x32,
0x97, 0x0a, 0xc1, 0x94, 0xca, 0x97, 0xc8, 0xbc, 0x83, 0x36, 0x95, 0x3b, 0x2a, 0xd6, 0x10, 0x82,
0xd9, 0x84, 0x16, 0x3d, 0x0b, 0x0a, 0x7f, 0x8c, 0xb0, 0x1f, 0x3f, 0x8c, 0xda, 0x8c, 0xfa, 0xe0,
0x06, 0xd1, 0x61, 0xac, 0x64, 0xbe, 0xd2, 0x32, 0x57, 0xcb, 0x32, 0xcd, 0x14, 0xb8, 0x17, 0x1d,
0xc6, 0x36, 0x89, 0x79, 0x7f, 0x00, 0x81, 0x03, 0x74, 0x31, 0xa7, 0x4f, 0xb7, 0x4b, 0x00, 0x17,
0xe4, 0x9b, 0x3b, 0xb6, 0x17, 0x3d, 0x93, 0x30, 0xdb, 0x71, 0x00, 0x7c, 0x50, 0xe6, 0x4d, 0x67,
0xd1, 0xb7, 0xa0, 0xf2, 0xb9, 0xed, 0x1c, 0x9a, 0xdd, 0xe9, 0x26, 0xe2, 0x91, 0x03, 0x3c, 0x89,
0x23, 0x0e, 0x6b, 0x8f, 0xd0, 0xf2, 0x29, 0xff, 0x14, 0x18, 0xa3, 0x09, 0x35, 0x36, 0x56, 0xd4,
0xd8, 0xa8, 0xbe, 0xe5, 0x38, 0x99, 0x3d, 0xa0, 0x66, 0x9c, 0x4c, 0x7f, 0xe3, 0xcb, 0x68, 0x86,
0x07, 0xdd, 0x24, 0x04, 0x57, 0xc4, 0x47, 0xa0, 0xa7, 0xc9, 0xaa, 0x53, 0xd3, 0xb1, 0x03, 0x19,
0xca, 0xbc, 0xdc, 0x7c, 0xeb, 0xc9, 0x5f, 0x2b, 0x67, 0x9e, 0x9c, 0xac, 0x54, 0x9e, 0x9e, 0xac,
0x54, 0xfe, 0x3c, 0x59, 0xa9, 0x7c, 0xfd, 0xf7, 0xca, 0x99, 0x0f, 0xaf, 0xb4, 0x63, 0xb5, 0xec,
0x7a, 0x10, 0x6f, 0xe4, 0x23, 0xf2, 0xd6, 0x46, 0x71, 0x2b, 0x5a, 0x93, 0x6a, 0xf2, 0xdd, 0x7a,
0x16, 0x00, 0x00, 0xff, 0xff, 0xb2, 0xa0, 0x15, 0x1f, 0x9b, 0x0b, 0x00, 0x00,
// 1072 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x7c, 0x56, 0x4b, 0x73, 0x1b, 0x45,
0x17, 0x8d, 0x6c, 0xc7, 0xb6, 0x5a, 0xb6, 0xe3, 0xb4, 0x9d, 0x2f, 0xfd, 0xd9, 0x55, 0xc6, 0x71,
0x48, 0x30, 0x10, 0xe4, 0x20, 0xc3, 0x02, 0x36, 0xa0, 0x48, 0x2e, 0xc7, 0x54, 0x48, 0xb9, 0x26,
0x81, 0x4a, 0x41, 0x51, 0x43, 0x6b, 0xe6, 0x5a, 0x9a, 0x78, 0x34, 0x33, 0x74, 0xb7, 0x14, 0x67,
0xcb, 0x92, 0x35, 0x50, 0xfc, 0x0c, 0x9e, 0xff, 0x21, 0x45, 0xf1, 0x08, 0xf0, 0x07, 0xc0, 0x6c,
0xd8, 0x03, 0x7b, 0xaa, 0x1f, 0xf3, 0x92, 0x5a, 0xde, 0x8d, 0xee, 0x3d, 0xf7, 0x9c, 0xd3, 0xdd,
0xb7, 0x5b, 0x17, 0xad, 0x30, 0x7a, 0x24, 0xdc, 0x20, 0x12, 0xc0, 0x22, 0x1a, 0xd6, 0x13, 0x16,
0x8b, 0x18, 0x2f, 0x80, 0xf0, 0x7c, 0x0e, 0x6c, 0x08, 0x2c, 0xe9, 0xac, 0xad, 0x76, 0xe3, 0x6e,
0xac, 0x12, 0x3b, 0xf2, 0x4b, 0x63, 0xd6, 0x96, 0x73, 0x8c, 0x89, 0x54, 0x59, 0xe2, 0x99, 0xcf,
0x4d, 0x99, 0xdc, 0xa1, 0x49, 0xb0, 0x33, 0x04, 0xc6, 0x83, 0x38, 0x4a, 0x3a, 0xe9, 0x97, 0x41,
0x5c, 0xcf, 0x10, 0x7d, 0xe8, 0x77, 0x80, 0xf1, 0x5e, 0x90, 0x24, 0x9d, 0xc2, 0x0f, 0x8d, 0xdb,
0x62, 0x68, 0xd1, 0x81, 0x8f, 0x06, 0xc0, 0xc5, 0x6d, 0xa0, 0x3e, 0x30, 0xbc, 0x84, 0xa6, 0x0e,
0xda, 0xa4, 0xb2, 0x59, 0xd9, 0x9e, 0x71, 0xa6, 0x0e, 0xda, 0x78, 0x0d, 0xcd, 0x0f, 0xb8, 0x34,
0xdf, 0x07, 0x32, 0xb5, 0x59, 0xd9, 0xae, 0x3a, 0xd9, 0x6f, 0x7c, 0x03, 0x2d, 0xd2, 0x81, 0xe8,
0xb9, 0x0c, 0x86, 0x81, 0xd4, 0x26, 0xd3, 0xb2, 0xec, 0xd6, 0xdc, 0x27, 0xdf, 0x91, 0xe9, 0xdd,
0xfa, 0xcb, 0xce, 0x82, 0xcc, 0x3a, 0x26, 0xf9, 0xfa, 0xdc, 0xc7, 0x2a, 0x7c, 0x73, 0xeb, 0x7b,
0x8c, 0x56, 0x0e, 0xcc, 0x8e, 0x38, 0xf4, 0x48, 0x18, 0x03, 0x78, 0x17, 0xcd, 0xf6, 0x94, 0x09,
0xe2, 0x6f, 0x56, 0xb6, 0x6b, 0x8d, 0xf5, 0x7a, 0x71, 0x9f, 0xea, 0x25, 0x9f, 0x8e, 0x81, 0x8e,
0xf9, 0xbd, 0x86, 0xa6, 0x86, 0x0d, 0xe5, 0xb4, 0xd6, 0xb8, 0x64, 0x25, 0x70, 0xa6, 0x86, 0x0d,
0x7c, 0x13, 0x9d, 0x67, 0x34, 0xea, 0x82, 0xb2, 0x5c, 0x6b, 0xac, 0x8d, 0x20, 0x65, 0x2a, 0x85,
0x6b, 0x20, 0x7e, 0x01, 0x4d, 0x27, 0x03, 0x41, 0x66, 0x14, 0x9e, 0x94, 0xf1, 0x87, 0x83, 0x74,
0x11, 0x8e, 0x04, 0xe1, 0x16, 0x5a, 0xf0, 0x21, 0x04, 0x01, 0xae, 0x16, 0x39, 0xaf, 0x8a, 0x36,
0xcb, 0x45, 0x6d, 0x85, 0x28, 0x49, 0xd5, 0xfc, 0x3c, 0x26, 0x05, 0xc5, 0x49, 0x44, 0x66, 0x6d,
0x82, 0xf7, 0x4f, 0xa2, 0x4c, 0x50, 0x9c, 0x44, 0xf8, 0x0d, 0x84, 0xbc, 0xb8, 0x9f, 0x50, 0x4f,
0xc8, 0x63, 0x98, 0x53, 0x25, 0xcf, 0x94, 0x4b, 0x5a, 0x59, 0x3e, 0xad, 0x2c, 0x94, 0xe0, 0x37,
0x51, 0x2d, 0x04, 0xca, 0xc1, 0xed, 0x32, 0x1a, 0x09, 0x32, 0x6f, 0x63, 0xb8, 0x23, 0x01, 0xfb,
0x32, 0x9f, 0x31, 0x84, 0x59, 0x48, 0xae, 0x59, 0x33, 0x30, 0x18, 0xc6, 0xc7, 0x40, 0xaa, 0xb6,
0x35, 0x2b, 0x0a, 0x47, 0x01, 0xb2, 0x35, 0x87, 0x79, 0x4c, 0x1e, 0x0b, 0x0d, 0x29, 0xeb, 0x13,
0x64, 0x3b, 0x96, 0xa6, 0x4c, 0x65, 0xc7, 0xa2, 0x80, 0xf8, 0x01, 0x5a, 0xd6, 0xb2, 0x5e, 0x0f,
0xbc, 0xe3, 0x24, 0x0e, 0x22, 0x41, 0x6a, 0xaa, 0xf8, 0x59, 0x8b, 0x74, 0x2b, 0x03, 0x19, 0x9a,
0xb4, 0x59, 0x5f, 0x71, 0x2e, 0x84, 0x65, 0x00, 0x6e, 0xa2, 0x9a, 0xea, 0x6e, 0x88, 0x68, 0x27,
0x04, 0xf2, 0x97, 0x75, 0x57, 0x9b, 0x03, 0xd1, 0xdb, 0x53, 0x80, 0x6c, 0x4f, 0x68, 0x16, 0xc2,
0x6d, 0xa4, 0xae, 0x80, 0xeb, 0x07, 0x5c, 0x71, 0xfc, 0x3d, 0x67, 0xdb, 0x14, 0xc9, 0xd1, 0xd6,
0x88, 0x6c, 0x53, 0x68, 0x1e, 0xc3, 0x6f, 0x19, 0x23, 0x5c, 0x50, 0x31, 0xe0, 0xe4, 0xdf, 0x89,
0x46, 0xee, 0x29, 0xc0, 0xc8, 0xca, 0x5e, 0xd5, 0x8e, 0x74, 0x0e, 0xdf, 0xd5, 0x8e, 0x20, 0x12,
0x81, 0x47, 0x05, 0x90, 0x7f, 0x34, 0xd9, 0xf3, 0x65, 0xb2, 0xf4, 0x76, 0x36, 0x0b, 0xd0, 0xd4,
0x5a, 0xa9, 0x1e, 0xef, 0x99, 0x27, 0x40, 0xbe, 0x09, 0x2e, 0xf5, 0x7d, 0xf2, 0xc3, 0xfc, 0xa4,
0x25, 0xbe, 0xc3, 0x81, 0x35, 0x7d, 0xbf, 0xb4, 0x44, 0x13, 0xc3, 0x77, 0xd1, 0x72, 0x4e, 0xa3,
0x2f, 0x01, 0xf9, 0x51, 0x33, 0x5d, 0xb5, 0x33, 0x99, 0xdb, 0x63, 0xc8, 0x96, 0x68, 0x29, 0x5c,
0xb6, 0xd5, 0x05, 0x41, 0x7e, 0x3a, 0xd3, 0xd6, 0x3e, 0x88, 0x31, 0x5b, 0xfb, 0x20, 0x70, 0x17,
0xfd, 0x3f, 0xa7, 0xf1, 0x7a, 0xf2, 0x5a, 0xba, 0x09, 0xe5, 0xfc, 0x51, 0xcc, 0x7c, 0xf2, 0xb3,
0xa6, 0x7c, 0xd1, 0x4e, 0xd9, 0x52, 0xe8, 0x43, 0x03, 0x4e, 0xd9, 0xff, 0x47, 0xad, 0x69, 0xfc,
0x00, 0xad, 0x16, 0xfc, 0xca, 0xfb, 0xe4, 0xb2, 0x38, 0x04, 0xf2, 0x54, 0x6b, 0x5c, 0x9f, 0x60,
0x5b, 0xdd, 0xc5, 0x38, 0x6f, 0x9b, 0x8b, 0x74, 0x34, 0x83, 0xdf, 0x47, 0x97, 0x72, 0x66, 0x7d,
0x35, 0x35, 0xf5, 0x2f, 0x9a, 0xfa, 0x39, 0x3b, 0xb5, 0xb9, 0xa3, 0x05, 0x6e, 0x4c, 0xc7, 0x52,
0xf8, 0x36, 0x5a, 0xca, 0xc9, 0xc3, 0x80, 0x0b, 0xf2, 0xab, 0x66, 0xbd, 0x62, 0x67, 0xbd, 0x13,
0x70, 0x51, 0xea, 0xa3, 0x34, 0x98, 0x31, 0x49, 0x6b, 0x9a, 0xe9, 0xb7, 0x89, 0x4c, 0x52, 0x7a,
0x8c, 0x29, 0x0d, 0x66, 0x47, 0xaf, 0x98, 0x64, 0x47, 0x7e, 0x59, 0x9d, 0x74, 0xf4, 0xb2, 0x66,
0xb4, 0x23, 0x4d, 0x2c, 0xeb, 0x48, 0x45, 0x63, 0x3a, 0xf2, 0xab, 0xea, 0xa4, 0x8e, 0x94, 0x55,
0x96, 0x8e, 0xcc, 0xc3, 0x65, 0x5b, 0xb2, 0x23, 0xbf, 0x3e, 0xd3, 0xd6, 0x68, 0x47, 0x9a, 0x18,
0x7e, 0x88, 0xd6, 0x0a, 0x34, 0xaa, 0x51, 0x12, 0x60, 0xfd, 0x80, 0xab, 0xff, 0xdf, 0x6f, 0x34,
0xe7, 0x8d, 0x09, 0x9c, 0x12, 0x7e, 0x98, 0xa1, 0x53, 0xfe, 0xcb, 0xd4, 0x9e, 0xc7, 0x7d, 0xb4,
0x9e, 0x6b, 0x99, 0xd6, 0x29, 0x88, 0x7d, 0xab, 0xc5, 0x5e, 0xb2, 0x8b, 0xe9, 0x2e, 0x19, 0x57,
0x23, 0x74, 0x02, 0x00, 0x7f, 0x88, 0x56, 0xbc, 0x70, 0xc0, 0x05, 0x30, 0xd7, 0xcc, 0x32, 0x2e,
0x07, 0x41, 0x3e, 0x45, 0xe6, 0x0a, 0x14, 0x07, 0x99, 0x7a, 0x4b, 0x23, 0xdf, 0xd5, 0xc0, 0x7b,
0x20, 0xc6, 0x5e, 0xbd, 0x8b, 0xde, 0x28, 0x04, 0x3f, 0x44, 0x97, 0x53, 0x05, 0x4d, 0xe6, 0x52,
0x21, 0x98, 0x52, 0xf9, 0x0c, 0x99, 0x77, 0xd0, 0xa6, 0xf2, 0xb6, 0x8a, 0x35, 0x85, 0x60, 0x36,
0xa1, 0x55, 0xcf, 0x82, 0xc2, 0x1f, 0x20, 0xec, 0xc7, 0x8f, 0xa2, 0x2e, 0xa3, 0x3e, 0xb8, 0x41,
0x74, 0x14, 0x2b, 0x99, 0xcf, 0xb5, 0xcc, 0xb5, 0xb2, 0x4c, 0x3b, 0x05, 0x1e, 0x44, 0x47, 0xb1,
0x4d, 0x62, 0xd9, 0x1f, 0x41, 0xe4, 0xc3, 0xd4, 0x05, 0xb4, 0xb8, 0xd7, 0x4f, 0xc4, 0x63, 0x07,
0x78, 0x12, 0x47, 0x1c, 0xb6, 0x1e, 0xa3, 0xf5, 0x33, 0x9e, 0x6f, 0x8c, 0xd1, 0x8c, 0x9a, 0xe5,
0x2a, 0x6a, 0x96, 0x53, 0xdf, 0x72, 0xc6, 0xcb, 0x5e, 0x35, 0x33, 0xe3, 0xa5, 0xbf, 0xf1, 0x15,
0xb4, 0xc0, 0x83, 0x7e, 0x12, 0x82, 0x2b, 0xe2, 0x63, 0xd0, 0x23, 0x5e, 0xd5, 0xa9, 0xe9, 0xd8,
0x7d, 0x19, 0xca, 0xbc, 0xdc, 0x7a, 0xed, 0xc9, 0x1f, 0x1b, 0xe7, 0x9e, 0x9c, 0x6e, 0x54, 0x9e,
0x9e, 0x6e, 0x54, 0x7e, 0x3f, 0xdd, 0xa8, 0x7c, 0xf1, 0xe7, 0xc6, 0xb9, 0xf7, 0xae, 0x76, 0x63,
0xd5, 0x22, 0xf5, 0x20, 0xde, 0xc9, 0xe7, 0xd6, 0xdd, 0x9d, 0x62, 0xdb, 0x74, 0x66, 0xd5, 0x38,
0xba, 0xfb, 0x5f, 0x00, 0x00, 0x00, 0xff, 0xff, 0x06, 0x59, 0x70, 0x10, 0x30, 0x0b, 0x00, 0x00,
}
func (m *RequestHeader) Marshal() (dAtA []byte, err error) {
@ -379,22 +376,6 @@ func (m *InternalRaftRequest) MarshalToSizedBuffer(dAtA []byte) (int, error) {
i -= len(m.XXX_unrecognized)
copy(dAtA[i:], m.XXX_unrecognized)
}
if m.DowngradeVersionTest != nil {
{
size, err := m.DowngradeVersionTest.MarshalToSizedBuffer(dAtA[:i])
if err != nil {
return 0, err
}
i -= size
i = encodeVarintRaftInternal(dAtA, i, uint64(size))
}
i--
dAtA[i] = 0x4
i--
dAtA[i] = 0xea
i--
dAtA[i] = 0xe2
}
if m.DowngradeInfoSet != nil {
{
size, err := m.DowngradeInfoSet.MarshalToSizedBuffer(dAtA[:i])
@ -1058,10 +1039,6 @@ func (m *InternalRaftRequest) Size() (n int) {
l = m.DowngradeInfoSet.Size()
n += 2 + l + sovRaftInternal(uint64(l))
}
if m.DowngradeVersionTest != nil {
l = m.DowngradeVersionTest.Size()
n += 3 + l + sovRaftInternal(uint64(l))
}
if m.XXX_unrecognized != nil {
n += len(m.XXX_unrecognized)
}
@ -2395,42 +2372,6 @@ func (m *InternalRaftRequest) Unmarshal(dAtA []byte) error {
return err
}
iNdEx = postIndex
case 9900:
if wireType != 2 {
return fmt.Errorf("proto: wrong wireType = %d for field DowngradeVersionTest", wireType)
}
var msglen int
for shift := uint(0); ; shift += 7 {
if shift >= 64 {
return ErrIntOverflowRaftInternal
}
if iNdEx >= l {
return io.ErrUnexpectedEOF
}
b := dAtA[iNdEx]
iNdEx++
msglen |= int(b&0x7F) << shift
if b < 0x80 {
break
}
}
if msglen < 0 {
return ErrInvalidLengthRaftInternal
}
postIndex := iNdEx + msglen
if postIndex < 0 {
return ErrInvalidLengthRaftInternal
}
if postIndex > l {
return io.ErrUnexpectedEOF
}
if m.DowngradeVersionTest == nil {
m.DowngradeVersionTest = &DowngradeVersionTestRequest{}
}
if err := m.DowngradeVersionTest.Unmarshal(dAtA[iNdEx:postIndex]); err != nil {
return err
}
iNdEx = postIndex
default:
iNdEx = preIndex
skippy, err := skipRaftInternal(dAtA[iNdEx:])

View File

@ -71,8 +71,6 @@ message InternalRaftRequest {
membershippb.ClusterVersionSetRequest cluster_version_set = 1300 [(versionpb.etcd_version_field) = "3.5"];
membershippb.ClusterMemberAttrSetRequest cluster_member_attr_set = 1301 [(versionpb.etcd_version_field) = "3.5"];
membershippb.DowngradeInfoSetRequest downgrade_info_set = 1302 [(versionpb.etcd_version_field) = "3.5"];
DowngradeVersionTestRequest downgrade_version_test = 9900 [(versionpb.etcd_version_field) = "3.6"];
}
message EmptyResponse {

View File

@ -72,13 +72,13 @@ func (as *InternalRaftStringer) String() string {
return as.Request.String()
}
// txnRequestStringer implements fmt.Stringer, a custom proto String to replace value bytes
// fields with value size fields in any nested txn and put operations.
// txnRequestStringer implements a custom proto String to replace value bytes fields with value size
// fields in any nested txn and put operations.
type txnRequestStringer struct {
Request *TxnRequest
}
func NewLoggableTxnRequest(request *TxnRequest) fmt.Stringer {
func NewLoggableTxnRequest(request *TxnRequest) *txnRequestStringer {
return &txnRequestStringer{request}
}
@ -155,8 +155,8 @@ func (m *loggableValueCompare) Reset() { *m = loggableValueCompare{} }
func (m *loggableValueCompare) String() string { return proto.CompactTextString(m) }
func (*loggableValueCompare) ProtoMessage() {}
// loggablePutRequest implements proto.Message, a custom proto String to replace value bytes
// field with a value size field.
// loggablePutRequest implements a custom proto String to replace value bytes field with a value
// size field.
// To preserve proto encoding of the key bytes, a faked out proto type is used here.
type loggablePutRequest struct {
Key []byte `protobuf:"bytes,1,opt,name=key,proto3"`
@ -167,7 +167,7 @@ type loggablePutRequest struct {
IgnoreLease bool `protobuf:"varint,6,opt,name=ignore_lease,proto3"`
}
func NewLoggablePutRequest(request *PutRequest) proto.Message {
func NewLoggablePutRequest(request *PutRequest) *loggablePutRequest {
return &loggablePutRequest{
request.Key,
int64(len(request.Value)),

View File

@ -17,8 +17,6 @@ package etcdserverpb_test
import (
"testing"
"github.com/stretchr/testify/assert"
pb "go.etcd.io/etcd/api/v3/etcdserverpb"
)
@ -26,5 +24,8 @@ import (
// 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
func TestInvalidGoTypeIntPanic(t *testing.T) {
assert.Empty(t, pb.NewLoggablePutRequest(&pb.PutRequest{}).String())
result := pb.NewLoggablePutRequest(&pb.PutRequest{}).String()
if result != "" {
t.Errorf("Got result: %s, expected empty string", result)
}
}

File diff suppressed because it is too large Load Diff

View File

@ -507,9 +507,7 @@ message RangeResponse {
repeated mvccpb.KeyValue kvs = 2;
// more indicates if there are more keys to return in the requested range.
bool more = 3;
// count is set to the actual number of keys within the range when requested.
// Unlike Kvs, it is unaffected by limits and filters (e.g., Min/Max, Create/Modify, Revisions)
// and reflects the full count within the specified range.
// count is set to the number of keys within the range when requested.
int64 count = 4;
}
@ -838,8 +836,7 @@ message WatchResponse {
// All events sent to the created watcher will attach with the same watch_id.
bool created = 3;
// canceled is set to true if the response is for a cancel watch request
// or if the start_revision has already been compacted.
// canceled is set to true if the response is for a cancel watch request.
// No further events will be sent to the canceled watcher.
bool canceled = 4;
@ -1160,16 +1157,6 @@ message DowngradeResponse {
string version = 2;
}
// DowngradeVersionTestRequest is used for test only. The version in
// this request will be read as the WAL record version.If the downgrade
// target version is less than this version, then the downgrade(online)
// or migration(offline) isn't safe, so shouldn't be allowed.
message DowngradeVersionTestRequest {
option (versionpb.etcd_version_msg) = "3.6";
string ver = 1;
}
message StatusRequest {
option (versionpb.etcd_version_msg) = "3.0";
}
@ -1196,19 +1183,8 @@ message StatusResponse {
int64 dbSizeInUse = 9 [(versionpb.etcd_version_field)="3.4"];
// isLearner indicates if the member is raft learner.
bool isLearner = 10 [(versionpb.etcd_version_field)="3.4"];
// storageVersion is the version of the db file. It might be updated with delay in relationship to the target cluster version.
// storageVersion is the version of the db file. It might be get updated with delay in relationship to the target cluster version.
string storageVersion = 11 [(versionpb.etcd_version_field)="3.6"];
// dbSizeQuota is the configured etcd storage quota in bytes (the value passed to etcd instance by flag --quota-backend-bytes)
int64 dbSizeQuota = 12 [(versionpb.etcd_version_field)="3.6"];
// downgradeInfo indicates if there is downgrade process.
DowngradeInfo downgradeInfo = 13 [(versionpb.etcd_version_field)="3.6"];
}
message DowngradeInfo {
// enabled indicates whether the cluster is enabled to downgrade.
bool enabled = 1;
// targetVersion is the target downgrade version.
string targetVersion = 2;
}
message AuthEnableRequest {

View File

@ -1,30 +1,28 @@
module go.etcd.io/etcd/api/v3
go 1.24
toolchain go1.24.1
go 1.21
require (
github.com/coreos/go-semver v0.3.1
github.com/gogo/protobuf v1.3.2
github.com/golang/protobuf v1.5.4
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3
github.com/stretchr/testify v1.10.0
google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb
google.golang.org/grpc v1.71.0
google.golang.org/protobuf v1.36.5
github.com/golang/protobuf v1.5.3
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0
github.com/stretchr/testify v1.8.4
google.golang.org/genproto/googleapis/api v0.0.0-20240102182953-50ed04b92917
google.golang.org/grpc v1.60.1
google.golang.org/protobuf v1.32.0
)
require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rogpeppe/go-internal v1.14.1 // indirect
go.opentelemetry.io/otel v1.35.0 // indirect
go.opentelemetry.io/otel/sdk v1.35.0 // indirect
golang.org/x/net v0.37.0 // indirect
golang.org/x/sys v0.31.0 // indirect
golang.org/x/text v0.23.0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb // indirect
github.com/rogpeppe/go-internal v1.11.0 // indirect
golang.org/x/net v0.20.0 // indirect
golang.org/x/sys v0.16.0 // indirect
golang.org/x/text v0.14.0 // indirect
google.golang.org/genproto v0.0.0-20231212172506-995d672761c0 // indirect
google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

View File

@ -1,21 +1,18 @@
github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4=
github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
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/go-logr/logr v1.4.2 h1:6pFjapn8bFcIbiKo3XT4j/BhANplGihG6tvd+8rYgrY=
github.com/go-logr/logr v1.4.2/go.mod h1:9T104GzyrTigFIr8wt5mBrctHMim0Nb2HLGrmQ40KvY=
github.com/go-logr/stdr v1.2.2 h1:hSWxHoqTgW2S2qGc0LTAI563KZ5YKYRhT3MFKZMbjag=
github.com/go-logr/stdr v1.2.2/go.mod h1:mMo/vtBO5dYbehREoey6XUKy/eSumjCCveDpRre4VKE=
github.com/gogo/protobuf v1.3.2 h1:Ov1cvc58UF3b5XjBnZv7+opcTcQFZebYjWzi34vdm4Q=
github.com/gogo/protobuf v1.3.2/go.mod h1:P1XiOD3dCwIKUDQYPy72D8LYyHL2YPYrpS2s69NZV8Q=
github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek=
github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps=
github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8=
github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU=
github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0=
github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3 h1:5ZPtiqj0JL5oKWmcsq4VMaAW5ukBEgSGXEN89zeH1Jo=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.26.3/go.mod h1:ndYquD05frm2vACXE1nsccT4oJzjhw2arTS2cpUD1PI=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/protobuf v1.5.3 h1:KhyjKVUg7Usr/dYsdSqoFveMYd5ko72D+zANwlG1mmg=
github.com/golang/protobuf v1.5.3/go.mod h1:XVQd3VNwM+JqD3oG2Ue2ip4fOMUkwXdXDdiuN0vRsmY=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI=
github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0 h1:Wqo399gCIufwto+VfwCSvsnfGpF/w5E9CNxSwbpD6No=
github.com/grpc-ecosystem/grpc-gateway/v2 v2.19.0/go.mod h1:qmOFXW2epJhM0qSnUUYpldc7gVz2KMQwJ/QYCDIa7XU=
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/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
@ -24,24 +21,12 @@ github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
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/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/rogpeppe/go-internal v1.11.0 h1:cWPaGQEPrBb5/AsnsZesgZZ9yb1OQ+GOISoDNXVBh4M=
github.com/rogpeppe/go-internal v1.11.0/go.mod h1:ddIwULY96R17DhadqLgMfk9H9tvdUzkipdSkR5nkCZA=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74=
go.opentelemetry.io/auto/sdk v1.1.0 h1:cH53jehLUN6UFLY71z+NDOiNJqDdPRaXzTel0sJySYA=
go.opentelemetry.io/auto/sdk v1.1.0/go.mod h1:3wSPjt5PWp2RhlCcmmOial7AvC4DQqZb7a7wCow3W8A=
go.opentelemetry.io/otel v1.35.0 h1:xKWKPxrxB6OtMCbmMY021CqC45J+3Onta9MqjhnusiQ=
go.opentelemetry.io/otel v1.35.0/go.mod h1:UEqy8Zp11hpkUrL73gSlELM0DupHoiq72dR+Zqel/+Y=
go.opentelemetry.io/otel/metric v1.35.0 h1:0znxYu2SNyuMSQT4Y9WDWej0VpcsxkuklLa4/siN90M=
go.opentelemetry.io/otel/metric v1.35.0/go.mod h1:nKVFgxBZ2fReX6IlyW28MgZojkoAkJGaE8CpgeAU3oE=
go.opentelemetry.io/otel/sdk v1.35.0 h1:iPctf8iprVySXSKJffSS79eOjl9pvxV9ZqOWT0QejKY=
go.opentelemetry.io/otel/sdk v1.35.0/go.mod h1:+ga1bZliga3DxJ3CQGg3updiaAJoNECOgJREo9KHGQg=
go.opentelemetry.io/otel/sdk/metric v1.34.0 h1:5CeK9ujjbFVL5c1PhLuStg1wxA7vQv7ce1EK0Gyvahk=
go.opentelemetry.io/otel/sdk/metric v1.34.0/go.mod h1:jQ/r8Ze28zRKoNRdkjCZxfs6YvBTG1+YIqyFVFYec5w=
go.opentelemetry.io/otel/trace v1.35.0 h1:dPpEfJu1sDIqruz7BHFG3c7528f6ddfSWfFDVt/xgMs=
go.opentelemetry.io/otel/trace v1.35.0/go.mod h1:WUk7DtFp1Aw2MkvqGdwiXYDZZNvA/1J8o6xRXLrIkyc=
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=
@ -51,20 +36,20 @@ golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn
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-20201021035429-f5854403a974/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.37.0 h1:1zLorHbz+LYj7MQlSf1+2tPIIgibq2eL5xkrGk6f+2c=
golang.org/x/net v0.37.0/go.mod h1:ivrbrMbzFq5J41QOQh0siUuly180yBYtLp+CKbEaFx8=
golang.org/x/net v0.20.0 h1:aCL9BSgETF1k+blQaYUBx9hJ9LOGP3gAVemcZlf1Kpo=
golang.org/x/net v0.20.0/go.mod h1:z8BVo6PvndSri0LbOE3hAn0apkU+1YvI6E70E9jsnvY=
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/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-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
golang.org/x/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.23.0 h1:D71I7dUrlY+VX0gQShAThNGHFxZ13dGLBHQLVl1mJlY=
golang.org/x/text v0.23.0/go.mod h1:/BLNzu4aZCJ1+kcD0DNRotWKage4q2rGVAg4o22unh4=
golang.org/x/text v0.14.0 h1:ScX5w1eTa3QqT8oi6+ziP7dTV1S2+ALU0bI+0zXKWiQ=
golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/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-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
@ -73,14 +58,18 @@ golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8T
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/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb h1:p31xT4yrYrSM/G4Sn2+TNUkVhFCbG9y8itM2S6Th950=
google.golang.org/genproto/googleapis/api v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:jbe3Bkdp+Dh2IrslsFCklNhweNTBgSYanP1UXhJDhKg=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb h1:TLPQVbx1GJ8VKZxz52VAxl1EBgKXXbTiU9Fc5fZeLn4=
google.golang.org/genproto/googleapis/rpc v0.0.0-20250303144028-a0af3efb3deb/go.mod h1:LuRYeWDFV6WOn90g357N17oMCaxpgCnbi/44qJvDn2I=
google.golang.org/grpc v1.71.0 h1:kF77BGdPTQ4/JZWMlb9VpJ5pa25aqvVqogsxNHHdeBg=
google.golang.org/grpc v1.71.0/go.mod h1:H0GRtasmQOh9LkFoCPDu3ZrwUtD1YGE+b2vYBYd/8Ec=
google.golang.org/protobuf v1.36.5 h1:tPhr+woSbjfYvY6/GPufUoYizxw1cF/yFoxJ2fmpwlM=
google.golang.org/protobuf v1.36.5/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE=
google.golang.org/genproto v0.0.0-20231212172506-995d672761c0 h1:YJ5pD9rF8o9Qtta0Cmy9rdBwkSjrTCT6XTiUQVOtIos=
google.golang.org/genproto v0.0.0-20231212172506-995d672761c0/go.mod h1:l/k7rMz0vFTBPy+tFSGvXEd3z+BcoG1k7EHbqm+YBsY=
google.golang.org/genproto/googleapis/api v0.0.0-20240102182953-50ed04b92917 h1:rcS6EyEaoCO52hQDupoSfrxI3R6C2Tq741is7X8OvnM=
google.golang.org/genproto/googleapis/api v0.0.0-20240102182953-50ed04b92917/go.mod h1:CmlNWB9lSezaYELKS5Ym1r44VrrbPUa7JTvw+6MbpJ0=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917 h1:6G8oQ016D88m1xAKljMlBOOGWDZkes4kMhgGFlf8WcQ=
google.golang.org/genproto/googleapis/rpc v0.0.0-20240102182953-50ed04b92917/go.mod h1:xtjpI3tXFPP051KaWnhvxkiubL/6dJ18vLVf7q2pTOU=
google.golang.org/grpc v1.60.1 h1:26+wFr+cNqSGFcOXcabYC0lUVJVRa2Sb2ortSK7VrEU=
google.golang.org/grpc v1.60.1/go.mod h1:OlCHIeLYqSSsLi6i49B5QGdzaMZK9+M7LXN2FKz4eGM=
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=
google.golang.org/protobuf v1.32.0 h1:pPC6BG5ex8PDFnkbrGU3EixyhKcQ2aDuBS36lqK/C7I=
google.golang.org/protobuf v1.32.0/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=

View File

@ -47,11 +47,7 @@ var (
ErrGRPCMemberNotLearner = status.Error(codes.FailedPrecondition, "etcdserver: can only promote a learner member")
ErrGRPCLearnerNotReady = status.Error(codes.FailedPrecondition, "etcdserver: can only promote a learner member which is in sync with leader")
ErrGRPCTooManyLearners = status.Error(codes.FailedPrecondition, "etcdserver: too many learner members in cluster")
ErrGRPCClusterIDMismatch = status.Error(codes.FailedPrecondition, "etcdserver: cluster ID mismatch")
//revive:disable:var-naming
// Deprecated: Please use ErrGRPCClusterIDMismatch.
ErrGRPCClusterIdMismatch = ErrGRPCClusterIDMismatch
//revive:enable:var-naming
ErrGRPCClusterIdMismatch = status.Error(codes.FailedPrecondition, "etcdserver: cluster ID mismatch")
ErrGRPCRequestTooLarge = status.Error(codes.InvalidArgument, "etcdserver: request is too large")
ErrGRPCRequestTooManyRequests = status.Error(codes.ResourceExhausted, "etcdserver: too many requests")
@ -122,7 +118,7 @@ var (
ErrorDesc(ErrGRPCMemberNotLearner): ErrGRPCMemberNotLearner,
ErrorDesc(ErrGRPCLearnerNotReady): ErrGRPCLearnerNotReady,
ErrorDesc(ErrGRPCTooManyLearners): ErrGRPCTooManyLearners,
ErrorDesc(ErrGRPCClusterIDMismatch): ErrGRPCClusterIDMismatch,
ErrorDesc(ErrGRPCClusterIdMismatch): ErrGRPCClusterIdMismatch,
ErrorDesc(ErrGRPCRequestTooLarge): ErrGRPCRequestTooLarge,
ErrorDesc(ErrGRPCRequestTooManyRequests): ErrGRPCRequestTooManyRequests,
@ -210,11 +206,7 @@ var (
ErrInvalidAuthToken = Error(ErrGRPCInvalidAuthToken)
ErrAuthOldRevision = Error(ErrGRPCAuthOldRevision)
ErrInvalidAuthMgmt = Error(ErrGRPCInvalidAuthMgmt)
ErrClusterIDMismatch = Error(ErrGRPCClusterIDMismatch)
//revive:disable:var-naming
// Deprecated: Please use ErrClusterIDMismatch.
ErrClusterIdMismatch = ErrClusterIDMismatch
//revive:enable:var-naming
ErrClusterIdMismatch = Error(ErrGRPCClusterIdMismatch)
ErrNoLeader = Error(ErrGRPCNoLeader)
ErrNotLeader = Error(ErrGRPCNotLeader)

View File

@ -15,10 +15,8 @@
package rpctypes
import (
"errors"
"testing"
"github.com/stretchr/testify/require"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
)
@ -26,16 +24,19 @@ import (
func TestConvert(t *testing.T) {
e1 := status.Error(codes.InvalidArgument, "etcdserver: key is not provided")
e2 := ErrGRPCEmptyKey
var e3 EtcdError
errors.As(ErrEmptyKey, &e3)
e3 := ErrEmptyKey
require.Equal(t, e1.Error(), e2.Error())
if ev1, ok := status.FromError(e1); ok {
require.Equal(t, ev1.Code(), e3.Code())
if e1.Error() != e2.Error() {
t.Fatalf("expected %q == %q", e1.Error(), e2.Error())
}
if ev1, ok := status.FromError(e1); ok && ev1.Code() != e3.(EtcdError).Code() {
t.Fatalf("expected them to be equal, got %v / %v", ev1.Code(), e3.(EtcdError).Code())
}
require.NotEqual(t, e1.Error(), e3.Error())
if ev2, ok := status.FromError(e2); ok {
require.Equal(t, ev2.Code(), e3.Code())
if e1.Error() == e3.Error() {
t.Fatalf("expected %q != %q", e1.Error(), e3.Error())
}
if ev2, ok := status.FromError(e2); ok && ev2.Code() != e3.(EtcdError).Code() {
t.Fatalf("expected them to be equal, got %v / %v", ev2.Code(), e3.(EtcdError).Code())
}
}

View File

@ -13,7 +13,7 @@
"licenses": [
{
"type": "MIT License",
"confidence": 0.96875
"confidence": 1
}
]
},
@ -144,7 +144,7 @@
]
},
{
"project": "github.com/golang-jwt/jwt/v5",
"project": "github.com/golang-jwt/jwt/v4",
"licenses": [
{
"type": "MIT License",
@ -188,15 +188,6 @@
}
]
},
{
"project": "github.com/google/uuid",
"licenses": [
{
"type": "BSD 3-clause \"New\" or \"Revised\" License",
"confidence": 0.9663865546218487
}
]
},
{
"project": "github.com/gorilla/websocket",
"licenses": [
@ -216,16 +207,7 @@
]
},
{
"project": "github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus",
"licenses": [
{
"type": "Apache License 2.0",
"confidence": 1
}
]
},
{
"project": "github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors",
"project": "github.com/grpc-ecosystem/go-grpc-prometheus",
"licenses": [
{
"type": "Apache License 2.0",
@ -260,33 +242,6 @@
}
]
},
{
"project": "github.com/klauspost/compress",
"licenses": [
{
"type": "Apache License 2.0",
"confidence": 0.9376299376299376
}
]
},
{
"project": "github.com/klauspost/compress/internal/snapref",
"licenses": [
{
"type": "BSD 3-clause \"New\" or \"Revised\" License",
"confidence": 0.9663865546218487
}
]
},
{
"project": "github.com/klauspost/compress/zstd/internal/xxhash",
"licenses": [
{
"type": "MIT License",
"confidence": 1
}
]
},
{
"project": "github.com/mattn/go-colorable",
"licenses": [
@ -314,15 +269,6 @@
}
]
},
{
"project": "github.com/munnerz/goautoneg",
"licenses": [
{
"type": "BSD 3-clause \"New\" or \"Revised\" License",
"confidence": 0.9794238683127572
}
]
},
{
"project": "github.com/olekukonko/tablewriter",
"licenses": [
@ -341,15 +287,6 @@
}
]
},
{
"project": "github.com/prometheus/client_golang/internal/github.com/golang/gddo/httputil",
"licenses": [
{
"type": "BSD 3-clause \"New\" or \"Revised\" License",
"confidence": 0.9663865546218487
}
]
},
{
"project": "github.com/prometheus/client_golang/prometheus",
"licenses": [
@ -575,15 +512,6 @@
}
]
},
{
"project": "go.opentelemetry.io/auto/sdk",
"licenses": [
{
"type": "Apache License 2.0",
"confidence": 1
}
]
},
{
"project": "go.opentelemetry.io/contrib/instrumentation/google.golang.org/grpc/otelgrpc",
"licenses": [
@ -794,10 +722,6 @@
{
"project": "sigs.k8s.io/yaml",
"licenses": [
{
"type": "Apache License 2.0",
"confidence": 1
},
{
"type": "BSD 3-clause \"New\" or \"Revised\" License",
"confidence": 1

View File

@ -7,15 +7,6 @@
}
]
},
{
"project": "github.com/grpc-ecosystem/go-grpc-middleware/v2/interceptors",
"licenses": [
{
"type": "Apache License 2.0",
"confidence": 1
}
]
},
{
"project": "github.com/inconshreveable/mousetrap",
"licenses": [

View File

@ -88,12 +88,11 @@ if err != nil {
kapi := client.NewKeysAPI(c)
resp, err := kapi.Set(ctx, "test", "bar", nil)
if err != nil {
var cerr *client.ClusterError
if errors.Is(err, context.Canceled) {
if err == context.Canceled {
// ctx is canceled by another routine
} else if errors.Is(err, context.DeadlineExceeded) {
} else if err == context.DeadlineExceeded {
// ctx is attached with a deadline and it exceeded
} else if errors.As(err, &cerr) {
} else if cerr, ok := err.(*client.ClusterError); ok {
// process (cerr.Errors)
} else {
// bad cluster endpoints, which are not etcd servers

View File

@ -135,7 +135,7 @@ func (r *httpAuthRoleAPI) AddRole(ctx context.Context, rolename string) error {
Role: rolename,
}
return r.addRemoveRole(ctx, &authRoleAPIAction{
verb: http.MethodPut,
verb: "PUT",
name: rolename,
role: role,
})
@ -143,7 +143,7 @@ func (r *httpAuthRoleAPI) AddRole(ctx context.Context, rolename string) error {
func (r *httpAuthRoleAPI) RemoveRole(ctx context.Context, rolename string) error {
return r.addRemoveRole(ctx, &authRoleAPIAction{
verb: http.MethodDelete,
verb: "DELETE",
name: rolename,
})
}
@ -166,7 +166,7 @@ func (r *httpAuthRoleAPI) addRemoveRole(ctx context.Context, req *authRoleAPIAct
func (r *httpAuthRoleAPI) GetRole(ctx context.Context, rolename string) (*Role, error) {
return r.modRole(ctx, &authRoleAPIAction{
verb: http.MethodGet,
verb: "GET",
name: rolename,
})
}
@ -194,7 +194,7 @@ func (r *httpAuthRoleAPI) GrantRoleKV(ctx context.Context, rolename string, pref
},
}
return r.modRole(ctx, &authRoleAPIAction{
verb: http.MethodPut,
verb: "PUT",
name: rolename,
role: role,
})
@ -209,7 +209,7 @@ func (r *httpAuthRoleAPI) RevokeRoleKV(ctx context.Context, rolename string, pre
},
}
return r.modRole(ctx, &authRoleAPIAction{
verb: http.MethodPut,
verb: "PUT",
name: rolename,
role: role,
})

View File

@ -23,7 +23,9 @@ import (
"path"
)
var defaultV2AuthPrefix = "/v2/auth"
var (
defaultV2AuthPrefix = "/v2/auth"
)
type User struct {
User string `json:"user"`
@ -74,11 +76,11 @@ type httpAuthAPI struct {
}
func (s *httpAuthAPI) Enable(ctx context.Context) error {
return s.enableDisable(ctx, &authAPIAction{http.MethodPut})
return s.enableDisable(ctx, &authAPIAction{"PUT"})
}
func (s *httpAuthAPI) Disable(ctx context.Context) error {
return s.enableDisable(ctx, &authAPIAction{http.MethodDelete})
return s.enableDisable(ctx, &authAPIAction{"DELETE"})
}
func (s *httpAuthAPI) enableDisable(ctx context.Context, req httpAction) error {
@ -217,7 +219,7 @@ func (u *httpAuthUserAPI) AddUser(ctx context.Context, username string, password
Password: password,
}
return u.addRemoveUser(ctx, &authUserAPIAction{
verb: http.MethodPut,
verb: "PUT",
username: username,
user: user,
})
@ -225,7 +227,7 @@ func (u *httpAuthUserAPI) AddUser(ctx context.Context, username string, password
func (u *httpAuthUserAPI) RemoveUser(ctx context.Context, username string) error {
return u.addRemoveUser(ctx, &authUserAPIAction{
verb: http.MethodDelete,
verb: "DELETE",
username: username,
})
}
@ -248,7 +250,7 @@ func (u *httpAuthUserAPI) addRemoveUser(ctx context.Context, req *authUserAPIAct
func (u *httpAuthUserAPI) GetUser(ctx context.Context, username string) (*User, error) {
return u.modUser(ctx, &authUserAPIAction{
verb: http.MethodGet,
verb: "GET",
username: username,
})
}
@ -259,7 +261,7 @@ func (u *httpAuthUserAPI) GrantUser(ctx context.Context, username string, roles
Grant: roles,
}
return u.modUser(ctx, &authUserAPIAction{
verb: http.MethodPut,
verb: "PUT",
username: username,
user: user,
})
@ -271,7 +273,7 @@ func (u *httpAuthUserAPI) RevokeUser(ctx context.Context, username string, roles
Revoke: roles,
}
return u.modUser(ctx, &authUserAPIAction{
verb: http.MethodPut,
verb: "PUT",
username: username,
user: user,
})
@ -283,7 +285,7 @@ func (u *httpAuthUserAPI) ChangePassword(ctx context.Context, username string, p
Password: password,
}
return u.modUser(ctx, &authUserAPIAction{
verb: http.MethodPut,
verb: "PUT",
username: username,
user: user,
})

View File

@ -365,10 +365,10 @@ func (c *httpClusterClient) Do(ctx context.Context, act httpAction) (*http.Respo
resp, body, err = hc.Do(ctx, action)
if err != nil {
cerr.Errors = append(cerr.Errors, err)
if errors.Is(err, ctx.Err()) {
if err == ctx.Err() {
return nil, nil, ctx.Err()
}
if errors.Is(err, context.Canceled) || errors.Is(err, context.DeadlineExceeded) {
if err == context.Canceled || err == context.DeadlineExceeded {
return nil, nil, err
}
} else if resp.StatusCode/100 == 5 {
@ -542,7 +542,7 @@ func (c *simpleHTTPClient) Do(ctx context.Context, act httpAction) (*http.Respon
var err error
isWait, err = strconv.ParseBool(ws)
if err != nil {
return nil, nil, fmt.Errorf("wrong wait value %s (%w for %+v)", ws, err, req)
return nil, nil, fmt.Errorf("wrong wait value %s (%v for %+v)", ws, err, req)
}
}
}

View File

@ -27,9 +27,6 @@ import (
"testing"
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.etcd.io/etcd/api/v3/version"
"go.etcd.io/etcd/client/pkg/v3/testutil"
)
@ -131,13 +128,20 @@ func TestSimpleHTTPClientDoSuccess(t *testing.T) {
Body: io.NopCloser(strings.NewReader("foo")),
}
resp, body, err := c.Do(t.Context(), &fakeAction{})
require.NoErrorf(t, err, "incorrect error value")
resp, body, err := c.Do(context.Background(), &fakeAction{})
if err != nil {
t.Fatalf("incorrect error value: want=nil got=%v", err)
}
wantCode := http.StatusTeapot
require.Equalf(t, wantCode, resp.StatusCode, "invalid response code: want=%d got=%d", wantCode, resp.StatusCode)
if wantCode != resp.StatusCode {
t.Fatalf("invalid response code: want=%d got=%d", wantCode, resp.StatusCode)
}
wantBody := []byte("foo")
require.Truef(t, reflect.DeepEqual(wantBody, body), "invalid response body: want=%q got=%q", wantBody, body)
if !reflect.DeepEqual(wantBody, body) {
t.Fatalf("invalid response body: want=%q got=%q", wantBody, body)
}
}
func TestSimpleHTTPClientDoError(t *testing.T) {
@ -146,8 +150,10 @@ func TestSimpleHTTPClientDoError(t *testing.T) {
tr.errchan <- errors.New("fixture")
_, _, err := c.Do(t.Context(), &fakeAction{})
assert.Errorf(t, err, "expected non-nil error, got nil")
_, _, err := c.Do(context.Background(), &fakeAction{})
if err == nil {
t.Fatalf("expected non-nil error, got nil")
}
}
type nilAction struct{}
@ -162,8 +168,10 @@ func TestSimpleHTTPClientDoNilRequest(t *testing.T) {
tr.errchan <- errors.New("fixture")
_, _, err := c.Do(t.Context(), &nilAction{})
require.ErrorIsf(t, err, ErrNoRequest, "expected non-nil error, got nil")
_, _, err := c.Do(context.Background(), &nilAction{})
if err != ErrNoRequest {
t.Fatalf("expected non-nil error, got nil")
}
}
func TestSimpleHTTPClientDoCancelContext(t *testing.T) {
@ -173,8 +181,10 @@ func TestSimpleHTTPClientDoCancelContext(t *testing.T) {
tr.startCancel <- struct{}{}
tr.finishCancel <- struct{}{}
_, _, err := c.Do(t.Context(), &fakeAction{})
assert.Errorf(t, err, "expected non-nil error, got nil")
_, _, err := c.Do(context.Background(), &fakeAction{})
if err == nil {
t.Fatalf("expected non-nil error, got nil")
}
}
type checkableReadCloser struct {
@ -195,7 +205,7 @@ func TestSimpleHTTPClientDoCancelContextResponseBodyClosed(t *testing.T) {
c := &simpleHTTPClient{transport: tr}
// create an already-cancelled context
ctx, cancel := context.WithCancel(t.Context())
ctx, cancel := context.WithCancel(context.Background())
cancel()
body := &checkableReadCloser{ReadCloser: io.NopCloser(strings.NewReader("foo"))}
@ -209,9 +219,13 @@ func TestSimpleHTTPClientDoCancelContextResponseBodyClosed(t *testing.T) {
}()
_, _, err := c.Do(ctx, &fakeAction{})
require.Errorf(t, err, "expected non-nil error, got nil")
if err == nil {
t.Fatalf("expected non-nil error, got nil")
}
require.Truef(t, body.closed, "expected closed body")
if !body.closed {
t.Fatalf("expected closed body")
}
}
type blockingBody struct {
@ -232,7 +246,7 @@ func TestSimpleHTTPClientDoCancelContextResponseBodyClosedWithBlockingBody(t *te
tr := newFakeTransport()
c := &simpleHTTPClient{transport: tr}
ctx, cancel := context.WithCancel(t.Context())
ctx, cancel := context.WithCancel(context.Background())
body := &checkableReadCloser{ReadCloser: &blockingBody{c: make(chan struct{})}}
go func() {
tr.respchan <- &http.Response{Body: body}
@ -242,9 +256,13 @@ func TestSimpleHTTPClientDoCancelContextResponseBodyClosedWithBlockingBody(t *te
}()
_, _, err := c.Do(ctx, &fakeAction{})
require.ErrorIsf(t, err, context.Canceled, "expected %+v, got %+v", context.Canceled, err)
if err != context.Canceled {
t.Fatalf("expected %+v, got %+v", context.Canceled, err)
}
require.Truef(t, body.closed, "expected closed body")
if !body.closed {
t.Fatalf("expected closed body")
}
}
func TestSimpleHTTPClientDoCancelContextWaitForRoundTrip(t *testing.T) {
@ -252,7 +270,7 @@ func TestSimpleHTTPClientDoCancelContextWaitForRoundTrip(t *testing.T) {
c := &simpleHTTPClient{transport: tr}
donechan := make(chan struct{})
ctx, cancel := context.WithCancel(t.Context())
ctx, cancel := context.WithCancel(context.Background())
go func() {
c.Do(ctx, &fakeAction{})
close(donechan)
@ -271,7 +289,7 @@ func TestSimpleHTTPClientDoCancelContextWaitForRoundTrip(t *testing.T) {
select {
case <-donechan:
// expected behavior
//expected behavior
return
case <-time.After(time.Second):
t.Fatalf("simpleHTTPClient.Do did not exit within 1s")
@ -285,13 +303,15 @@ func TestSimpleHTTPClientDoHeaderTimeout(t *testing.T) {
errc := make(chan error, 1)
go func() {
_, _, err := c.Do(t.Context(), &fakeAction{})
_, _, err := c.Do(context.Background(), &fakeAction{})
errc <- err
}()
select {
case err := <-errc:
require.Errorf(t, err, "expected non-nil error, got nil")
if err == nil {
t.Fatalf("expected non-nil error, got nil")
}
case <-time.After(time.Second):
t.Fatalf("unexpected timeout when waiting for the test to finish")
}
@ -407,7 +427,7 @@ func TestHTTPClusterClientDo(t *testing.T) {
),
rand: rand.New(rand.NewSource(0)),
},
ctx: context.WithValue(t.Context(), &oneShotCtxValue, &oneShotCtxValue),
ctx: context.WithValue(context.Background(), &oneShotCtxValue, &oneShotCtxValue),
wantErr: errors.New("client: etcd member returns server error [Bad Gateway]"),
wantPinned: 1,
},
@ -415,10 +435,10 @@ func TestHTTPClusterClientDo(t *testing.T) {
for i, tt := range tests {
if tt.ctx == nil {
tt.ctx = t.Context()
tt.ctx = context.Background()
}
resp, _, err := tt.client.Do(tt.ctx, nil)
if (tt.wantErr == nil && !errors.Is(err, tt.wantErr)) || (tt.wantErr != nil && tt.wantErr.Error() != err.Error()) {
if (tt.wantErr == nil && tt.wantErr != err) || (tt.wantErr != nil && tt.wantErr.Error() != err.Error()) {
t.Errorf("#%d: got err=%v, want=%v", i, err, tt.wantErr)
continue
}
@ -450,7 +470,7 @@ func TestHTTPClusterClientDoDeadlineExceedContext(t *testing.T) {
errc := make(chan error, 1)
go func() {
ctx, cancel := context.WithTimeout(t.Context(), time.Millisecond)
ctx, cancel := context.WithTimeout(context.Background(), time.Millisecond)
defer cancel()
_, _, err := c.Do(ctx, &fakeAction{})
errc <- err
@ -458,7 +478,7 @@ func TestHTTPClusterClientDoDeadlineExceedContext(t *testing.T) {
select {
case err := <-errc:
if !errors.Is(err, context.DeadlineExceeded) {
if err != context.DeadlineExceeded {
t.Errorf("err = %+v, want %+v", err, context.DeadlineExceeded)
}
case <-time.After(time.Second):
@ -481,8 +501,7 @@ func (f fakeCancelContext) Value(key any) any { return 1 }
func withTimeout(parent context.Context, _timeout time.Duration) (
ctx context.Context,
cancel context.CancelFunc,
) {
cancel context.CancelFunc) {
ctx = parent
cancel = func() {
ctx = nil
@ -509,7 +528,7 @@ func TestHTTPClusterClientDoCanceledContext(t *testing.T) {
select {
case err := <-errc:
if !errors.Is(err, errFakeCancelContext) {
if err != errFakeCancelContext {
t.Errorf("err = %+v, want %+v", err, errFakeCancelContext)
}
case <-time.After(time.Second):
@ -521,7 +540,7 @@ func TestRedirectedHTTPAction(t *testing.T) {
act := &redirectedHTTPAction{
action: &staticHTTPAction{
request: http.Request{
Method: http.MethodDelete,
Method: "DELETE",
URL: &url.URL{
Scheme: "https",
Host: "foo.example.com",
@ -537,7 +556,7 @@ func TestRedirectedHTTPAction(t *testing.T) {
}
want := &http.Request{
Method: http.MethodDelete,
Method: "DELETE",
URL: &url.URL{
Scheme: "https",
Host: "bar.example.com",
@ -546,7 +565,9 @@ func TestRedirectedHTTPAction(t *testing.T) {
}
got := act.HTTPRequest(url.URL{Scheme: "http", Host: "baz.example.com", Path: "/pang"})
require.Truef(t, reflect.DeepEqual(want, got), "HTTPRequest is %#v, want %#v", want, got)
if !reflect.DeepEqual(want, got) {
t.Fatalf("HTTPRequest is %#v, want %#v", want, got)
}
}
func TestRedirectFollowingHTTPClient(t *testing.T) {
@ -722,8 +743,8 @@ func TestRedirectFollowingHTTPClient(t *testing.T) {
for i, tt := range tests {
client := &redirectFollowingHTTPClient{client: tt.client, checkRedirect: tt.checkRedirect}
resp, _, err := client.Do(t.Context(), nil)
if (tt.wantErr == nil && !errors.Is(err, tt.wantErr)) || (tt.wantErr != nil && tt.wantErr.Error() != err.Error()) {
resp, _, err := client.Do(context.Background(), nil)
if (tt.wantErr == nil && tt.wantErr != err) || (tt.wantErr != nil && tt.wantErr.Error() != err.Error()) {
t.Errorf("#%d: got err=%v, want=%v", i, err, tt.wantErr)
continue
}
@ -775,26 +796,38 @@ func TestHTTPClusterClientSync(t *testing.T) {
rand: rand.New(rand.NewSource(0)),
}
err := hc.SetEndpoints([]string{"http://127.0.0.1:2379"})
require.NoErrorf(t, err, "unexpected error during setup")
if err != nil {
t.Fatalf("unexpected error during setup: %#v", err)
}
want := []string{"http://127.0.0.1:2379"}
got := hc.Endpoints()
require.Truef(t, reflect.DeepEqual(want, got), "incorrect endpoints: want=%#v got=%#v", want, got)
if !reflect.DeepEqual(want, got) {
t.Fatalf("incorrect endpoints: want=%#v got=%#v", want, got)
}
err = hc.Sync(t.Context())
require.NoErrorf(t, err, "unexpected error during Sync: %#v", err)
err = hc.Sync(context.Background())
if err != nil {
t.Fatalf("unexpected error during Sync: %#v", err)
}
want = []string{"http://127.0.0.1:2379", "http://127.0.0.1:4001", "http://127.0.0.1:4002", "http://127.0.0.1:4003"}
got = hc.Endpoints()
sort.Strings(got)
require.Truef(t, reflect.DeepEqual(want, got), "incorrect endpoints post-Sync: want=%#v got=%#v", want, got)
if !reflect.DeepEqual(want, got) {
t.Fatalf("incorrect endpoints post-Sync: want=%#v got=%#v", want, got)
}
err = hc.SetEndpoints([]string{"http://127.0.0.1:4009"})
require.NoErrorf(t, err, "unexpected error during reset: %#v", err)
if err != nil {
t.Fatalf("unexpected error during reset: %#v", err)
}
want = []string{"http://127.0.0.1:4009"}
got = hc.Endpoints()
require.Truef(t, reflect.DeepEqual(want, got), "incorrect endpoints post-reset: want=%#v got=%#v", want, got)
if !reflect.DeepEqual(want, got) {
t.Fatalf("incorrect endpoints post-reset: want=%#v got=%#v", want, got)
}
}
func TestHTTPClusterClientSyncFail(t *testing.T) {
@ -807,17 +840,25 @@ func TestHTTPClusterClientSyncFail(t *testing.T) {
rand: rand.New(rand.NewSource(0)),
}
err := hc.SetEndpoints([]string{"http://127.0.0.1:2379"})
require.NoErrorf(t, err, "unexpected error during setup")
if err != nil {
t.Fatalf("unexpected error during setup: %#v", err)
}
want := []string{"http://127.0.0.1:2379"}
got := hc.Endpoints()
require.Truef(t, reflect.DeepEqual(want, got), "incorrect endpoints: want=%#v got=%#v", want, got)
if !reflect.DeepEqual(want, got) {
t.Fatalf("incorrect endpoints: want=%#v got=%#v", want, got)
}
err = hc.Sync(t.Context())
require.Errorf(t, err, "got nil error during Sync")
err = hc.Sync(context.Background())
if err == nil {
t.Fatalf("got nil error during Sync")
}
got = hc.Endpoints()
require.Truef(t, reflect.DeepEqual(want, got), "incorrect endpoints after failed Sync: want=%#v got=%#v", want, got)
if !reflect.DeepEqual(want, got) {
t.Fatalf("incorrect endpoints after failed Sync: want=%#v got=%#v", want, got)
}
}
func TestHTTPClusterClientAutoSyncCancelContext(t *testing.T) {
@ -833,13 +874,16 @@ func TestHTTPClusterClientAutoSyncCancelContext(t *testing.T) {
rand: rand.New(rand.NewSource(0)),
}
err := hc.SetEndpoints([]string{"http://127.0.0.1:2379"})
require.NoErrorf(t, err, "unexpected error during setup")
ctx, cancel := context.WithCancel(t.Context())
if err != nil {
t.Fatalf("unexpected error during setup: %#v", err)
}
ctx, cancel := context.WithCancel(context.Background())
cancel()
err = hc.AutoSync(ctx, time.Hour)
require.ErrorIsf(t, err, context.Canceled, "incorrect error value: want=%v got=%v", context.Canceled, err)
if err != context.Canceled {
t.Fatalf("incorrect error value: want=%v got=%v", context.Canceled, err)
}
}
func TestHTTPClusterClientAutoSyncFail(t *testing.T) {
@ -852,10 +896,14 @@ func TestHTTPClusterClientAutoSyncFail(t *testing.T) {
rand: rand.New(rand.NewSource(0)),
}
err := hc.SetEndpoints([]string{"http://127.0.0.1:2379"})
require.NoErrorf(t, err, "unexpected error during setup")
if err != nil {
t.Fatalf("unexpected error during setup: %#v", err)
}
err = hc.AutoSync(t.Context(), time.Hour)
require.Truef(t, strings.HasPrefix(err.Error(), ErrClusterUnavailable.Error()), "incorrect error value: want=%v got=%v", ErrClusterUnavailable, err)
err = hc.AutoSync(context.Background(), time.Hour)
if !strings.HasPrefix(err.Error(), ErrClusterUnavailable.Error()) {
t.Fatalf("incorrect error value: want=%v got=%v", ErrClusterUnavailable, err)
}
}
func TestHTTPClusterClientGetVersion(t *testing.T) {
@ -872,9 +920,11 @@ func TestHTTPClusterClientGetVersion(t *testing.T) {
rand: rand.New(rand.NewSource(0)),
}
err := hc.SetEndpoints([]string{"http://127.0.0.1:4003", "http://127.0.0.1:2379", "http://127.0.0.1:4001", "http://127.0.0.1:4002"})
require.NoErrorf(t, err, "unexpected error during setup")
if err != nil {
t.Fatalf("unexpected error during setup: %#v", err)
}
actual, err := hc.GetVersion(t.Context())
actual, err := hc.GetVersion(context.Background())
if err != nil {
t.Errorf("non-nil error: %#v", err)
}
@ -907,12 +957,16 @@ func TestHTTPClusterClientSyncPinEndpoint(t *testing.T) {
rand: rand.New(rand.NewSource(0)),
}
err := hc.SetEndpoints([]string{"http://127.0.0.1:4003", "http://127.0.0.1:2379", "http://127.0.0.1:4001", "http://127.0.0.1:4002"})
require.NoErrorf(t, err, "unexpected error during setup")
if err != nil {
t.Fatalf("unexpected error during setup: %#v", err)
}
pinnedEndpoint := hc.endpoints[hc.pinned]
for i := 0; i < 3; i++ {
err = hc.Sync(t.Context())
require.NoErrorf(t, err, "#%d: unexpected error during Sync", i)
err = hc.Sync(context.Background())
if err != nil {
t.Fatalf("#%d: unexpected error during Sync: %#v", i, err)
}
if g := hc.endpoints[hc.pinned]; g != pinnedEndpoint {
t.Errorf("#%d: pinned endpoint = %v, want %v", i, g, pinnedEndpoint)
@ -943,12 +997,16 @@ func TestHTTPClusterClientSyncUnpinEndpoint(t *testing.T) {
rand: rand.New(rand.NewSource(0)),
}
err := hc.SetEndpoints([]string{"http://127.0.0.1:4003", "http://127.0.0.1:2379", "http://127.0.0.1:4001", "http://127.0.0.1:4002"})
require.NoErrorf(t, err, "unexpected error during setup")
if err != nil {
t.Fatalf("unexpected error during setup: %#v", err)
}
wants := []string{"http://127.0.0.1:2379", "http://127.0.0.1:4001", "http://127.0.0.1:4002"}
for i := 0; i < 3; i++ {
err = hc.Sync(t.Context())
require.NoErrorf(t, err, "#%d: unexpected error during Sync", i)
err = hc.Sync(context.Background())
if err != nil {
t.Fatalf("#%d: unexpected error during Sync: %#v", i, err)
}
if g := hc.endpoints[hc.pinned]; g.String() != wants[i] {
t.Errorf("#%d: pinned endpoint = %v, want %v", i, g, wants[i])
@ -988,8 +1046,10 @@ func TestHTTPClusterClientSyncPinLeaderEndpoint(t *testing.T) {
wants := []string{"http://127.0.0.1:4003", "http://127.0.0.1:4002"}
for i, want := range wants {
err := hc.Sync(t.Context())
require.NoErrorf(t, err, "#%d: unexpected error during Sync", i)
err := hc.Sync(context.Background())
if err != nil {
t.Fatalf("#%d: unexpected error during Sync: %#v", i, err)
}
pinned := hc.endpoints[hc.pinned].String()
if pinned != want {
@ -1022,7 +1082,9 @@ func TestHTTPClusterClientResetPinRandom(t *testing.T) {
for i := 0; i < round; i++ {
hc := &httpClusterClient{rand: rand.New(rand.NewSource(int64(i)))}
err := hc.SetEndpoints([]string{"http://127.0.0.1:4001", "http://127.0.0.1:4002", "http://127.0.0.1:4003"})
require.NoErrorf(t, err, "#%d: reset error", i)
if err != nil {
t.Fatalf("#%d: reset error (%v)", i, err)
}
if hc.endpoints[hc.pinned].String() == "http://127.0.0.1:4001" {
pinNum++
}

View File

@ -22,7 +22,9 @@ import (
"os"
)
var cURLDebug = false
var (
cURLDebug = false
)
func EnablecURLDebug() {
cURLDebug = true

View File

@ -1,11 +1,8 @@
module go.etcd.io/etcd/client/v2
go 1.24
toolchain go1.24.1
go 1.21
require (
github.com/stretchr/testify v1.10.0
go.etcd.io/etcd/api/v3 v3.6.0-alpha.0
go.etcd.io/etcd/client/pkg/v3 v3.6.0-alpha.0
sigs.k8s.io/json v0.0.0-20211020170558-c049b76a60c6
@ -14,8 +11,9 @@ require (
require (
github.com/coreos/go-semver v0.3.1 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/kr/text v0.2.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/stretchr/testify v1.8.4 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

View File

@ -1,18 +1,17 @@
github.com/coreos/go-semver v0.3.1 h1:yi21YpKnrx1gt5R+la8n5WgS0kCrsPp33dmEyHReZr4=
github.com/coreos/go-semver v0.3.1/go.mod h1:irMmmIw/7yzSRPWryHsK7EYSg09caPQL03VsM8rvUec=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
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/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pretty v0.2.1 h1:Fmg33tUaq4/8ym9TJN1x7sLJnHVwhP33CNkpYV/7rwI=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=

View File

@ -79,7 +79,9 @@ const (
PrevNoExist = PrevExistType("false")
)
var defaultV2KeysPrefix = "/v2/keys"
var (
defaultV2KeysPrefix = "/v2/keys"
)
// NewKeysAPI builds a KeysAPI that interacts with etcd's key-value
// API over HTTP.
@ -457,7 +459,7 @@ func (hw *httpWatcher) Next(ctx context.Context) (*Response, error) {
resp, err := unmarshalHTTPResponse(httpresp.StatusCode, httpresp.Header, body)
if err != nil {
if errors.Is(err, ErrEmptyBody) {
if err == ErrEmptyBody {
continue
}
return nil, err

View File

@ -20,8 +20,6 @@ import (
"reflect"
"strings"
"testing"
"github.com/stretchr/testify/require"
)
func createTestNode(size int) *Node {
@ -51,12 +49,13 @@ func createTestResponse(children, size int) *Response {
}
func benchmarkResponseUnmarshalling(b *testing.B, children, size int) {
b.Helper()
header := http.Header{}
header.Add("X-Etcd-Index", "123456")
response := createTestResponse(children, size)
body, err := json.Marshal(response)
require.NoError(b, err)
if err != nil {
b.Fatal(err)
}
b.ResetTimer()
newResponse := new(Response)
@ -64,6 +63,7 @@ func benchmarkResponseUnmarshalling(b *testing.B, children, size int) {
if newResponse, err = unmarshalSuccessfulKeysResponse(header, body); err != nil {
b.Errorf("error unmarshalling response (%v)", err)
}
}
if !reflect.DeepEqual(response.Node, newResponse.Node) {
b.Errorf("Unexpected difference in a parsed response: \n%+v\n%+v", response, newResponse)

View File

@ -15,6 +15,7 @@
package client
import (
"context"
"errors"
"fmt"
"io"
@ -161,7 +162,7 @@ func TestGetAction(t *testing.T) {
wantURL := baseWantURL
wantURL.RawQuery = tt.wantQuery
err := assertRequest(got, http.MethodGet, wantURL, wantHeader, nil)
err := assertRequest(got, "GET", wantURL, wantHeader, nil)
if err != nil {
t.Errorf("#%d: %v", i, err)
}
@ -210,7 +211,7 @@ func TestWaitAction(t *testing.T) {
wantURL := baseWantURL
wantURL.RawQuery = tt.wantQuery
err := assertRequest(got, http.MethodGet, wantURL, wantHeader, nil)
err := assertRequest(got, "GET", wantURL, wantHeader, nil)
if err != nil {
t.Errorf("#%d: unexpected error: %#v", i, err)
}
@ -423,7 +424,7 @@ func TestSetAction(t *testing.T) {
}
got := tt.act.HTTPRequest(url.URL{Scheme: "http", Host: "example.com"})
if err := assertRequest(*got, http.MethodPut, u, wantHeader, []byte(tt.wantBody)); err != nil {
if err := assertRequest(*got, "PUT", u, wantHeader, []byte(tt.wantBody)); err != nil {
t.Errorf("#%d: %v", i, err)
}
}
@ -524,7 +525,7 @@ func TestCreateInOrderAction(t *testing.T) {
}
got := tt.act.HTTPRequest(url.URL{Scheme: "http", Host: "example.com"})
if err := assertRequest(*got, http.MethodPost, u, wantHeader, []byte(tt.wantBody)); err != nil {
if err := assertRequest(*got, "POST", u, wantHeader, []byte(tt.wantBody)); err != nil {
t.Errorf("#%d: %v", i, err)
}
}
@ -626,7 +627,7 @@ func TestDeleteAction(t *testing.T) {
}
got := tt.act.HTTPRequest(url.URL{Scheme: "http", Host: "example.com"})
if err := assertRequest(*got, http.MethodDelete, u, wantHeader, nil); err != nil {
if err := assertRequest(*got, "DELETE", u, wantHeader, nil); err != nil {
t.Errorf("#%d: %v", i, err)
}
}
@ -829,10 +830,9 @@ func TestUnmarshalFailedKeysResponse(t *testing.T) {
func TestUnmarshalFailedKeysResponseBadJSON(t *testing.T) {
err := unmarshalFailedKeysResponse([]byte(`{"er`))
var cErr Error
if err == nil {
t.Errorf("got nil error")
} else if errors.As(err, &cErr) {
} else if _, ok := err.(Error); ok {
t.Errorf("error is of incorrect type *Error: %#v", err)
}
}
@ -874,7 +874,7 @@ func TestHTTPWatcherNextWaitAction(t *testing.T) {
nextWait: initAction,
}
resp, err := watcher.Next(t.Context())
resp, err := watcher.Next(context.Background())
if err != nil {
t.Errorf("non-nil error: %#v", err)
}
@ -924,7 +924,7 @@ func TestHTTPWatcherNextFail(t *testing.T) {
nextWait: act,
}
resp, err := watcher.Next(t.Context())
resp, err := watcher.Next(context.Background())
if err == nil {
t.Errorf("#%d: expected non-nil error", i)
}
@ -1072,7 +1072,7 @@ func TestHTTPKeysAPISetAction(t *testing.T) {
for i, tt := range tests {
client := &actionAssertingHTTPClient{t: t, num: i, act: tt.wantAction}
kAPI := httpKeysAPI{client: client}
kAPI.Set(t.Context(), tt.key, tt.value, tt.opts)
kAPI.Set(context.Background(), tt.key, tt.value, tt.opts)
}
}
@ -1101,7 +1101,7 @@ func TestHTTPKeysAPISetError(t *testing.T) {
for i, tt := range tests {
kAPI := httpKeysAPI{client: tt}
resp, err := kAPI.Set(t.Context(), "/foo", "bar", nil)
resp, err := kAPI.Set(context.Background(), "/foo", "bar", nil)
if err == nil {
t.Errorf("#%d: received nil error", i)
}
@ -1128,7 +1128,7 @@ func TestHTTPKeysAPISetResponse(t *testing.T) {
}
kAPI := &httpKeysAPI{client: client, prefix: "/pants"}
resp, err := kAPI.Set(t.Context(), "/foo/bar/baz", "snarf", nil)
resp, err := kAPI.Set(context.Background(), "/foo/bar/baz", "snarf", nil)
if err != nil {
t.Errorf("non-nil error: %#v", err)
}
@ -1183,7 +1183,7 @@ func TestHTTPKeysAPIGetAction(t *testing.T) {
for i, tt := range tests {
client := &actionAssertingHTTPClient{t: t, num: i, act: tt.wantAction}
kAPI := httpKeysAPI{client: client}
kAPI.Get(t.Context(), tt.key, tt.opts)
kAPI.Get(context.Background(), tt.key, tt.opts)
}
}
@ -1212,7 +1212,7 @@ func TestHTTPKeysAPIGetError(t *testing.T) {
for i, tt := range tests {
kAPI := httpKeysAPI{client: tt}
resp, err := kAPI.Get(t.Context(), "/foo", nil)
resp, err := kAPI.Get(context.Background(), "/foo", nil)
if err == nil {
t.Errorf("#%d: received nil error", i)
}
@ -1245,7 +1245,7 @@ func TestHTTPKeysAPIGetResponse(t *testing.T) {
}
kAPI := &httpKeysAPI{client: client, prefix: "/pants"}
resp, err := kAPI.Get(t.Context(), "/foo/bar", &GetOptions{Recursive: true})
resp, err := kAPI.Get(context.Background(), "/foo/bar", &GetOptions{Recursive: true})
if err != nil {
t.Errorf("non-nil error: %#v", err)
}
@ -1302,7 +1302,7 @@ func TestHTTPKeysAPIDeleteAction(t *testing.T) {
for i, tt := range tests {
client := &actionAssertingHTTPClient{t: t, num: i, act: tt.wantAction}
kAPI := httpKeysAPI{client: client}
kAPI.Delete(t.Context(), tt.key, tt.opts)
kAPI.Delete(context.Background(), tt.key, tt.opts)
}
}
@ -1331,7 +1331,7 @@ func TestHTTPKeysAPIDeleteError(t *testing.T) {
for i, tt := range tests {
kAPI := httpKeysAPI{client: tt}
resp, err := kAPI.Delete(t.Context(), "/foo", nil)
resp, err := kAPI.Delete(context.Background(), "/foo", nil)
if err == nil {
t.Errorf("#%d: received nil error", i)
}
@ -1358,7 +1358,7 @@ func TestHTTPKeysAPIDeleteResponse(t *testing.T) {
}
kAPI := &httpKeysAPI{client: client, prefix: "/pants"}
resp, err := kAPI.Delete(t.Context(), "/foo/bar/baz", nil)
resp, err := kAPI.Delete(context.Background(), "/foo/bar/baz", nil)
if err != nil {
t.Errorf("non-nil error: %#v", err)
}
@ -1378,7 +1378,7 @@ func TestHTTPKeysAPICreateAction(t *testing.T) {
}
kAPI := httpKeysAPI{client: &actionAssertingHTTPClient{t: t, act: act}}
kAPI.Create(t.Context(), "/foo", "bar")
kAPI.Create(context.Background(), "/foo", "bar")
}
func TestHTTPKeysAPICreateInOrderAction(t *testing.T) {
@ -1388,7 +1388,7 @@ func TestHTTPKeysAPICreateInOrderAction(t *testing.T) {
TTL: 0,
}
kAPI := httpKeysAPI{client: &actionAssertingHTTPClient{t: t, act: act}}
kAPI.CreateInOrder(t.Context(), "/foo", "bar", nil)
kAPI.CreateInOrder(context.Background(), "/foo", "bar", nil)
}
func TestHTTPKeysAPIUpdateAction(t *testing.T) {
@ -1402,7 +1402,7 @@ func TestHTTPKeysAPIUpdateAction(t *testing.T) {
}
kAPI := httpKeysAPI{client: &actionAssertingHTTPClient{t: t, act: act}}
kAPI.Update(t.Context(), "/foo", "bar")
kAPI.Update(context.Background(), "/foo", "bar")
}
func TestNodeTTLDuration(t *testing.T) {

View File

@ -15,6 +15,7 @@
package client
import (
"context"
"encoding/json"
"errors"
"net/http"
@ -22,8 +23,6 @@ import (
"reflect"
"testing"
"github.com/stretchr/testify/require"
"go.etcd.io/etcd/client/pkg/v3/types"
)
@ -38,7 +37,7 @@ func TestMembersAPIActionList(t *testing.T) {
}
got := *act.HTTPRequest(ep)
err := assertRequest(got, http.MethodGet, wantURL, http.Header{}, nil)
err := assertRequest(got, "GET", wantURL, http.Header{}, nil)
if err != nil {
t.Error(err.Error())
}
@ -64,7 +63,7 @@ func TestMembersAPIActionAdd(t *testing.T) {
wantBody := []byte(`{"peerURLs":["https://127.0.0.1:8081","http://127.0.0.1:8080"]}`)
got := *act.HTTPRequest(ep)
err := assertRequest(got, http.MethodPost, wantURL, wantHeader, wantBody)
err := assertRequest(got, "POST", wantURL, wantHeader, wantBody)
if err != nil {
t.Error(err.Error())
}
@ -91,7 +90,7 @@ func TestMembersAPIActionUpdate(t *testing.T) {
wantBody := []byte(`{"peerURLs":["https://127.0.0.1:8081","http://127.0.0.1:8080"]}`)
got := *act.HTTPRequest(ep)
err := assertRequest(got, http.MethodPut, wantURL, wantHeader, wantBody)
err := assertRequest(got, "PUT", wantURL, wantHeader, wantBody)
if err != nil {
t.Error(err.Error())
}
@ -108,7 +107,7 @@ func TestMembersAPIActionRemove(t *testing.T) {
}
got := *act.HTTPRequest(ep)
err := assertRequest(got, http.MethodDelete, wantURL, http.Header{}, nil)
err := assertRequest(got, "DELETE", wantURL, http.Header{}, nil)
if err != nil {
t.Error(err.Error())
}
@ -125,7 +124,7 @@ func TestMembersAPIActionLeader(t *testing.T) {
}
got := *act.HTTPRequest(ep)
err := assertRequest(got, http.MethodGet, wantURL, http.Header{}, nil)
err := assertRequest(got, "GET", wantURL, http.Header{}, nil)
if err != nil {
t.Error(err.Error())
}
@ -153,7 +152,9 @@ func TestV2MembersURL(t *testing.T) {
Path: "/pants/v2/members",
}
require.Truef(t, reflect.DeepEqual(want, got), "v2MembersURL got %#v, want %#v", got, want)
if !reflect.DeepEqual(want, got) {
t.Fatalf("v2MembersURL got %#v, want %#v", got, want)
}
}
func TestMemberUnmarshal(t *testing.T) {
@ -311,9 +312,13 @@ func TestMemberCreateRequestMarshal(t *testing.T) {
want := []byte(`{"peerURLs":["http://127.0.0.1:8081","https://127.0.0.1:8080"]}`)
got, err := json.Marshal(&req)
require.NoErrorf(t, err, "Marshal returned unexpected err")
if err != nil {
t.Fatalf("Marshal returned unexpected err=%v", err)
}
require.Truef(t, reflect.DeepEqual(want, got), "Failed to marshal memberCreateRequest: want=%s, got=%s", want, got)
if !reflect.DeepEqual(want, got) {
t.Fatalf("Failed to marshal memberCreateRequest: want=%s, got=%s", want, got)
}
}
func TestHTTPMembersAPIAddSuccess(t *testing.T) {
@ -339,7 +344,7 @@ func TestHTTPMembersAPIAddSuccess(t *testing.T) {
PeerURLs: []string{"http://127.0.0.1:7002"},
}
m, err := mAPI.Add(t.Context(), "http://127.0.0.1:7002")
m, err := mAPI.Add(context.Background(), "http://127.0.0.1:7002")
if err != nil {
t.Errorf("got non-nil err: %#v", err)
}
@ -414,7 +419,7 @@ func TestHTTPMembersAPIAddError(t *testing.T) {
for i, tt := range tests {
mAPI := &httpMembersAPI{client: tt.client}
m, err := mAPI.Add(t.Context(), tt.peerURL)
m, err := mAPI.Add(context.Background(), tt.peerURL)
if err == nil {
t.Errorf("#%d: got nil err", i)
}
@ -442,7 +447,7 @@ func TestHTTPMembersAPIRemoveSuccess(t *testing.T) {
},
}
if err := mAPI.Remove(t.Context(), "94088180e21eb87b"); err != nil {
if err := mAPI.Remove(context.Background(), "94088180e21eb87b"); err != nil {
t.Errorf("got non-nil err: %#v", err)
}
}
@ -464,7 +469,7 @@ func TestHTTPMembersAPIRemoveFail(t *testing.T) {
for i, tt := range tests {
mAPI := &httpMembersAPI{client: tt}
if err := mAPI.Remove(t.Context(), "94088180e21eb87b"); err == nil {
if err := mAPI.Remove(context.Background(), "94088180e21eb87b"); err == nil {
t.Errorf("#%d: got nil err", i)
}
}
@ -492,7 +497,7 @@ func TestHTTPMembersAPIListSuccess(t *testing.T) {
},
}
m, err := mAPI.List(t.Context())
m, err := mAPI.List(context.Background())
if err != nil {
t.Errorf("got non-nil err: %#v", err)
}
@ -522,7 +527,7 @@ func TestHTTPMembersAPIListError(t *testing.T) {
for i, tt := range tests {
mAPI := &httpMembersAPI{client: tt}
ms, err := mAPI.List(t.Context())
ms, err := mAPI.List(context.Background())
if err == nil {
t.Errorf("#%d: got nil err", i)
}
@ -552,7 +557,7 @@ func TestHTTPMembersAPILeaderSuccess(t *testing.T) {
ClientURLs: []string{"http://127.0.0.1:4002"},
}
m, err := mAPI.Leader(t.Context())
m, err := mAPI.Leader(context.Background())
if err != nil {
t.Errorf("err = %v, want %v", err, nil)
}
@ -582,7 +587,7 @@ func TestHTTPMembersAPILeaderError(t *testing.T) {
for i, tt := range tests {
mAPI := &httpMembersAPI{client: tt}
m, err := mAPI.Leader(t.Context())
m, err := mAPI.Leader(context.Background())
if err == nil {
t.Errorf("#%d: err = nil, want not nil", i)
}

View File

@ -15,7 +15,6 @@
package client
import (
"errors"
"regexp"
)
@ -31,18 +30,24 @@ func init() {
// IsKeyNotFound returns true if the error code is ErrorCodeKeyNotFound.
func IsKeyNotFound(err error) bool {
var cErr Error
return errors.As(err, &cErr) && cErr.Code == ErrorCodeKeyNotFound
if cErr, ok := err.(Error); ok {
return cErr.Code == ErrorCodeKeyNotFound
}
return false
}
// IsRoleNotFound returns true if the error means role not found of v2 API.
func IsRoleNotFound(err error) bool {
var ae authError
return errors.As(err, &ae) && roleNotFoundRegExp.MatchString(ae.Message)
if ae, ok := err.(authError); ok {
return roleNotFoundRegExp.MatchString(ae.Message)
}
return false
}
// IsUserNotFound returns true if the error means user not found of v2 API.
func IsUserNotFound(err error) bool {
var ae authError
return errors.As(err, &ae) && userNotFoundRegExp.MatchString(ae.Message)
if ae, ok := err.(authError); ok {
return userNotFoundRegExp.MatchString(ae.Message)
}
return false
}

View File

@ -20,7 +20,7 @@ import "os"
const (
// PrivateDirMode grants owner to make/remove files inside the directory.
PrivateDirMode = 0o700
PrivateDirMode = 0700
)
// OpenDir opens a directory for syncing.

View File

@ -23,7 +23,7 @@ import (
const (
// PrivateDirMode grants owner to make/remove files inside the directory.
PrivateDirMode = 0o777
PrivateDirMode = 0777
)
// OpenDir opens a directory in windows with write access for syncing.

View File

@ -28,7 +28,7 @@ import (
const (
// PrivateFileMode grants owner to read/write a file.
PrivateFileMode = 0o600
PrivateFileMode = 0600
)
// IsDirWriteable checks if dir is writable by writing and removing a file
@ -125,7 +125,7 @@ func CheckDirPermission(dir string, perm os.FileMode) error {
if !Exist(dir) {
return fmt.Errorf("directory %q empty, cannot check permission", dir)
}
// check the existing permission on the directory
//check the existing permission on the directory
dirInfo, err := os.Stat(dir)
if err != nil {
return err
@ -160,6 +160,7 @@ func RemoveMatchFile(lg *zap.Logger, dir string, matchFunc func(fileName string)
lg.Error("remove file failed",
zap.String("file", file),
zap.Error(err))
continue
}
}
}

View File

@ -27,14 +27,17 @@ import (
"time"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.uber.org/zap/zaptest"
)
func TestIsDirWriteable(t *testing.T) {
tmpdir := t.TempDir()
require.NoErrorf(t, IsDirWriteable(tmpdir), "unexpected IsDirWriteable error")
require.NoErrorf(t, os.Chmod(tmpdir, 0o444), "unexpected os.Chmod error")
if err := IsDirWriteable(tmpdir); err != nil {
t.Fatalf("unexpected IsDirWriteable error: %v", err)
}
if err := os.Chmod(tmpdir, 0444); err != nil {
t.Fatalf("unexpected os.Chmod error: %v", err)
}
me, err := user.Current()
if err != nil {
// err can be non-nil when cross compiled
@ -47,16 +50,22 @@ func TestIsDirWriteable(t *testing.T) {
// Chmod is not supported under windows.
t.Skipf("running as a superuser or in windows")
}
require.Errorf(t, IsDirWriteable(tmpdir), "expected IsDirWriteable to error")
if err := IsDirWriteable(tmpdir); err == nil {
t.Fatalf("expected IsDirWriteable to error")
}
}
func TestCreateDirAll(t *testing.T) {
tmpdir := t.TempDir()
tmpdir2 := filepath.Join(tmpdir, "testdir")
require.NoError(t, CreateDirAll(zaptest.NewLogger(t), tmpdir2))
if err := CreateDirAll(zaptest.NewLogger(t), tmpdir2); err != nil {
t.Fatal(err)
}
require.NoError(t, os.WriteFile(filepath.Join(tmpdir2, "text.txt"), []byte("test text"), PrivateFileMode))
if err := os.WriteFile(filepath.Join(tmpdir2, "text.txt"), []byte("test text"), PrivateFileMode); err != nil {
t.Fatal(err)
}
if err := CreateDirAll(zaptest.NewLogger(t), tmpdir2); err == nil || !strings.Contains(err.Error(), "to be empty, got") {
t.Fatalf("unexpected error %v", err)
@ -66,14 +75,18 @@ func TestCreateDirAll(t *testing.T) {
func TestExist(t *testing.T) {
fdir := filepath.Join(os.TempDir(), fmt.Sprint(time.Now().UnixNano()+rand.Int63n(1000)))
os.RemoveAll(fdir)
if err := os.Mkdir(fdir, 0o666); err != nil {
if err := os.Mkdir(fdir, 0666); err != nil {
t.Skip(err)
}
defer os.RemoveAll(fdir)
require.Truef(t, Exist(fdir), "expected Exist true, got %v", Exist(fdir))
if !Exist(fdir) {
t.Fatalf("expected Exist true, got %v", Exist(fdir))
}
f, err := os.CreateTemp(os.TempDir(), "fileutil")
require.NoError(t, err)
if err != nil {
t.Fatal(err)
}
f.Close()
if g := Exist(f.Name()); !g {
@ -89,41 +102,62 @@ func TestExist(t *testing.T) {
func TestDirEmpty(t *testing.T) {
dir := t.TempDir()
require.Truef(t, DirEmpty(dir), "expected DirEmpty true, got %v", DirEmpty(dir))
if !DirEmpty(dir) {
t.Fatalf("expected DirEmpty true, got %v", DirEmpty(dir))
}
file, err := os.CreateTemp(dir, "new_file")
require.NoError(t, err)
if err != nil {
t.Fatal(err)
}
file.Close()
require.Falsef(t, DirEmpty(dir), "expected DirEmpty false, got %v", DirEmpty(dir))
require.Falsef(t, DirEmpty(file.Name()), "expected DirEmpty false, got %v", DirEmpty(file.Name()))
if DirEmpty(dir) {
t.Fatalf("expected DirEmpty false, got %v", DirEmpty(dir))
}
if DirEmpty(file.Name()) {
t.Fatalf("expected DirEmpty false, got %v", DirEmpty(file.Name()))
}
}
func TestZeroToEnd(t *testing.T) {
f, err := os.CreateTemp(os.TempDir(), "fileutil")
require.NoError(t, err)
if err != nil {
t.Fatal(err)
}
defer os.Remove(f.Name())
defer f.Close()
// Ensure 0 size is a nop so zero-to-end on an empty file won't give EINVAL.
require.NoError(t, ZeroToEnd(f))
if err = ZeroToEnd(f); err != nil {
t.Fatal(err)
}
b := make([]byte, 1024)
for i := range b {
b[i] = 12
}
_, err = f.Write(b)
require.NoError(t, err)
_, err = f.Seek(512, io.SeekStart)
require.NoError(t, err)
require.NoError(t, ZeroToEnd(f))
if _, err = f.Write(b); err != nil {
t.Fatal(err)
}
if _, err = f.Seek(512, io.SeekStart); err != nil {
t.Fatal(err)
}
if err = ZeroToEnd(f); err != nil {
t.Fatal(err)
}
off, serr := f.Seek(0, io.SeekCurrent)
require.NoError(t, serr)
require.Equalf(t, int64(512), off, "expected offset 512, got %d", off)
if serr != nil {
t.Fatal(serr)
}
if off != 512 {
t.Fatalf("expected offset 512, got %d", off)
}
b = make([]byte, 512)
_, err = f.Read(b)
require.NoError(t, err)
if _, err = f.Read(b); err != nil {
t.Fatal(err)
}
for i := range b {
if b[i] != 0 {
t.Errorf("expected b[%d] = 0, got %d", i, b[i])
@ -136,9 +170,11 @@ func TestDirPermission(t *testing.T) {
tmpdir2 := filepath.Join(tmpdir, "testpermission")
// create a new dir with 0700
require.NoError(t, CreateDirAll(zaptest.NewLogger(t), tmpdir2))
if err := CreateDirAll(zaptest.NewLogger(t), tmpdir2); err != nil {
t.Fatal(err)
}
// check dir permission with mode different than created dir
if err := CheckDirPermission(tmpdir2, 0o600); err == nil {
if err := CheckDirPermission(tmpdir2, 0600); err == nil {
t.Errorf("expected error, got nil")
}
}
@ -146,10 +182,14 @@ func TestDirPermission(t *testing.T) {
func TestRemoveMatchFile(t *testing.T) {
tmpdir := t.TempDir()
f, err := os.CreateTemp(tmpdir, "tmp")
require.NoError(t, err)
if err != nil {
t.Fatal(err)
}
f.Close()
f, err = os.CreateTemp(tmpdir, "foo.tmp")
require.NoError(t, err)
if err != nil {
t.Fatal(err)
}
f.Close()
err = RemoveMatchFile(zaptest.NewLogger(t), tmpdir, func(fileName string) bool {
@ -159,13 +199,17 @@ func TestRemoveMatchFile(t *testing.T) {
t.Errorf("expected nil, got error")
}
fnames, err := ReadDir(tmpdir)
require.NoError(t, err)
if err != nil {
t.Fatal(err)
}
if len(fnames) != 1 {
t.Errorf("expected exist 1 files, got %d", len(fnames))
}
f, err = os.CreateTemp(tmpdir, "tmp")
require.NoError(t, err)
if err != nil {
t.Fatal(err)
}
f.Close()
err = RemoveMatchFile(zaptest.NewLogger(t), tmpdir, func(fileName string) bool {
os.Remove(filepath.Join(tmpdir, fileName))
@ -178,9 +222,11 @@ func TestRemoveMatchFile(t *testing.T) {
func TestTouchDirAll(t *testing.T) {
tmpdir := t.TempDir()
assert.Panicsf(t, func() {
assert.Panics(t, func() {
TouchDirAll(nil, tmpdir)
}, "expected panic with nil log")
assert.NoError(t, TouchDirAll(zaptest.NewLogger(t), tmpdir))
if err := TouchDirAll(zaptest.NewLogger(t), tmpdir); err != nil {
t.Fatal(err)
}
}

View File

@ -19,6 +19,8 @@ import (
"os"
)
var ErrLocked = errors.New("fileutil: file already locked")
var (
ErrLocked = errors.New("fileutil: file already locked")
)
type LockedFile struct{ *os.File }

View File

@ -17,7 +17,6 @@
package fileutil
import (
"errors"
"os"
"syscall"
)
@ -29,7 +28,7 @@ func flockTryLockFile(path string, flag int, perm os.FileMode) (*LockedFile, err
}
if err = syscall.Flock(int(f.Fd()), syscall.LOCK_EX|syscall.LOCK_NB); err != nil {
f.Close()
if errors.Is(err, syscall.EWOULDBLOCK) {
if err == syscall.EWOULDBLOCK {
err = ErrLocked
}
return nil, err

View File

@ -17,7 +17,6 @@
package fileutil
import (
"errors"
"fmt"
"io"
"os"
@ -59,13 +58,13 @@ func TryLockFile(path string, flag int, perm os.FileMode) (*LockedFile, error) {
func ofdTryLockFile(path string, flag int, perm os.FileMode) (*LockedFile, error) {
f, err := os.OpenFile(path, flag, perm)
if err != nil {
return nil, fmt.Errorf("ofdTryLockFile failed to open %q (%w)", path, err)
return nil, fmt.Errorf("ofdTryLockFile failed to open %q (%v)", path, err)
}
flock := wrlck
if err = syscall.FcntlFlock(f.Fd(), unix.F_OFD_SETLK, &flock); err != nil {
f.Close()
if errors.Is(err, syscall.EWOULDBLOCK) {
if err == syscall.EWOULDBLOCK {
err = ErrLocked
}
return nil, err
@ -80,7 +79,7 @@ func LockFile(path string, flag int, perm os.FileMode) (*LockedFile, error) {
func ofdLockFile(path string, flag int, perm os.FileMode) (*LockedFile, error) {
f, err := os.OpenFile(path, flag, perm)
if err != nil {
return nil, fmt.Errorf("ofdLockFile failed to open %q (%w)", path, err)
return nil, fmt.Errorf("ofdLockFile failed to open %q (%v)", path, err)
}
flock := wrlck

View File

@ -18,28 +18,36 @@ import (
"os"
"testing"
"time"
"github.com/stretchr/testify/require"
)
func TestLockAndUnlock(t *testing.T) {
f, err := os.CreateTemp(t.TempDir(), "lock")
require.NoError(t, err)
f, err := os.CreateTemp("", "lock")
if err != nil {
t.Fatal(err)
}
f.Close()
defer func() {
require.NoError(t, os.Remove(f.Name()))
err = os.Remove(f.Name())
if err != nil {
t.Fatal(err)
}
}()
// lock the file
l, err := LockFile(f.Name(), os.O_WRONLY, PrivateFileMode)
require.NoError(t, err)
if err != nil {
t.Fatal(err)
}
// try lock a locked file
_, err = TryLockFile(f.Name(), os.O_WRONLY, PrivateFileMode)
require.ErrorIs(t, err, ErrLocked)
if _, err = TryLockFile(f.Name(), os.O_WRONLY, PrivateFileMode); err != ErrLocked {
t.Fatal(err)
}
// unlock the file
require.NoError(t, l.Close())
if err = l.Close(); err != nil {
t.Fatal(err)
}
// try lock the unlocked file
dupl, err := TryLockFile(f.Name(), os.O_WRONLY, PrivateFileMode)
@ -67,7 +75,9 @@ func TestLockAndUnlock(t *testing.T) {
}
// unlock
require.NoError(t, dupl.Close())
if err = dupl.Close(); err != nil {
t.Fatal(err)
}
// the previously blocked routine should be unblocked
select {

View File

@ -17,7 +17,6 @@
package fileutil
import (
"errors"
"os"
"syscall"
@ -40,7 +39,7 @@ func preallocFixed(f *os.File, sizeInBytes int64) error {
Length: sizeInBytes,
}
err := unix.FcntlFstore(f.Fd(), unix.F_PREALLOCATE, fstore)
if err == nil || errors.Is(err, unix.ENOTSUP) {
if err == nil || err == unix.ENOTSUP {
return nil
}

View File

@ -17,34 +17,29 @@ package fileutil
import (
"os"
"testing"
"github.com/stretchr/testify/require"
)
func TestPreallocateExtend(t *testing.T) {
pf := func(f *os.File, sz int64) error { return Preallocate(f, sz, true) }
tf := func(t *testing.T, f *os.File) {
t.Helper()
testPreallocateExtend(t, f, pf)
}
tf := func(t *testing.T, f *os.File) { testPreallocateExtend(t, f, pf) }
runPreallocTest(t, tf)
}
func TestPreallocateExtendTrunc(t *testing.T) {
tf := func(t *testing.T, f *os.File) {
t.Helper()
testPreallocateExtend(t, f, preallocExtendTrunc)
}
tf := func(t *testing.T, f *os.File) { testPreallocateExtend(t, f, preallocExtendTrunc) }
runPreallocTest(t, tf)
}
func testPreallocateExtend(t *testing.T, f *os.File, pf func(*os.File, int64) error) {
t.Helper()
size := int64(64 * 1000)
require.NoError(t, pf(f, size))
if err := pf(f, size); err != nil {
t.Fatal(err)
}
stat, err := f.Stat()
require.NoError(t, err)
if err != nil {
t.Fatal(err)
}
if stat.Size() != size {
t.Errorf("size = %d, want %d", stat.Size(), size)
}
@ -52,22 +47,26 @@ func testPreallocateExtend(t *testing.T, f *os.File, pf func(*os.File, int64) er
func TestPreallocateFixed(t *testing.T) { runPreallocTest(t, testPreallocateFixed) }
func testPreallocateFixed(t *testing.T, f *os.File) {
t.Helper()
size := int64(64 * 1000)
require.NoError(t, Preallocate(f, size, false))
if err := Preallocate(f, size, false); err != nil {
t.Fatal(err)
}
stat, err := f.Stat()
require.NoError(t, err)
if err != nil {
t.Fatal(err)
}
if stat.Size() != 0 {
t.Errorf("size = %d, want %d", stat.Size(), 0)
}
}
func runPreallocTest(t *testing.T, test func(*testing.T, *os.File)) {
t.Helper()
p := t.TempDir()
f, err := os.CreateTemp(p, "")
require.NoError(t, err)
if err != nil {
t.Fatal(err)
}
test(t, f)
}

View File

@ -17,7 +17,6 @@
package fileutil
import (
"errors"
"os"
"syscall"
)
@ -26,10 +25,10 @@ func preallocExtend(f *os.File, sizeInBytes int64) error {
// use mode = 0 to change size
err := syscall.Fallocate(int(f.Fd()), 0, 0, sizeInBytes)
if err != nil {
var errno syscall.Errno
errno, ok := err.(syscall.Errno)
// not supported; fallback
// fallocate EINTRs frequently in some environments; fallback
if errors.As(err, &errno) && (errno == syscall.ENOTSUP || errno == syscall.EINTR) {
if ok && (errno == syscall.ENOTSUP || errno == syscall.EINTR) {
return preallocExtendTrunc(f, sizeInBytes)
}
}
@ -40,9 +39,9 @@ func preallocFixed(f *os.File, sizeInBytes int64) error {
// use mode = 1 to keep size; see FALLOC_FL_KEEP_SIZE
err := syscall.Fallocate(int(f.Fd()), 1, 0, sizeInBytes)
if err != nil {
var errno syscall.Errno
errno, ok := err.(syscall.Errno)
// treat not supported as nil error
if errors.As(err, &errno) && errno == syscall.ENOTSUP {
if ok && errno == syscall.ENOTSUP {
return nil
}
}

View File

@ -17,6 +17,7 @@ package fileutil
import (
"os"
"path/filepath"
"sort"
"strings"
"time"
@ -57,14 +58,21 @@ func purgeFile(lg *zap.Logger, dirname string, suffix string, max uint, interval
defer close(donec)
}
for {
fnamesWithSuffix, err := readDirWithSuffix(dirname, suffix)
fnames, err := ReadDir(dirname)
if err != nil {
errC <- err
return
}
nPurged := 0
for nPurged < len(fnamesWithSuffix)-int(max) {
f := filepath.Join(dirname, fnamesWithSuffix[nPurged])
newfnames := make([]string, 0)
for _, fname := range fnames {
if strings.HasSuffix(fname, suffix) {
newfnames = append(newfnames, fname)
}
}
sort.Strings(newfnames)
fnames = newfnames
for len(newfnames) > int(max) {
f := filepath.Join(dirname, newfnames[0])
var l *LockedFile
if flock {
l, err = TryLockFile(f, os.O_WRONLY, PrivateFileMode)
@ -86,12 +94,11 @@ func purgeFile(lg *zap.Logger, dirname string, suffix string, max uint, interval
}
}
lg.Info("purged", zap.String("path", f))
nPurged++
newfnames = newfnames[1:]
}
if purgec != nil {
for i := 0; i < nPurged; i++ {
purgec <- fnamesWithSuffix[i]
for i := 0; i < len(fnames)-len(newfnames); i++ {
purgec <- fnames[i]
}
}
select {
@ -103,18 +110,3 @@ func purgeFile(lg *zap.Logger, dirname string, suffix string, max uint, interval
}()
return errC
}
func readDirWithSuffix(dirname string, suffix string) ([]string, error) {
fnames, err := ReadDir(dirname)
if err != nil {
return nil, err
}
// filter in place (ref. https://go.dev/wiki/SliceTricks#filtering-without-allocating)
fnamesWithSuffix := fnames[:0]
for _, fname := range fnames {
if strings.HasSuffix(fname, suffix) {
fnamesWithSuffix = append(fnamesWithSuffix, fname)
}
}
return fnamesWithSuffix, nil
}

View File

@ -22,7 +22,6 @@ import (
"testing"
"time"
"github.com/stretchr/testify/require"
"go.uber.org/zap/zaptest"
)
@ -32,7 +31,9 @@ func TestPurgeFile(t *testing.T) {
// minimal file set
for i := 0; i < 3; i++ {
f, ferr := os.Create(filepath.Join(dir, fmt.Sprintf("%d.test", i)))
require.NoError(t, ferr)
if ferr != nil {
t.Fatal(ferr)
}
f.Close()
}
@ -67,7 +68,9 @@ func TestPurgeFile(t *testing.T) {
}
fnames, rerr := ReadDir(dir)
require.NoError(t, rerr)
if rerr != nil {
t.Fatal(rerr)
}
wnames := []string{"7.test", "8.test", "9.test"}
if !reflect.DeepEqual(fnames, wnames) {
t.Errorf("filenames = %v, want %v", fnames, wnames)
@ -90,14 +93,18 @@ func TestPurgeFileHoldingLockFile(t *testing.T) {
for i := 0; i < 10; i++ {
var f *os.File
f, err := os.Create(filepath.Join(dir, fmt.Sprintf("%d.test", i)))
require.NoError(t, err)
if err != nil {
t.Fatal(err)
}
f.Close()
}
// create a purge barrier at 5
p := filepath.Join(dir, fmt.Sprintf("%d.test", 5))
l, err := LockFile(p, os.O_WRONLY, PrivateFileMode)
require.NoError(t, err)
if err != nil {
t.Fatal(err)
}
stop, purgec := make(chan struct{}), make(chan string, 10)
errch := purgeFile(zaptest.NewLogger(t), dir, "test", 3, time.Millisecond, stop, purgec, nil, true)
@ -111,7 +118,9 @@ func TestPurgeFileHoldingLockFile(t *testing.T) {
}
fnames, rerr := ReadDir(dir)
require.NoError(t, rerr)
if rerr != nil {
t.Fatal(rerr)
}
wnames := []string{"5.test", "6.test", "7.test", "8.test", "9.test"}
if !reflect.DeepEqual(fnames, wnames) {
@ -127,7 +136,9 @@ func TestPurgeFileHoldingLockFile(t *testing.T) {
}
// remove the purge barrier
require.NoError(t, l.Close())
if err = l.Close(); err != nil {
t.Fatal(err)
}
// wait for rest of purges (5, 6)
for i := 0; i < 2; i++ {
@ -139,7 +150,9 @@ func TestPurgeFileHoldingLockFile(t *testing.T) {
}
fnames, rerr = ReadDir(dir)
require.NoError(t, rerr)
if rerr != nil {
t.Fatal(rerr)
}
wnames = []string{"7.test", "8.test", "9.test"}
if !reflect.DeepEqual(fnames, wnames) {
t.Errorf("filenames = %v, want %v", fnames, wnames)

View File

@ -19,9 +19,6 @@ import (
"path/filepath"
"reflect"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
func TestReadDir(t *testing.T) {
@ -32,23 +29,34 @@ func TestReadDir(t *testing.T) {
writeFunc(t, filepath.Join(tmpdir, f))
}
fs, err := ReadDir(tmpdir)
require.NoErrorf(t, err, "error calling ReadDir")
if err != nil {
t.Fatalf("error calling ReadDir: %v", err)
}
wfs := []string{"abc", "def", "ghi", "xyz"}
require.Truef(t, reflect.DeepEqual(fs, wfs), "ReadDir: got %v, want %v", fs, wfs)
if !reflect.DeepEqual(fs, wfs) {
t.Fatalf("ReadDir: got %v, want %v", fs, wfs)
}
files = []string{"def.wal", "abc.wal", "xyz.wal", "ghi.wal"}
for _, f := range files {
writeFunc(t, filepath.Join(tmpdir, f))
}
fs, err = ReadDir(tmpdir, WithExt(".wal"))
require.NoErrorf(t, err, "error calling ReadDir")
if err != nil {
t.Fatalf("error calling ReadDir: %v", err)
}
wfs = []string{"abc.wal", "def.wal", "ghi.wal", "xyz.wal"}
require.Truef(t, reflect.DeepEqual(fs, wfs), "ReadDir: got %v, want %v", fs, wfs)
if !reflect.DeepEqual(fs, wfs) {
t.Fatalf("ReadDir: got %v, want %v", fs, wfs)
}
}
func writeFunc(t *testing.T, path string) {
t.Helper()
fh, err := os.Create(path)
require.NoErrorf(t, err, "error creating file")
assert.NoErrorf(t, fh.Close(), "error closing file")
if err != nil {
t.Fatalf("error creating file: %v", err)
}
if err = fh.Close(); err != nil {
t.Fatalf("error closing file: %v", err)
}
}

View File

@ -1,22 +1,17 @@
module go.etcd.io/etcd/client/pkg/v3
go 1.24
toolchain go1.24.1
go 1.21
require (
github.com/coreos/go-systemd/v22 v22.5.0
github.com/stretchr/testify v1.10.0
go.uber.org/zap v1.27.0
golang.org/x/sys v0.31.0
github.com/stretchr/testify v1.8.4
go.uber.org/zap v1.26.0
golang.org/x/sys v0.16.0
)
require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rogpeppe/go-internal v1.14.1 // indirect
go.uber.org/multierr v1.11.0 // indirect
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect
)

View File

@ -1,34 +1,21 @@
github.com/coreos/go-systemd/v22 v22.5.0 h1:RrqgGjYQKalulkV8NGVIfkXQf6YYmOyiJKk8iXXhfZs=
github.com/coreos/go-systemd/v22 v22.5.0/go.mod h1:Y58oyj3AT4RCenI/lSvhwexgC+NSVTIJ3seZv2GcEnc=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
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/godbus/dbus/v5 v5.0.4/go.mod h1:xhWf0FNVPg57R7Z0UbKHbJfkEywrmjJnf7w5xrFpKfA=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE=
github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
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/rogpeppe/go-internal v1.9.0/go.mod h1:WtVeX8xhTBvf0smdhujwtBcq4Qrzq/fJaraNFVN+nFs=
github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ=
github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc=
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
go.uber.org/goleak v1.3.0 h1:2K3zAYmnTNqV73imy9J1T3WC+gmCePx2hEGkimedGto=
go.uber.org/goleak v1.3.0/go.mod h1:CoHD4mav9JJNrW/WLlf7HGZPjdw8EucARQHekz1X6bE=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
go.uber.org/goleak v1.2.0 h1:xqgm/S+aQvhWFTtR0XK3Jvg7z8kGV8P4X14IzwN3Eqk=
go.uber.org/goleak v1.2.0/go.mod h1:XJYK+MuIchqpmGmUSAzotztawfKvYLUIgg7guXrwVUo=
go.uber.org/multierr v1.11.0 h1:blXXJkSxSSfBVBlC76pxqeO+LN3aDfLQo+309xJstO0=
go.uber.org/multierr v1.11.0/go.mod h1:20+QtiLqy0Nd6FdQB9TLXag12DsQkrbs3htMFfDN80Y=
go.uber.org/zap v1.27.0 h1:aJMhYGrd5QSmlpLMr2MftRKl7t8J8PTZPA732ud/XR8=
go.uber.org/zap v1.27.0/go.mod h1:GB2qFLM7cTU87MWRP2mPIjqfIDnGu+VIO4V/SdhGo2E=
golang.org/x/sys v0.31.0 h1:ioabZlmFYtWhL+TRYpcnNlLwhyxaM9kWTDEmfnprqik=
golang.org/x/sys v0.31.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k=
go.uber.org/zap v1.26.0 h1:sI7k6L95XOKS281NhVKOFCUNIvv9e0w4BF8N3u+tCRo=
go.uber.org/zap v1.26.0/go.mod h1:dtElttAiwGvoJ/vj4IwHBS/gXsEu/pZ50mUIRWuG0so=
golang.org/x/sys v0.16.0 h1:xWw16ngr6ZMtmxDyKyIgsE93KNKz5HKmMa3b8ALHidU=
golang.org/x/sys v0.16.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=

View File

@ -17,23 +17,19 @@ package logutil
import "fmt"
const (
JSONLogFormat = "json"
JsonLogFormat = "json"
ConsoleLogFormat = "console"
//revive:disable:var-naming
// Deprecated: Please use JSONLogFormat.
JsonLogFormat = JSONLogFormat
//revive:enable:var-naming
)
var DefaultLogFormat = JSONLogFormat
var DefaultLogFormat = JsonLogFormat
// ConvertToZapFormat converts and validated log format string.
func ConvertToZapFormat(format string) (string, error) {
switch format {
case ConsoleLogFormat:
return ConsoleLogFormat, nil
case JSONLogFormat:
return JSONLogFormat, nil
case JsonLogFormat:
return JsonLogFormat, nil
case "":
return DefaultLogFormat, nil
default:

View File

@ -24,9 +24,9 @@ func TestLogFormat(t *testing.T) {
want string
errExpected bool
}{
{"json", JSONLogFormat, false},
{"json", JsonLogFormat, false},
{"console", ConsoleLogFormat, false},
{"", JSONLogFormat, false},
{"", JsonLogFormat, false},
{"konsole", "", true},
}

View File

@ -15,7 +15,7 @@
package logutil
import (
"slices"
"sort"
"time"
"go.uber.org/zap"
@ -58,7 +58,7 @@ var DefaultZapLoggerConfig = zap.Config{
// 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.000000Z0700"))
enc.AppendString(t.Format("2006-01-02T15:04:05.999999Z0700"))
},
EncodeDuration: zapcore.StringDurationEncoder,
@ -72,22 +72,37 @@ var DefaultZapLoggerConfig = zap.Config{
// MergeOutputPaths merges logging output paths, resolving conflicts.
func MergeOutputPaths(cfg zap.Config) zap.Config {
cfg.OutputPaths = mergePaths(cfg.OutputPaths)
cfg.ErrorOutputPaths = mergePaths(cfg.ErrorOutputPaths)
outputs := make(map[string]struct{})
for _, v := range cfg.OutputPaths {
outputs[v] = struct{}{}
}
outputSlice := make([]string, 0)
if _, ok := outputs["/dev/null"]; ok {
// "/dev/null" to discard all
outputSlice = []string{"/dev/null"}
} else {
for k := range outputs {
outputSlice = append(outputSlice, k)
}
}
cfg.OutputPaths = outputSlice
sort.Strings(cfg.OutputPaths)
errOutputs := make(map[string]struct{})
for _, v := range cfg.ErrorOutputPaths {
errOutputs[v] = struct{}{}
}
errOutputSlice := make([]string, 0)
if _, ok := errOutputs["/dev/null"]; ok {
// "/dev/null" to discard all
errOutputSlice = []string{"/dev/null"}
} else {
for k := range errOutputs {
errOutputSlice = append(errOutputSlice, k)
}
}
cfg.ErrorOutputPaths = errOutputSlice
sort.Strings(cfg.ErrorOutputPaths)
return cfg
}
func mergePaths(old []string) []string {
if len(old) == 0 {
// the original implementation ensures the result is non-nil
return []string{}
}
// use "/dev/null" to discard all
if slices.Contains(old, "/dev/null") {
return []string{"/dev/null"}
}
// clone a new one; don't modify the original, in case it matters.
dup := slices.Clone(old)
slices.Sort(dup)
return slices.Compact(dup)
}

Some files were not shown because too many files have changed in this diff Show More