diff --git a/.dockerignore b/.dockerignore index 2c64c3e57..12b45844f 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,2 +1,7 @@ ./.dapper ./.cache +.git +*.swp +.idea +# /bin is not excluded — package/Dockerfile and package/Dockerfile.webhook +# reference bin/ directly as part of the docker buildx build context. diff --git a/.gitignore b/.gitignore index 01227f33a..c5decfa78 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,4 @@ /bin *.swp .idea +/scripts/.version_env diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 000000000..8ceb2c1b8 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,80 @@ +# syntax=docker/dockerfile:1 +# check=skip=InvalidDefaultArgInFrom +FROM registry.suse.com/bci/golang:1.25.7 AS builder +ARG MK_HOST_ARCH +ENV ARCH=$MK_HOST_ARCH + +RUN zypper -n rm container-suseconnect && \ + zypper -n install git curl docker gzip tar wget awk docker-buildx + +COPY --from=golangci/golangci-lint:v2.11.4-alpine@sha256:72bcd68512b4e27540dd3a778a1b7afd45759d8145cfb3c089f1d7af53e718e9 \ + /usr/bin/golangci-lint /usr/local/bin/golangci-lint + +RUN go install sigs.k8s.io/controller-tools/cmd/controller-gen@v0.18.0 + +RUN go install k8s.io/code-generator/cmd/openapi-gen@v0.29.13 + +ENV HOME=/go/src/github.com/harvester/node-disk-manager + +# ---- base ---- +FROM builder AS base +WORKDIR /go/src/github.com/harvester/node-disk-manager +COPY . . + +# ---- build ---- +FROM base AS build +ARG MK_REPO_ID + +RUN --mount=type=cache,target=/go/pkg/mod,id=harvester-ndm-go-mod-${MK_REPO_ID} \ + --mount=type=cache,target=/go/src/github.com/harvester/node-disk-manager/.cache/go-build,id=harvester-ndm-go-build-${MK_REPO_ID} \ + ./scripts/build + +FROM scratch AS build-output +COPY --from=build /go/src/github.com/harvester/node-disk-manager/bin/ /bin/ + +# ---- validate ---- +FROM base AS validate +ARG MK_REPO_ID + +RUN --mount=type=cache,target=/go/pkg/mod,id=harvester-ndm-go-mod-${MK_REPO_ID} \ + --mount=type=cache,target=/go/src/github.com/harvester/node-disk-manager/.cache/go-build,id=harvester-ndm-go-build-${MK_REPO_ID} \ + ./scripts/validate + +# ---- validate-ci ---- +FROM base AS validate-ci +ARG MK_REPO_ID + +RUN git config --global user.email "ci@example.com" && \ + git config --global user.name "ci" && \ + git init 2>/dev/null && git add . && git commit -q -m "commit for validate-ci" + +RUN --mount=type=cache,target=/go/pkg/mod,id=harvester-ndm-go-mod-${MK_REPO_ID} \ + --mount=type=cache,target=/go/src/github.com/harvester/node-disk-manager/.cache/go-build,id=harvester-ndm-go-build-${MK_REPO_ID} \ + ./scripts/validate-ci + +# ---- test ---- +FROM base AS test +ARG MK_REPO_ID + +RUN --mount=type=cache,target=/go/pkg/mod,id=harvester-ndm-go-mod-${MK_REPO_ID} \ + --mount=type=cache,target=/go/src/github.com/harvester/node-disk-manager/.cache/go-build,id=harvester-ndm-go-build-${MK_REPO_ID} \ + ./scripts/test + +# ---- generate ---- +FROM base AS generate +ARG MK_REPO_ID + +RUN --mount=type=cache,target=/go/pkg/mod,id=harvester-ndm-go-mod-${MK_REPO_ID} \ + --mount=type=cache,target=/go/src/github.com/harvester/node-disk-manager/.cache/go-build,id=harvester-ndm-go-build-${MK_REPO_ID} \ + ./scripts/generate + +FROM scratch AS generate-output +COPY --from=generate /go/src/github.com/harvester/node-disk-manager/pkg/ /pkg/ + +# ---- generate-manifest ---- +FROM base AS generate-manifest + +RUN ./scripts/generate-manifest + +FROM scratch AS generate-manifest-output +COPY --from=generate-manifest /go/src/github.com/harvester/node-disk-manager/manifests/ /manifests/ diff --git a/Dockerfile.dapper b/Dockerfile.dapper deleted file mode 100644 index 479db67fc..000000000 --- a/Dockerfile.dapper +++ /dev/null @@ -1,26 +0,0 @@ -FROM registry.suse.com/bci/golang:1.25.7 - -ARG DAPPER_HOST_ARCH -ENV HOST_ARCH=${DAPPER_HOST_ARCH} ARCH=${DAPPER_HOST_ARCH} - -RUN zypper -n rm container-suseconnect && \ - zypper -n install git curl docker gzip tar wget awk docker-buildx - -## install golangci -COPY --from=golangci/golangci-lint:v2.11.4-alpine@sha256:72bcd68512b4e27540dd3a778a1b7afd45759d8145cfb3c089f1d7af53e718e9 /usr/bin/golangci-lint /usr/local/bin/golangci-lint - -## install controller-gen -RUN go install sigs.k8s.io/controller-tools/cmd/controller-gen@v0.18.0 - -# install openapi-gen -RUN go install k8s.io/code-generator/cmd/openapi-gen@v0.29.13 - -ENV DAPPER_ENV REPO TAG DRONE_TAG CROSS BUILD_FOR_CI -ENV DAPPER_SOURCE /go/src/github.com/harvester/node-disk-manager/ -ENV DAPPER_OUTPUT ./bin ./manifests ./pkg -ENV DAPPER_DOCKER_SOCKET true -ENV HOME ${DAPPER_SOURCE} -WORKDIR ${DAPPER_SOURCE} - -ENTRYPOINT ["./scripts/entry"] -CMD ["ci"] diff --git a/Makefile b/Makefile index 109983ebc..9f58be4de 100644 --- a/Makefile +++ b/Makefile @@ -1,26 +1,94 @@ -TARGETS := $(shell ls scripts) - -SHA512SUM_Linux_aarch64 := 781951b31e5ff018a04e755c6da7163b31a81edda61f1bed4def8d0e24229865c58a3d26aa0cc4184058d91ebcae300ead2cad16d3c46ccb1098419e3e41a016 -SHA512SUM_Linux_x86_64 := d2ec27ecf9362e2fafd27d76d85a5c5b92b53aefe07cffa76bf9887db6bee07b1023cca8fc32a2c9bdd2ecfadaee71397066b41bd37c9ebbbbce09913f0884d4 -SHA512SUM_Darwin_arm64 := 8a356c89ad32af1698ae8615a6e303773a8ac58b114368454d59965ec2aa8282e780d1e228d37c301ce6f87596f68bfe7f204eb5f4c019c386a58dd94153ddcf -SHA512SUM_Darwin_x86_64 := dbab05de04dda26793f4ae7875d0fba96ee54b0228e192fd40c0b2116ed345b5444047fc2e0c90cb481f28cbe0e0452bcecb268c8d074cd8615eb2f5463c30b6 -SHA512SUM_Windows_x86_64 := 807aee2f68b6da35cb0885558f5cbc9a6c8747a56c7a200f0e1fcac9e2fd0da570cbb39e48b3192bd1a71805f2ab38fd19d77faebba97a89e5d9a8b430ee429e - -.dapper: - @echo Downloading dapper - @curl -sL https://releases.rancher.com/dapper/v0.6.0/dapper-`uname -s`-`uname -m` > .dapper.tmp - @CHECKSUM=$$(shasum -a 512 .dapper.tmp | awk '{print $$1}'); \ - if [ "$$CHECKSUM" != "$(SHA512SUM_$(shell uname -s)_$(shell uname -m))" ]; then \ - echo "Checksum verification failed!"; \ - exit 1; \ - fi - @@chmod +x .dapper.tmp - @./.dapper.tmp -v - @mv .dapper.tmp .dapper - -$(TARGETS): .dapper - ./.dapper $@ - -.DEFAULT_GOAL := default - -.PHONY: $(TARGETS) +ROOT := $(shell dirname $(realpath $(lastword $(MAKEFILE_LIST)))) + +MK_HOST_ARCH := $(shell uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/') +export MK_HOST_ARCH + +MK_REPO_ID := $(shell echo -n "$(ROOT)$$(cat /etc/machine-id 2>/dev/null)" | sha256sum | cut -c1-8) +export MK_REPO_ID + +MK_DOCKER_PROGRESS ?= plain +export MK_DOCKER_PROGRESS + +DOCKER_BUILDKIT := 1 +export DOCKER_BUILDKIT + +BUILD_FOR_CI ?= +export BUILD_FOR_CI + + +ifdef CI + BOLD := + CYAN := + RESET := +else + BOLD := \033[1m + CYAN := \033[36m + RESET := \033[0m +endif + +BANNER = @printf "$(BOLD)$(CYAN)[target: $@]$(RESET)\n" + +DOCKER_BUILD = docker build \ + --progress=$(MK_DOCKER_PROGRESS) \ + --build-arg MK_REPO_ID \ + --build-arg MK_HOST_ARCH \ + -f $(ROOT)/Dockerfile $(ROOT) + +.DEFAULT_GOAL := ci + +.PHONY: build validate validate-ci test generate generate-manifest package ci gen-version-env clean + +# ---- gen-version-env ---- +# Pre-generate version env for container builds (no .git needed inside Docker). +# Also handles git worktree checkouts where .git is a pointer file to an external directory. +gen-version-env: + @bash $(ROOT)/scripts/version > /dev/null + +# ---- build ---- +build: gen-version-env | $(ROOT)/bin + $(BANNER) + $(DOCKER_BUILD) --target build-output \ + --output type=local,dest=$(ROOT) + +$(ROOT)/bin: + @mkdir -p $(ROOT)/bin + +# ---- validate ---- +validate: gen-version-env + $(BANNER) + $(DOCKER_BUILD) --target validate + +# ---- validate-ci ---- +validate-ci: gen-version-env + $(BANNER) + $(DOCKER_BUILD) --target validate-ci + +# ---- test ---- +test: gen-version-env + $(BANNER) + $(DOCKER_BUILD) --target test + +# ---- generate ---- +generate: gen-version-env + $(BANNER) + $(DOCKER_BUILD) --target generate-output \ + --output type=local,dest=$(ROOT) + +# ---- generate-manifest ---- +generate-manifest: gen-version-env + $(BANNER) + $(DOCKER_BUILD) --target generate-manifest-output \ + --output type=local,dest=$(ROOT) + +# ---- package ---- +package: build + $(BANNER) + ARCH=$(MK_HOST_ARCH) $(ROOT)/scripts/package + +# ---- ci ---- +ci: build test validate validate-ci package + +# ---- clean ---- +clean: + @rm -rf $(ROOT)/bin + @rm -f $(ROOT)/scripts/.version_env diff --git a/scripts/ci b/scripts/ci deleted file mode 100755 index 523341057..000000000 --- a/scripts/ci +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/bash -set -e - -cd $(dirname $0) - -./build -./test -./validate -./validate-ci -./package diff --git a/scripts/default b/scripts/default deleted file mode 100755 index af2ad2db1..000000000 --- a/scripts/default +++ /dev/null @@ -1,8 +0,0 @@ -#!/bin/bash -set -e - -cd $(dirname $0) - -./build -./test -./package diff --git a/scripts/entry b/scripts/entry deleted file mode 100755 index c58311c9e..000000000 --- a/scripts/entry +++ /dev/null @@ -1,11 +0,0 @@ -#!/bin/bash -set -e - -mkdir -p bin -if [ -e ./scripts/$1 ]; then - ./scripts/"$@" -else - exec "$@" -fi - -chown -R $DAPPER_UID:$DAPPER_GID . diff --git a/scripts/package b/scripts/package index 2ca805682..65aad5b85 100755 --- a/scripts/package +++ b/scripts/package @@ -1,5 +1,8 @@ #!/bin/bash set -e +SCRIPTS_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )/" &> /dev/null && pwd )" + +cd "${SCRIPTS_DIR}" ./package_controller -./package_webhook \ No newline at end of file +./package_webhook diff --git a/scripts/package_controller b/scripts/package_controller index 65e24262e..fd11a635d 100755 --- a/scripts/package_controller +++ b/scripts/package_controller @@ -14,7 +14,7 @@ if [ -e ${DOCKERFILE}.${ARCH} ]; then DOCKERFILE=${DOCKERFILE}.${ARCH} fi -docker buildx build --load -f ${DOCKERFILE} -t ${IMAGE} . +docker build -f ${DOCKERFILE} -t ${IMAGE} . echo Built ${IMAGE} if [[ -n ${BUILD_FOR_CI} ]]; then docker push ${IMAGE} diff --git a/scripts/package_webhook b/scripts/package_webhook index 282680157..e63ae4f71 100755 --- a/scripts/package_webhook +++ b/scripts/package_webhook @@ -14,7 +14,7 @@ if [ -e ${DOCKERFILE}.${ARCH} ]; then DOCKERFILE=${DOCKERFILE}.${ARCH} fi -docker buildx build --load -f ${DOCKERFILE} -t ${IMAGE} . +docker build -f ${DOCKERFILE} -t ${IMAGE} . echo Built ${IMAGE} if [[ -n ${BUILD_FOR_CI} ]]; then docker push ${IMAGE} diff --git a/scripts/release b/scripts/release deleted file mode 100755 index 7af0df35f..000000000 --- a/scripts/release +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -exec $(dirname $0)/ci diff --git a/scripts/version b/scripts/version index 982401211..fad47f08a 100755 --- a/scripts/version +++ b/scripts/version @@ -1,5 +1,22 @@ #!/bin/bash +TOP_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)" +_VERSION_ENV="${TOP_DIR}/scripts/.version_env" + +# When .git is not available (container build or git worktree checkout where the +# linked git dir is outside the Docker context), fall back to a pre-generated env +# file. Run 'make gen-version-env' on a host with git access first. +if ! git -C "${TOP_DIR}" rev-parse HEAD &>/dev/null 2>&1; then + if [[ -f "${_VERSION_ENV}" ]]; then + # shellcheck source=/dev/null + source "${_VERSION_ENV}" + return 0 2>/dev/null || true + fi + echo "ERROR: git is unavailable and no pre-generated scripts/.version_env was found." >&2 + echo "Run 'make gen-version-env' on a host with git access first." >&2 + return 1 2>/dev/null || exit 1 +fi + if [ -n "$(git status --porcelain --untracked-files=no)" ]; then DIRTY="-dirty" fi @@ -14,18 +31,32 @@ else fi if [ -z "$ARCH" ]; then - ARCH=$(go env GOHOSTARCH) + ARCH=$(uname -m | sed 's/x86_64/amd64/;s/aarch64/arm64/') fi SUFFIX="-${ARCH}" TAG=${TAG:-${VERSION}${SUFFIX}} REPO=${REPO:-harvester} + if [[ -n ${BUILD_FOR_CI} ]]; then - TAG=${COMMIT} - return + TAG=${COMMIT} + return 0 2>/dev/null || true fi if echo $TAG | grep -q dirty; then TAG=dev fi + +cat > "${_VERSION_ENV}" <<__EOF__ +# Auto-generated by scripts/version — do not edit manually. +# Refresh by running 'make gen-version-env' on a host with git access. +DIRTY="${DIRTY}" +COMMIT="${COMMIT}" +GIT_TAG="${GIT_TAG}" +VERSION="${VERSION}" +ARCH="${ARCH}" +SUFFIX="${SUFFIX}" +TAG="${TAG}" +REPO="${REPO}" +__EOF__