diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 803eedad..b8126d21 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -29,6 +29,7 @@ jobs: - name: Run checks run: | + sudo apt-get -qq update || true make ci - name: Test Vulnerability diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 435ead3d..596ce96c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -15,8 +15,13 @@ jobs: name: Build runs-on: ubuntu-24.04 steps: - - name: Check out code into the Go module directory - uses: actions/checkout@v1 + - uses: actions/checkout@v1 + + - name: Set up Go 1.24 + uses: actions/setup-go@v5 + with: + go-version: '1.24' + id: go - name: Print version info id: semver @@ -32,21 +37,26 @@ jobs: - name: Set up Docker Buildx uses: docker/setup-buildx-action@v3 - - name: Build + - name: Publish to GitHub Container Registry env: + REGISTRY: ghcr.io/appscode + DOCKER_TOKEN: ${{ secrets.LGTM_GITHUB_TOKEN }} + USERNAME: 1gtm APPSCODE_ENV: prod run: | - make release + docker login ghcr.io --username ${USERNAME} --password ${DOCKER_TOKEN} + make release COMPRESS=yes - name: Release uses: softprops/action-gh-release@v1 if: startsWith(github.ref, 'refs/tags/') with: files: | - bin/offline-license-server-linux-amd64 - bin/offline-license-server-linux-arm - bin/offline-license-server-linux-arm64 - bin/offline-license-server-darwin-amd64 - bin/offline-license-server-darwin-arm64 + bin/offline-license-server-darwin-amd64.tar.gz + bin/offline-license-server-darwin-arm64.tar.gz + bin/offline-license-server-linux-amd64.tar.gz + bin/offline-license-server-linux-arm64.tar.gz + bin/offline-license-server-windows-amd64.zip + bin/offline-license-server-checksums.txt env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/Dockerfile.dbg b/Dockerfile.dbg new file mode 100644 index 00000000..88600ded --- /dev/null +++ b/Dockerfile.dbg @@ -0,0 +1,33 @@ +# Copyright AppsCode Inc. +# +# 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. + +FROM ghcr.io/appscode/dlv:1.24 + +FROM {ARG_FROM} + +LABEL org.opencontainers.image.source https://github.com/appscode-cloud/offline-license-server + +RUN set -x \ + && apt-get update \ + && apt-get upgrade -y \ + && apt-get install -y --no-install-recommends ca-certificates openssh-client \ + && rm -rf /var/lib/apt/lists/* /usr/share/doc /usr/share/man /tmp/* \ + && echo 'Etc/UTC' > /etc/timezone + +ADD bin/{ARG_BIN}-{ARG_OS}-{ARG_ARCH} /{ARG_BIN} +COPY --from=0 /usr/local/bin/dlv /bin/dlv + +EXPOSE 40000 + +ENTRYPOINT ["/bin/dlv", "--listen=:40000", "--headless=true", "--api-version=2", "exec", "/{ARG_BIN}", "--"] diff --git a/Dockerfile.in b/Dockerfile.in new file mode 100644 index 00000000..f98137ea --- /dev/null +++ b/Dockerfile.in @@ -0,0 +1,27 @@ +# Copyright AppsCode Inc. +# +# 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. + +FROM {ARG_FROM} + +LABEL org.opencontainers.image.source https://github.com/appscode-cloud/offline-license-server + +RUN set -x \ + && apk add --update --upgrade --no-cache pcre2 ca-certificates tzdata openssh-client \ + && echo 'Etc/UTC' > /etc/timezone + +ADD bin/{ARG_BIN}-{ARG_OS}-{ARG_ARCH} /{ARG_BIN} + +USER 65534 + +ENTRYPOINT ["/{ARG_BIN}"] diff --git a/Makefile b/Makefile index ed8bca09..5983c3ea 100644 --- a/Makefile +++ b/Makefile @@ -14,11 +14,19 @@ SHELL=/bin/bash -o pipefail +PRODUCT_OWNER_NAME := appscode +PRODUCT_NAME := offline-license-server +ENFORCE_LICENSE ?= + GO_PKG := go.bytebuilders.dev REPO := $(notdir $(shell pwd)) BIN := offline-license-server COMPRESS ?= no +# Where to push the docker image. +REGISTRY ?= ghcr.io/appscode +SRC_REG ?= + # This version-strategy uses git tags to set the version string git_branch := $(shell git rev-parse --abbrev-ref HEAD) git_tag := $(shell git describe --exact-match --abbrev=0 2>/dev/null || echo "") @@ -46,15 +54,26 @@ endif SRC_PKGS := cmds pkg templates SRC_DIRS := $(SRC_PKGS) *.go # directories which hold app source (not vendored) -DOCKER_PLATFORMS := linux/amd64 linux/arm linux/arm64 -BIN_PLATFORMS := $(DOCKER_PLATFORMS) darwin/amd64 darwin/arm64 +DOCKER_PLATFORMS := linux/amd64 linux/arm64 +BIN_PLATFORMS := $(DOCKER_PLATFORMS) windows/amd64 darwin/amd64 darwin/arm64 # Used internally. Users should pass GOOS and/or GOARCH. OS := $(if $(GOOS),$(GOOS),$(shell go env GOOS)) ARCH := $(if $(GOARCH),$(GOARCH),$(shell go env GOARCH)) +BASEIMAGE_PROD ?= alpine +BASEIMAGE_DBG ?= debian:12 + +IMAGE := $(REGISTRY)/$(BIN) +VERSION_PROD := $(VERSION) +VERSION_DBG := $(VERSION)-dbg +TAG := $(VERSION)_$(OS)_$(ARCH) +TAG_PROD := $(TAG) +TAG_DBG := $(VERSION)-dbg_$(OS)_$(ARCH) + GO_VERSION ?= 1.24 BUILD_IMAGE ?= ghcr.io/appscode/golang-dev:$(GO_VERSION) +CHART_TEST_IMAGE ?= quay.io/helmpack/chart-testing:v3.11.0 OUTBIN = bin/$(BIN)-$(OS)-$(ARCH) ifeq ($(OS),windows) @@ -68,8 +87,10 @@ BUILD_DIRS := bin/$(OS)_$(ARCH) \ .go/cache \ hack/config \ $(HOME)/.credentials \ - $(HOME)/.kube \ - $(HOME)/.minikube + $(HOME)/.kube + +DOCKERFILE_PROD = Dockerfile.in +DOCKERFILE_DBG = Dockerfile.dbg DOCKER_REPO_ROOT := /go/src/$(GO_PKG)/$(REPO) @@ -87,17 +108,36 @@ build-%: GOOS=$(firstword $(subst _, ,$*)) \ GOARCH=$(lastword $(subst _, ,$*)) +container-%: + @$(MAKE) container \ + --no-print-directory \ + GOOS=$(firstword $(subst _, ,$*)) \ + GOARCH=$(lastword $(subst _, ,$*)) + +push-%: + @$(MAKE) push \ + --no-print-directory \ + GOOS=$(firstword $(subst _, ,$*)) \ + GOARCH=$(lastword $(subst _, ,$*)) + all-build: $(addprefix build-, $(subst /,_, $(BIN_PLATFORMS))) +ifeq ($(COMPRESS),yes) + @cd bin; \ + sha256sum $(patsubst $(BIN)-windows-%.tar.gz,$(BIN)-windows-%.zip, $(addsuffix .tar.gz, $(addprefix $(BIN)-, $(subst /,-, $(BIN_PLATFORMS))))) > $(BIN)-checksums.txt +endif + +all-container: $(addprefix container-, $(subst /,_, $(DOCKER_PLATFORMS))) + +all-push: $(addprefix push-, $(subst /,_, $(DOCKER_PLATFORMS))) version: - @echo ::set-output name=version::$(VERSION) - @echo ::set-output name=version_strategy::$(version_strategy) - @echo ::set-output name=git_tag::$(git_tag) - @echo ::set-output name=git_branch::$(git_branch) - @echo ::set-output name=commit_hash::$(commit_hash) - @echo ::set-output name=commit_timestamp::$(commit_timestamp) - -.PHONY: gen + @echo version=$(VERSION) + @echo version_strategy=$(version_strategy) + @echo git_tag=$(git_tag) + @echo git_branch=$(git_branch) + @echo commit_hash=$(commit_hash) + @echo commit_timestamp=$(commit_timestamp) + gen: @true @@ -145,6 +185,9 @@ $(OUTBIN): .go/$(OUTBIN).stamp --env HTTPS_PROXY=$(HTTPS_PROXY) \ $(BUILD_IMAGE) \ /bin/bash -c " \ + PRODUCT_OWNER_NAME=$(PRODUCT_OWNER_NAME) \ + PRODUCT_NAME=$(PRODUCT_NAME) \ + ENFORCE_LICENSE=$(ENFORCE_LICENSE) \ ARCH=$(ARCH) \ OS=$(OS) \ VERSION=$(VERSION) \ @@ -155,27 +198,57 @@ $(OUTBIN): .go/$(OUTBIN).stamp commit_timestamp=$(commit_timestamp) \ ./hack/build.sh \ " - @if [ $(COMPRESS) = yes ] && [ $(OS) != darwin ]; then \ - echo "compressing $(OUTBIN)"; \ - docker run \ - -i \ - --rm \ - -u $$(id -u):$$(id -g) \ - -v $$(pwd):/src \ - -w /src \ - -v $$(pwd)/.go/bin/$(OS)_$(ARCH):/go/bin \ - -v $$(pwd)/.go/bin/$(OS)_$(ARCH):/go/bin/$(OS)_$(ARCH) \ - -v $$(pwd)/.go/cache:/.cache \ - --env HTTP_PROXY=$(HTTP_PROXY) \ - --env HTTPS_PROXY=$(HTTPS_PROXY) \ - $(BUILD_IMAGE) \ - upx --brute /go/bin/$(BIN); \ - fi @if ! cmp -s .go/bin/$(OS)_$(ARCH)/$(BIN) $(OUTBIN); then \ mv .go/bin/$(OS)_$(ARCH)/$(BIN) $(OUTBIN); \ date >$@; \ fi +ifeq ($(COMPRESS),yes) +ifeq ($(OS),windows) + @echo "compressing $(OUTBIN)"; \ + cd bin; \ + zip -j $(subst .exe,,$(BIN))-$(OS)-$(ARCH).zip $(subst .exe,,$(BIN))-$(OS)-$(ARCH).exe ../LICENSE.md +else + @echo "compressing $(OUTBIN)"; \ + cd bin; \ + tar -czvf $(BIN)-$(OS)-$(ARCH).tar.gz $(BIN)-$(OS)-$(ARCH) ../LICENSE.md +endif +endif + @echo + +# Used to track state in hidden files. +DOTFILE_IMAGE = $(subst /,_,$(IMAGE))-$(TAG) + +container: bin/.container-$(DOTFILE_IMAGE)-PROD bin/.container-$(DOTFILE_IMAGE)-DBG +ifeq (,$(SRC_REG)) +bin/.container-$(DOTFILE_IMAGE)-%: bin/$(BIN)-$(OS)-$(ARCH) $(DOCKERFILE_%) + @echo "container: $(IMAGE):$(TAG_$*)" + @sed \ + -e 's|{ARG_BIN}|$(BIN)|g' \ + -e 's|{ARG_ARCH}|$(ARCH)|g' \ + -e 's|{ARG_OS}|$(OS)|g' \ + -e 's|{ARG_FROM}|$(BASEIMAGE_$*)|g' \ + $(DOCKERFILE_$*) > bin/.dockerfile-$*-$(OS)_$(ARCH) + @docker buildx build --platform $(OS)/$(ARCH) --load --pull -t $(IMAGE):$(TAG_$*) -f bin/.dockerfile-$*-$(OS)_$(ARCH) . + @docker images -q $(IMAGE):$(TAG_$*) > $@ + @echo +else +bin/.container-$(DOTFILE_IMAGE)-%: + @echo "container: $(IMAGE):$(TAG_$*)" + @docker tag $(SRC_REG)/$(BIN):$(TAG_$*) $(IMAGE):$(TAG_$*) @echo +endif + +push: bin/.push-$(DOTFILE_IMAGE)-PROD bin/.push-$(DOTFILE_IMAGE)-DBG +bin/.push-$(DOTFILE_IMAGE)-%: bin/.container-$(DOTFILE_IMAGE)-% + @docker push $(IMAGE):$(TAG_$*) + @echo "pushed: $(IMAGE):$(TAG_$*)" + @echo + +.PHONY: docker-manifest +docker-manifest: docker-manifest-PROD docker-manifest-DBG +docker-manifest-%: + docker manifest create -a $(IMAGE):$(VERSION_$*) $(foreach PLATFORM,$(DOCKER_PLATFORMS),$(IMAGE):$(VERSION_$*)_$(subst /,_,$(PLATFORM))) + docker manifest push $(IMAGE):$(VERSION_$*) .PHONY: test test: unit-tests @@ -216,24 +289,53 @@ lint: $(BUILD_DIRS) -v $$(pwd)/.go/cache:/.cache \ --env HTTP_PROXY=$(HTTP_PROXY) \ --env HTTPS_PROXY=$(HTTPS_PROXY) \ - --env GO111MODULE=on \ --env GOFLAGS="-mod=vendor" \ $(BUILD_IMAGE) \ - golangci-lint run --enable $(ADDTL_LINTERS) --timeout=10m --exclude-files="generated.*\.go$\" --exclude-dirs-use-default + golangci-lint run --enable $(ADDTL_LINTERS) --max-same-issues=100 --timeout=10m --exclude-files="generated.*\.go$\" --exclude-dirs-use-default --exclude-dirs=client,vendor $(BUILD_DIRS): @mkdir -p $@ +KUBE_NAMESPACE ?= kubeops +REGISTRY_SECRET ?= +IMAGE_PULL_POLICY ?= IfNotPresent + +ifeq ($(strip $(REGISTRY_SECRET)),) + IMAGE_PULL_SECRETS = +else + IMAGE_PULL_SECRETS = --set imagePullSecrets[0].name=$(REGISTRY_SECRET) +endif + +.PHONY: install +install: + @cd ../installer; \ + kubectl create ns $(KUBE_NAMESPACE) || true; \ + kubectl label ns $(KUBE_NAMESPACE) pod-security.kubernetes.io/enforce=restricted; \ + helm upgrade -i offline-license-server charts/offline-license-server --wait \ + --namespace=$(KUBE_NAMESPACE) --create-namespace \ + --set image.tag=$(TAG_PROD) \ + --set imagePullPolicy=$(IMAGE_PULL_POLICY) \ + $(IMAGE_PULL_SECRETS); + +.PHONY: uninstall +uninstall: + @cd ../installer; \ + helm uninstall offline-license-server --namespace=$(KUBE_NAMESPACE) || true + +.PHONY: purge +purge: uninstall + @true + .PHONY: dev -dev: gen fmt build +dev: gen fmt push .PHONY: verify verify: verify-gen verify-modules .PHONY: verify-modules verify-modules: - GO111MODULE=on go mod tidy - GO111MODULE=on go mod vendor + go mod tidy + go mod vendor @if !(git diff --exit-code HEAD); then \ echo "go module files are out of date"; exit 1; \ fi @@ -241,7 +343,7 @@ verify-modules: .PHONY: verify-gen verify-gen: gen fmt @if !(git diff --exit-code HEAD); then \ - echo "files are out of date, run make gen fmt"; exit 1; \ + echo "generated files are out of date, run make gen fmt"; exit 1; \ fi .PHONY: add-license @@ -255,11 +357,11 @@ add-license: --env HTTP_PROXY=$(HTTP_PROXY) \ --env HTTPS_PROXY=$(HTTPS_PROXY) \ $(BUILD_IMAGE) \ - ltag -t "./hack/license" --excludes "vendor contrib" -v + ltag -t "./hack/license" --excludes "vendor contrib bin" -v .PHONY: check-license check-license: - @echo "Checking files for license header" + @echo "Checking files have proper license header" @docker run --rm \ -u $$(id -u):$$(id -g) \ -v /tmp:/.cache \ @@ -268,7 +370,7 @@ check-license: --env HTTP_PROXY=$(HTTP_PROXY) \ --env HTTPS_PROXY=$(HTTPS_PROXY) \ $(BUILD_IMAGE) \ - ltag -t "./hack/license" --excludes "vendor contrib" --check -v + ltag -t "./hack/license" --excludes "vendor contrib bin" --check -v .PHONY: ci ci: verify check-license lint build unit-tests #cover @@ -283,7 +385,7 @@ qa: echo "Are you trying to 'release' binaries to prod?"; \ exit 1; \ fi - @$(MAKE) clean all-build --no-print-directory + @$(MAKE) clean all-build all-push docker-manifest --no-print-directory .PHONY: release release: @@ -295,8 +397,20 @@ release: echo "apply tag to release binaries and/or docker images."; \ exit 1; \ fi - @$(MAKE) clean all-build --no-print-directory + @$(MAKE) clean all-build all-push docker-manifest --no-print-directory .PHONY: clean clean: rm -rf .go bin + +.PHONY: push-to-kind +push-to-kind: container + @echo "Loading docker image into kind cluster...." + @kind load docker-image $(IMAGE):$(TAG_PROD) + @echo "Image has been pushed successfully into kind cluster." + +.PHONY: deploy-to-kind +deploy-to-kind: push-to-kind install + +.PHONY: deploy +deploy: uninstall push install