]> git.feebdaed.xyz Git - 0xmirror/kubernetes.git/commitdiff
etcd: Remove unused legacy image build code
authorCiprian Hacman <ciprian@hakman.dev>
Thu, 18 Dec 2025 12:35:19 +0000 (14:35 +0200)
committerCiprian Hacman <ciprian@hakman.dev>
Thu, 18 Dec 2025 16:15:13 +0000 (18:15 +0200)
25 files changed:
build/dependencies.yaml
cluster/images/etcd/Dockerfile [deleted file]
cluster/images/etcd/Dockerfile.windows [deleted file]
cluster/images/etcd/Makefile [deleted file]
cluster/images/etcd/OWNERS [deleted file]
cluster/images/etcd/README.md [deleted file]
cluster/images/etcd/cloudbuild.yaml [deleted file]
cluster/images/etcd/migrate-if-needed.bat [deleted file]
cluster/images/etcd/migrate-if-needed.sh [deleted file]
cluster/images/etcd/migrate/copy_file.go [deleted file]
cluster/images/etcd/migrate/data_dir.go [deleted file]
cluster/images/etcd/migrate/data_dir_test.go [deleted file]
cluster/images/etcd/migrate/integration_test.go [deleted file]
cluster/images/etcd/migrate/migrate.go [deleted file]
cluster/images/etcd/migrate/migrate_client.go [deleted file]
cluster/images/etcd/migrate/migrate_server.go [deleted file]
cluster/images/etcd/migrate/migrator.go [deleted file]
cluster/images/etcd/migrate/options.go [deleted file]
cluster/images/etcd/migrate/options_test.go [deleted file]
cluster/images/etcd/migrate/testdata/datadir_with_version/version.txt [deleted file]
cluster/images/etcd/migrate/testdata/datadir_without_version/.placeholder [deleted file]
cluster/images/etcd/migrate/util_others.go [deleted file]
cluster/images/etcd/migrate/utils_windows.go [deleted file]
cluster/images/etcd/migrate/versions.go [deleted file]
cluster/images/etcd/migrate/versions_test.go [deleted file]

index 695e1c2f3d475c021d9b7742a6c76deb7177f27b..5e64aa79b71e2ab05794ad80ef3f7cd260c0d889 100644 (file)
@@ -79,13 +79,6 @@ dependencies:
     - path: test/utils/image/manifest.go
       match: configs\[Etcd\] = Config{list\.GcEtcdRegistry, "etcd", "\d+\.\d+.\d+(-(alpha|beta|rc).\d+)?(-\d+)?"}
 
-  - name: "etcd-image"
-    version: 3.6.4
-    refPaths:
-    - path: cluster/images/etcd/Makefile
-      match: BUNDLED_ETCD_VERSIONS\?|LATEST_ETCD_VERSION\?
-    - path: cluster/images/etcd/migrate/options.go
-
   - name: "node-problem-detector"
     version: 1.34.0
     refPaths:
@@ -107,13 +100,6 @@ dependencies:
     #- path: cluster/gce/windows/k8s-node-setup.psm1
     #  match: DEFAULT_NPD_VERSION
 
-  # From https://github.com/etcd-io/etcd/blob/main/Makefile
-  - name: "golang: etcd release version"
-    version: 1.23.11 # https://github.com/etcd-io/etcd/blob/main/CHANGELOG/CHANGELOG-3.6.md
-    refPaths:
-    - path: cluster/images/etcd/Makefile
-      match: 'GOLANG_VERSION := \d+.\d+(alpha|beta|rc)?\.?(\d+)?'
-
   # Golang
   # TODO: this should really be eliminated and controlled by .go-version
   - name: "golang: upstream version"
@@ -151,16 +137,6 @@ dependencies:
   - name: "registry.k8s.io/debian-base: dependents"
     version: bookworm-v1.0.6
     refPaths:
-    - path: cluster/images/etcd/Makefile
-      match: BASEIMAGE\?\=registry\.k8s\.io\/build-image\/debian-base:[a-zA-Z]+\-v((([0-9]+)\.([0-9]+)\.([0-9]+)(?:-([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?)(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?)
-    - path: cluster/images/etcd/Makefile
-      match: BASEIMAGE\?\=registry\.k8s\.io\/build-image\/debian-base-arm:[a-zA-Z]+\-v((([0-9]+)\.([0-9]+)\.([0-9]+)(?:-([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?)(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?)
-    - path: cluster/images/etcd/Makefile
-      match: BASEIMAGE\?\=registry\.k8s\.io\/build-image\/debian-base-arm64:[a-zA-Z]+\-v((([0-9]+)\.([0-9]+)\.([0-9]+)(?:-([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?)(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?)
-    - path: cluster/images/etcd/Makefile
-      match: BASEIMAGE\?\=registry\.k8s\.io\/build-image\/debian-base-ppc64le:[a-zA-Z]+\-v((([0-9]+)\.([0-9]+)\.([0-9]+)(?:-([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?)(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?)
-    - path: cluster/images/etcd/Makefile
-      match: BASEIMAGE\?\=registry\.k8s\.io\/build-image\/debian-base-s390x:[a-zA-Z]+\-v((([0-9]+)\.([0-9]+)\.([0-9]+)(?:-([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?)(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?)
     - path: test/conformance/image/Makefile
       match: BASE_IMAGE_VERSION\?=
     - path: test/images/pets/peer-finder/BASEIMAGE
@@ -267,7 +243,5 @@ dependencies:
     refPaths:
     - path: build/pause/cloudbuild.yaml
       match: gcr.io/k8s-staging-test-infra/gcb-docker-gcloud
-    - path: cluster/images/etcd/cloudbuild.yaml
-      match: gcr.io/k8s-staging-test-infra/gcb-docker-gcloud
     - path: test/images/cloudbuild.yaml
       match: gcr.io/k8s-staging-test-infra/gcb-docker-gcloud
diff --git a/cluster/images/etcd/Dockerfile b/cluster/images/etcd/Dockerfile
deleted file mode 100644 (file)
index 36dc862..0000000
+++ /dev/null
@@ -1,37 +0,0 @@
-# Copyright 2016 The Kubernetes Authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-ARG BASEIMAGE
-ARG RUNNERIMAGE
-
-FROM ${BASEIMAGE} as builder
-
-# This image needs bash for running "migrate-if-needed.sh". Instead of a full debian image
-# we use just the bash-static and we wrap bash-static into a distroless image instead of
-# a full debian image
-RUN apt-get update -y \
-       && apt-get -yy -q install --no-install-recommends --no-install-suggests --fix-missing \
-               bash-static
-
-RUN cp /bin/bash-static /sh
-
-FROM ${RUNNERIMAGE}
-WORKDIR /
-
-COPY --from=builder /sh /bin/
-
-EXPOSE 2379 2380 4001 7001
-# etcdctl is used by etcd.manifest for livenessProbe.
-COPY etcd* etcdctl* /usr/local/bin/
-COPY migrate-if-needed.sh migrate /usr/local/bin/
diff --git a/cluster/images/etcd/Dockerfile.windows b/cluster/images/etcd/Dockerfile.windows
deleted file mode 100644 (file)
index c88131f..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-# Copyright 2021 The Kubernetes Authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-ARG RUNNERIMAGE
-FROM ${RUNNERIMAGE}
-
-EXPOSE 2379 2380 4001 7001
-
-WORKDIR C:/usr/local/bin
-COPY etcd* etcdctl* /usr/local/bin/
-COPY migrate-if-needed.bat /usr/local/bin/
-COPY migrate /usr/local/bin/migrate.exe
-
-# NOTE(claudiub): docker buildx sets the PATH env variable to a Linux-like PATH,
-# # which is not desirable. See: https://github.com/moby/buildkit/issues/1560
-# # TODO(claudiub): remove this once the issue has been resolved.
-ENV PATH="C:\usr\local\bin;C:\Windows\system32;C:\Windows;"
diff --git a/cluster/images/etcd/Makefile b/cluster/images/etcd/Makefile
deleted file mode 100644 (file)
index 7178ef7..0000000
+++ /dev/null
@@ -1,266 +0,0 @@
-# Copyright 2016 The Kubernetes Authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-# Build the etcd image
-#
-# Usage:
-#      [BUNDLED_ETCD_VERSIONS=3.4.18 3.5.21 3.6.4] [REGISTRY=registry.k8s.io] [ARCH=amd64] [BASEIMAGE=busybox] make (build|push)
-#
-# The image contains different etcd versions to simplify
-# upgrades. Thus be careful when removing any versions from here.
-#
-# NOTE: The etcd upgrade rules are that you can upgrade only 1 minor
-# version at a time, and patch release don't matter.
-#
-# Except from etcd-$(version) and etcdctl-$(version) binaries, we also
-# need etcd and etcdctl binaries for backward compatibility reasons.
-# That binary will be set to the last version from $(BUNDLED_ETCD_VERSIONS).
-BUNDLED_ETCD_VERSIONS?=3.4.18 3.5.21 3.6.4
-
-# LATEST_ETCD_VERSION identifies the most recent etcd version available.
-LATEST_ETCD_VERSION?=3.6.4
-
-# REVISION provides a version number for this image and all it's bundled
-# artifacts. It should start at zero for each LATEST_ETCD_VERSION and increment
-# for each revision of this image at that etcd version.
-REVISION?=0
-
-# IMAGE_TAG Uniquely identifies registry.k8s.io/etcd docker image with a tag of the form "<etcd-version>-<revision>".
-IMAGE_TAG=$(LATEST_ETCD_VERSION)-$(REVISION)
-
-ARCH?=amd64
-
-# Operating systems supported: linux, windows
-OS ?= linux
-# OS Version for the Windows images: 1809, ltsc2022
-OSVERSION ?= 1809
-
-# The output type could either be docker (local), or registry.
-# If it is registry, it will also allow us to push the Windows images.
-OUTPUT_TYPE ?= docker
-
-ALL_OS = linux windows
-ALL_ARCH.linux = amd64 arm arm64 ppc64le s390x
-ALL_OS_ARCH.linux = $(foreach arch, ${ALL_ARCH.linux}, linux-$(arch))
-ALL_ARCH.windows = amd64
-ALL_OSVERSIONS.windows := 1809 ltsc2022
-ALL_OS_ARCH.windows = $(foreach arch, $(ALL_ARCH.windows), $(foreach osversion, ${ALL_OSVERSIONS.windows}, windows-$(arch)-${osversion}))
-ALL_OS_ARCH = $(foreach os, $(ALL_OS), ${ALL_OS_ARCH.${os}})
-
-IMAGE_SUFFIX.linux = $(OS)-$(ARCH)
-IMAGE_SUFFIX.windows = $(OS)-$(ARCH)-$(OSVERSION)
-IMAGE_SUFFIX := ${IMAGE_SUFFIX.${OS}}
-
-# Image should be pulled from registry.k8s.io, which will auto-detect
-# region (us, eu, asia, ...) and pull from the closest.
-REGISTRY?=registry.k8s.io
-# Images should be pushed to staging-k8s.gcr.io.
-PUSH_REGISTRY?=staging-k8s.gcr.io
-
-MANIFEST_IMAGE := $(PUSH_REGISTRY)/etcd
-
-# Install binaries matching base distro permissions
-BIN_INSTALL := install -m 0555
-
-# Hosts running SELinux need :z added to volume mounts
-SELINUX_ENABLED := $(shell cat /sys/fs/selinux/enforce 2> /dev/null || echo 0)
-
-ifeq ($(SELINUX_ENABLED),1)
-  DOCKER_VOL_OPTS?=:z
-endif
-
-# This option is for running docker manifest command
-export DOCKER_CLI_EXPERIMENTAL := enabled
-# golang version should match the golang version of the official build from https://github.com/etcd-io/etcd/releases.
-GOLANG_VERSION := 1.23.11 # https://github.com/etcd-io/etcd/blob/main/CHANGELOG/CHANGELOG-3.6.md
-GOARM?=7
-TEMP_DIR:=$(shell mktemp -d)
-
-DOCKERFILE.linux = Dockerfile
-DOCKERFILE.windows = Dockerfile.windows
-DOCKERFILE := ${DOCKERFILE.${OS}}
-
-ifeq ($(ARCH),amd64)
-    BASEIMAGE?=registry.k8s.io/build-image/debian-base:bookworm-v1.0.6
-endif
-ifeq ($(ARCH),arm)
-    BASEIMAGE?=registry.k8s.io/build-image/debian-base-arm:bookworm-v1.0.6
-endif
-ifeq ($(ARCH),arm64)
-    BASEIMAGE?=registry.k8s.io/build-image/debian-base-arm64:bookworm-v1.0.6
-endif
-ifeq ($(ARCH),ppc64le)
-    BASEIMAGE?=registry.k8s.io/build-image/debian-base-ppc64le:bookworm-v1.0.6
-endif
-ifeq ($(ARCH),s390x)
-    BASEIMAGE?=registry.k8s.io/build-image/debian-base-s390x:bookworm-v1.0.6
-endif
-
-BASE.windows = mcr.microsoft.com/windows/nanoserver
-
-RUNNERIMAGE.windows?=$(BASE.windows):$(OSVERSION)
-RUNNERIMAGE.linux?=gcr.io/distroless/static:latest
-RUNNERIMAGE := ${RUNNERIMAGE.${OS}}
-
-QEMUVERSION?=5.2.0-2
-
-build:
-       # Explicitly copy files to the temp directory
-       $(BIN_INSTALL) migrate-if-needed.sh $(TEMP_DIR)
-       $(BIN_INSTALL) migrate-if-needed.bat $(TEMP_DIR)
-       install $(DOCKERFILE) $(TEMP_DIR)
-
-       # Compile migrate
-       migrate_tmp_dir=$(shell mktemp -d); \
-       docker run --rm --interactive -v $(shell pwd)/../../../:/go/src/k8s.io/kubernetes$(DOCKER_VOL_OPTS) -v $${migrate_tmp_dir}:/build$(DOCKER_VOL_OPTS) -e GOOS=$(OS) -e GOARCH=$(ARCH) golang:$(GOLANG_VERSION) \
-               /bin/bash -c "CGO_ENABLED=0 GO111MODULE=off go build -o /build/migrate k8s.io/kubernetes/cluster/images/etcd/migrate"; \
-       $(BIN_INSTALL) $${migrate_tmp_dir}/migrate $(TEMP_DIR);
-
-ifeq ($(ARCH),amd64)
-
-       # Do not compile if we should make an image for amd64, use the official etcd binaries instead
-       # For each release create a tmp dir 'etcd_release_tmp_dir' and unpack the release tar there.
-ifeq ($(OS),windows)
-       for version in $(BUNDLED_ETCD_VERSIONS); do \
-               etcd_release_tmp_dir=$(shell mktemp -d); \
-               curl -sSL --retry 5 https://github.com/etcd-io/etcd/releases/download/v$$version/etcd-v$$version-windows-amd64.zip -o etcd-v$$version-windows-amd64.zip; \
-               unzip -q -d $$etcd_release_tmp_dir etcd-v$$version-windows-amd64.zip; \
-               rm etcd-v$$version-windows-amd64.zip; \
-               $(BIN_INSTALL) $$etcd_release_tmp_dir/etcd-v$$version-windows-amd64/etcd.exe $$etcd_release_tmp_dir/etcd-v$$version-windows-amd64/etcdctl.exe $(TEMP_DIR)/; \
-               $(BIN_INSTALL) $(TEMP_DIR)/etcd.exe $(TEMP_DIR)/etcd-$$version.exe; \
-               $(BIN_INSTALL) $(TEMP_DIR)/etcdctl.exe $(TEMP_DIR)/etcdctl-$$version.exe; \
-       done
-else
-       for version in $(BUNDLED_ETCD_VERSIONS); do \
-               etcd_release_tmp_dir=$(shell mktemp -d); \
-               curl -sSL --retry 5 https://github.com/etcd-io/etcd/releases/download/v$$version/etcd-v$$version-linux-amd64.tar.gz | tar -xz -C $$etcd_release_tmp_dir --strip-components=1; \
-               $(BIN_INSTALL) $$etcd_release_tmp_dir/etcd $$etcd_release_tmp_dir/etcdctl $(TEMP_DIR)/; \
-               $(BIN_INSTALL) $(TEMP_DIR)/etcd $(TEMP_DIR)/etcd-$$version; \
-               $(BIN_INSTALL) $(TEMP_DIR)/etcdctl $(TEMP_DIR)/etcdctl-$$version; \
-       done
-endif
-
-else
-
-       # Download etcd in a golang container and cross-compile it statically
-       # For each release create a tmp dir 'etcd_release_tmp_dir' and unpack the release tar there.
-       arch_prefix=""
-        ifeq ($(ARCH),arm)
-               arch_prefix="GOARM=$(GOARM)"
-        endif
-
-       # use '/go/src/go.etcd.io/etcd' to build etcd 3.4 and later.
-       for version in $(BUNDLED_ETCD_VERSIONS); do \
-               etcd_release_tmp_dir=$(shell mktemp -d); \
-               etcd_build_dir="/go/src/github.com/coreos/etcd"; \
-               etcd_build_script="./build.sh"; \
-               if [ $$(echo $$version | cut -d. -f2) -gt 3 ]; then \
-                       etcd_build_dir="/go/src/go.etcd.io/etcd"; \
-               fi; \
-               if [ $$(echo $$version | cut -d. -f2) -gt 5 ]; then \
-                       etcd_build_script="./scripts/build.sh"; \
-               fi; \
-               docker run --rm --interactive -v $${etcd_release_tmp_dir}:/etcdbin golang:$(GOLANG_VERSION)$(DOCKER_VOL_OPTS) /bin/bash -c \
-                       "git clone https://github.com/etcd-io/etcd $$etcd_build_dir \
-                       && cd $$etcd_build_dir \
-                       && git checkout v$${version} \
-                       && $(arch_prefix) GOARCH=$(ARCH) $$etcd_build_script \
-                       && cp -f bin/$(ARCH)/etcd* bin/etcd* /etcdbin; echo 'done'"; \
-               $(BIN_INSTALL) $$etcd_release_tmp_dir/etcd $$etcd_release_tmp_dir/etcdctl $(TEMP_DIR)/; \
-               $(BIN_INSTALL) $(TEMP_DIR)/etcd $(TEMP_DIR)/etcd-$$version; \
-               $(BIN_INSTALL) $(TEMP_DIR)/etcdctl $(TEMP_DIR)/etcdctl-$$version; \
-       done
-
-       # Add this ENV variable in order to workaround an unsupported arch blocker
-       # On arm (which is 32-bit), it can't handle >1GB data in-memory
-        ifeq ($(ARCH),arm)
-               cd $(TEMP_DIR) && echo "ENV ETCD_UNSUPPORTED_ARCH=$(ARCH)" >> $(DOCKERFILE)
-        endif
-endif
-
-       docker run --rm --privileged multiarch/qemu-user-static:$(QEMUVERSION) --reset -p yes
-       docker buildx version
-       BUILDER=$(shell docker buildx create --use)
-
-       # And build the image
-       docker buildx build \
-               --pull \
-               --provenance=false \
-               --sbom=false \
-               --output=type=$(OUTPUT_TYPE) \
-               --platform "$(OS)/$(ARCH)" \
-               -t $(REGISTRY)/etcd:$(IMAGE_TAG)-$(IMAGE_SUFFIX) \
-               --build-arg BASEIMAGE=$(BASEIMAGE) \
-               --build-arg RUNNERIMAGE=$(RUNNERIMAGE) \
-               -f $(TEMP_DIR)/$(DOCKERFILE) \
-               $(TEMP_DIR)
-       docker buildx rm $$BUILDER
-
-push: build
-
-# split words on hyphen, access by 1-index
-word-hyphen = $(word $2,$(subst -, ,$1))
-
-sub-build-%:
-       $(MAKE) OUTPUT_TYPE=docker OS=$(call word-hyphen,$*,1) ARCH=$(call word-hyphen,$*,2) build
-
-all-build: $(addprefix sub-build-,$(ALL_OS_ARCH))
-
-sub-push-image-%:
-       $(MAKE) OUTPUT_TYPE=registry OS=$(call word-hyphen,$*,1) ARCH=$(call word-hyphen,$*,2) OSVERSION=$(call word-hyphen,$*,3) REGISTRY=$(PUSH_REGISTRY) push
-
-all-push-images: $(addprefix sub-push-image-,$(ALL_OS_ARCH))
-
-# NOTE(claudiub): A non-default builder instance is needed in order to build Windows images.
-all-push: all-push-images push-manifest
-
-push-manifest:
-       docker manifest create --amend $(MANIFEST_IMAGE):$(IMAGE_TAG) $(shell echo $(ALL_OS_ARCH) | sed -e "s~[^ ]*~$(MANIFEST_IMAGE):$(IMAGE_TAG)\-&~g")
-       set -x; for arch in $(ALL_ARCH.linux); do docker manifest annotate --os linux --arch $${arch} ${MANIFEST_IMAGE}:${IMAGE_TAG} ${MANIFEST_IMAGE}:${IMAGE_TAG}-linux-$${arch}; done
-       # For Windows images, we also need to include the "os.version" in the manifest list, so the Windows node can pull the proper image it needs.
-       # we use awk to also trim the quotes around the OS version string.
-       set -x; \
-       for arch in $(ALL_ARCH.windows);  do \
-               for osversion in ${ALL_OSVERSIONS.windows}; do \
-                       full_version=`docker manifest inspect ${BASE.windows}:$${osversion} | grep "os.version" | head -n 1 | awk -F\" '{print $$4}'` || true; \
-                       docker manifest annotate --os windows --arch $${arch} --os-version $${full_version} ${MANIFEST_IMAGE}:${IMAGE_TAG} ${MANIFEST_IMAGE}:${IMAGE_TAG}-windows-$${arch}-$${osversion}; \
-               done; \
-       done
-       docker manifest push --purge ${MANIFEST_IMAGE}:${IMAGE_TAG}
-
-unit-test:
-       docker run --rm --interactive -v $(shell pwd)/../../../:/go/src/k8s.io/kubernetes$(DOCKER_VOL_OPTS) -e GOARCH=$(ARCH) golang:$(GOLANG_VERSION) \
-               /bin/bash -c "CGO_ENABLED=0 go test -v k8s.io/kubernetes/cluster/images/etcd/migrate"
-
-# Integration tests require both a golang build environment and all the etcd binaries from a `registry.k8s.io/etcd` image (`/usr/local/bin/etcd-<version>`, ...).
-# Since the `registry.k8s.io/etcd` image is for runtime only and does not have a build golang environment, we create a new docker image to run integration tests
-# with.
-build-integration-test-image: build
-       cp -r $(TEMP_DIR) $(TEMP_DIR)_integration_test
-       cp Dockerfile $(TEMP_DIR)_integration_test/Dockerfile
-       docker build \
-               --pull \
-               -t etcd-integration-test \
-               --build-arg BASEIMAGE=golang:$(GOLANG_VERSION) \
-               --build-arg RUNNERIMAGE=$(RUNNERIMAGE) \
-               $(TEMP_DIR)_integration_test
-
-integration-test:
-       docker run --rm --interactive -v $(shell pwd)/../../../:/go/src/k8s.io/kubernetes$(DOCKER_VOL_OPTS) -e GOARCH=$(ARCH) etcd-integration-test \
-               /bin/bash -c "CGO_ENABLED=0 go test -tags=integration k8s.io/kubernetes/cluster/images/etcd/migrate -args -v 10 -logtostderr true"
-
-integration-build-test: build-integration-test-image integration-test
-test: unit-test integration-build-test
-all: all-build test
-.PHONY:        build push push-manifest all-push all-push-images all-build unit-test build-integration-test-image integration-test integration-build-test test
diff --git a/cluster/images/etcd/OWNERS b/cluster/images/etcd/OWNERS
deleted file mode 100644 (file)
index 30affa9..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-# See the OWNERS docs at https://go.k8s.io/owners
-
-reviewers:
-  - jpbetz
-  - serathius
-approvers:
-  - jpbetz
-  - serathius
-labels:
-  - sig/etcd
diff --git a/cluster/images/etcd/README.md b/cluster/images/etcd/README.md
deleted file mode 100644 (file)
index 4e26caa..0000000
+++ /dev/null
@@ -1,79 +0,0 @@
-### registry.k8s.io/etcd docker image
-
-Provides docker images containing etcd and etcdctl binaries for multiple etcd
-version as well as a migration operator utility for upgrading and downgrading
-etcd--it's data directory in particular--to a target version.
-
-#### Versioning
-
-Each `registry.k8s.io/etcd` docker image is tagged with an version string of the form
-`<etcd-version>-<image-revision>`, e.g. `3.0.17-0`.  The etcd version is the
-SemVer of latest etcd version available in the image. The image revision
-distinguishes between docker images with the same lastest etcd version but
-changes (bug fixes and backward compatible improvements) to the migration
-utility bundled with the image.
-
-In addition to the latest etcd version, each `registry.k8s.io/etcd` image contains
-etcd and etcdctl binaries for older versions of etcd. These are used by the
-migration operator utility when performing downgrades and multi-step upgrades,
-but can also be used as the etcd target version.
-
-#### Usage
-
-Always run `/usr/local/bin/migrate` (or the
-`/usr/local/bin/migrate-if-needed.sh` wrapper script) before starting the etcd
-server. On Windows, run `C:\bin\migrate.exe` (or the `C:\bin\migrate-if-needed.bat
-wrapper script`).
-
-`migrate` writes a `version.txt` file to track the "current" version
-of etcd that was used to persist data to disk. A "target" version may also be provided
-by the `TARGET_STORAGE` (e.g. "etcd3") and `TARGET_VERSION` (e.g. "3.4.13" )
-environment variables. If the persisted version differs from the target version,
-`migrate-if-needed.sh` will migrate the data from the current to the target
-version.
-
-Upgrades to any target version are supported. The data will be automatically upgraded
-in steps to each minor version until the target version is reached.
-
-Downgrades to the previous minor version of the 3.x series is supported.
-
-#### Permissions
-
-By default, `migrate` will write data directory files with default permissions
-according to the umask it is run with. When run in the published
-`registry.k8s.io/etcd` images the default umask is 0022 which will result in 0755
-directory permissions and 0644 file permissions.
-
-#### Cross building
-
-For `amd64`, official `etcd` and `etcdctl` binaries are downloaded from Github
-to maintain official support.  For other architectures, `etcd` is cross-compiled
-from source. Arch-specific `debian` images serve as base images.
-
-Windows images can be built on Linux nodes due to `docker buildx`, but they will
-only be created and pushed when using the `all-push` make target.
-
-#### How to release
-
-First, update `ETCD_VERSION` and `REVSION` in the `Makefile`.
-
-Next, build and test the image:
-
-```console
-$ make build test
-```
-
-Last, build and push the docker images for all supported architectures.
-
-```console
-# Build images for all the architecture and push the manifest image as well
-$ make all-push
-
-# Build images for all the architecture
-$ make all-build
-
-# Build image for target architecture(default=amd64)
-$ make build ARCH=ppc64le
-```
-
-If you don't want to push the images, run `make` or `make build` instead
diff --git a/cluster/images/etcd/cloudbuild.yaml b/cluster/images/etcd/cloudbuild.yaml
deleted file mode 100644 (file)
index 520fb8e..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-# See https://cloud.google.com/cloud-build/docs/build-config
-timeout: 1200s
-options:
-  substitution_option: ALLOW_LOOSE
-  machineType: 'N1_HIGHCPU_8'
-steps:
-  - name: 'gcr.io/k8s-staging-test-infra/gcb-docker-gcloud:v20240523-a15ad90fc9@sha256:bb04162508c2c61637eae700a0d8e8c8be8f2d4c831d2b75e59db2d4dd6cf75d'
-    entrypoint: 'bash'
-    dir: ./cluster/images/etcd
-    env:
-      - DOCKER_CLI_EXPERIMENTAL=enabled
-      - REGISTRY=gcr.io/$PROJECT_ID
-      - PUSH_REGISTRY=gcr.io/$PROJECT_ID
-      - IMAGE=gcr.io/$PROJECT_ID/etcd
-      - BUILD_IMAGE=debian-build
-      - TMPDIR=/workspace
-      - HOME=/root  # for docker buildx
-    args:
-      - '-c'
-      - |
-        gcloud auth configure-docker \
-        && docker buildx create --name img-builder --use \
-        && docker buildx inspect --bootstrap \
-        && docker run --rm --privileged linuxkit/binfmt:4ea3b9b0938cbd19834c096aa31ff475cc75d281 \
-        && make all-push
diff --git a/cluster/images/etcd/migrate-if-needed.bat b/cluster/images/etcd/migrate-if-needed.bat
deleted file mode 100755 (executable)
index a264f82..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-@echo off
-REM Copyright 2021 The Kubernetes Authors.
-REM
-REM Licensed under the Apache License, Version 2.0 (the "License");
-REM you may not use this file except in compliance with the License.
-REM You may obtain a copy of the License at
-REM
-REM     http://www.apache.org/licenses/LICENSE-2.0
-REM
-REM Unless required by applicable law or agreed to in writing, software
-REM distributed under the License is distributed on an "AS IS" BASIS,
-REM WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-REM See the License for the specific language governing permissions and
-REM limitations under the License.
-
-REM DEPRECATED:
-REM The functionality has been moved to migrate binary and this script
-REM if left for backward compatibility with previous manifests. It will be
-REM removed in the future.
-
-C:\bin\migrate.exe
diff --git a/cluster/images/etcd/migrate-if-needed.sh b/cluster/images/etcd/migrate-if-needed.sh
deleted file mode 100755 (executable)
index 7500270..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-#!/bin/sh
-
-# Copyright 2016 The Kubernetes Authors.
-#
-# Licensed under the Apache License, Version 2.0 (the "License");
-# you may not use this file except in compliance with the License.
-# You may obtain a copy of the License at
-#
-#     http://www.apache.org/licenses/LICENSE-2.0
-#
-# Unless required by applicable law or agreed to in writing, software
-# distributed under the License is distributed on an "AS IS" BASIS,
-# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-# See the License for the specific language governing permissions and
-# limitations under the License.
-
-
-# DEPRECATED:
-# The functionality has been moved to migrate binary and this script
-# if left for backward compatibility with previous manifests. It will be
-# removed in the future.
-
-set -o errexit
-set -o nounset
-
-/usr/local/bin/migrate
diff --git a/cluster/images/etcd/migrate/copy_file.go b/cluster/images/etcd/migrate/copy_file.go
deleted file mode 100644 (file)
index 7a84212..0000000
+++ /dev/null
@@ -1,56 +0,0 @@
-/*
-Copyright 2020 The Kubernetes Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package main
-
-import (
-       "fmt"
-       "io"
-       "os"
-       "path/filepath"
-)
-
-func copyFile(source, dest string) error {
-       sf, err := os.Open(source)
-       if err != nil {
-               return fmt.Errorf("unable to open source file [%s]: %q", source, err)
-       }
-       defer sf.Close()
-       fi, err := sf.Stat()
-       if err != nil {
-               return fmt.Errorf("unable to stat source file [%s]: %q", source, err)
-       }
-
-       dir := filepath.Dir(dest)
-       if err := os.MkdirAll(dir, 0755); err != nil {
-               return fmt.Errorf("unable to create directory [%s]: %q", dir, err)
-       }
-       df, err := os.Create(dest)
-       if err != nil {
-               return fmt.Errorf("unable to create destination file [%s]: %q", dest, err)
-       }
-       defer df.Close()
-
-       _, err = io.Copy(df, sf)
-       if err != nil {
-               return fmt.Errorf("unable to copy [%s] to [%s]: %q", source, dest, err)
-       }
-
-       if err := os.Chmod(dest, fi.Mode()); err != nil {
-               return fmt.Errorf("unable to close destination file: %q", err)
-       }
-       return nil
-}
diff --git a/cluster/images/etcd/migrate/data_dir.go b/cluster/images/etcd/migrate/data_dir.go
deleted file mode 100644 (file)
index f13c555..0000000
+++ /dev/null
@@ -1,189 +0,0 @@
-/*
-Copyright 2018 The Kubernetes Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package main
-
-import (
-       "fmt"
-       "io"
-       "os"
-       "path/filepath"
-       "strings"
-
-       "k8s.io/klog/v2"
-)
-
-// DataDirectory provides utilities for initializing and backing up an
-// etcd "data-dir" as well as managing a version.txt file to track the
-// etcd server version and storage version of the etcd data in the
-// directory.
-type DataDirectory struct {
-       path        string
-       versionFile *VersionFile
-}
-
-// OpenOrCreateDataDirectory opens a data directory, creating the directory
-// if it doesn't not already exist.
-func OpenOrCreateDataDirectory(path string) (*DataDirectory, error) {
-       exists, err := exists(path)
-       if err != nil {
-               return nil, err
-       }
-       if !exists {
-               klog.Infof("data directory '%s' does not exist, creating it", path)
-               err := os.MkdirAll(path, 0777)
-               if err != nil {
-                       return nil, fmt.Errorf("failed to create data directory %s: %v", path, err)
-               }
-       }
-       versionFile := &VersionFile{
-               path: filepath.Join(path, versionFilename),
-       }
-       return &DataDirectory{path, versionFile}, nil
-}
-
-// Initialize set the version.txt to the target version if the data
-// directory is empty. If the data directory is non-empty, no
-// version.txt file will be written since the actual version of etcd
-// used to create the data is unknown.
-func (d *DataDirectory) Initialize(target *EtcdVersionPair) error {
-       isEmpty, err := d.IsEmpty()
-       if err != nil {
-               return err
-       }
-       if isEmpty {
-               klog.Infof("data directory '%s' is empty, writing target version '%s' to version.txt", d.path, target)
-               err = d.versionFile.Write(target)
-               if err != nil {
-                       return fmt.Errorf("failed to write version.txt to '%s': %v", d.path, err)
-               }
-               return nil
-       }
-       return nil
-}
-
-// Backup creates a backup copy of data directory.
-func (d *DataDirectory) Backup() error {
-       backupDir := fmt.Sprintf("%s.bak", d.path)
-       err := os.RemoveAll(backupDir)
-       if err != nil {
-               return err
-       }
-       err = os.MkdirAll(backupDir, 0777)
-       if err != nil {
-               return err
-       }
-       err = copyDirectory(d.path, backupDir)
-       if err != nil {
-               return err
-       }
-
-       return nil
-}
-
-// IsEmpty returns true if the data directory is entirely empty.
-func (d *DataDirectory) IsEmpty() (bool, error) {
-       dir, err := os.Open(d.path)
-       if err != nil {
-               return false, fmt.Errorf("failed to open data directory %s: %v", d.path, err)
-       }
-       defer dir.Close()
-       _, err = dir.Readdirnames(1)
-       if err == io.EOF {
-               return true, nil
-       }
-       return false, err
-}
-
-// String returns the data directory path.
-func (d *DataDirectory) String() string {
-       return d.path
-}
-
-// VersionFile provides utilities for reading and writing version.txt files
-// to etcd "data-dir" for tracking the etcd server and storage versions
-// of the data in the directory.
-type VersionFile struct {
-       path string
-}
-
-func (v *VersionFile) nextPath() string {
-       return fmt.Sprintf("%s-next", v.path)
-}
-
-// Exists returns true if a version.txt file exists on the file system.
-func (v *VersionFile) Exists() (bool, error) {
-       return exists(v.path)
-}
-
-// Read parses the version.txt file and returns it's contents.
-func (v *VersionFile) Read() (*EtcdVersionPair, error) {
-       data, err := os.ReadFile(v.path)
-       if err != nil {
-               return nil, fmt.Errorf("failed to read version file %s: %v", v.path, err)
-       }
-       txt := strings.TrimSpace(string(data))
-       vp, err := ParseEtcdVersionPair(txt)
-       if err != nil {
-               return nil, fmt.Errorf("failed to parse etcd '<version>/<storage-version>' string from version.txt file contents '%s': %v", txt, err)
-       }
-       return vp, nil
-}
-
-// equals returns true iff VersionFile exists and contains given EtcdVersionPair.
-func (v *VersionFile) equals(vp *EtcdVersionPair) (bool, error) {
-       exists, err := v.Exists()
-       if err != nil {
-               return false, err
-       }
-       if !exists {
-               return false, nil
-       }
-       cvp, err := v.Read()
-       if err != nil {
-               return false, err
-       }
-       return vp.Equals(cvp), nil
-}
-
-// Write creates or overwrites the contents of the version.txt file with the given EtcdVersionPair.
-func (v *VersionFile) Write(vp *EtcdVersionPair) error {
-       // We do write only if file content differs from given EtcdVersionPair.
-       isUpToDate, err := v.equals(vp)
-       if err != nil {
-               return fmt.Errorf("failed to to check if version file %s should be changed: %v", v.path, err)
-       }
-       if isUpToDate {
-               return nil
-       }
-       // We do write + rename instead of just write to protect from version.txt
-       // corruption under full disk condition.
-       // See https://github.com/kubernetes/kubernetes/issues/98989.
-       err = os.WriteFile(v.nextPath(), []byte(vp.String()), 0666)
-       if err != nil {
-               return fmt.Errorf("failed to write new version file %s: %v", v.nextPath(), err)
-       }
-       return os.Rename(v.nextPath(), v.path)
-}
-
-func exists(path string) (bool, error) {
-       if _, err := os.Stat(path); os.IsNotExist(err) {
-               return false, nil
-       } else if err != nil {
-               return false, err
-       }
-       return true, nil
-}
diff --git a/cluster/images/etcd/migrate/data_dir_test.go b/cluster/images/etcd/migrate/data_dir_test.go
deleted file mode 100644 (file)
index 41b7279..0000000
+++ /dev/null
@@ -1,167 +0,0 @@
-/*
-Copyright 2018 The Kubernetes Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package main
-
-import (
-       "os"
-       "path/filepath"
-       "testing"
-
-       "github.com/blang/semver/v4"
-)
-
-var (
-       latestVersion = semver.MustParse("3.1.12")
-)
-
-func TestExistingDataDirWithVersionFile(t *testing.T) {
-       d, err := OpenOrCreateDataDirectory("testdata/datadir_with_version")
-       if err != nil {
-               t.Fatalf("Failed to open data dir: %v", err)
-       }
-       isEmpty, err := d.IsEmpty()
-       if err != nil {
-               t.Fatalf("Failed to check if data dir is empty: %v", err)
-       }
-       if isEmpty {
-               t.Errorf("Expected non-empty data directory to exist")
-       }
-       exists, err := d.versionFile.Exists()
-       if err != nil {
-               t.Fatal(err)
-       }
-       if !exists {
-               t.Fatalf("Expected version file %s to exist", d.versionFile.path)
-       }
-       vp, err := d.versionFile.Read()
-       if err != nil {
-               t.Fatalf("Failed to read version file %s: %v", d.versionFile.path, err)
-       }
-       expectedVersion := &EtcdVersionPair{&EtcdVersion{latestVersion}, storageEtcd3}
-       if !vp.Equals(expectedVersion) {
-               t.Errorf("Expected version file to contain %s, but got %s", expectedVersion, vp)
-       }
-}
-
-func TestExistingDataDirWithoutVersionFile(t *testing.T) {
-       targetVersion := &EtcdVersionPair{&EtcdVersion{latestVersion}, storageEtcd3}
-
-       d, err := OpenOrCreateDataDirectory("testdata/datadir_without_version")
-       if err != nil {
-               t.Fatalf("Failed to open data dir: %v", err)
-       }
-       exists, err := d.versionFile.Exists()
-       if err != nil {
-               t.Fatal(err)
-       }
-       if exists {
-               t.Errorf("Expected version file %s not to exist", d.versionFile.path)
-       }
-       err = d.Initialize(targetVersion)
-       if err != nil {
-               t.Fatalf("Failed initialize data directory %s: %v", d.path, err)
-       }
-       exists, err = d.versionFile.Exists()
-       if err != nil {
-               t.Fatal(err)
-       }
-       if exists {
-               t.Fatalf("Expected version file %s not to exist after initializing non-empty data-dir", d.versionFile.path)
-       }
-}
-
-func TestNonexistingDataDir(t *testing.T) {
-       targetVersion := &EtcdVersionPair{&EtcdVersion{latestVersion}, storageEtcd3}
-       path := newTestPath(t)
-       defer os.RemoveAll(path)
-       d, err := OpenOrCreateDataDirectory(filepath.Join(path, "data-dir"))
-       if err != nil {
-               t.Fatalf("Failed to open data dir: %v", err)
-       }
-       isEmpty, err := d.IsEmpty()
-       if err != nil {
-               t.Fatalf("Failed to check if data dir is empty: %v", err)
-       }
-       if !isEmpty {
-               t.Errorf("Expected empty data directory to exist")
-       }
-       err = d.Initialize(targetVersion)
-       if err != nil {
-               t.Fatalf("Failed initialize data directory %s: %v", d.path, err)
-       }
-       exists, err := d.versionFile.Exists()
-       if err != nil {
-               t.Fatal(err)
-       }
-       if !exists {
-               t.Fatalf("Expected version file %s to exist", d.versionFile.path)
-       }
-       isEmpty, err = d.IsEmpty()
-       if err != nil {
-               t.Fatalf("Failed to check if data dir is empty: %v", err)
-       }
-       if isEmpty {
-               t.Errorf("Expected non-empty data directory to exist after Initialize()")
-       }
-       vp, err := d.versionFile.Read()
-       if err != nil {
-               t.Fatalf("Failed to read version file %s: %v", d.versionFile.path, err)
-       }
-       if !vp.Equals(targetVersion) {
-               t.Errorf("Expected version file to contain %s, but got %s", targetVersion, vp)
-       }
-}
-
-func TestBackup(t *testing.T) {
-       path := newTestPath(t)
-       defer os.RemoveAll(path)
-       d, err := OpenOrCreateDataDirectory(filepath.Join(path, "data-dir"))
-       if err != nil {
-               t.Fatalf("Failed to open data dir: %v", err)
-       }
-       _, err = os.Create(filepath.Join(path, "data-dir", "empty.txt"))
-       if err != nil {
-               t.Fatal(err)
-       }
-       err = d.Backup()
-       if err != nil {
-               t.Fatalf("Failed to backup data directory %s: %v", d.path, err)
-       }
-       bak, err := OpenOrCreateDataDirectory(filepath.Join(path, "data-dir.bak"))
-       if err != nil {
-               t.Fatalf("Failed to open backup data dir: %v", err)
-       }
-       isEmpty, err := bak.IsEmpty()
-       if err != nil {
-               t.Fatal(err)
-       }
-       if isEmpty {
-               t.Errorf("Expected non-empty backup directory to exist after Backup()")
-       }
-}
-
-func newTestPath(t *testing.T) string {
-       path, err := os.MkdirTemp("", "etcd-migrate-test-")
-       if err != nil {
-               t.Fatalf("Failed to create tmp dir for test: %v", err)
-       }
-       err = os.Chmod(path, 0777)
-       if err != nil {
-               t.Fatalf("Failed to granting permission to tmp dir for test: %v", err)
-       }
-       return path
-}
diff --git a/cluster/images/etcd/migrate/integration_test.go b/cluster/images/etcd/migrate/integration_test.go
deleted file mode 100644 (file)
index 6f7b255..0000000
+++ /dev/null
@@ -1,384 +0,0 @@
-//go:build integration
-
-/*
-Copyright 2018 The Kubernetes Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package main
-
-import (
-       "bytes"
-       cryptorand "crypto/rand"
-       "crypto/rsa"
-       "crypto/x509"
-       "crypto/x509/pkix"
-       "encoding/pem"
-       "flag"
-       "fmt"
-       "math/big"
-       "net"
-       "os"
-       "path/filepath"
-       "strings"
-       "sync"
-       "testing"
-       "time"
-
-       "github.com/blang/semver/v4"
-       "k8s.io/klog/v2"
-       netutils "k8s.io/utils/net"
-)
-
-var (
-       testSupportedVersions = mustParseSupportedVersions([]string{"3.0.17", "3.1.12"})
-       testVersionPrevious   = &EtcdVersion{semver.MustParse("3.0.17")}
-       testVersionLatest     = &EtcdVersion{semver.MustParse("3.1.12")}
-)
-
-func init() {
-       // Enable klog which is used in dependencies
-       klog.InitFlags(nil)
-       flag.Set("logtostderr", "true")
-       flag.Set("v", "9")
-}
-
-func TestMigrate(t *testing.T) {
-       migrations := []struct {
-               title            string
-               memberCount      int
-               startVersion     string
-               endVersion       string
-               protocol         string
-               clientListenUrls string
-       }{
-               // upgrades
-               {"v3-v3-up", 1, "3.0.17/etcd3", "3.1.12/etcd3", "https", ""},
-               {"oldest-newest-up", 1, "3.0.17/etcd3", "3.1.12/etcd3", "https", ""},
-               {"v3-v3-up-with-additional-client-url", 1, "3.0.17/etcd3", "3.1.12/etcd3", "https", "http://127.0.0.1:2379,http://10.128.0.1:2379"},
-
-               // warning: v2->v3 ha upgrades not currently supported.
-               {"ha-v3-v3-up", 3, "3.0.17/etcd3", "3.1.12/etcd3", "https", ""},
-
-               // downgrades
-               {"v3-v3-down", 1, "3.1.12/etcd3", "3.0.17/etcd3", "https", ""},
-
-               // warning: ha downgrades not yet supported.
-       }
-
-       for _, m := range migrations {
-               t.Run(m.title, func(t *testing.T) {
-                       start := mustParseEtcdVersionPair(m.startVersion)
-                       end := mustParseEtcdVersionPair(m.endVersion)
-
-                       testCfgs := clusterConfig(t, m.title, m.memberCount, m.protocol, m.clientListenUrls)
-
-                       servers := []*EtcdMigrateServer{}
-                       for _, cfg := range testCfgs {
-                               client, err := NewEtcdMigrateClient(cfg)
-                               if err != nil {
-                                       t.Fatalf("Failed to create client: %v", err)
-                               }
-                               server := NewEtcdMigrateServer(cfg, client)
-                               servers = append(servers, server)
-                       }
-
-                       // Start the servers.
-                       parallel(servers, func(server *EtcdMigrateServer) {
-                               dataDir, err := OpenOrCreateDataDirectory(server.cfg.dataDirectory)
-                               if err != nil {
-                                       t.Fatalf("Error opening or creating data directory %s: %v", server.cfg.dataDirectory, err)
-                               }
-                               migrator := &Migrator{server.cfg, dataDir, server.client}
-                               err = migrator.MigrateIfNeeded(start)
-                               if err != nil {
-                                       t.Fatalf("Migration failed: %v", err)
-                               }
-                               err = server.Start(start.version)
-                               if err != nil {
-                                       t.Fatalf("Failed to start server: %v", err)
-                               }
-                       })
-
-                       // Write a value to each server, read it back.
-                       parallel(servers, func(server *EtcdMigrateServer) {
-                               key := fmt.Sprintf("/registry/%s", server.cfg.name)
-                               value := fmt.Sprintf("value-%s", server.cfg.name)
-                               err := server.client.Put(start.version, key, value)
-                               if err != nil {
-                                       t.Fatalf("failed to write text value: %v", err)
-                               }
-
-                               checkVal, err := server.client.Get(start.version, key)
-                               if err != nil {
-                                       t.Errorf("Error getting %s for validation: %v", key, err)
-                               }
-                               if checkVal != value {
-                                       t.Errorf("Expected %s from %s but got %s", value, key, checkVal)
-                               }
-                       })
-
-                       // Migrate the servers in series.
-                       serial(servers, func(server *EtcdMigrateServer) {
-                               err := server.Stop()
-                               if err != nil {
-                                       t.Fatalf("Stop server failed: %v", err)
-                               }
-                               dataDir, err := OpenOrCreateDataDirectory(server.cfg.dataDirectory)
-                               if err != nil {
-                                       t.Fatalf("Error opening or creating data directory %s: %v", server.cfg.dataDirectory, err)
-                               }
-                               migrator := &Migrator{server.cfg, dataDir, server.client}
-                               err = migrator.MigrateIfNeeded(end)
-                               if err != nil {
-                                       t.Fatalf("Migration failed: %v", err)
-                               }
-                               err = server.Start(end.version)
-                               if err != nil {
-                                       t.Fatalf("Start server failed: %v", err)
-                               }
-                       })
-
-                       // Check that all test values can be read back from all the servers.
-                       parallel(servers, func(server *EtcdMigrateServer) {
-                               for _, s := range servers {
-                                       key := fmt.Sprintf("/registry/%s", s.cfg.name)
-                                       value := fmt.Sprintf("value-%s", s.cfg.name)
-                                       checkVal, err := server.client.Get(end.version, key)
-                                       if err != nil {
-                                               t.Errorf("Error getting %s from etcd 2.x after rollback from 3.x: %v", key, err)
-                                       }
-                                       if checkVal != value {
-                                               t.Errorf("Expected %s from %s but got %s when reading after rollback from %s to %s", value, key, checkVal, start, end)
-                                       }
-                               }
-                       })
-
-                       // Stop the servers.
-                       parallel(servers, func(server *EtcdMigrateServer) {
-                               err := server.Stop()
-                               if err != nil {
-                                       t.Fatalf("Failed to stop server: %v", err)
-                               }
-                       })
-
-                       // Check that version.txt contains the correct end version.
-                       parallel(servers, func(server *EtcdMigrateServer) {
-                               dataDir, err := OpenOrCreateDataDirectory(server.cfg.dataDirectory)
-                               v, err := dataDir.versionFile.Read()
-                               if err != nil {
-                                       t.Fatalf("Failed to read version.txt file: %v", err)
-                               }
-                               if !v.Equals(end) {
-                                       t.Errorf("Expected version.txt to contain %s but got %s", end, v)
-                               }
-                               // Integration tests are run in a docker container with umask of 0022.
-                               checkPermissions(t, server.cfg.dataDirectory, 0755|os.ModeDir)
-                               checkPermissions(t, dataDir.versionFile.path, 0644)
-                       })
-               })
-       }
-}
-
-func parallel(servers []*EtcdMigrateServer, fn func(server *EtcdMigrateServer)) {
-       var wg sync.WaitGroup
-       wg.Add(len(servers))
-       for _, server := range servers {
-               go func(s *EtcdMigrateServer) {
-                       defer wg.Done()
-                       fn(s)
-               }(server)
-       }
-       wg.Wait()
-}
-
-func serial(servers []*EtcdMigrateServer, fn func(server *EtcdMigrateServer)) {
-       for _, server := range servers {
-               fn(server)
-       }
-}
-
-func checkPermissions(t *testing.T, path string, expected os.FileMode) {
-       info, err := os.Stat(path)
-       if err != nil {
-               t.Fatalf("Failed to stat file %s: %v", path, err)
-       }
-       if info.Mode() != expected {
-               t.Errorf("Expected permissions for file %s of %s, but got %s", path, expected, info.Mode())
-       }
-}
-
-func clusterConfig(t *testing.T, name string, memberCount int, protocol string, clientListenUrls string) []*EtcdMigrateCfg {
-       peers := []string{}
-       for i := 0; i < memberCount; i++ {
-               memberName := fmt.Sprintf("%s-%d", name, i)
-               peerPort := uint64(2380 + i*10000)
-               peer := fmt.Sprintf("%s=%s://127.0.0.1:%d", memberName, protocol, peerPort)
-               peers = append(peers, peer)
-       }
-       initialCluster := strings.Join(peers, ",")
-
-       extraArgs := ""
-       if protocol == "https" {
-               extraArgs = getOrCreateTLSPeerCertArgs(t)
-       }
-
-       cfgs := []*EtcdMigrateCfg{}
-       for i := 0; i < memberCount; i++ {
-               memberName := fmt.Sprintf("%s-%d", name, i)
-               peerURL := fmt.Sprintf("%s://127.0.0.1:%d", protocol, uint64(2380+i*10000))
-               cfg := &EtcdMigrateCfg{
-                       binPath:           "/usr/local/bin",
-                       name:              memberName,
-                       initialCluster:    initialCluster,
-                       port:              uint64(2379 + i*10000),
-                       peerListenUrls:    peerURL,
-                       peerAdvertiseUrls: peerURL,
-                       clientListenUrls:  clientListenUrls,
-                       etcdDataPrefix:    "/registry",
-                       ttlKeysDirectory:  "/registry/events",
-                       supportedVersions: testSupportedVersions,
-                       dataDirectory:     fmt.Sprintf("/tmp/etcd-data-dir-%s", memberName),
-                       etcdServerArgs:    extraArgs,
-               }
-               cfgs = append(cfgs, cfg)
-       }
-       return cfgs
-}
-
-func getOrCreateTLSPeerCertArgs(t *testing.T) string {
-       spec := TestCertSpec{
-               host: "localhost",
-               ips:  []string{"127.0.0.1"},
-       }
-       certDir := "/tmp/certs"
-       certFile := filepath.Join(certDir, "test.crt")
-       keyFile := filepath.Join(certDir, "test.key")
-       err := getOrCreateTestCertFiles(certFile, keyFile, spec)
-       if err != nil {
-               t.Fatalf("failed to create server cert: %v", err)
-       }
-       return fmt.Sprintf("--peer-client-cert-auth --peer-trusted-ca-file=%s --peer-cert-file=%s --peer-key-file=%s", certFile, certFile, keyFile)
-}
-
-type TestCertSpec struct {
-       host       string
-       names, ips []string // in certificate
-}
-
-func getOrCreateTestCertFiles(certFileName, keyFileName string, spec TestCertSpec) (err error) {
-       if _, err := os.Stat(certFileName); err == nil {
-               if _, err := os.Stat(keyFileName); err == nil {
-                       return nil
-               }
-       }
-
-       certPem, keyPem, err := generateSelfSignedCertKey(spec.host, parseIPList(spec.ips), spec.names)
-       if err != nil {
-               return err
-       }
-
-       os.MkdirAll(filepath.Dir(certFileName), os.FileMode(0777))
-       err = os.WriteFile(certFileName, certPem, os.FileMode(0777))
-       if err != nil {
-               return err
-       }
-
-       os.MkdirAll(filepath.Dir(keyFileName), os.FileMode(0777))
-       err = os.WriteFile(keyFileName, keyPem, os.FileMode(0777))
-       if err != nil {
-               return err
-       }
-
-       return nil
-}
-
-func parseIPList(ips []string) []net.IP {
-       var netIPs []net.IP
-       for _, ip := range ips {
-               netIPs = append(netIPs, netutils.ParseIPSloppy(ip))
-       }
-       return netIPs
-}
-
-// generateSelfSignedCertKey creates a self-signed certificate and key for the given host.
-// Host may be an IP or a DNS name
-// You may also specify additional subject alt names (either ip or dns names) for the certificate
-func generateSelfSignedCertKey(host string, alternateIPs []net.IP, alternateDNS []string) ([]byte, []byte, error) {
-       priv, err := rsa.GenerateKey(cryptorand.Reader, 2048)
-       if err != nil {
-               return nil, nil, err
-       }
-
-       template := x509.Certificate{
-               SerialNumber: big.NewInt(1),
-               Subject: pkix.Name{
-                       CommonName: fmt.Sprintf("%s@%d", host, time.Now().Unix()),
-               },
-               NotBefore: time.Unix(0, 0),
-               NotAfter:  time.Now().Add(time.Hour * 24 * 365 * 100),
-
-               KeyUsage:              x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign,
-               ExtKeyUsage:           []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
-               BasicConstraintsValid: true,
-               IsCA:                  true,
-       }
-
-       if ip := netutils.ParseIPSloppy(host); ip != nil {
-               template.IPAddresses = append(template.IPAddresses, ip)
-       } else {
-               template.DNSNames = append(template.DNSNames, host)
-       }
-
-       template.IPAddresses = append(template.IPAddresses, alternateIPs...)
-       template.DNSNames = append(template.DNSNames, alternateDNS...)
-
-       derBytes, err := x509.CreateCertificate(cryptorand.Reader, &template, &template, &priv.PublicKey, priv)
-       if err != nil {
-               return nil, nil, err
-       }
-
-       // Generate cert
-       certBuffer := bytes.Buffer{}
-       if err := pem.Encode(&certBuffer, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}); err != nil {
-               return nil, nil, err
-       }
-
-       // Generate key
-       keyBuffer := bytes.Buffer{}
-       if err := pem.Encode(&keyBuffer, &pem.Block{Type: "RSA PRIVATE KEY", Bytes: x509.MarshalPKCS1PrivateKey(priv)}); err != nil {
-               return nil, nil, err
-       }
-
-       return certBuffer.Bytes(), keyBuffer.Bytes(), nil
-}
-
-// mustParseEtcdVersionPair parses a "<version>/<storage-version>" string to an EtcdVersionPair
-// or panics if the parse fails.
-func mustParseEtcdVersionPair(s string) *EtcdVersionPair {
-       pair, err := ParseEtcdVersionPair(s)
-       if err != nil {
-               panic(err)
-       }
-       return pair
-}
-
-// mustParseSupportedVersions parses a comma separated list of etcd versions or panics if the parse fails.
-func mustParseSupportedVersions(list []string) SupportedVersions {
-       versions, err := ParseSupportedVersions(list)
-       if err != nil {
-               panic(err)
-       }
-       return versions
-}
diff --git a/cluster/images/etcd/migrate/migrate.go b/cluster/images/etcd/migrate/migrate.go
deleted file mode 100644 (file)
index e089786..0000000
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
-Copyright 2018 The Kubernetes Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package main
-
-import (
-       "fmt"
-       "path/filepath"
-
-       "github.com/spf13/cobra"
-       "k8s.io/klog/v2"
-)
-
-const (
-       versionFilename = "version.txt"
-)
-
-var (
-       migrateCmd = &cobra.Command{
-               Short: "Upgrade/downgrade etcd data across multiple versions",
-               Long: `Upgrade or downgrade etcd data across multiple versions to the target version
-
-Given a 'bin-dir' directory of etcd and etcdctl binaries, an etcd 'data-dir' with a 'version.txt' file and
-a target etcd version, this tool will upgrade or downgrade the etcd data from the version specified in
-'version.txt' to the target version.
-`,
-               Run: func(cmd *cobra.Command, args []string) {
-                       runMigrate()
-               },
-       }
-       opts = migrateOpts{}
-)
-
-func main() {
-       registerFlags(migrateCmd.Flags(), &opts)
-       err := migrateCmd.Execute()
-       if err != nil {
-               klog.Errorf("Failed to execute migratecmd: %s", err)
-       }
-}
-
-// runMigrate starts the migration.
-func runMigrate() {
-       if err := opts.validateAndDefault(); err != nil {
-               klog.Fatalf("%v", err)
-       }
-       copyBinaries()
-
-       target := &EtcdVersionPair{
-               version:        MustParseEtcdVersion(opts.targetVersion),
-               storageVersion: MustParseEtcdStorageVersion(opts.targetStorage),
-       }
-
-       migrate(
-               opts.name, opts.port, opts.peerListenUrls, opts.peerAdvertiseUrls, opts.clientListenUrls,
-               opts.binDir, opts.dataDir, opts.etcdDataPrefix, opts.ttlKeysDirectory, opts.initialCluster,
-               target, opts.supportedVersions, opts.etcdServerArgs)
-}
-
-func copyBinaries() {
-       if val, err := lookupEnv("DO_NOT_MOVE_BINARIES"); err != nil || val != "true" {
-               etcdVersioned := fmt.Sprintf("etcd-%s", opts.targetVersion)
-               etcdctlVersioned := fmt.Sprintf("etcdctl-%s", opts.targetVersion)
-               if err := copyFile(filepath.Join(opts.binDir, etcdVersioned), filepath.Join(opts.binDir, "etcd")); err != nil {
-                       klog.Fatalf("Failed to copy %s: %v", etcdVersioned, err)
-               }
-               if err := copyFile(filepath.Join(opts.binDir, etcdctlVersioned), filepath.Join(opts.binDir, "etcdctl")); err != nil {
-                       klog.Fatalf("Failed to copy %s: %v", etcdctlVersioned, err)
-               }
-       }
-}
-
-// migrate opens or initializes the etcd data directory, configures the migrator, and starts the migration.
-func migrate(name string, port uint64, peerListenUrls string, peerAdvertiseUrls string, clientListenUrls string,
-       binPath string, dataDirPath string, etcdDataPrefix string, ttlKeysDirectory string,
-       initialCluster string, target *EtcdVersionPair, bundledVersions SupportedVersions, etcdServerArgs string) {
-
-       dataDir, err := OpenOrCreateDataDirectory(dataDirPath)
-       if err != nil {
-               klog.Fatalf("Error opening or creating data directory %s: %v", dataDirPath, err)
-       }
-
-       cfg := &EtcdMigrateCfg{
-               binPath:           binPath,
-               name:              name,
-               port:              port,
-               peerListenUrls:    peerListenUrls,
-               peerAdvertiseUrls: peerAdvertiseUrls,
-               clientListenUrls:  clientListenUrls,
-               etcdDataPrefix:    etcdDataPrefix,
-               ttlKeysDirectory:  ttlKeysDirectory,
-               initialCluster:    initialCluster,
-               supportedVersions: bundledVersions,
-               dataDirectory:     dataDirPath,
-               etcdServerArgs:    etcdServerArgs,
-       }
-       client, err := NewEtcdMigrateClient(cfg)
-       if err != nil {
-               klog.Fatalf("Migration failed: %v", err)
-       }
-       defer client.Close()
-
-       migrator := &Migrator{cfg, dataDir, client}
-
-       err = migrator.MigrateIfNeeded(target)
-       if err != nil {
-               klog.Fatalf("Migration failed: %v", err)
-       }
-}
diff --git a/cluster/images/etcd/migrate/migrate_client.go b/cluster/images/etcd/migrate/migrate_client.go
deleted file mode 100644 (file)
index 229356b..0000000
+++ /dev/null
@@ -1,201 +0,0 @@
-/*
-Copyright 2018 The Kubernetes Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package main
-
-import (
-       "bytes"
-       "context"
-       "fmt"
-       "os"
-       "os/exec"
-       "path/filepath"
-       "strings"
-       "time"
-
-       clientv3 "go.etcd.io/etcd/client/v3"
-       "google.golang.org/grpc"
-       "k8s.io/klog/v2"
-)
-
-// CombinedEtcdClient provides an implementation of EtcdMigrateClient using a combination of the etcd v2 client, v3 client
-// and etcdctl commands called via the shell.
-type CombinedEtcdClient struct {
-       cfg *EtcdMigrateCfg
-}
-
-// NewEtcdMigrateClient creates a new EtcdMigrateClient from the given EtcdMigrateCfg.
-func NewEtcdMigrateClient(cfg *EtcdMigrateCfg) (EtcdMigrateClient, error) {
-       return &CombinedEtcdClient{cfg}, nil
-}
-
-// Close closes the client and releases any resources it holds.
-func (e *CombinedEtcdClient) Close() error {
-       return nil
-}
-
-// SetEtcdVersionKeyValue writes the given version to the etcd 'etcd_version' key.
-// If no error is returned, the write was successful, indicating the etcd server is available
-// and able to perform consensus writes.
-func (e *CombinedEtcdClient) SetEtcdVersionKeyValue(version *EtcdVersion) error {
-       return e.Put(version, "etcd_version", version.String())
-}
-
-// Put write a single key value pair to etcd.
-func (e *CombinedEtcdClient) Put(version *EtcdVersion, key, value string) error {
-       v3client, err := e.clientV3()
-       if err != nil {
-               return err
-       }
-       defer v3client.Close()
-       _, err = v3client.KV.Put(context.Background(), key, value)
-       return err
-}
-
-// Get reads a single value for a given key.
-func (e *CombinedEtcdClient) Get(version *EtcdVersion, key string) (string, error) {
-       v3client, err := e.clientV3()
-       if err != nil {
-               return "", err
-       }
-       defer v3client.Close()
-       resp, err := v3client.KV.Get(context.Background(), key)
-       if err != nil {
-               return "", err
-       }
-       kvs := resp.Kvs
-       if len(kvs) != 1 {
-               return "", fmt.Errorf("expected exactly one value for key %s but got %d", key, len(kvs))
-       }
-
-       return string(kvs[0].Value), nil
-}
-
-func (e *CombinedEtcdClient) clientV3() (*clientv3.Client, error) {
-       return clientv3.New(clientv3.Config{
-               Endpoints:   []string{e.endpoint()},
-               DialTimeout: 20 * time.Second,
-               DialOptions: []grpc.DialOption{
-                       grpc.WithBlock(), // block until the underlying connection is up
-               },
-       })
-}
-
-// Backup creates a backup of an etcd2 data directory at the given backupDir.
-func (e *CombinedEtcdClient) Backup(version *EtcdVersion, backupDir string) error {
-       // We cannot use etcd/client (v2) to make this call. It is implemented in the etcdctl client code.
-       if version.Major != 2 {
-               return fmt.Errorf("etcd 2.x required but got version '%s'", version)
-       }
-       return e.runEtcdctlCommand(version,
-               "--debug",
-               "backup",
-               "--data-dir", e.cfg.dataDirectory,
-               "--backup-dir", backupDir,
-       )
-}
-
-// Snapshot captures a snapshot from a running etcd3 server and saves it to the given snapshotFile.
-// We cannot use etcd/clientv3 to make this call. It is implemented in the etcdctl client code.
-func (e *CombinedEtcdClient) Snapshot(version *EtcdVersion, snapshotFile string) error {
-       if version.Major != 3 {
-               return fmt.Errorf("etcd 3.x required but got version '%s'", version)
-       }
-       return e.runEtcdctlCommand(version,
-               "--endpoints", e.endpoint(),
-               "snapshot", "save", snapshotFile,
-       )
-}
-
-// Restore restores a given snapshotFile into the data directory specified this clients config.
-func (e *CombinedEtcdClient) Restore(version *EtcdVersion, snapshotFile string) error {
-       // We cannot use etcd/clientv3 to make this call. It is implemented in the etcdctl client code.
-       if version.Major != 3 {
-               return fmt.Errorf("etcd 3.x required but got version '%s'", version)
-       }
-       return e.runEtcdctlCommand(version,
-               "snapshot", "restore", snapshotFile,
-               "--data-dir", e.cfg.dataDirectory,
-               "--name", e.cfg.name,
-               "--initial-advertise-peer-urls", e.cfg.peerAdvertiseUrls,
-               "--initial-cluster", e.cfg.initialCluster,
-       )
-}
-
-// Migrate upgrades a 'etcd2' storage version data directory to a 'etcd3' storage version
-// data directory.
-func (e *CombinedEtcdClient) Migrate(version *EtcdVersion) error {
-       // We cannot use etcd/clientv3 to make this call as it is implemented in etcd/etcdctl.
-       if version.Major != 3 {
-               return fmt.Errorf("etcd 3.x required but got version '%s'", version)
-       }
-       return e.runEtcdctlCommand(version,
-               "migrate",
-               "--data-dir", e.cfg.dataDirectory,
-       )
-}
-
-func (e *CombinedEtcdClient) runEtcdctlCommand(version *EtcdVersion, args ...string) error {
-       etcdctlCmd := exec.Command(filepath.Join(e.cfg.binPath, fmt.Sprintf("etcdctl-%s", version)), args...)
-       etcdctlCmd.Env = []string{fmt.Sprintf("ETCDCTL_API=%d", version.Major)}
-       etcdctlCmd.Stdout = os.Stdout
-       etcdctlCmd.Stderr = os.Stderr
-       return etcdctlCmd.Run()
-}
-
-// AttachLease attaches leases of the given leaseDuration to all the  etcd objects under
-// ttlKeysDirectory specified in this client's config.
-func (e *CombinedEtcdClient) AttachLease(leaseDuration time.Duration) error {
-       ttlKeysPrefix := e.cfg.ttlKeysDirectory
-       // Make sure that ttlKeysPrefix is ended with "/" so that we only get children "directories".
-       if !strings.HasSuffix(ttlKeysPrefix, "/") {
-               ttlKeysPrefix += "/"
-       }
-       ctx := context.Background()
-
-       v3client, err := e.clientV3()
-       if err != nil {
-               return err
-       }
-       defer v3client.Close()
-       objectsResp, err := v3client.KV.Get(ctx, ttlKeysPrefix, clientv3.WithPrefix())
-       if err != nil {
-               return fmt.Errorf("error while getting objects to attach to the lease")
-       }
-
-       lease, err := v3client.Lease.Grant(ctx, int64(leaseDuration/time.Second))
-       if err != nil {
-               return fmt.Errorf("error while creating lease: %v", err)
-       }
-       klog.Infof("Lease with TTL: %v created", lease.TTL)
-
-       klog.Infof("Attaching lease to %d entries", len(objectsResp.Kvs))
-       for _, kv := range objectsResp.Kvs {
-               putResp, err := v3client.KV.Put(ctx, string(kv.Key), string(kv.Value), clientv3.WithLease(lease.ID), clientv3.WithPrevKV())
-               if err != nil {
-                       klog.Errorf("Error while attaching lease to: %s", string(kv.Key))
-               }
-               if !bytes.Equal(putResp.PrevKv.Value, kv.Value) {
-                       return fmt.Errorf("concurrent access to key detected when setting lease on %s, expected previous value of %s but got %s",
-                               kv.Key, kv.Value, putResp.PrevKv.Value)
-               }
-       }
-       return nil
-}
-
-func (e *CombinedEtcdClient) endpoint() string {
-       return fmt.Sprintf("http://127.0.0.1:%d", e.cfg.port)
-}
diff --git a/cluster/images/etcd/migrate/migrate_server.go b/cluster/images/etcd/migrate/migrate_server.go
deleted file mode 100644 (file)
index da9c659..0000000
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
-Copyright 2018 The Kubernetes Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package main
-
-import (
-       "fmt"
-       "os"
-       "os/exec"
-       "strings"
-       "time"
-
-       "k8s.io/klog/v2"
-)
-
-// EtcdMigrateServer manages starting and stopping a versioned etcd server binary.
-type EtcdMigrateServer struct {
-       cfg    *EtcdMigrateCfg
-       client EtcdMigrateClient
-       cmd    *exec.Cmd
-}
-
-// NewEtcdMigrateServer creates a EtcdMigrateServer for starting and stopping a etcd server at the given version.
-func NewEtcdMigrateServer(cfg *EtcdMigrateCfg, client EtcdMigrateClient) *EtcdMigrateServer {
-       return &EtcdMigrateServer{cfg: cfg, client: client}
-}
-
-// Start starts an etcd server as a separate process, waits until it has started, and returns a exec.Cmd.
-// TODO: Add support for listening to client via TLS.
-func (r *EtcdMigrateServer) Start(version *EtcdVersion) error {
-       etcdCmd := exec.Command(
-               fmt.Sprintf("%s/etcd-%s", r.cfg.binPath, version),
-               "--name", r.cfg.name,
-               "--initial-cluster", r.cfg.initialCluster,
-               "--debug",
-               "--data-dir", r.cfg.dataDirectory,
-               "--listen-client-urls", r.cfg.clientListenUrls,
-               "--advertise-client-urls", fmt.Sprintf("http://127.0.0.1:%d", r.cfg.port),
-               "--listen-peer-urls", r.cfg.peerListenUrls,
-               "--initial-advertise-peer-urls", r.cfg.peerAdvertiseUrls,
-       )
-       if r.cfg.etcdServerArgs != "" {
-               extraArgs := strings.Fields(r.cfg.etcdServerArgs)
-               etcdCmd.Args = append(etcdCmd.Args, extraArgs...)
-       }
-       fmt.Printf("Starting server %s: %+v\n", r.cfg.name, etcdCmd.Args)
-
-       etcdCmd.Stdout = os.Stdout
-       etcdCmd.Stderr = os.Stderr
-       err := etcdCmd.Start()
-       if err != nil {
-               return err
-       }
-       interval := time.NewTicker(time.Millisecond * 500)
-       defer interval.Stop()
-       done := make(chan bool)
-       go func() {
-               time.Sleep(time.Minute * 2)
-               close(done)
-       }()
-       for {
-               select {
-               case <-interval.C:
-                       err := r.client.SetEtcdVersionKeyValue(version)
-                       if err != nil {
-                               klog.Infof("Still waiting for etcd to start, current error: %v", err)
-                               // keep waiting
-                       } else {
-                               klog.Infof("Etcd on port %d is up.", r.cfg.port)
-                               r.cmd = etcdCmd
-                               return nil
-                       }
-               case <-done:
-                       err = etcdCmd.Process.Kill()
-                       if err != nil {
-                               return fmt.Errorf("error killing etcd: %v", err)
-                       }
-                       return fmt.Errorf("timed out waiting for etcd on port %d", r.cfg.port)
-               }
-       }
-}
-
-// Stop terminates the etcd server process. If the etcd server process has not been started
-// or is not still running, this returns an error.
-func (r *EtcdMigrateServer) Stop() error {
-       if r.cmd == nil {
-               return fmt.Errorf("cannot stop EtcdMigrateServer that has not been started")
-       }
-       err := r.cmd.Process.Signal(os.Interrupt)
-       if err != nil {
-               return fmt.Errorf("error sending SIGINT to etcd for graceful shutdown: %v", err)
-       }
-       gracefulWait := time.Minute * 2
-       stopped := make(chan bool)
-       timedout := make(chan bool)
-       go func() {
-               time.Sleep(gracefulWait)
-               close(timedout)
-       }()
-       go func() {
-               select {
-               case <-stopped:
-                       return
-               case <-timedout:
-                       klog.Infof("etcd server has not terminated gracefully after %s, killing it.", gracefulWait)
-                       r.cmd.Process.Kill()
-                       return
-               }
-       }()
-       err = r.cmd.Wait()
-       close(stopped)
-       if exiterr, ok := err.(*exec.ExitError); ok {
-               klog.Infof("etcd server stopped (signal: %s)", exiterr.Error())
-               // stopped
-       } else if err != nil {
-               return fmt.Errorf("error waiting for etcd to stop: %v", err)
-       }
-       klog.Infof("Stopped etcd server %s", r.cfg.name)
-       return nil
-}
diff --git a/cluster/images/etcd/migrate/migrator.go b/cluster/images/etcd/migrate/migrator.go
deleted file mode 100644 (file)
index 2ecc87c..0000000
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
-Copyright 2018 The Kubernetes Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package main
-
-import (
-       "fmt"
-       "os"
-       "time"
-
-       "github.com/blang/semver/v4"
-       "k8s.io/klog/v2"
-)
-
-// EtcdMigrateCfg provides all configuration required to perform etcd data upgrade/downgrade migrations.
-type EtcdMigrateCfg struct {
-       binPath           string
-       name              string
-       initialCluster    string
-       port              uint64
-       peerListenUrls    string
-       peerAdvertiseUrls string
-       clientListenUrls  string
-       etcdDataPrefix    string
-       ttlKeysDirectory  string
-       supportedVersions SupportedVersions
-       dataDirectory     string
-       etcdServerArgs    string
-}
-
-// EtcdMigrateClient defines the etcd client operations required to perform migrations.
-type EtcdMigrateClient interface {
-       SetEtcdVersionKeyValue(version *EtcdVersion) error
-       Get(version *EtcdVersion, key string) (string, error)
-       Put(version *EtcdVersion, key, value string) error
-       Backup(version *EtcdVersion, backupDir string) error
-       Snapshot(version *EtcdVersion, snapshotFile string) error
-       Restore(version *EtcdVersion, snapshotFile string) error
-       Migrate(version *EtcdVersion) error
-       AttachLease(leaseDuration time.Duration) error
-       Close() error
-}
-
-// Migrator manages etcd data migrations.
-type Migrator struct {
-       cfg           *EtcdMigrateCfg // TODO: don't wire this directly in
-       dataDirectory *DataDirectory
-       client        EtcdMigrateClient
-}
-
-// MigrateIfNeeded upgrades or downgrades the etcd data directory to the given target version.
-func (m *Migrator) MigrateIfNeeded(target *EtcdVersionPair) error {
-       klog.Infof("Starting migration to %s", target)
-       err := m.dataDirectory.Initialize(target)
-       if err != nil {
-               return fmt.Errorf("failed to initialize data directory %s: %v", m.dataDirectory.path, err)
-       }
-
-       var current *EtcdVersionPair
-       vfExists, err := m.dataDirectory.versionFile.Exists()
-       if err != nil {
-               return err
-       }
-       if vfExists {
-               current, err = m.dataDirectory.versionFile.Read()
-               if err != nil {
-                       return err
-               }
-       } else {
-               return fmt.Errorf("existing data directory '%s' is missing version.txt file, unable to migrate", m.dataDirectory.path)
-       }
-
-       for {
-               klog.Infof("Converging current version '%s' to target version '%s'", current, target)
-               currentNextMinorVersion := &EtcdVersion{Version: semver.Version{Major: current.version.Major, Minor: current.version.Minor + 1}}
-               switch {
-               case current.version.MajorMinorEquals(target.version) || currentNextMinorVersion.MajorMinorEquals(target.version):
-                       klog.Infof("current version '%s' equals or is one minor version previous of target version '%s' - migration complete", current, target)
-                       err = m.dataDirectory.versionFile.Write(target)
-                       if err != nil {
-                               return fmt.Errorf("failed to write version.txt to '%s': %v", m.dataDirectory.path, err)
-                       }
-                       return nil
-               case current.storageVersion == storageEtcd2 && target.storageVersion == storageEtcd3:
-                       return fmt.Errorf("upgrading from etcd2 storage to etcd3 storage is not supported")
-               case current.version.Major == 3 && target.version.Major == 2:
-                       return fmt.Errorf("downgrading from etcd 3.x to 2.x is not supported")
-               case current.version.Major == target.version.Major && current.version.Minor < target.version.Minor:
-                       stepVersion := m.cfg.supportedVersions.NextVersionPair(current)
-                       klog.Infof("upgrading etcd from %s to %s", current, stepVersion)
-                       current, err = m.minorVersionUpgrade(current, stepVersion)
-               case current.version.Major == 3 && target.version.Major == 3 && current.version.Minor > target.version.Minor:
-                       klog.Infof("rolling etcd back from %s to %s", current, target)
-                       current, err = m.rollbackEtcd3MinorVersion(current, target)
-               }
-               if err != nil {
-                       return err
-               }
-       }
-}
-
-func (m *Migrator) rollbackEtcd3MinorVersion(current *EtcdVersionPair, target *EtcdVersionPair) (*EtcdVersionPair, error) {
-       if target.version.Minor != current.version.Minor-1 {
-               return nil, fmt.Errorf("rollback from %s to %s not supported, only rollbacks to the previous minor version are supported", current.version, target.version)
-       }
-
-       klog.Infof("Performing etcd %s -> %s rollback", current.version, target.version)
-       err := m.dataDirectory.Backup()
-       if err != nil {
-               return nil, err
-       }
-
-       snapshotFilename := fmt.Sprintf("%s.snapshot.db", m.dataDirectory.path)
-       err = os.Remove(snapshotFilename)
-       if err != nil && !os.IsNotExist(err) {
-               return nil, fmt.Errorf("failed to clean snapshot file before rollback: %v", err)
-       }
-
-       // Start current version of etcd.
-       runner := m.newServer()
-       klog.Infof("Starting etcd version %s to capture rollback snapshot.", current.version)
-       err = runner.Start(current.version)
-       if err != nil {
-               klog.Fatalf("Unable to automatically downgrade etcd: starting etcd version %s to capture rollback snapshot failed: %v", current.version, err)
-               return nil, err
-       }
-
-       klog.Infof("Snapshotting etcd %s to %s", current.version, snapshotFilename)
-       err = m.client.Snapshot(current.version, snapshotFilename)
-       if err != nil {
-               return nil, err
-       }
-
-       err = runner.Stop()
-       if err != nil {
-               return nil, err
-       }
-
-       klog.Info("Backing up data before rolling back")
-       backupDir := fmt.Sprintf("%s.bak", m.dataDirectory)
-       err = os.RemoveAll(backupDir)
-       if err != nil {
-               return nil, err
-       }
-       origInfo, err := os.Stat(m.dataDirectory.path)
-       if err != nil {
-               return nil, err
-       }
-       err = os.Rename(m.dataDirectory.path, backupDir)
-       if err != nil {
-               return nil, err
-       }
-
-       klog.Infof("Restoring etcd %s from %s", target.version, snapshotFilename)
-       err = m.client.Restore(target.version, snapshotFilename)
-       if err != nil {
-               return nil, err
-       }
-       err = os.Chmod(m.dataDirectory.path, origInfo.Mode())
-       if err != nil {
-               return nil, err
-       }
-
-       return target, nil
-}
-
-func (m *Migrator) minorVersionUpgrade(current *EtcdVersionPair, target *EtcdVersionPair) (*EtcdVersionPair, error) {
-       runner := m.newServer()
-
-       // Do the migration step, by just starting etcd in the target version.
-       err := runner.Start(target.version)
-       if err != nil {
-               return nil, err
-       }
-       err = runner.Stop()
-       return target, err
-}
-
-func (m *Migrator) newServer() *EtcdMigrateServer {
-       return NewEtcdMigrateServer(m.cfg, m.client)
-}
diff --git a/cluster/images/etcd/migrate/options.go b/cluster/images/etcd/migrate/options.go
deleted file mode 100644 (file)
index 42fbb37..0000000
+++ /dev/null
@@ -1,249 +0,0 @@
-/*
-Copyright 2018 The Kubernetes Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package main
-
-import (
-       "fmt"
-       "os"
-       "path/filepath"
-       "regexp"
-       "strings"
-
-       flag "github.com/spf13/pflag"
-       "k8s.io/klog/v2"
-)
-
-var (
-       supportedEtcdVersions = []string{"3.4.18", "3.5.21", "3.6.4"}
-)
-
-const (
-       etcdNameEnv           = "ETCD_NAME"
-       etcdHostnameEnv       = "ETCD_HOSTNAME"
-       hostnameEnv           = "HOSTNAME"
-       dataDirEnv            = "DATA_DIRECTORY"
-       initialClusterEnv     = "INITIAL_CLUSTER"
-       initialClusterFmt     = "%s=http://localhost:%d"
-       peerListenUrlsEnv     = "LISTEN_PEER_URLS"
-       peerListenUrlsFmt     = "http://localhost:%d"
-       peerAdvertiseUrlsEnv  = "INITIAL_ADVERTISE_PEER_URLS"
-       peerAdvertiseUrlsFmt  = "http://localhost:%d"
-       clientListenURLsEnv   = "LISTEN_CLIENT_URLS"
-       clientListenURLFmt    = "http://127.0.0.1:%d"
-       targetVersionEnv      = "TARGET_VERSION"
-       targetStorageEnv      = "TARGET_STORAGE"
-       etcdDataPrefixEnv     = "ETCD_DATA_PREFIX"
-       etcdDataPrefixDefault = "/registry"
-       ttlKeysDirectoryFmt   = "%s/events"
-       etcdServerArgsEnv     = "ETCD_CREDS"
-)
-
-type migrateOpts struct {
-       name              string
-       port              uint64
-       peerPort          uint64
-       peerListenUrls    string
-       peerAdvertiseUrls string
-       binDir            string
-       dataDir           string
-       bundledVersions   []string
-       supportedVersions SupportedVersions
-       etcdDataPrefix    string
-       ttlKeysDirectory  string
-       initialCluster    string
-       targetVersion     string
-       targetStorage     string
-       etcdServerArgs    string
-       clientListenUrls  string
-}
-
-func registerFlags(flags *flag.FlagSet, opt *migrateOpts) {
-       flags.StringVar(&opts.name, "name", "",
-               "etcd cluster member name. If unset fallbacks to defaults to ETCD_NAME env, if unset defaults to etcd-<ETCD_HOSTNAME> env, if unset defaults to etcd-<HOSTNAME> env.")
-       flags.Uint64Var(&opts.port, "port", 0,
-               "etcd client port to use during migration operations. "+
-                       "This should be a different port than typically used by etcd to avoid clients accidentally connecting during upgrade/downgrade operations. "+
-                       "If unset default to 18629 or 18631 depending on <data-dir>.")
-       flags.Uint64Var(&opts.peerPort, "peer-port", 0,
-               "etcd peer port to use during migration operations. If unset defaults to 2380 or 2381 depending on <data-dir>.")
-       flags.StringVar(&opts.peerListenUrls, "listen-peer-urls", "",
-               "etcd --listen-peer-urls flag. If unset, fallbacks to LISTEN_PEER_URLS env and if unset defaults to http://localhost:<peer-port>.")
-       flags.StringVar(&opts.peerAdvertiseUrls, "initial-advertise-peer-urls", "",
-               "etcd --initial-advertise-peer-urls flag. If unset fallbacks to INITIAL_ADVERTISE_PEER_URLS env and if unset defaults to http://localhost:<peer-port>.")
-       flags.StringVar(&opts.clientListenUrls, "listen-client-urls", "",
-               "etcd --listen-client-urls flag. If unset, fallbacks to LISTEN_CLIENT_URLS env, and if unset defaults to http://127.0.0.1:<port>.")
-       flags.StringVar(&opts.binDir, "bin-dir", "/usr/local/bin",
-               "directory of etcd and etcdctl binaries, must contain etcd-<version> and etcdctl-<version> for each version listed in <bundled-versions>.")
-       flags.StringVar(&opts.dataDir, "data-dir", "",
-               "etcd data directory of etcd server to migrate. If unset fallbacks to DATA_DIRECTORY env.")
-       flags.StringSliceVar(&opts.bundledVersions, "bundled-versions", supportedEtcdVersions,
-               "comma separated list of etcd binary versions present under the bin-dir.")
-       flags.StringVar(&opts.etcdDataPrefix, "etcd-data-prefix", "",
-               "etcd key prefix under which all objects are kept. If unset fallbacks to ETCD_DATA_PREFIX env and if unset defaults to /registry.")
-       flags.StringVar(&opts.ttlKeysDirectory, "ttl-keys-directory", "",
-               "etcd key prefix under which all keys with TTLs are kept. Defaults to <etcd-data-prefix>/events")
-       flags.StringVar(&opts.initialCluster, "initial-cluster", "",
-               "comma separated list of name=endpoint pairs. If unset fallbacks to INITIAL_CLUSTER and if unset defaults to <etcd-name>=https://localhost:<peer-port>.")
-       flags.StringVar(&opts.targetVersion, "target-version", "",
-               "version of etcd to migrate to. Format must be <major>.<minor>.<patch>. If unset fallbacks to TARGET_VERSION env.")
-       flags.StringVar(&opts.targetStorage, "target-storage", "",
-               "storage version of etcd to migrate to, one of: etcd2, etcd3. If unset fallbacks to TARGET_STORAGE env.")
-       flags.StringVar(&opts.etcdServerArgs, "etcd-server-extra-args", "",
-               "additional etcd server args for starting etcd servers during migration steps, need to set TLS certs flags for multi-member clusters using mTLS for communication. "+
-                       "If unset fallbacks to ETCD_CREDS env.")
-}
-
-func lookupEnv(env string) (string, error) {
-       result, ok := os.LookupEnv(env)
-       if !ok || len(result) == 0 {
-               return result, fmt.Errorf("%s variable unset - expected failure", env)
-       }
-       return result, nil
-}
-
-func fallbackToEnv(flag, env string) (string, error) {
-       klog.Infof("--%s unset - falling back to %s variable", flag, env)
-       return lookupEnv(env)
-}
-
-func fallbackToEnvWithDefault(flag, env, def string) string {
-       if value, err := lookupEnv(env); err == nil {
-               return value
-       }
-       klog.Warningf("%s variable for %s flag unset - defaulting to %s", env, flag, def)
-       return def
-}
-
-func defaultName() (string, error) {
-       if etcdName, err := lookupEnv(etcdNameEnv); err == nil {
-               return etcdName, nil
-       }
-       klog.Warningf("%s variable unset - falling back to etcd-%s variable", etcdNameEnv, etcdHostnameEnv)
-       if etcdHostname, err := lookupEnv(etcdHostnameEnv); err == nil {
-               return fmt.Sprintf("etcd-%s", etcdHostname), nil
-       }
-       klog.Warningf("%s variable unset - falling back to etcd-%s variable", etcdHostnameEnv, hostnameEnv)
-       if hostname, err := lookupEnv(hostnameEnv); err == nil {
-               return fmt.Sprintf("etcd-%s", hostname), nil
-       }
-       return "", fmt.Errorf("defaulting --name failed due to all ETCD_NAME, ETCD_HOSTNAME and HOSTNAME unset")
-}
-
-func (opts *migrateOpts) validateAndDefault() error {
-       var err error
-
-       if opts.name == "" {
-               klog.Infof("--name unset - falling back to %s variable", etcdNameEnv)
-               if opts.name, err = defaultName(); err != nil {
-                       return err
-               }
-       }
-
-       if opts.dataDir == "" {
-               if opts.dataDir, err = fallbackToEnv("data-dir", dataDirEnv); err != nil {
-                       return err
-               }
-       }
-
-       etcdEventsRE := regexp.MustCompile("event")
-       if opts.port == 0 {
-               if etcdEventsRE.MatchString(opts.dataDir) {
-                       opts.port = 18631
-               } else {
-                       opts.port = 18629
-               }
-               klog.Infof("--port unset - defaulting to %d", opts.port)
-       }
-       if opts.peerPort == 0 {
-               if etcdEventsRE.MatchString(opts.dataDir) {
-                       opts.peerPort = 2381
-               } else {
-                       opts.peerPort = 2380
-               }
-               klog.Infof("--peer-port unset - defaulting to %d", opts.peerPort)
-       }
-
-       if opts.initialCluster == "" {
-               def := fmt.Sprintf(initialClusterFmt, opts.name, opts.peerPort)
-               opts.initialCluster = fallbackToEnvWithDefault("initial-cluster", initialClusterEnv, def)
-       }
-
-       if opts.peerListenUrls == "" {
-               def := fmt.Sprintf(peerListenUrlsFmt, opts.peerPort)
-               opts.peerListenUrls = fallbackToEnvWithDefault("listen-peer-urls", peerListenUrlsEnv, def)
-       }
-
-       if opts.peerAdvertiseUrls == "" {
-               def := fmt.Sprintf(peerAdvertiseUrlsFmt, opts.peerPort)
-               opts.peerAdvertiseUrls = fallbackToEnvWithDefault("initial-advertise-peer-urls", peerAdvertiseUrlsEnv, def)
-       }
-
-       if opts.clientListenUrls == "" {
-               def := fmt.Sprintf(clientListenURLFmt, opts.port)
-               opts.clientListenUrls = fallbackToEnvWithDefault("listen-client-urls", clientListenURLsEnv, def)
-       }
-
-       if opts.targetVersion == "" {
-               if opts.targetVersion, err = fallbackToEnv("target-version", targetVersionEnv); err != nil {
-                       return err
-               }
-       }
-
-       if opts.targetStorage == "" {
-               if opts.targetStorage, err = fallbackToEnv("target-storage", targetStorageEnv); err != nil {
-                       return err
-               }
-       }
-
-       if opts.etcdDataPrefix == "" {
-               opts.etcdDataPrefix = fallbackToEnvWithDefault("etcd-data-prefix", etcdDataPrefixEnv, etcdDataPrefixDefault)
-       }
-
-       if opts.ttlKeysDirectory == "" {
-               opts.ttlKeysDirectory = fmt.Sprintf(ttlKeysDirectoryFmt, opts.etcdDataPrefix)
-               klog.Infof("--ttl-keys-directory unset - defaulting to %s", opts.ttlKeysDirectory)
-       }
-
-       if opts.etcdServerArgs == "" {
-               opts.etcdServerArgs = fallbackToEnvWithDefault("etcd-server-extra-args", etcdServerArgsEnv, "")
-       }
-
-       if opts.supportedVersions, err = ParseSupportedVersions(opts.bundledVersions); err != nil {
-               return fmt.Errorf("failed to parse --bundled-versions: %v", err)
-       }
-
-       if err := validateBundledVersions(opts.supportedVersions, opts.binDir); err != nil {
-               return fmt.Errorf("failed to validate that 'etcd-<version>' and 'etcdctl-<version>' binaries exist in --bin-dir '%s' for all --bundled-versions '%s': %v",
-                       opts.binDir, strings.Join(opts.bundledVersions, ","), err)
-       }
-       return nil
-}
-
-// validateBundledVersions checks that 'etcd-<version>' and 'etcdctl-<version>' binaries exist in the binDir
-// for each version in the bundledVersions list.
-func validateBundledVersions(bundledVersions SupportedVersions, binDir string) error {
-       for _, v := range bundledVersions {
-               for _, binaryName := range []string{"etcd", "etcdctl"} {
-                       fn := filepath.Join(binDir, fmt.Sprintf("%s-%s", binaryName, v))
-                       if _, err := os.Stat(fn); err != nil {
-                               return fmt.Errorf("failed to validate '%s' binary exists for bundled-version '%s': %v", fn, v, err)
-                       }
-
-               }
-       }
-       return nil
-}
diff --git a/cluster/images/etcd/migrate/options_test.go b/cluster/images/etcd/migrate/options_test.go
deleted file mode 100644 (file)
index 6b1f3e9..0000000
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
-Copyright 2018 The Kubernetes Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package main
-
-import (
-       "os"
-       "testing"
-)
-
-func setEnvVar(t *testing.T, env, val string, exists bool) {
-       if exists {
-               t.Setenv(env, val)
-       } else if prev, ok := os.LookupEnv(env); ok {
-               t.Cleanup(func() { os.Setenv(env, prev) })
-
-               if err := os.Unsetenv(env); err != nil {
-                       t.Errorf("couldn't unset env %s: %v", env, err)
-               }
-       }
-}
-
-func TestFallbackToEnv(t *testing.T) {
-       testCases := []struct {
-               desc          string
-               env           string
-               value         string
-               valueSet      bool
-               expectedValue string
-               expectedError bool
-       }{
-               {
-                       desc:          "value unset",
-                       env:           "FOO",
-                       valueSet:      false,
-                       expectedValue: "",
-                       expectedError: true,
-               },
-               {
-                       desc:          "value set empty",
-                       env:           "FOO",
-                       value:         "",
-                       valueSet:      true,
-                       expectedValue: "",
-                       expectedError: true,
-               },
-               {
-                       desc:          "value set",
-                       env:           "FOO",
-                       value:         "foo",
-                       valueSet:      true,
-                       expectedValue: "foo",
-                       expectedError: false,
-               },
-       }
-
-       for _, test := range testCases {
-               t.Run(test.desc, func(t *testing.T) {
-                       setEnvVar(t, test.env, test.value, test.valueSet)
-                       value, err := fallbackToEnv("some-flag", test.env)
-                       if test.expectedError {
-                               if err == nil {
-                                       t.Errorf("expected error, got: %v", err)
-                               }
-                       } else {
-                               if err != nil {
-                                       t.Errorf("unexpected error: %v", err)
-                               }
-                               if value != test.expectedValue {
-                                       t.Errorf("unexpected result: %s, expected: %s", value, test.expectedValue)
-                               }
-                       }
-               })
-       }
-}
-
-func TestFallbackToEnvWithDefault(t *testing.T) {
-       testCases := []struct {
-               desc          string
-               env           string
-               value         string
-               valueSet      bool
-               defaultValue  string
-               expectedValue string
-               expectedError bool
-       }{
-               {
-                       desc:          "value unset",
-                       env:           "FOO",
-                       valueSet:      false,
-                       defaultValue:  "default",
-                       expectedValue: "default",
-               },
-               {
-                       desc:          "value set empty",
-                       env:           "FOO",
-                       value:         "",
-                       valueSet:      true,
-                       defaultValue:  "default",
-                       expectedValue: "default",
-               },
-               {
-                       desc:          "value set",
-                       env:           "FOO",
-                       value:         "foo",
-                       valueSet:      true,
-                       defaultValue:  "default",
-                       expectedValue: "foo",
-               },
-       }
-
-       for _, test := range testCases {
-               t.Run(test.desc, func(t *testing.T) {
-                       setEnvVar(t, test.env, test.value, test.valueSet)
-                       value := fallbackToEnvWithDefault("some-flag", test.env, test.defaultValue)
-                       if value != test.expectedValue {
-                               t.Errorf("unexpected result: %s, expected: %s", value, test.expectedValue)
-                       }
-               })
-       }
-}
diff --git a/cluster/images/etcd/migrate/testdata/datadir_with_version/version.txt b/cluster/images/etcd/migrate/testdata/datadir_with_version/version.txt
deleted file mode 100644 (file)
index d557c02..0000000
+++ /dev/null
@@ -1 +0,0 @@
-3.1.12/etcd3
diff --git a/cluster/images/etcd/migrate/testdata/datadir_without_version/.placeholder b/cluster/images/etcd/migrate/testdata/datadir_without_version/.placeholder
deleted file mode 100644 (file)
index e69de29..0000000
diff --git a/cluster/images/etcd/migrate/util_others.go b/cluster/images/etcd/migrate/util_others.go
deleted file mode 100644 (file)
index 7640bb7..0000000
+++ /dev/null
@@ -1,27 +0,0 @@
-//go:build !windows
-
-/*
-Copyright 2020 The Kubernetes Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package main
-
-import (
-       "github.com/mrunalp/fileutils"
-)
-
-func copyDirectory(source string, dest string) error {
-       return fileutils.CopyDirectory(source, dest)
-}
diff --git a/cluster/images/etcd/migrate/utils_windows.go b/cluster/images/etcd/migrate/utils_windows.go
deleted file mode 100644 (file)
index 47a9663..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-//go:build windows
-
-/*
-Copyright 2020 The Kubernetes Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package main
-
-import "fmt"
-
-func copyDirectory(source string, dest string) error {
-       return fmt.Errorf("no support for windows")
-}
diff --git a/cluster/images/etcd/migrate/versions.go b/cluster/images/etcd/migrate/versions.go
deleted file mode 100644 (file)
index 4982ea8..0000000
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
-Copyright 2018 The Kubernetes Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package main
-
-import (
-       "fmt"
-       "strings"
-
-       "github.com/blang/semver/v4"
-)
-
-// EtcdVersion specifies an etcd server binaries SemVer.
-type EtcdVersion struct {
-       semver.Version
-}
-
-// ParseEtcdVersion parses a SemVer string to an EtcdVersion.
-func ParseEtcdVersion(s string) (*EtcdVersion, error) {
-       v, err := semver.Make(s)
-       if err != nil {
-               return nil, err
-       }
-       return &EtcdVersion{v}, nil
-}
-
-// MustParseEtcdVersion parses a SemVer string to an EtcdVersion and panics if the parse fails.
-func MustParseEtcdVersion(s string) *EtcdVersion {
-       return &EtcdVersion{semver.MustParse(s)}
-}
-
-// String returns the version in SemVer string format.
-func (v *EtcdVersion) String() string {
-       return v.Version.String()
-}
-
-// Equals returns true if the versions are exactly equal.
-func (v *EtcdVersion) Equals(o *EtcdVersion) bool {
-       return v.Version.Equals(o.Version)
-}
-
-// MajorMinorEquals returns true if the major and minor parts of the versions are equal;
-// if only patch versions differ, this returns true.
-func (v *EtcdVersion) MajorMinorEquals(o *EtcdVersion) bool {
-       return v.Major == o.Major && v.Minor == o.Minor
-}
-
-// EtcdStorageVersion identifies the storage version of an etcd data directory.
-type EtcdStorageVersion int
-
-const (
-       storageUnknown EtcdStorageVersion = iota
-       storageEtcd2
-       storageEtcd3
-)
-
-// ParseEtcdStorageVersion parses an etcd storage version string to an EtcdStorageVersion.
-func ParseEtcdStorageVersion(s string) (EtcdStorageVersion, error) {
-       switch s {
-       case "etcd2":
-               return storageEtcd2, nil
-       case "etcd3":
-               return storageEtcd3, nil
-       default:
-               return storageUnknown, fmt.Errorf("unrecognized storage version: %s", s)
-       }
-}
-
-// MustParseEtcdStorageVersion parses an etcd storage version string to an EtcdStorageVersion and
-// panics if the parse fails.
-func MustParseEtcdStorageVersion(s string) EtcdStorageVersion {
-       version, err := ParseEtcdStorageVersion(s)
-       if err != nil {
-               panic(err)
-       }
-       return version
-}
-
-// String returns the text representation of the EtcdStorageVersion, 'etcd2' or 'etcd3'.
-func (v EtcdStorageVersion) String() string {
-       switch v {
-       case storageEtcd2:
-               return "etcd2"
-       case storageEtcd3:
-               return "etcd3"
-       default:
-               panic(fmt.Sprintf("enum value %d missing from EtcdStorageVersion String() function", v))
-       }
-}
-
-// EtcdVersionPair is composed of an etcd version and storage version.
-type EtcdVersionPair struct {
-       version        *EtcdVersion
-       storageVersion EtcdStorageVersion
-}
-
-// ParseEtcdVersionPair parses a "<version>/<storage-version>" string to an EtcdVersionPair.
-func ParseEtcdVersionPair(s string) (*EtcdVersionPair, error) {
-       parts := strings.Split(s, "/")
-       if len(parts) != 2 {
-               return nil, fmt.Errorf("malformed version file, expected <major>.<minor>.<patch>/<storage> but got %s", s)
-       }
-       version, err := ParseEtcdVersion(parts[0])
-       if err != nil {
-               return nil, err
-       }
-       storageVersion, err := ParseEtcdStorageVersion(parts[1])
-       if err != nil {
-               return nil, err
-       }
-       return &EtcdVersionPair{version, storageVersion}, nil
-}
-
-// String returns "<version>/<storage-version>" string of the EtcdVersionPair.
-func (vp *EtcdVersionPair) String() string {
-       return fmt.Sprintf("%s/%s", vp.version, vp.storageVersion)
-}
-
-// Equals returns true if both the versions and storage versions are exactly equal.
-func (vp *EtcdVersionPair) Equals(o *EtcdVersionPair) bool {
-       return vp.version.Equals(o.version) && vp.storageVersion == o.storageVersion
-}
-
-// SupportedVersions provides a list of etcd versions that are "supported" for some purpose.
-// The list must be sorted from lowest semantic version to high.
-type SupportedVersions []*EtcdVersion
-
-// NextVersion returns the next supported version after the given current version, or nil if no
-// next version exists.
-func (sv SupportedVersions) NextVersion(current *EtcdVersion) *EtcdVersion {
-       var nextVersion *EtcdVersion
-       for i, supportedVersion := range sv {
-               if current.MajorMinorEquals(supportedVersion) && len(sv) > i+1 {
-                       nextVersion = sv[i+1]
-               }
-       }
-       return nextVersion
-}
-
-// NextVersionPair returns the next supported version after the given current version and infers
-// the storage version from the major version part of the next version.
-func (sv SupportedVersions) NextVersionPair(current *EtcdVersionPair) *EtcdVersionPair {
-       nextVersion := sv.NextVersion(current.version)
-       if nextVersion == nil {
-               return nil
-       }
-       storageVersion := storageEtcd3
-       if nextVersion.Major == 2 {
-               storageVersion = storageEtcd2
-       }
-       return &EtcdVersionPair{version: nextVersion, storageVersion: storageVersion}
-}
-
-// ParseSupportedVersions parses a list of etcd versions.
-func ParseSupportedVersions(list []string) (SupportedVersions, error) {
-       var err error
-       versions := make(SupportedVersions, len(list))
-       for i, v := range list {
-               versions[i], err = ParseEtcdVersion(strings.TrimSpace(v))
-               if err != nil {
-                       return nil, err
-               }
-       }
-       return versions, nil
-}
diff --git a/cluster/images/etcd/migrate/versions_test.go b/cluster/images/etcd/migrate/versions_test.go
deleted file mode 100644 (file)
index 3e4114f..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
-Copyright 2018 The Kubernetes Authors.
-
-Licensed under the Apache License, Version 2.0 (the "License");
-you may not use this file except in compliance with the License.
-You may obtain a copy of the License at
-
-    http://www.apache.org/licenses/LICENSE-2.0
-
-Unless required by applicable law or agreed to in writing, software
-distributed under the License is distributed on an "AS IS" BASIS,
-WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-See the License for the specific language governing permissions and
-limitations under the License.
-*/
-
-package main
-
-import (
-       "testing"
-
-       "github.com/blang/semver/v4"
-)
-
-func TestSerializeEtcdVersionPair(t *testing.T) {
-       cases := []struct {
-               versionTxt string
-               version    *EtcdVersionPair
-               match      bool
-       }{
-               {"3.1.2/etcd3", &EtcdVersionPair{&EtcdVersion{semver.MustParse("3.1.2")}, storageEtcd3}, true},
-               {"1.1.1-rc.0/etcd3", &EtcdVersionPair{&EtcdVersion{semver.MustParse("1.1.1-rc.0")}, storageEtcd3}, true},
-               {"10.100.1000/etcd3", &EtcdVersionPair{&EtcdVersion{semver.MustParse("10.100.1000")}, storageEtcd3}, true},
-       }
-
-       for _, c := range cases {
-               vp, err := ParseEtcdVersionPair(c.versionTxt)
-               if err != nil {
-                       t.Errorf("Failed to parse '%s': %v", c.versionTxt, err)
-               }
-               if vp.Equals(c.version) != c.match {
-                       t.Errorf("Expected '%s' to be parsed as '%+v', got '%+v'", c.versionTxt, c.version, vp)
-               }
-               if vp.String() != c.versionTxt {
-                       t.Errorf("Expected round trip serialization back to '%s', got '%s'", c.versionTxt, vp.String())
-               }
-       }
-
-       unparsables := []string{
-               "1.1/etcd3",
-               "1.1.1.1/etcd3",
-               "1.1.1/etcd4",
-       }
-       for _, unparsable := range unparsables {
-               vp, err := ParseEtcdVersionPair(unparsable)
-               if err == nil {
-                       t.Errorf("Should have failed to parse '%s' but got '%s'", unparsable, vp)
-               }
-       }
-}
-
-func TestMajorMinorEquals(t *testing.T) {
-       cases := []struct {
-               first  *EtcdVersion
-               second *EtcdVersion
-               match  bool
-       }{
-               {&EtcdVersion{semver.Version{Major: 3, Minor: 1, Patch: 2}}, &EtcdVersion{semver.Version{Major: 3, Minor: 1, Patch: 0}}, true},
-               {&EtcdVersion{semver.Version{Major: 3, Minor: 1, Patch: 2}}, &EtcdVersion{semver.Version{Major: 3, Minor: 1, Patch: 2}}, true},
-
-               {&EtcdVersion{semver.Version{Major: 3, Minor: 0, Patch: 0}}, &EtcdVersion{semver.Version{Major: 3, Minor: 1, Patch: 0}}, false},
-               {&EtcdVersion{semver.Version{Major: 2, Minor: 0, Patch: 0}}, &EtcdVersion{semver.Version{Major: 3, Minor: 0, Patch: 0}}, false},
-       }
-
-       for _, c := range cases {
-               if c.first.MajorMinorEquals(c.second) != c.match {
-                       t.Errorf("Expected (%+v == %+v) == %t, got %t", c.first, c.second, c.match, !c.match)
-               }
-       }
-}