From 30467e60cf1bc6c133e228690739a4797f744570 Mon Sep 17 00:00:00 2001 From: Ramkumar Chinchani <45800463+rchincha@users.noreply.github.com> Date: Fri, 21 Mar 2025 12:51:44 -0700 Subject: [PATCH] feat: build windows binaries (#3047) Currently zot project doesn't build and ship Windows binaries. This PR adds that support. Signed-off-by: Ramkumar Chinchani --- .github/workflows/build.yaml | 2 +- Makefile | 16 ++++++++----- pkg/api/controller.go | 23 ------------------- pkg/api/runtime.go | 35 ++++++++++++++++++++++++++++ pkg/api/runtime_windows.go | 44 ++++++++++++++++++++++++++++++++++++ 5 files changed, 90 insertions(+), 30 deletions(-) create mode 100644 pkg/api/runtime.go create mode 100644 pkg/api/runtime_windows.go diff --git a/.github/workflows/build.yaml b/.github/workflows/build.yaml index 3402548b..706059ed 100644 --- a/.github/workflows/build.yaml +++ b/.github/workflows/build.yaml @@ -21,7 +21,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - os: [linux, darwin, freebsd] + os: [linux, darwin, freebsd, windows] arch: [amd64, arm64] steps: - name: Check out source code diff --git a/Makefile b/Makefile index 3ab1d578..33444eb5 100644 --- a/Makefile +++ b/Makefile @@ -62,6 +62,10 @@ BUILDMODE_FLAGS := -buildmode=pie ifeq ($(OS),freebsd) BUILDMODE_FLAGS= endif +BIN_EXT := +ifeq ($(OS),windows) + BIN_EXT=.exe +endif comma:= , space := $(null) # hyphen:= - @@ -164,30 +168,30 @@ gen-protobuf: check-not-freebds $(PROTOC) .PHONY: binary-minimal binary-minimal: EXTENSIONS= binary-minimal: modcheck build-metadata - env CGO_ENABLED=0 GOOS=$(OS) GOARCH=$(ARCH) go build -o bin/zot-$(OS)-$(ARCH)-minimal $(BUILDMODE_FLAGS) -tags containers_image_openpgp -v -trimpath -ldflags "-X zotregistry.dev/zot/pkg/api/config.ReleaseTag=${RELEASE_TAG} -X zotregistry.dev/zot/pkg/api/config.Commit=${COMMIT} -X zotregistry.dev/zot/pkg/api/config.BinaryType=minimal -X zotregistry.dev/zot/pkg/api/config.GoVersion=${GO_VERSION} -s -w" ./cmd/zot + env CGO_ENABLED=0 GOOS=$(OS) GOARCH=$(ARCH) go build -o bin/zot-$(OS)-$(ARCH)-minimal$(BIN_EXT) $(BUILDMODE_FLAGS) -tags containers_image_openpgp -v -trimpath -ldflags "-X zotregistry.dev/zot/pkg/api/config.ReleaseTag=${RELEASE_TAG} -X zotregistry.dev/zot/pkg/api/config.Commit=${COMMIT} -X zotregistry.dev/zot/pkg/api/config.BinaryType=minimal -X zotregistry.dev/zot/pkg/api/config.GoVersion=${GO_VERSION} -s -w" ./cmd/zot .PHONY: binary binary: $(if $(findstring ui,$(BUILD_LABELS)), ui) binary: modcheck build-metadata - env CGO_ENABLED=0 GOOS=$(OS) GOARCH=$(ARCH) go build -o bin/zot-$(OS)-$(ARCH) $(BUILDMODE_FLAGS) -tags $(BUILD_LABELS),containers_image_openpgp -v -trimpath -ldflags "-X zotregistry.dev/zot/pkg/api/config.ReleaseTag=${RELEASE_TAG} -X zotregistry.dev/zot/pkg/api/config.Commit=${COMMIT} -X zotregistry.dev/zot/pkg/api/config.BinaryType=$(extended-name) -X zotregistry.dev/zot/pkg/api/config.GoVersion=${GO_VERSION} -s -w" ./cmd/zot + env CGO_ENABLED=0 GOOS=$(OS) GOARCH=$(ARCH) go build -o bin/zot-$(OS)-$(ARCH)$(BIN_EXT) $(BUILDMODE_FLAGS) -tags $(BUILD_LABELS),containers_image_openpgp -v -trimpath -ldflags "-X zotregistry.dev/zot/pkg/api/config.ReleaseTag=${RELEASE_TAG} -X zotregistry.dev/zot/pkg/api/config.Commit=${COMMIT} -X zotregistry.dev/zot/pkg/api/config.BinaryType=$(extended-name) -X zotregistry.dev/zot/pkg/api/config.GoVersion=${GO_VERSION} -s -w" ./cmd/zot .PHONY: binary-debug binary-debug: $(if $(findstring ui,$(BUILD_LABELS)), ui) binary-debug: modcheck swaggercheck build-metadata - env CGO_ENABLED=0 GOOS=$(OS) GOARCH=$(ARCH) go build -o bin/zot-$(OS)-$(ARCH)-debug $(BUILDMODE_FLAGS) -tags $(BUILD_LABELS),debug,containers_image_openpgp -v -gcflags all='-N -l' -ldflags "-X zotregistry.dev/zot/pkg/api/config.ReleaseTag=${RELEASE_TAG} -X zotregistry.dev/zot/pkg/api/config.Commit=${COMMIT} -X zotregistry.dev/zot/pkg/api/config.BinaryType=$(extended-name) -X zotregistry.dev/zot/pkg/api/config.GoVersion=${GO_VERSION}" ./cmd/zot + env CGO_ENABLED=0 GOOS=$(OS) GOARCH=$(ARCH) go build -o bin/zot-$(OS)-$(ARCH)-debug$(BIN_EXT) $(BUILDMODE_FLAGS) -tags $(BUILD_LABELS),debug,containers_image_openpgp -v -gcflags all='-N -l' -ldflags "-X zotregistry.dev/zot/pkg/api/config.ReleaseTag=${RELEASE_TAG} -X zotregistry.dev/zot/pkg/api/config.Commit=${COMMIT} -X zotregistry.dev/zot/pkg/api/config.BinaryType=$(extended-name) -X zotregistry.dev/zot/pkg/api/config.GoVersion=${GO_VERSION}" ./cmd/zot .PHONY: cli cli: modcheck build-metadata - env CGO_ENABLED=0 GOOS=$(OS) GOARCH=$(ARCH) go build -o bin/zli-$(OS)-$(ARCH) $(BUILDMODE_FLAGS) -tags $(BUILD_LABELS),search,containers_image_openpgp -v -trimpath -ldflags "-X zotregistry.dev/zot/pkg/api/config.Commit=${COMMIT} -X zotregistry.dev/zot/pkg/api/config.BinaryType=$(extended-name) -X zotregistry.dev/zot/pkg/api/config.GoVersion=${GO_VERSION} -s -w" ./cmd/zli + env CGO_ENABLED=0 GOOS=$(OS) GOARCH=$(ARCH) go build -o bin/zli-$(OS)-$(ARCH)$(BIN_EXT) $(BUILDMODE_FLAGS) -tags $(BUILD_LABELS),search,containers_image_openpgp -v -trimpath -ldflags "-X zotregistry.dev/zot/pkg/api/config.Commit=${COMMIT} -X zotregistry.dev/zot/pkg/api/config.BinaryType=$(extended-name) -X zotregistry.dev/zot/pkg/api/config.GoVersion=${GO_VERSION} -s -w" ./cmd/zli .PHONY: bench bench: modcheck build-metadata - env CGO_ENABLED=0 GOOS=$(OS) GOARCH=$(ARCH) go build -o bin/zb-$(OS)-$(ARCH) $(BUILDMODE_FLAGS) -tags $(BUILD_LABELS),containers_image_openpgp -v -trimpath -ldflags "-X zotregistry.dev/zot/pkg/api/config.Commit=${COMMIT} -X zotregistry.dev/zot/pkg/api/config.BinaryType=$(extended-name) -X zotregistry.dev/zot/pkg/api/config.GoVersion=${GO_VERSION} -s -w" ./cmd/zb + env CGO_ENABLED=0 GOOS=$(OS) GOARCH=$(ARCH) go build -o bin/zb-$(OS)-$(ARCH)$(BIN_EXT) $(BUILDMODE_FLAGS) -tags $(BUILD_LABELS),containers_image_openpgp -v -trimpath -ldflags "-X zotregistry.dev/zot/pkg/api/config.Commit=${COMMIT} -X zotregistry.dev/zot/pkg/api/config.BinaryType=$(extended-name) -X zotregistry.dev/zot/pkg/api/config.GoVersion=${GO_VERSION} -s -w" ./cmd/zb .PHONY: exporter-minimal exporter-minimal: EXTENSIONS= exporter-minimal: modcheck build-metadata - env CGO_ENABLED=0 GOOS=$(OS) GOARCH=$(ARCH) go build -o bin/zxp-$(OS)-$(ARCH) $(BUILDMODE_FLAGS) -tags containers_image_openpgp -v -trimpath ./cmd/zxp + env CGO_ENABLED=0 GOOS=$(OS) GOARCH=$(ARCH) go build -o bin/zxp-$(OS)-$(ARCH)$(BIN_EXT) $(BUILDMODE_FLAGS) -tags containers_image_openpgp -v -trimpath ./cmd/zxp .PHONY: test-prereq test-prereq: check-skopeo $(TESTDATA) $(ORAS) diff --git a/pkg/api/controller.go b/pkg/api/controller.go index 24b5ac2c..bfd2fd79 100644 --- a/pkg/api/controller.go +++ b/pkg/api/controller.go @@ -8,10 +8,8 @@ import ( "net" "net/http" "os" - "runtime" "strconv" "strings" - "syscall" "time" "github.com/gorilla/mux" @@ -120,27 +118,6 @@ func NewController(appConfig *config.Config) *Controller { return &controller } -func DumpRuntimeParams(log log.Logger) { - var rLimit syscall.Rlimit - - evt := log.Info().Int("cpus", runtime.NumCPU()) //nolint: zerologlint - - err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit) - if err == nil { - evt = evt.Uint64("max. open files", uint64(rLimit.Cur)) //nolint: unconvert // required for *BSD - } - - if content, err := os.ReadFile("/proc/sys/net/core/somaxconn"); err == nil { - evt = evt.Str("listen backlog", strings.TrimSuffix(string(content), "\n")) - } - - if content, err := os.ReadFile("/proc/sys/user/max_inotify_watches"); err == nil { - evt = evt.Str("max. inotify watches", strings.TrimSuffix(string(content), "\n")) - } - - evt.Msg("runtime params") -} - func (c *Controller) GetPort() int { return c.chosenPort } diff --git a/pkg/api/runtime.go b/pkg/api/runtime.go new file mode 100644 index 00000000..d3458166 --- /dev/null +++ b/pkg/api/runtime.go @@ -0,0 +1,35 @@ +//go:build !windows +// +build !windows + +package api + +import ( + "os" + "runtime" + "strings" + "syscall" + + "zotregistry.dev/zot/pkg/log" +) + +// DumpRuntimeParams dumps important runtime state such as file and socket limits. +func DumpRuntimeParams(log log.Logger) { + var rLimit syscall.Rlimit + + evt := log.Info().Int("cpus", runtime.NumCPU()) //nolint: zerologlint + + err := syscall.Getrlimit(syscall.RLIMIT_NOFILE, &rLimit) + if err == nil { + evt = evt.Uint64("max. open files", uint64(rLimit.Cur)) //nolint: unconvert // required for *BSD + } + + if content, err := os.ReadFile("/proc/sys/net/core/somaxconn"); err == nil { + evt = evt.Str("listen backlog", strings.TrimSuffix(string(content), "\n")) + } + + if content, err := os.ReadFile("/proc/sys/user/max_inotify_watches"); err == nil { + evt = evt.Str("max. inotify watches", strings.TrimSuffix(string(content), "\n")) + } + + evt.Msg("runtime params") +} diff --git a/pkg/api/runtime_windows.go b/pkg/api/runtime_windows.go new file mode 100644 index 00000000..6b7d67dd --- /dev/null +++ b/pkg/api/runtime_windows.go @@ -0,0 +1,44 @@ +//go:build windows +// +build windows + +package api + +import ( + "runtime" + "syscall" + "unsafe" + + "zotregistry.dev/zot/pkg/log" +) + +func getCurrentHandleCount() (uint32, error) { + kernel32 := syscall.NewLazyDLL("kernel32.dll") + + getProcessHandleCount := kernel32.NewProc("GetProcessHandleCount") + getCurrentProcess := kernel32.NewProc("GetCurrentProcess") + currentProcess, _, _ := getCurrentProcess.Call() + + var handleCount uint32 + ret, _, err := getProcessHandleCount.Call( + currentProcess, + uintptr(unsafe.Pointer(&handleCount)), + ) + + if ret == 0 { + return 0, err + } + + return handleCount, nil +} + +// DumpRuntimeParams dumps important runtime state such as file and socket limits. +func DumpRuntimeParams(log log.Logger) { + evt := log.Info().Int("cpus", runtime.NumCPU()) //nolint: zerologlint + + nofile, err := getCurrentHandleCount() + if err == nil { + evt = evt.Uint64("curr. open files", uint64(nofile)) //nolint: unconvert // required for *BSD + } + + evt.Msg("runtime params") +}