diff --git a/.github/dependabot.yaml b/.github/dependabot.yaml new file mode 100644 index 0000000..81b9297 --- /dev/null +++ b/.github/dependabot.yaml @@ -0,0 +1,20 @@ +# THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. +# Edit https://github.com/cert-manager/makefile-modules/blob/main/modules/repository-base/base/.github/dependabot.yaml instead. + +# Update Go dependencies and GitHub Actions dependencies daily. +version: 2 +updates: +- package-ecosystem: gomod + directory: / + schedule: + interval: daily + groups: + all: + patterns: ["*"] +- package-ecosystem: github-actions + directory: / + schedule: + interval: daily + groups: + all: + patterns: ["*"] diff --git a/.github/workflows/goreleaser.yaml b/.github/workflows/goreleaser.yaml deleted file mode 100644 index f15aeb7..0000000 --- a/.github/workflows/goreleaser.yaml +++ /dev/null @@ -1,53 +0,0 @@ -name: GoReleaser - -on: - pull_request: - push: - tags: - - "*" - -permissions: - contents: write # needed to update the data of a release - packages: write - -jobs: - goreleaser: - name: Release - runs-on: ubuntu-latest - steps: - - name: Checkout repository - uses: actions/checkout@v3 - with: - fetch-depth: 0 - - name: Fetch all tags - run: git fetch --force --tags - - name: Install Go - uses: actions/setup-go@v4 - with: - # The reason we don't use `go-version: go.mod` is because go.mod's - # version is the minimal required version. But for building the - # binaries, we want to use a Go version that is still supported. - go-version: "^1.21" - - uses: docker/login-action@v2 - with: - registry: ghcr.io - username: ${{ github.actor }} - password: ${{ secrets.GITHUB_TOKEN }} - - name: Run GoReleaser (PR) - uses: goreleaser/goreleaser-action@v4 - if: "!startsWith(github.ref, 'refs/tags')" # runs on a PR - with: - distribution: goreleaser - version: latest - args: release --snapshot - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - name: Run GoReleaser (Publish Release) - uses: goreleaser/goreleaser-action@v4 - if: "startsWith(github.ref, 'refs/tags')" # runs on a Tag being pushed - with: - distribution: goreleaser - version: latest - args: release - env: - GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/govulncheck.yaml b/.github/workflows/govulncheck.yaml new file mode 100644 index 0000000..405e8de --- /dev/null +++ b/.github/workflows/govulncheck.yaml @@ -0,0 +1,28 @@ +# THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. +# Edit https://github.com/cert-manager/makefile-modules/blob/main/modules/go/base/.github/workflows/govulncheck.yaml instead. + +# Run govulncheck at midnight every night on the main branch, +# to alert us to recent vulnerabilities which affect the Go code in this +# project. +name: govulncheck +on: + workflow_dispatch: {} + schedule: + - cron: '0 0 * * *' + +jobs: + govulncheck: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - id: go-version + run: | + make print-go-version >> "$GITHUB_OUTPUT" + + - uses: actions/setup-go@v5 + with: + go-version: ${{ steps.go-version.outputs.result }} + + - run: make verify-govulncheck diff --git a/.github/workflows/make-self-upgrade.yaml b/.github/workflows/make-self-upgrade.yaml new file mode 100644 index 0000000..93beedf --- /dev/null +++ b/.github/workflows/make-self-upgrade.yaml @@ -0,0 +1,90 @@ +# THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. +# Edit https://github.com/cert-manager/makefile-modules/blob/main/modules/repository-base/base/.github/workflows/make-self-upgrade.yaml instead. + +name: make-self-upgrade +concurrency: make-self-upgrade +on: + workflow_dispatch: {} + schedule: + - cron: '0 0 * * *' + +jobs: + self_upgrade: + runs-on: ubuntu-latest + + permissions: + contents: write + pull-requests: write + + env: + SOURCE_BRANCH: "${{ github.ref_name }}" + SELF_UPGRADE_BRANCH: "self-upgrade-${{ github.ref_name }}" + + steps: + - name: Fail if branch is not head of branch. + if: ${{ !startsWith(github.ref, 'refs/heads/') && env.SOURCE_BRANCH != '' && env.SELF_UPGRADE_BRANCH != '' }} + run: | + echo "This workflow should not be run on a non-branch-head." + exit 1 + + - uses: actions/checkout@v4 + + - id: go-version + run: | + make print-go-version >> "$GITHUB_OUTPUT" + + - uses: actions/setup-go@v5 + with: + go-version: ${{ steps.go-version.outputs.result }} + + - run: | + git checkout -B "$SELF_UPGRADE_BRANCH" + + - run: | + make -j upgrade-klone + make -j generate + + - id: is-up-to-date + shell: bash + run: | + git_status=$(git status -s) + is_up_to_date="true" + if [ -n "$git_status" ]; then + is_up_to_date="false" + echo "The following changes will be committed:" + echo "$git_status" + fi + echo "result=$is_up_to_date" >> "$GITHUB_OUTPUT" + + - if: ${{ steps.is-up-to-date.outputs.result != 'true' }} + run: | + git config --global user.name "cert-manager-bot" + git config --global user.email "cert-manager-bot@users.noreply.github.com" + git add -A && git commit -m "BOT: run 'make upgrade-klone' and 'make generate'" --signoff + git push -f origin "$SELF_UPGRADE_BRANCH" + + - if: ${{ steps.is-up-to-date.outputs.result != 'true' }} + uses: actions/github-script@v7 + with: + script: | + const { repo, owner } = context.repo; + const pulls = await github.rest.pulls.list({ + owner: owner, + repo: repo, + head: owner + ':' + process.env.SELF_UPGRADE_BRANCH, + base: process.env.SOURCE_BRANCH, + state: 'open', + }); + + if (pulls.data.length < 1) { + await github.rest.pulls.create({ + title: '[CI] Merge ' + process.env.SELF_UPGRADE_BRANCH + ' into ' + process.env.SOURCE_BRANCH, + owner: owner, + repo: repo, + head: process.env.SELF_UPGRADE_BRANCH, + base: process.env.SOURCE_BRANCH, + body: [ + 'This PR is auto-generated to bump the Makefile modules.', + ].join('\n'), + }); + } diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml new file mode 100644 index 0000000..729886f --- /dev/null +++ b/.github/workflows/release.yaml @@ -0,0 +1,85 @@ +name: release +on: + push: + tags: + - "v*" + +env: + VERSION: ${{ github.ref_name }} + +jobs: + build_images: + runs-on: ubuntu-latest + + permissions: + contents: read # needed for checkout + packages: write # needed for push images + id-token: write # needed for keyless signing + + steps: + - uses: actions/checkout@v4 + + - id: go-version + run: | + make print-go-version >> "$GITHUB_OUTPUT" + + - uses: docker/login-action@v2 + with: + registry: ghcr.io + username: ${{ github.actor }} + password: ${{ secrets.GITHUB_TOKEN }} + + - uses: actions/setup-go@v5 + with: + go-version: ${{ steps.go-version.outputs.result }} + + - id: release + run: make release + + - uses: actions/upload-artifact@v4 + with: + name: ${{ steps.release.outputs.RELEASE_HELM_CHART_NAME }}-${{ steps.release.outputs.RELEASE_HELM_CHART_VERSION }}.tgz + path: ${{ steps.release.outputs.RELEASE_HELM_CHART_TAR }} + if-no-files-found: error + + outputs: + RELEASE_OCI_MANAGER_IMAGE: ${{ steps.release.outputs.RELEASE_OCI_MANAGER_IMAGE }} + RELEASE_OCI_MANAGER_TAG: ${{ steps.release.outputs.RELEASE_OCI_MANAGER_TAG }} + RELEASE_HELM_CHART_NAME: ${{ steps.release.outputs.RELEASE_HELM_CHART_NAME }} + RELEASE_HELM_CHART_VERSION: ${{ steps.release.outputs.RELEASE_HELM_CHART_VERSION }} + + github_release: + runs-on: ubuntu-latest + + needs: build_images + + permissions: + contents: write # needed for creating a PR + pull-requests: write # needed for creating a PR + + steps: + - run: | + touch .notes-file + echo "OCI_MANAGER_IMAGE: ${{ needs.build_images.outputs.RELEASE_OCI_MANAGER_IMAGE }}" >> .notes-file + echo "OCI_MANAGER_TAG: ${{ needs.build_images.outputs.RELEASE_OCI_MANAGER_TAG }}" >> .notes-file + echo "HELM_CHART_NAME: ${{ needs.build_images.outputs.RELEASE_HELM_CHART_NAME }}" >> .notes-file + echo "HELM_CHART_VERSION: ${{ needs.build_images.outputs.RELEASE_HELM_CHART_VERSION }}" >> .notes-file + + - id: chart_download + uses: actions/download-artifact@v4 + with: + name: ${{ needs.build_images.outputs.RELEASE_HELM_CHART_NAME }}-${{ needs.build_images.outputs.RELEASE_HELM_CHART_VERSION }}.tgz + + - env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + gh release create "$VERSION" \ + --repo="$GITHUB_REPOSITORY" \ + --title="${VERSION}" \ + --draft \ + --verify-tag \ + --notes-file .notes-file + + gh release upload "$VERSION" \ + --repo="$GITHUB_REPOSITORY" \ + "${{ steps.chart_download.outputs.download-path }}/${{ needs.build_images.outputs.RELEASE_HELM_CHART_NAME }}-${{ needs.build_images.outputs.RELEASE_HELM_CHART_VERSION }}.tgz" \ No newline at end of file diff --git a/.gitignore b/.gitignore index 1521c8b..40111d3 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,27 @@ -dist +# Binaries for programs and plugins +*.exe +*.exe~ +*.dll +*.so +*.dylib +_bin +bin + +# Test binary, build with `go test -c` +*.test + +# Output of the go coverage tool, specifically when used with LiteIDE +*.out + +# Kubernetes Generated files - skip generated files, except for vendored files + +!vendor/**/zz_generated.* + +# editor and IDE paraphernalia +.idea +*.iml +*.swp +*.swo +*~ + +.vscode diff --git a/.golangci.yaml b/.golangci.yaml new file mode 100644 index 0000000..0f83386 --- /dev/null +++ b/.golangci.yaml @@ -0,0 +1,80 @@ +issues: + exclude-rules: + - linters: + - errcheck + - unconvert + - unparam + - dupword + - gosimple + - nilerr + - nilnil + text: ".*" +linters: + # Explicitly define all enabled linters + disable-all: true + enable: + - asasalint + - asciicheck + - bidichk + - bodyclose + - contextcheck + - decorder + - dogsled + - dupword + - durationcheck + - errcheck + - errchkjson + - errname + - execinquery + - exhaustive + - exportloopref + - forbidigo + - gci + - ginkgolinter + - gocheckcompilerdirectives + - gochecksumtype + - gocritic + - gofmt + - goheader + - goprintffuncname + - gosec + - gosimple + - gosmopolitan + - govet + - grouper + - importas + - ineffassign + - interfacebloat + - loggercheck + - makezero + - mirror + - misspell + - musttag + - nakedret + - nilerr + - nilnil + - noctx + - nosprintfhostport + - predeclared + - promlinter + - protogetter + - reassign + - sloglint + - staticcheck + - tagalign + - tenv + - testableexamples + - typecheck + - unconvert + - unparam + - unused + - usestdlibvars + - wastedassign +linters-settings: + gci: + sections: + - standard # Standard section: captures all standard packages. + - default # Default section: contains all imports that could not be matched to another section type. + - prefix(github.com/cert-manager/openshift-routes) # Custom section: groups all imports with the specified Prefix. + - blank # Blank section: contains all blank imports. This section is not present unless explicitly enabled. + - dot # Dot section: contains all dot imports. This section is not present unless explicitly enabled. diff --git a/.goreleaser.yaml b/.goreleaser.yaml deleted file mode 100644 index fe4b96e..0000000 --- a/.goreleaser.yaml +++ /dev/null @@ -1,143 +0,0 @@ -project_name: cert-manager-openshift-routes -before: - hooks: - - go test -v ./... - # update static manifests - - ./hack/generate-static-manifest.sh {{ .Version }} - # update and package new Helm chart - - helm package ./deploy/chart --version {{ trimprefix .Version "v"}} --app-version {{ .Version }} - # upload Helm chart as OCI artifact to GitHub Container Registry - - '{{if .IsSnapshot}}echo SKIPPING: {{end}}helm push ./openshift-routes-{{ trimprefix .Version "v"}}.tgz oci://ghcr.io/cert-manager/charts' - -builds: - - id: cert-manager-openshift-routes - main: ./internal/cmd - binary: cert-manager-openshift-routes - env: - - CGO_ENABLED=0 - goos: - - linux - goarch: - - amd64 - - arm - - arm64 - - s390x - - riscv64 - - ppc64le - goarm: - - "6" - - "7" -archives: - - format: tar.gz - format_overrides: - - goos: windows - format: zip - files: - - LICENSE -dockers: - - id: cert-manager-openshift-routes-amd64 - goarch: amd64 - image_templates: - - ghcr.io/cert-manager/cert-manager-openshift-routes:{{ .Version }}-amd64 - use: buildx - dockerfile: internal/cmd/Dockerfile - build_flag_templates: - - "--platform=linux/amd64" - - "--label=org.opencontainers.image.created={{.Date}}" - - "--label=org.opencontainers.image.title={{.ProjectName}}" - - "--label=org.opencontainers.image.revision={{.FullCommit}}" - - "--label=org.opencontainers.image.version={{.Version}}" - - id: cert-manager-openshift-routes-arm64 - goarch: arm64 - image_templates: - - ghcr.io/cert-manager/cert-manager-openshift-routes:{{ .Version }}-arm64 - use: buildx - dockerfile: internal/cmd/Dockerfile - build_flag_templates: - - "--platform=linux/arm64" - - "--label=org.opencontainers.image.created={{.Date}}" - - "--label=org.opencontainers.image.title={{.ProjectName}}" - - "--label=org.opencontainers.image.revision={{.FullCommit}}" - - "--label=org.opencontainers.image.version={{.Version}}" - - id: cert-manager-openshift-routes-armv6 - goarch: arm - goarm: "6" - image_templates: - - ghcr.io/cert-manager/cert-manager-openshift-routes:{{ .Version }}-armv6 - use: buildx - dockerfile: internal/cmd/Dockerfile - build_flag_templates: - - "--platform=linux/arm/v6" - - "--label=org.opencontainers.image.created={{.Date}}" - - "--label=org.opencontainers.image.title={{.ProjectName}}" - - "--label=org.opencontainers.image.revision={{.FullCommit}}" - - "--label=org.opencontainers.image.version={{.Version}}" - - id: cert-manager-openshift-routes-armv7 - goarch: arm - goarm: "7" - image_templates: - - ghcr.io/cert-manager/cert-manager-openshift-routes:{{ .Version }}-armv7 - use: buildx - dockerfile: internal/cmd/Dockerfile - build_flag_templates: - - "--platform=linux/arm/v7" - - "--label=org.opencontainers.image.created={{.Date}}" - - "--label=org.opencontainers.image.title={{.ProjectName}}" - - "--label=org.opencontainers.image.revision={{.FullCommit}}" - - "--label=org.opencontainers.image.version={{.Version}}" - - id: cert-manager-openshift-routes-s390x - goarch: s390x - image_templates: - - ghcr.io/cert-manager/cert-manager-openshift-routes:{{ .Version }}-s390x - use: buildx - dockerfile: internal/cmd/Dockerfile - build_flag_templates: - - "--platform=linux/s390x" - - "--label=org.opencontainers.image.created={{.Date}}" - - "--label=org.opencontainers.image.title={{.ProjectName}}" - - "--label=org.opencontainers.image.revision={{.FullCommit}}" - - "--label=org.opencontainers.image.version={{.Version}}" - - id: cert-manager-openshift-routes-riscv64 - goarch: riscv64 - image_templates: - - ghcr.io/cert-manager/cert-manager-openshift-routes:{{ .Version }}-riscv64 - use: buildx - dockerfile: internal/cmd/Dockerfile - build_flag_templates: - - "--platform=linux/riscv64" - - "--label=org.opencontainers.image.created={{.Date}}" - - "--label=org.opencontainers.image.title={{.ProjectName}}" - - "--label=org.opencontainers.image.revision={{.FullCommit}}" - - "--label=org.opencontainers.image.version={{.Version}}" - - id: cert-manager-openshift-routes-ppc64le - goarch: ppc64le - image_templates: - - ghcr.io/cert-manager/cert-manager-openshift-routes:{{ .Version }}-ppc64le - use: buildx - dockerfile: internal/cmd/Dockerfile - build_flag_templates: - - "--platform=linux/ppc64le" - - "--label=org.opencontainers.image.created={{.Date}}" - - "--label=org.opencontainers.image.title={{.ProjectName}}" - - "--label=org.opencontainers.image.revision={{.FullCommit}}" - - "--label=org.opencontainers.image.version={{.Version}}" -docker_manifests: - - name_template: ghcr.io/cert-manager/cert-manager-openshift-routes:{{ .Version }} - image_templates: - - ghcr.io/cert-manager/cert-manager-openshift-routes:{{ .Version }}-amd64 - - ghcr.io/cert-manager/cert-manager-openshift-routes:{{ .Version }}-arm64 - - ghcr.io/cert-manager/cert-manager-openshift-routes:{{ .Version }}-armv6 - - ghcr.io/cert-manager/cert-manager-openshift-routes:{{ .Version }}-armv7 - - ghcr.io/cert-manager/cert-manager-openshift-routes:{{ .Version }}-s390x - - ghcr.io/cert-manager/cert-manager-openshift-routes:{{ .Version }}-riscv64 - - ghcr.io/cert-manager/cert-manager-openshift-routes:{{ .Version }}-ppc64le -checksum: - name_template: "checksums.txt" -release: - draft: true - replace_existing_draft: true - extra_files: - - glob: ./cert-manager-openshift-routes-*.yaml - name_template: cert-manager-openshift-routes.yaml - - glob: ./openshift-routes-*.tgz - name_template: openshift-routes-chart.tgz diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..6c5aa12 --- /dev/null +++ b/Makefile @@ -0,0 +1,116 @@ +# Copyright 2023 The cert-manager 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. + +# THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. +# Edit https://github.com/cert-manager/makefile-modules/blob/main/modules/repository-base/base/Makefile instead. + +# NOTE FOR DEVELOPERS: "How do the Makefiles work and how can I extend them?" +# +# Shared Makefile logic lives in the make/_shared/ directory. The source of truth for these files +# lies outside of this repository, eg. in the cert-manager/makefile-modules repository. +# +# Logic specific to this repository must be defined in the make/00_mod.mk and make/02_mod.mk files: +# - The make/00_mod.mk file is included first and contains variable definitions needed by +# the shared Makefile logic. +# - The make/02_mod.mk file is included later, it can make use of most of the shared targets +# defined in the make/_shared/ directory (all targets defined in 00_mod.mk and 01_mod.mk). +# This file should be used to define targets specific to this repository. + +################################## + +# Some modules build their dependencies from variables, we want these to be +# evalutated at the last possible moment. For this we use second expansion to +# re-evaluate the generate and verify targets a second time. +# +# See https://www.gnu.org/software/make/manual/html_node/Secondary-Expansion.html +.SECONDEXPANSION: + +# For details on some of these "prelude" settings, see: +# https://clarkgrubb.com/makefile-style-guide +MAKEFLAGS += --warn-undefined-variables --no-builtin-rules +SHELL := /usr/bin/env bash +.SHELLFLAGS := -uo pipefail -c +.DEFAULT_GOAL := help +.DELETE_ON_ERROR: +.SUFFIXES: +FORCE: + +noop: # do nothing + +# Set empty value for MAKECMDGOALS to prevent the "warning: undefined variable 'MAKECMDGOALS'" +# warning from happening when running make without arguments +MAKECMDGOALS ?= + +################################## +# Host OS and architecture setup # +################################## + +# The reason we don't use "go env GOOS" or "go env GOARCH" is that the "go" +# binary may not be available in the PATH yet when the Makefiles are +# evaluated. HOST_OS and HOST_ARCH only support Linux, *BSD and macOS (M1 +# and Intel). +host_os := $(shell uname -s | tr A-Z a-z) +host_arch := $(shell uname -m) +HOST_OS ?= $(host_os) +HOST_ARCH ?= $(host_arch) + +ifeq (x86_64, $(HOST_ARCH)) + HOST_ARCH = amd64 +else ifeq (aarch64, $(HOST_ARCH)) + # linux reports the arm64 arch as aarch64 + HOST_ARCH = arm64 +endif + +################################## +# Git and versioning information # +################################## + +git_version := $(shell git describe --tags --always --match='v*' --abbrev=14 --dirty) +VERSION ?= $(git_version) +IS_PRERELEASE := $(shell git describe --tags --always --match='v*' --abbrev=0 | grep -q '-' && echo true || echo false) +GITCOMMIT := $(shell git rev-parse HEAD) +GITEPOCH := $(shell git show -s --format=%ct HEAD) + +################################## +# Global variables and dirs # +################################## + +bin_dir := _bin + +# The ARTIFACTS environment variable is set by the CI system to a directory +# where artifacts should be placed. These artifacts are then uploaded to a +# storage bucket by the CI system (https://docs.prow.k8s.io/docs/components/pod-utilities/). +# An example of such an artifact is a jUnit XML file containing test results. +# If the ARTIFACTS environment variable is not set, we default to a local +# directory in the _bin directory. +ARTIFACTS ?= $(bin_dir)/artifacts + +$(bin_dir) $(ARTIFACTS) $(bin_dir)/scratch: + mkdir -p $@ + +.PHONY: clean +## Clean all temporary files +## @category [shared] Tools +clean: + rm -rf $(bin_dir) + +################################## +# Include all the Makefiles # +################################## + +-include make/00_mod.mk +-include make/_shared/*/00_mod.mk +-include make/_shared/*/01_mod.mk +-include make/02_mod.mk +-include make/_shared/*/02_mod.mk diff --git a/OWNERS b/OWNERS index 6807d01..a3da4dd 100644 --- a/OWNERS +++ b/OWNERS @@ -1,15 +1,4 @@ approvers: -- munnerz -- joshvanl -- wallrj -- jakexks -- maelvls -- irbekrm -- sgtcodfish +- cm-maintainers reviewers: -- joshvanl -- wallrj -- jakexks -- maelvls -- irbekrm -- sgtcodfish +- cm-maintainers diff --git a/OWNERS_ALIASES b/OWNERS_ALIASES new file mode 100644 index 0000000..10d1279 --- /dev/null +++ b/OWNERS_ALIASES @@ -0,0 +1,14 @@ +# THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. +# Edit https://github.com/cert-manager/makefile-modules/blob/main/modules/repository-base/base/OWNERS_ALIASES instead. + +aliases: + cm-maintainers: + - munnerz + - joshvanl + - wallrj + - jakexks + - maelvls + - irbekrm + - sgtcodfish + - inteon + - thatsmrtalbot diff --git a/deploy/chart/Chart.yaml b/deploy/chart/Chart.yaml deleted file mode 100644 index 5207a95..0000000 --- a/deploy/chart/Chart.yaml +++ /dev/null @@ -1,12 +0,0 @@ -apiVersion: v2 -name: openshift-routes -description: A Helm chart to deploy openshift-routes adapter for cert-manager on Kubernetes -type: application - -# This is the chart version. This version number should be incremented each time you make changes -# to the chart and its templates, including the app version. -# Versions are expected to follow Semantic Versioning (https://semver.org/) -version: 0.1.0 - -# This is the version of the application, i.e. openshift-routes -appVersion: 0.2.0 diff --git a/deploy/chart/values.yaml b/deploy/chart/values.yaml deleted file mode 100644 index 2990d56..0000000 --- a/deploy/chart/values.yaml +++ /dev/null @@ -1,83 +0,0 @@ -# Default values for openshift-routes. - -replicas: 1 -logLevel: 5 -nameOverride: "" -fullnameOverride: "" - -# This namespace allows you to define where the services are installed into. -# If not set then they use the namespace of the release. -# This is helpful when installing cert manager as a chart dependency (sub chart). -namespace: "" - -image: - # https://github.com/cert-manager/openshift-routes/pkgs/container/cert-manager-openshift-routes - # the final image is generated as "${registry}/${repostiory}:${tag|digest}" - - # -- Target image repository. - repository: ghcr.io/cert-manager/cert-manager-openshift-routes - # -- Target image registry. Will be prepended to the target image repositry if set. - registry: - - # -- Target image version tag. Defaults to the chart's appVersion. - tag: - - # -- Target image digest. Will override any tag if set. - # for example: - # digest: sha256:0e072dddd1f7f8fc8909a2ca6f65e76c5f0d2fcfb8be47935ae3457e8bbceb20 - digest: - - -imagePullSecrets: [] - -serviceAccount: - # Specifies whether a service account should be created - create: true - # Annotations to add to the service account - annotations: {} - # The name of the service account to use. - # If not set and create is true, a name is generated using the fullname template - name: "" - -rbac: - # create (Cluster-) Roles and RoleBindings for the ServiceAccount - create: true - -podAnnotations: {} - -podSecurityContext: {} - # fsGroup: 2000 - -securityContext: {} - # capabilities: - # drop: - # - ALL - # readOnlyRootFilesystem: true - # runAsNonRoot: true - # runAsUser: 1000 - -resources: {} - # We usually recommend not to specify default resources and to leave this as a conscious - # choice for the user. This also increases chances charts run on environments with little - # resources, such as Minikube. If you do want to specify resources, uncomment the following - # lines, adjust them as necessary, and remove the curly braces after 'resources:'. - # limits: - # cpu: 100m - # memory: 128Mi - # requests: - # cpu: 100m - # memory: 128Mi - -nodeSelector: {} - -tolerations: [] - -affinity: {} - -metrics: - # when enabled, a service is created that exposes the metrics endpoint - enabled: false - serviceMonitor: - # when enabled, a ServiceMonitor object is created - note that his requires the monitoring.coreos.com CRDs! - enabled: false - interval: 60s diff --git a/deploy/chart/.helmignore b/deploy/charts/openshift-routes/.helmignore similarity index 100% rename from deploy/chart/.helmignore rename to deploy/charts/openshift-routes/.helmignore diff --git a/deploy/charts/openshift-routes/Chart.yaml b/deploy/charts/openshift-routes/Chart.yaml new file mode 100644 index 0000000..9b5d51d --- /dev/null +++ b/deploy/charts/openshift-routes/Chart.yaml @@ -0,0 +1,27 @@ +apiVersion: v2 + +name: openshift-routes +type: application +description: A Helm chart to deploy openshift-routes adapter for cert-manager on Kubernetes + +home: https://github.com/cert-manager/openshift-routes +icon: https://raw.githubusercontent.com/cert-manager/community/4d35a69437d21b76322157e6284be4cd64e6d2b7/logo/logo-small.png +keywords: +- cert-manager +- openshift +- routes +annotations: + artifacthub.io/alternativeName: openshift-routes + artifacthub.io/license: Apache-2.0 + artifacthub.io/category: security + artifacthub.io/recommendations: | + - url: https://artifacthub.io/packages/helm/cert-manager/cert-manager +maintainers: +- name: cert-manager-maintainers + email: cert-manager-maintainers@googlegroups.com + url: https://cert-manager.io +sources: +- https://github.com/cert-manager/openshift-routes + +appVersion: v0.0.0 +version: v0.0.0 \ No newline at end of file diff --git a/deploy/charts/openshift-routes/README.md b/deploy/charts/openshift-routes/README.md new file mode 100644 index 0000000..acf23b1 --- /dev/null +++ b/deploy/charts/openshift-routes/README.md @@ -0,0 +1,220 @@ +# cert-manager Openshift Routes + + + +## Helm Values + + + +#### **replicas** ~ `number` +> Default value: +> ```yaml +> 1 +> ``` +#### **logLevel** ~ `number` +> Default value: +> ```yaml +> 5 +> ``` +#### **namespace** ~ `string` +> Default value: +> ```yaml +> "" +> ``` + +This namespace allows you to define where the services are installed into. If not set then they use the namespace of the release. This is helpful when installing cert manager as a chart dependency (sub chart). +#### **fullnameOverride** ~ `string` + +Override the "cert-manager.fullname" value. This value is used as part of most of the names of the resources created by this Helm chart. + +#### **nameOverride** ~ `string` + +Override the "cert-manager.name" value, which is used to annotate some of the resources that are created by this Chart (using "app.kubernetes.io/name"). NOTE: There are some inconsitencies in the Helm chart when it comes to these annotations (some resources use eg. "cainjector.name" which resolves to the value "cainjector"). + +#### **image.registry** ~ `string` + +Target image registry. This value is prepended to the target image repository, if set. +For example: + +```yaml +registry: quay.io +repository: jetstack/cert-manager-openshift-routes +``` + +#### **image.repository** ~ `string` +> Default value: +> ```yaml +> ghcr.io/cert-manager/cert-manager-openshift-routes +> ``` + +Target image repository. +#### **image.tag** ~ `string` + +Override the image tag to deploy by setting this variable. If no value is set, the chart's appVersion is used. + +#### **image.digest** ~ `string` + +Target image digest. Override any tag, if set. +For example: + +```yaml +digest: sha256:0e072dddd1f7f8fc8909a2ca6f65e76c5f0d2fcfb8be47935ae3457e8bbceb20 +``` + +#### **image.pullPolicy** ~ `string` +> Default value: +> ```yaml +> IfNotPresent +> ``` + +Kubernetes imagePullPolicy on Deployment. +#### **imagePullSecrets** ~ `array` +> Default value: +> ```yaml +> [] +> ``` + +Optional secrets used for pulling the openshift-routes container image. +#### **serviceAccount.create** ~ `bool` +> Default value: +> ```yaml +> true +> ``` + +Specifies whether a service account should be created +#### **serviceAccount.name** ~ `string` + +The name of the service account to use. +If not set and create is true, a name is generated using the fullname template. + +#### **serviceAccount.annotations** ~ `object` + +Optional additional annotations to add to the controller's Service Account. + +#### **rbac.create** ~ `bool` +> Default value: +> ```yaml +> true +> ``` + +create (Cluster-) Roles and RoleBindings for the ServiceAccount +#### **podAnnotations** ~ `object` +> Default value: +> ```yaml +> {} +> ``` + +Annotations to add to the openshift-routes pod. +#### **podSecurityContext** ~ `object` +> Default value: +> ```yaml +> runAsNonRoot: true +> seccompProfile: +> type: RuntimeDefault +> ``` + +Pod Security Context. +For more information, see [Configure a Security Context for a Pod or Container](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/). + +#### **securityContext** ~ `object` +> Default value: +> ```yaml +> allowPrivilegeEscalation: false +> capabilities: +> drop: +> - ALL +> readOnlyRootFilesystem: true +> ``` + +Container Security Context to be set on the controller component container. For more information, see [Configure a Security Context for a Pod or Container](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/). + +#### **resources** ~ `object` +> Default value: +> ```yaml +> {} +> ``` + +Kubernetes pod resources +ref: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ + +For example: + +```yaml +resources: + limits: + memory: 128Mi + requests: + cpu: 100m + memory: 128Mi +``` +#### **nodeSelector** ~ `object` +> Default value: +> ```yaml +> kubernetes.io/os: linux +> ``` + +The nodeSelector on Pods tells Kubernetes to schedule Pods on the nodes with matching labels. For more information, see [Assigning Pods to Nodes](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/). + +This default ensures that Pods are only scheduled to Linux nodes. It prevents Pods being scheduled to Windows nodes in a mixed OS cluster. + +#### **tolerations** ~ `array` +> Default value: +> ```yaml +> [] +> ``` + +A list of Kubernetes Tolerations, if required. For more information, see [Toleration v1 core](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#toleration-v1-core). + +For example: + +```yaml +tolerations: +- key: foo.bar.com/role + operator: Equal + value: master + effect: NoSchedule +``` +#### **affinity** ~ `object` +> Default value: +> ```yaml +> {} +> ``` + +A Kubernetes Affinity, if required. For more information, see [Affinity v1 core](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#affinity-v1-core). + +For example: + +```yaml +affinity: + nodeAffinity: + requiredDuringSchedulingIgnoredDuringExecution: + nodeSelectorTerms: + - matchExpressions: + - key: foo.bar.com/role + operator: In + values: + - master +``` +#### **metrics.enabled** ~ `bool` +> Default value: +> ```yaml +> false +> ``` + +when enabled, a service is created that exposes the metrics endpoint +#### **metrics.serviceMonitor.enabled** ~ `bool` +> Default value: +> ```yaml +> false +> ``` + +Create a ServiceMonitor to add openshift-routes to Prometheus. +#### **metrics.serviceMonitor.interval** ~ `string` +> Default value: +> ```yaml +> 60s +> ``` + +The interval to scrape metrics. + + \ No newline at end of file diff --git a/deploy/chart/templates/_helpers.tpl b/deploy/charts/openshift-routes/templates/_helpers.tpl similarity index 98% rename from deploy/chart/templates/_helpers.tpl rename to deploy/charts/openshift-routes/templates/_helpers.tpl index 9551bee..b253bc6 100644 --- a/deploy/chart/templates/_helpers.tpl +++ b/deploy/charts/openshift-routes/templates/_helpers.tpl @@ -1,3 +1,4 @@ +{{/* vim: set filetype=mustache: */}} {{/* Expand the name of the chart. */}} diff --git a/deploy/chart/templates/deployment.yaml b/deploy/charts/openshift-routes/templates/deployment.yaml similarity index 100% rename from deploy/chart/templates/deployment.yaml rename to deploy/charts/openshift-routes/templates/deployment.yaml diff --git a/deploy/chart/templates/rbac.yaml b/deploy/charts/openshift-routes/templates/rbac.yaml similarity index 100% rename from deploy/chart/templates/rbac.yaml rename to deploy/charts/openshift-routes/templates/rbac.yaml diff --git a/deploy/chart/templates/service.yaml b/deploy/charts/openshift-routes/templates/service.yaml similarity index 100% rename from deploy/chart/templates/service.yaml rename to deploy/charts/openshift-routes/templates/service.yaml diff --git a/deploy/chart/templates/serviceaccount.yaml b/deploy/charts/openshift-routes/templates/serviceaccount.yaml similarity index 100% rename from deploy/chart/templates/serviceaccount.yaml rename to deploy/charts/openshift-routes/templates/serviceaccount.yaml diff --git a/deploy/chart/templates/servicemonitor.yaml b/deploy/charts/openshift-routes/templates/servicemonitor.yaml similarity index 100% rename from deploy/chart/templates/servicemonitor.yaml rename to deploy/charts/openshift-routes/templates/servicemonitor.yaml diff --git a/deploy/charts/openshift-routes/values.linter.exceptions b/deploy/charts/openshift-routes/values.linter.exceptions new file mode 100644 index 0000000..e69de29 diff --git a/deploy/charts/openshift-routes/values.schema.json b/deploy/charts/openshift-routes/values.schema.json new file mode 100644 index 0000000..27cb457 --- /dev/null +++ b/deploy/charts/openshift-routes/values.schema.json @@ -0,0 +1,271 @@ +{ + "$defs": { + "helm-values": { + "additionalProperties": false, + "properties": { + "affinity": { + "$ref": "#/$defs/helm-values.affinity" + }, + "fullnameOverride": { + "$ref": "#/$defs/helm-values.fullnameOverride" + }, + "global": { + "$ref": "#/$defs/helm-values.global" + }, + "image": { + "$ref": "#/$defs/helm-values.image" + }, + "imagePullSecrets": { + "$ref": "#/$defs/helm-values.imagePullSecrets" + }, + "logLevel": { + "$ref": "#/$defs/helm-values.logLevel" + }, + "metrics": { + "$ref": "#/$defs/helm-values.metrics" + }, + "nameOverride": { + "$ref": "#/$defs/helm-values.nameOverride" + }, + "namespace": { + "$ref": "#/$defs/helm-values.namespace" + }, + "nodeSelector": { + "$ref": "#/$defs/helm-values.nodeSelector" + }, + "podAnnotations": { + "$ref": "#/$defs/helm-values.podAnnotations" + }, + "podSecurityContext": { + "$ref": "#/$defs/helm-values.podSecurityContext" + }, + "rbac": { + "$ref": "#/$defs/helm-values.rbac" + }, + "replicas": { + "$ref": "#/$defs/helm-values.replicas" + }, + "resources": { + "$ref": "#/$defs/helm-values.resources" + }, + "securityContext": { + "$ref": "#/$defs/helm-values.securityContext" + }, + "serviceAccount": { + "$ref": "#/$defs/helm-values.serviceAccount" + }, + "tolerations": { + "$ref": "#/$defs/helm-values.tolerations" + } + }, + "type": "object" + }, + "helm-values.affinity": { + "default": {}, + "description": "A Kubernetes Affinity, if required. For more information, see [Affinity v1 core](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#affinity-v1-core).\n\nFor example:\naffinity:\n nodeAffinity:\n requiredDuringSchedulingIgnoredDuringExecution:\n nodeSelectorTerms:\n - matchExpressions:\n - key: foo.bar.com/role\n operator: In\n values:\n - master", + "type": "object" + }, + "helm-values.fullnameOverride": { + "description": "Override the \"cert-manager.fullname\" value. This value is used as part of most of the names of the resources created by this Helm chart.", + "type": "string" + }, + "helm-values.global": { + "description": "Global values shared across all (sub)charts" + }, + "helm-values.image": { + "additionalProperties": false, + "properties": { + "digest": { + "$ref": "#/$defs/helm-values.image.digest" + }, + "pullPolicy": { + "$ref": "#/$defs/helm-values.image.pullPolicy" + }, + "registry": { + "$ref": "#/$defs/helm-values.image.registry" + }, + "repository": { + "$ref": "#/$defs/helm-values.image.repository" + }, + "tag": { + "$ref": "#/$defs/helm-values.image.tag" + } + }, + "type": "object" + }, + "helm-values.image.digest": { + "description": "Target image digest. Override any tag, if set.\nFor example:\ndigest: sha256:0e072dddd1f7f8fc8909a2ca6f65e76c5f0d2fcfb8be47935ae3457e8bbceb20", + "type": "string" + }, + "helm-values.image.pullPolicy": { + "default": "IfNotPresent", + "description": "Kubernetes imagePullPolicy on Deployment.", + "type": "string" + }, + "helm-values.image.registry": { + "description": "Target image registry. This value is prepended to the target image repository, if set.\nFor example:\nregistry: quay.io\nrepository: jetstack/cert-manager-openshift-routes", + "type": "string" + }, + "helm-values.image.repository": { + "default": "ghcr.io/cert-manager/cert-manager-openshift-routes", + "description": "Target image repository.", + "type": "string" + }, + "helm-values.image.tag": { + "description": "Override the image tag to deploy by setting this variable. If no value is set, the chart's appVersion is used.", + "type": "string" + }, + "helm-values.imagePullSecrets": { + "default": [], + "description": "Optional secrets used for pulling the openshift-routes container image.", + "items": {}, + "type": "array" + }, + "helm-values.logLevel": { + "default": 5, + "type": "number" + }, + "helm-values.metrics": { + "additionalProperties": false, + "properties": { + "enabled": { + "$ref": "#/$defs/helm-values.metrics.enabled" + }, + "serviceMonitor": { + "$ref": "#/$defs/helm-values.metrics.serviceMonitor" + } + }, + "type": "object" + }, + "helm-values.metrics.enabled": { + "default": false, + "description": "when enabled, a service is created that exposes the metrics endpoint", + "type": "boolean" + }, + "helm-values.metrics.serviceMonitor": { + "additionalProperties": false, + "properties": { + "enabled": { + "$ref": "#/$defs/helm-values.metrics.serviceMonitor.enabled" + }, + "interval": { + "$ref": "#/$defs/helm-values.metrics.serviceMonitor.interval" + } + }, + "type": "object" + }, + "helm-values.metrics.serviceMonitor.enabled": { + "default": false, + "description": "Create a ServiceMonitor to add openshift-routes to Prometheus.", + "type": "boolean" + }, + "helm-values.metrics.serviceMonitor.interval": { + "default": "60s", + "description": "The interval to scrape metrics.", + "type": "string" + }, + "helm-values.nameOverride": { + "description": "Override the \"cert-manager.name\" value, which is used to annotate some of the resources that are created by this Chart (using \"app.kubernetes.io/name\"). NOTE: There are some inconsitencies in the Helm chart when it comes to these annotations (some resources use eg. \"cainjector.name\" which resolves to the value \"cainjector\").", + "type": "string" + }, + "helm-values.namespace": { + "default": "", + "description": "This namespace allows you to define where the services are installed into. If not set then they use the namespace of the release. This is helpful when installing cert manager as a chart dependency (sub chart).", + "type": "string" + }, + "helm-values.nodeSelector": { + "default": { + "kubernetes.io/os": "linux" + }, + "description": "The nodeSelector on Pods tells Kubernetes to schedule Pods on the nodes with matching labels. For more information, see [Assigning Pods to Nodes](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/).\n\nThis default ensures that Pods are only scheduled to Linux nodes. It prevents Pods being scheduled to Windows nodes in a mixed OS cluster.", + "type": "object" + }, + "helm-values.podAnnotations": { + "default": {}, + "description": "Annotations to add to the openshift-routes pod.", + "type": "object" + }, + "helm-values.podSecurityContext": { + "default": { + "runAsNonRoot": true, + "seccompProfile": { + "type": "RuntimeDefault" + } + }, + "description": "Pod Security Context.\nFor more information, see [Configure a Security Context for a Pod or Container](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/).", + "type": "object" + }, + "helm-values.rbac": { + "additionalProperties": false, + "properties": { + "create": { + "$ref": "#/$defs/helm-values.rbac.create" + } + }, + "type": "object" + }, + "helm-values.rbac.create": { + "default": true, + "description": "create (Cluster-) Roles and RoleBindings for the ServiceAccount", + "type": "boolean" + }, + "helm-values.replicas": { + "default": 1, + "type": "number" + }, + "helm-values.resources": { + "default": {}, + "description": "Kubernetes pod resources\nref: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/\n\nFor example:\nresources:\n limits:\n memory: 128Mi\n requests:\n cpu: 100m\n memory: 128Mi", + "type": "object" + }, + "helm-values.securityContext": { + "default": { + "allowPrivilegeEscalation": false, + "capabilities": { + "drop": [ + "ALL" + ] + }, + "readOnlyRootFilesystem": true + }, + "description": "Container Security Context to be set on the controller component container. For more information, see [Configure a Security Context for a Pod or Container](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/).", + "type": "object" + }, + "helm-values.serviceAccount": { + "additionalProperties": false, + "properties": { + "annotations": { + "$ref": "#/$defs/helm-values.serviceAccount.annotations" + }, + "create": { + "$ref": "#/$defs/helm-values.serviceAccount.create" + }, + "name": { + "$ref": "#/$defs/helm-values.serviceAccount.name" + } + }, + "type": "object" + }, + "helm-values.serviceAccount.annotations": { + "description": "Optional additional annotations to add to the controller's Service Account.", + "type": "object" + }, + "helm-values.serviceAccount.create": { + "default": true, + "description": "Specifies whether a service account should be created", + "type": "boolean" + }, + "helm-values.serviceAccount.name": { + "description": "The name of the service account to use.\nIf not set and create is true, a name is generated using the fullname template.", + "type": "string" + }, + "helm-values.tolerations": { + "default": [], + "description": "A list of Kubernetes Tolerations, if required. For more information, see [Toleration v1 core](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#toleration-v1-core).\n\nFor example:\ntolerations:\n- key: foo.bar.com/role\n operator: Equal\n value: master\n effect: NoSchedule", + "items": {}, + "type": "array" + } + }, + "$ref": "#/$defs/helm-values", + "$schema": "http://json-schema.org/draft-07/schema#" +} diff --git a/deploy/charts/openshift-routes/values.yaml b/deploy/charts/openshift-routes/values.yaml new file mode 100644 index 0000000..0995474 --- /dev/null +++ b/deploy/charts/openshift-routes/values.yaml @@ -0,0 +1,145 @@ +# Default values for openshift-routes. + +replicas: 1 +logLevel: 5 + +# This namespace allows you to define where the services are installed into. +# If not set then they use the namespace of the release. +# This is helpful when installing cert manager as a chart dependency (sub chart). +namespace: "" + +# Override the "cert-manager.fullname" value. This value is used as part of +# most of the names of the resources created by this Helm chart. +# +docs:property +# fullnameOverride: "my-cert-manager" + +# Override the "cert-manager.name" value, which is used to annotate some of +# the resources that are created by this Chart (using "app.kubernetes.io/name"). +# NOTE: There are some inconsitencies in the Helm chart when it comes to +# these annotations (some resources use eg. "cainjector.name" which resolves +# to the value "cainjector"). +# +docs:property +# nameOverride: "my-cert-manager" + +image: + # Target image registry. This value is prepended to the target image repository, if set. + # For example: + # registry: quay.io + # repository: jetstack/cert-manager-openshift-routes + # +docs:property + # registry: quay.io + + # Target image repository. + repository: ghcr.io/cert-manager/cert-manager-openshift-routes + + # Override the image tag to deploy by setting this variable. + # If no value is set, the chart's appVersion is used. + # +docs:property + # tag: vX.Y.Z + + # Target image digest. Override any tag, if set. + # For example: + # digest: sha256:0e072dddd1f7f8fc8909a2ca6f65e76c5f0d2fcfb8be47935ae3457e8bbceb20 + # +docs:property + # digest: sha256:... + + # Kubernetes imagePullPolicy on Deployment. + pullPolicy: IfNotPresent + +# Optional secrets used for pulling the openshift-routes container image. +imagePullSecrets: [] + +serviceAccount: + # Specifies whether a service account should be created + create: true + + # The name of the service account to use. + # If not set and create is true, a name is generated using the fullname template. + # +docs:property + # name: "" + + # Optional additional annotations to add to the controller's Service Account. + # +docs:property + # annotations: {} + +rbac: + # create (Cluster-) Roles and RoleBindings for the ServiceAccount + create: true + +# Annotations to add to the openshift-routes pod. +podAnnotations: {} + +# Pod Security Context. +# For more information, see [Configure a Security Context for a Pod or Container](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/). +# +docs:property +podSecurityContext: + runAsNonRoot: true + seccompProfile: + type: RuntimeDefault + +# Container Security Context to be set on the controller component container. +# For more information, see [Configure a Security Context for a Pod or Container](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/). +# +docs:property +securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + readOnlyRootFilesystem: true + +# Kubernetes pod resources +# ref: https://kubernetes.io/docs/concepts/configuration/manage-resources-containers/ +# +# For example: +# resources: +# limits: +# memory: 128Mi +# requests: +# cpu: 100m +# memory: 128Mi +resources: {} + +# The nodeSelector on Pods tells Kubernetes to schedule Pods on the nodes with +# matching labels. +# For more information, see [Assigning Pods to Nodes](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/). +# +# This default ensures that Pods are only scheduled to Linux nodes. +# It prevents Pods being scheduled to Windows nodes in a mixed OS cluster. +# +docs:property +nodeSelector: + kubernetes.io/os: linux + +# A list of Kubernetes Tolerations, if required. For more information, see [Toleration v1 core](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#toleration-v1-core). +# +# For example: +# tolerations: +# - key: foo.bar.com/role +# operator: Equal +# value: master +# effect: NoSchedule +tolerations: [] + +# A Kubernetes Affinity, if required. For more information, see [Affinity v1 core](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#affinity-v1-core). +# +# For example: +# affinity: +# nodeAffinity: +# requiredDuringSchedulingIgnoredDuringExecution: +# nodeSelectorTerms: +# - matchExpressions: +# - key: foo.bar.com/role +# operator: In +# values: +# - master +affinity: {} + +metrics: + # when enabled, a service is created that exposes the metrics endpoint + enabled: false + + serviceMonitor: + # Create a ServiceMonitor to add openshift-routes to Prometheus. + enabled: false + + # The interval to scrape metrics. + interval: 60s diff --git a/deploy/static/cert-manager-openshift-routes.yaml b/deploy/static/cert-manager-openshift-routes.yaml deleted file mode 100644 index 8d4c795..0000000 --- a/deploy/static/cert-manager-openshift-routes.yaml +++ /dev/null @@ -1,130 +0,0 @@ ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRole -metadata: - name: cert-manager-openshift-routes -rules: -- apiGroups: - - route.openshift.io - resources: - - routes - verbs: - - get - - list - - watch - - patch - - update -- apiGroups: - - route.openshift.io - resources: - - routes/finalizers - verbs: - - update -- apiGroups: - - route.openshift.io - resources: - - routes/custom-host - verbs: - - create - - update -- apiGroups: - - cert-manager.io - resources: - - certificaterequests - verbs: - - create - - get - - list - - watch -- apiGroups: - - cert-manager.io - resources: - - certificaterequests/status - verbs: - - get - - list - - watch -- apiGroups: - - "" - resources: - - events - verbs: - - create - - patch -- apiGroups: - - coordination.k8s.io - resources: - - leases - verbs: - - create - - get - - list - - update ---- -apiVersion: v1 -kind: ServiceAccount -metadata: - name: cert-manager-openshift-routes - namespace: cert-manager -automountServiceAccountToken: false ---- -apiVersion: rbac.authorization.k8s.io/v1 -kind: ClusterRoleBinding -metadata: - name: cert-manager-openshift-routes -roleRef: - apiGroup: rbac.authorization.k8s.io - kind: ClusterRole - name: cert-manager-openshift-routes -subjects: -- kind: ServiceAccount - name: cert-manager-openshift-routes - namespace: cert-manager ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: cert-manager-openshift-routes - namespace: cert-manager - labels: - app.kubernetes.io/name: cert-manager-openshift-routes - app.kubernetes.io/version: "$RELEASED_VERSION" - app.kubernetes.io/component: controller - app.kubernetes.io/part-of: cert-manager -spec: - replicas: 1 - selector: - matchLabels: - app.kubernetes.io/name: cert-manager-openshift-routes - app.kubernetes.io/version: "$RELEASED_VERSION" - app.kubernetes.io/component: controller - app.kubernetes.io/part-of: cert-manager - template: - metadata: - labels: - app.kubernetes.io/name: cert-manager-openshift-routes - app.kubernetes.io/version: "$RELEASED_VERSION" - app.kubernetes.io/component: controller - app.kubernetes.io/part-of: cert-manager - spec: - serviceAccountName: cert-manager-openshift-routes - automountServiceAccountToken: true - containers: - - name: cert-manager-openshift-routes - image: "ghcr.io/cert-manager/cert-manager-openshift-routes:$RELEASED_VERSION" - args: - - -v=5 - ports: - - containerPort: 6060 - name: readiness - protocol: TCP - - containerPort: 9402 - name: metrics - protocol: TCP - readinessProbe: - httpGet: - port: readiness - path: "/readyz" - initialDelaySeconds: 3 - periodSeconds: 5 - timeoutSeconds: 3 diff --git a/hack/generate-static-manifest.sh b/hack/generate-static-manifest.sh deleted file mode 100755 index aa50a43..0000000 --- a/hack/generate-static-manifest.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/usr/bin/env bash -set -euo pipefail -if [ $# -ne 1 ]; then - echo "Usage: $0 RELEASED_VERSION" - exit 1 -fi -export RELEASED_VERSION="$1" -envsubst < "./deploy/static/cert-manager-openshift-routes.yaml" > "cert-manager-openshift-routes-$RELEASED_VERSION.yaml" -exit 0 diff --git a/hack/test.sh b/hack/test.sh index 9fb013f..66b9e6b 100755 --- a/hack/test.sh +++ b/hack/test.sh @@ -1,5 +1,23 @@ #!/usr/bin/env bash +# Copyright 2023 The cert-manager 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. + +set -o errexit +set -o nounset +set -o pipefail + kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.12.1/cert-manager.yaml cat < $@ + +include make/test-unit.mk + +.PHONY: release +## Publish all release artifacts (image + helm chart) +## @category [shared] Release +release: $(helm_chart_archive) $(NEEDS_HELM) + $(MAKE) oci-push-manager + + $(HELM) push "$(helm_chart_archive)" "oci://ghcr.io/cert-manager/charts" + + @echo "RELEASE_OCI_MANAGER_IMAGE=$(oci_manager_image_name)" >> "$(GITHUB_OUTPUT)" + @echo "RELEASE_OCI_MANAGER_TAG=$(oci_manager_image_tag)" >> "$(GITHUB_OUTPUT)" + @echo "RELEASE_HELM_CHART_NAME=$(helm_chart_name)" >> "$(GITHUB_OUTPUT)" + @echo "RELEASE_HELM_CHART_VERSION=$(helm_chart_version)" >> "$(GITHUB_OUTPUT)" + @echo "RELEASE_HELM_CHART_TAR=$(helm_chart_archive)" >> "$(GITHUB_OUTPUT)" + + @echo "Release complete!" diff --git a/internal/cmd/Dockerfile b/make/_shared/boilerplate/00_mod.mk similarity index 73% rename from internal/cmd/Dockerfile rename to make/_shared/boilerplate/00_mod.mk index 878997b..46f32fc 100644 --- a/internal/cmd/Dockerfile +++ b/make/_shared/boilerplate/00_mod.mk @@ -1,18 +1,17 @@ -# Copyright 2022 The cert-manager Authors. -# +# Copyright 2023 The cert-manager 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. -FROM scratch -COPY cert-manager-openshift-routes /cert-manager-openshift-routes -USER 65534:65534 -ENTRYPOINT ["/cert-manager-openshift-routes"] +default_go_header_file := $(dir $(lastword $(MAKEFILE_LIST)))/template/boilerplate.go.txt + +go_header_file ?= $(default_go_header_file) diff --git a/make/_shared/boilerplate/01_mod.mk b/make/_shared/boilerplate/01_mod.mk new file mode 100644 index 0000000..677fdff --- /dev/null +++ b/make/_shared/boilerplate/01_mod.mk @@ -0,0 +1,21 @@ +# Copyright 2023 The cert-manager 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. + +.PHONY: verify-boilerplate +## Verify that all files have the correct boilerplate. +## @category [shared] Generate/ Verify +verify-boilerplate: | $(NEEDS_BOILERSUITE) + $(BOILERSUITE) . + +shared_verify_targets += verify-boilerplate diff --git a/make/_shared/boilerplate/template/boilerplate.go.txt b/make/_shared/boilerplate/template/boilerplate.go.txt new file mode 100644 index 0000000..f021458 --- /dev/null +++ b/make/_shared/boilerplate/template/boilerplate.go.txt @@ -0,0 +1,15 @@ +/* +Copyright The cert-manager 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. +*/ \ No newline at end of file diff --git a/make/_shared/cert-manager/00_mod.mk b/make/_shared/cert-manager/00_mod.mk new file mode 100644 index 0000000..a1d2429 --- /dev/null +++ b/make/_shared/cert-manager/00_mod.mk @@ -0,0 +1,28 @@ +# Copyright 2023 The cert-manager 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. + +images_amd64 ?= +images_arm64 ?= + +cert_manager_version := v1.15.0 + +images_amd64 += quay.io/jetstack/cert-manager-controller:$(cert_manager_version)@sha256:9b5d5e9c0fd4944221d059921cc05f388c9a5fc0b02a60b47f0eccfcd8243331 +images_amd64 += quay.io/jetstack/cert-manager-cainjector:$(cert_manager_version)@sha256:edb1c1e0083ee4cd8e2ccb296ee0f436d2e465ecf90159f9d03141fc19bd3c23 +images_amd64 += quay.io/jetstack/cert-manager-webhook:$(cert_manager_version)@sha256:85df7b64a3d66de3cd7995ae0f2151b54fd18db424cb7cf84d3bd6d4a39d975f +images_amd64 += quay.io/jetstack/cert-manager-startupapicheck:$(cert_manager_version)@sha256:6365e940a5a913a3aeca0ea519102236d9bec5f0e8f0011fa3498c26d18348e5 + +images_arm64 += quay.io/jetstack/cert-manager-controller:$(cert_manager_version)@sha256:716c154f0eecb381d5f63ba78ee1dd0cce4b57dbe15cbbc121f7e8b1071e6268 +images_arm64 += quay.io/jetstack/cert-manager-cainjector:$(cert_manager_version)@sha256:59cbf06f489a7bb2c859296fa32ac7fcfd315c3f2e802be7805b598303b6cef5 +images_arm64 += quay.io/jetstack/cert-manager-webhook:$(cert_manager_version)@sha256:039c83b5b081d519e9152c19aedd1c7c17daa09187d1ad21df6689da342bb5b7 +images_arm64 += quay.io/jetstack/cert-manager-startupapicheck:$(cert_manager_version)@sha256:b2d5b00de8b1de6051c02a3f82cfa4ee617210ef1db5c295440e9a2d2069e547 diff --git a/make/_shared/cert-manager/01_mod.mk b/make/_shared/cert-manager/01_mod.mk new file mode 100644 index 0000000..f1af5da --- /dev/null +++ b/make/_shared/cert-manager/01_mod.mk @@ -0,0 +1,17 @@ +# Copyright 2023 The cert-manager 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. + +cert_manager_crds := $(bin_dir)/scratch/cert-manager-$(cert_manager_version).yaml +$(cert_manager_crds): | $(bin_dir)/scratch + curl -sSLo $@ https://github.com/cert-manager/cert-manager/releases/download/$(cert_manager_version)/cert-manager.crds.yaml diff --git a/make/_shared/controller-gen/01_mod.mk b/make/_shared/controller-gen/01_mod.mk new file mode 100644 index 0000000..7dedf6b --- /dev/null +++ b/make/_shared/controller-gen/01_mod.mk @@ -0,0 +1,34 @@ +# Copyright 2023 The cert-manager 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. + +################ +# Check Inputs # +################ + +ifndef go_header_file +$(error go_header_file is not set) +endif + +################ +# Add targets # +################ + +.PHONY: generate-deepcopy +## Generate code containing DeepCopy, DeepCopyInto, and DeepCopyObject method implementations. +## @category [shared] Generate/ Verify +generate-deepcopy: | $(NEEDS_CONTROLLER-GEN) + $(eval directories := $(shell ls -d */ | grep -v '_bin' | grep -v 'make')) + $(CONTROLLER-GEN) object:headerFile=$(go_header_file) $(directories:%=paths=./%...) + +shared_generate_targets += generate-deepcopy diff --git a/make/_shared/generate-verify/00_mod.mk b/make/_shared/generate-verify/00_mod.mk new file mode 100644 index 0000000..4355513 --- /dev/null +++ b/make/_shared/generate-verify/00_mod.mk @@ -0,0 +1,18 @@ +# Copyright 2023 The cert-manager 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. + +shared_generate_targets ?= +shared_generate_targets_dirty ?= +shared_verify_targets ?= +shared_verify_targets_dirty ?= diff --git a/make/_shared/generate-verify/02_mod.mk b/make/_shared/generate-verify/02_mod.mk new file mode 100644 index 0000000..c1ed5e2 --- /dev/null +++ b/make/_shared/generate-verify/02_mod.mk @@ -0,0 +1,39 @@ +# Copyright 2023 The cert-manager 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. + +.PHONY: generate +## Generate all generate targets. +## @category [shared] Generate/ Verify +generate: $$(shared_generate_targets) + @echo "The following targets cannot be run simultaniously with each other or other generate scripts:" + $(foreach TARGET,$(shared_generate_targets_dirty), $(MAKE) $(TARGET)) + +verify_script := $(dir $(lastword $(MAKEFILE_LIST)))/util/verify.sh + +# Run the supplied make target argument in a temporary workspace and diff the results. +verify-%: FORCE + +$(verify_script) $(MAKE) $* + +verify_generated_targets = $(shared_generate_targets:%=verify-%) +verify_generated_targets_dirty = $(shared_generate_targets_dirty:%=verify-%) + +verify_targets = $(sort $(verify_generated_targets) $(shared_verify_targets)) +verify_targets_dirty = $(sort $(verify_generated_targets_dirty) $(shared_verify_targets_dirty)) + +.PHONY: verify +## Verify code and generate targets. +## @category [shared] Generate/ Verify +verify: $$(verify_targets) + @echo "The following targets create temporary files in the current directory, that is why they have to be run last:" + $(foreach TARGET,$(verify_targets_dirty), $(MAKE) $(TARGET)) diff --git a/make/_shared/generate-verify/util/verify.sh b/make/_shared/generate-verify/util/verify.sh new file mode 100755 index 0000000..4dbaefa --- /dev/null +++ b/make/_shared/generate-verify/util/verify.sh @@ -0,0 +1,63 @@ +#!/usr/bin/env bash + +# Copyright 2023 The cert-manager 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. + +# Verify that the supplied command does not make any changes to the repository. +# +# This is called from the Makefile to verify that all code generation scripts +# have been run and that their changes have been committed to the repository. +# +# Runs any of the scripts or Make targets in this repository, after making a +# copy of the repository, then reports any changes to the files in the copy. + +# For example: +# +# make verify-helm-chart-update || \ +# make helm-chart-update +# +set -o errexit +set -o nounset +set -o pipefail + +projectdir="$( cd "$( dirname "${BASH_SOURCE[0]}" )/../../../.." && pwd )" + +cd "${projectdir}" + +# Use short form arguments here to support BSD/macOS. `-d` instructs +# it to make a directory, `-t` provides a prefix to use for the directory name. +tmp="$(mktemp -d /tmp/verify.sh.XXXXXXXX)" + +cleanup() { + rm -rf "${tmp}" +} +trap "cleanup" EXIT SIGINT + +rsync -aEq "${projectdir}/." "${tmp}" --exclude "_bin/" +pushd "${tmp}" >/dev/null + +"$@" + +popd >/dev/null + +if ! diff \ + --exclude=".git" \ + --exclude="_bin" \ + --new-file --unified --show-c-function --recursive "${projectdir}" "${tmp}" +then + echo + echo "Project '${projectdir}' is out of date." + echo "Please run '${*}'" + exit 1 +fi diff --git a/make/_shared/go/.golangci.override.yaml b/make/_shared/go/.golangci.override.yaml new file mode 100644 index 0000000..86c2337 --- /dev/null +++ b/make/_shared/go/.golangci.override.yaml @@ -0,0 +1,69 @@ +linters: + # Explicitly define all enabled linters + disable-all: true + enable: + - asasalint + - asciicheck + - bidichk + - bodyclose + - contextcheck + - decorder + - dogsled + - dupword + - durationcheck + - errcheck + - errchkjson + - errname + - execinquery + - exhaustive + - exportloopref + - forbidigo + - gci + - ginkgolinter + - gocheckcompilerdirectives + - gochecksumtype + - gocritic + - gofmt + - goheader + - goprintffuncname + - gosec + - gosimple + - gosmopolitan + - govet + - grouper + - importas + - ineffassign + - interfacebloat + - loggercheck + - makezero + - mirror + - misspell + - musttag + - nakedret + - nilerr + - nilnil + - noctx + - nosprintfhostport + - predeclared + - promlinter + - protogetter + - reassign + - sloglint + - staticcheck + - tagalign + - tenv + - testableexamples + - typecheck + - unconvert + - unparam + - unused + - usestdlibvars + - wastedassign +linters-settings: + gci: + sections: + - standard # Standard section: captures all standard packages. + - default # Default section: contains all imports that could not be matched to another section type. + - prefix({{REPO-NAME}}) # Custom section: groups all imports with the specified Prefix. + - blank # Blank section: contains all blank imports. This section is not present unless explicitly enabled. + - dot # Dot section: contains all dot imports. This section is not present unless explicitly enabled. diff --git a/make/_shared/go/01_mod.mk b/make/_shared/go/01_mod.mk new file mode 100644 index 0000000..0e4d418 --- /dev/null +++ b/make/_shared/go/01_mod.mk @@ -0,0 +1,110 @@ +# Copyright 2023 The cert-manager 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. + +ifndef bin_dir +$(error bin_dir is not set) +endif + +ifndef repo_name +$(error repo_name is not set) +endif + +go_base_dir := $(dir $(lastword $(MAKEFILE_LIST)))/base/ +golangci_lint_override := $(dir $(lastword $(MAKEFILE_LIST)))/.golangci.override.yaml + +.PHONY: generate-govulncheck +## Generate base files in the repository +## @category [shared] Generate/ Verify +generate-govulncheck: + cp -r $(go_base_dir)/. ./ + +shared_generate_targets += generate-govulncheck + +.PHONY: verify-govulncheck +## Verify all Go modules for vulnerabilities using govulncheck +## @category [shared] Generate/ Verify +# +# Runs `govulncheck` on all Go modules related to the project. +# Ignores Go modules among the temporary build artifacts in _bin, to avoid +# scanning the code of the vendored Go, after running make vendor-go. +# Ignores Go modules in make/_shared, because those will be checked in centrally +# in the makefile_modules repository. +# +# `verify-govulncheck` not added to the `shared_verify_targets` variable and is +# not run by `make verify`, because `make verify` is run for each PR, and we do +# not want new vulnerabilities in existing code to block the merging of PRs. +# Instead `make verify-govulnecheck` is intended to be run periodically by a CI job. +verify-govulncheck: | $(NEEDS_GOVULNCHECK) + @find . -name go.mod -not \( -path "./$(bin_dir)/*" -or -path "./make/_shared/*" \) \ + | while read d; do \ + target=$$(dirname $${d}); \ + echo "Running 'GOTOOLCHAIN=go$(VENDORED_GO_VERSION) $(bin_dir)/tools/govulncheck ./...' in directory '$${target}'"; \ + pushd "$${target}" >/dev/null; \ + GOTOOLCHAIN=go$(VENDORED_GO_VERSION) $(GOVULNCHECK) ./... || exit; \ + popd >/dev/null; \ + echo ""; \ + done + +ifdef golangci_lint_config + +.PHONY: generate-golangci-lint-config +## Generate a golangci-lint configuration file +## @category [shared] Generate/ Verify +generate-golangci-lint-config: | $(NEEDS_YQ) $(bin_dir)/scratch + cp $(golangci_lint_config) $(bin_dir)/scratch/golangci-lint.yaml.tmp + $(YQ) -i 'del(.linters.enable)' $(bin_dir)/scratch/golangci-lint.yaml.tmp + $(YQ) eval-all -i '. as $$item ireduce ({}; . * $$item)' $(bin_dir)/scratch/golangci-lint.yaml.tmp $(golangci_lint_override) + $(YQ) -i '(.. | select(tag == "!!str")) |= sub("{{REPO-NAME}}", "$(repo_name)")' $(bin_dir)/scratch/golangci-lint.yaml.tmp + mv $(bin_dir)/scratch/golangci-lint.yaml.tmp $(golangci_lint_config) + +shared_generate_targets += generate-golangci-lint-config + +.PHONY: verify-golangci-lint +## Verify all Go modules using golangci-lint +## @category [shared] Generate/ Verify +verify-golangci-lint: | $(NEEDS_GO) $(NEEDS_GOLANGCI-LINT) $(NEEDS_YQ) $(bin_dir)/scratch + @find . -name go.mod -not \( -path "./$(bin_dir)/*" -or -path "./make/_shared/*" \) \ + | while read d; do \ + target=$$(dirname $${d}); \ + echo "Running '$(bin_dir)/tools/golangci-lint run --go $(VENDORED_GO_VERSION) -c $(CURDIR)/$(golangci_lint_config)' in directory '$${target}'"; \ + pushd "$${target}" >/dev/null; \ + $(GOLANGCI-LINT) run --go $(VENDORED_GO_VERSION) -c $(CURDIR)/$(golangci_lint_config) --timeout 4m || exit; \ + popd >/dev/null; \ + echo ""; \ + done + +shared_verify_targets_dirty += verify-golangci-lint + +.PHONY: fix-golangci-lint +## Fix all Go modules using golangci-lint +## @category [shared] Generate/ Verify +fix-golangci-lint: | $(NEEDS_GOLANGCI-LINT) $(NEEDS_YQ) $(NEEDS_GCI) $(bin_dir)/scratch + $(GCI) write \ + -s "standard" \ + -s "default" \ + -s "prefix($(repo_name))" \ + -s "blank" \ + -s "dot" . + + @find . -name go.mod -not \( -path "./$(bin_dir)/*" -or -path "./make/_shared/*" \) \ + | while read d; do \ + target=$$(dirname $${d}); \ + echo "Running '$(bin_dir)/tools/golangci-lint run --go $(VENDORED_GO_VERSION) -c $(CURDIR)/$(golangci_lint_config) --fix' in directory '$${target}'"; \ + pushd "$${target}" >/dev/null; \ + $(GOLANGCI-LINT) run --go $(VENDORED_GO_VERSION) -c $(CURDIR)/$(golangci_lint_config) --fix || exit; \ + popd >/dev/null; \ + echo ""; \ + done + +endif diff --git a/make/_shared/go/README.md b/make/_shared/go/README.md new file mode 100644 index 0000000..ad1962b --- /dev/null +++ b/make/_shared/go/README.md @@ -0,0 +1,3 @@ +# README + +A module for various Go static checks. diff --git a/make/_shared/go/base/.github/workflows/govulncheck.yaml b/make/_shared/go/base/.github/workflows/govulncheck.yaml new file mode 100644 index 0000000..405e8de --- /dev/null +++ b/make/_shared/go/base/.github/workflows/govulncheck.yaml @@ -0,0 +1,28 @@ +# THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. +# Edit https://github.com/cert-manager/makefile-modules/blob/main/modules/go/base/.github/workflows/govulncheck.yaml instead. + +# Run govulncheck at midnight every night on the main branch, +# to alert us to recent vulnerabilities which affect the Go code in this +# project. +name: govulncheck +on: + workflow_dispatch: {} + schedule: + - cron: '0 0 * * *' + +jobs: + govulncheck: + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v4 + + - id: go-version + run: | + make print-go-version >> "$GITHUB_OUTPUT" + + - uses: actions/setup-go@v5 + with: + go-version: ${{ steps.go-version.outputs.result }} + + - run: make verify-govulncheck diff --git a/make/_shared/helm/01_mod.mk b/make/_shared/helm/01_mod.mk new file mode 100644 index 0000000..8b365a0 --- /dev/null +++ b/make/_shared/helm/01_mod.mk @@ -0,0 +1,17 @@ +# Copyright 2023 The cert-manager 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. + +include $(dir $(lastword $(MAKEFILE_LIST)))/crds.mk +include $(dir $(lastword $(MAKEFILE_LIST)))/helm.mk +include $(dir $(lastword $(MAKEFILE_LIST)))/deploy.mk diff --git a/make/_shared/helm/crd.template.footer.yaml b/make/_shared/helm/crd.template.footer.yaml new file mode 100644 index 0000000..0a67617 --- /dev/null +++ b/make/_shared/helm/crd.template.footer.yaml @@ -0,0 +1 @@ +{{- end }} \ No newline at end of file diff --git a/make/_shared/helm/crd.template.header.yaml b/make/_shared/helm/crd.template.header.yaml new file mode 100644 index 0000000..663d712 --- /dev/null +++ b/make/_shared/helm/crd.template.header.yaml @@ -0,0 +1,11 @@ +{{- if .Values.crds.enabled }} +apiVersion: apiextensions.k8s.io/v1 +kind: CustomResourceDefinition +metadata: + name: "REPLACE_CRD_NAME" + {{- if .Values.crds.keep }} + annotations: + helm.sh/resource-policy: keep + {{- end }} + labels: + {{- include "REPLACE_LABELS_TEMPLATE" . | nindent 4 }} \ No newline at end of file diff --git a/make/_shared/helm/crds.mk b/make/_shared/helm/crds.mk new file mode 100644 index 0000000..3ddd6b5 --- /dev/null +++ b/make/_shared/helm/crds.mk @@ -0,0 +1,66 @@ +# Copyright 2023 The cert-manager 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. + +################ +# Check Inputs # +################ + +ifndef helm_chart_source_dir +$(error helm_chart_source_dir is not set) +endif + +ifndef helm_labels_template_name +$(error helm_labels_template_name is not set) +endif + +################ +# Add targets # +################ + +crd_template_header := $(dir $(lastword $(MAKEFILE_LIST)))/crd.template.header.yaml +crd_template_footer := $(dir $(lastword $(MAKEFILE_LIST)))/crd.template.footer.yaml + +# see https://stackoverflow.com/a/53408233 +sed_inplace := sed -i'' +ifeq ($(HOST_OS),darwin) + sed_inplace := sed -i '' +endif + +.PHONY: generate-crds +## Generate CRD manifests. +## @category [shared] Generate/ Verify +generate-crds: | $(NEEDS_CONTROLLER-GEN) $(NEEDS_YQ) + $(eval crds_gen_temp := $(bin_dir)/scratch/crds) + $(eval directories := $(shell ls -d */ | grep -v '_bin' | grep -v 'make')) + + rm -rf $(crds_gen_temp) + mkdir -p $(crds_gen_temp) + + $(CONTROLLER-GEN) crd \ + $(directories:%=paths=./%...) \ + output:crd:artifacts:config=$(crds_gen_temp) + + echo "Updating CRDs with helm templating, writing to $(helm_chart_source_dir)/templates" + + @for i in $$(ls $(crds_gen_temp)); do \ + crd_name=$$($(YQ) eval '.metadata.name' $(crds_gen_temp)/$$i); \ + cat $(crd_template_header) > $(helm_chart_source_dir)/templates/crd-$$i; \ + echo "" >> $(helm_chart_source_dir)/templates/crd-$$i; \ + $(sed_inplace) "s/REPLACE_CRD_NAME/$$crd_name/g" $(helm_chart_source_dir)/templates/crd-$$i; \ + $(sed_inplace) "s/REPLACE_LABELS_TEMPLATE/$(helm_labels_template_name)/g" $(helm_chart_source_dir)/templates/crd-$$i; \ + $(YQ) -I2 '{"spec": .spec}' $(crds_gen_temp)/$$i >> $(helm_chart_source_dir)/templates/crd-$$i; \ + cat $(crd_template_footer) >> $(helm_chart_source_dir)/templates/crd-$$i; \ + done + +shared_generate_targets += generate-crds diff --git a/make/_shared/helm/deploy.mk b/make/_shared/helm/deploy.mk new file mode 100644 index 0000000..8bc6ebb --- /dev/null +++ b/make/_shared/helm/deploy.mk @@ -0,0 +1,54 @@ +# Copyright 2023 The cert-manager 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. + +ifndef deploy_name +$(error deploy_name is not set) +endif + +ifndef deploy_namespace +$(error deploy_namespace is not set) +endif + +# Install options allows the user configuration of extra flags +INSTALL_OPTIONS ?= + +########################################## + +.PHONY: install +## Install controller helm chart on the current active K8S cluster. +## @category [shared] Deployment +install: $(helm_chart_archive) | $(NEEDS_HELM) + $(HELM) upgrade $(deploy_name) $(helm_chart_archive) \ + --wait \ + --install \ + --create-namespace \ + $(INSTALL_OPTIONS) \ + --namespace $(deploy_namespace) + +.PHONY: uninstall +## Uninstall controller helm chart from the current active K8S cluster. +## @category [shared] Deployment +uninstall: | $(NEEDS_HELM) + $(HELM) uninstall $(deploy_name) \ + --wait \ + --namespace $(deploy_namespace) + +.PHONY: template +## Template the helm chart. +## @category [shared] Deployment +template: $(helm_chart_archive) | $(NEEDS_HELM) + @$(HELM) template $(deploy_name) $(helm_chart_archive) \ + --create-namespace \ + $(INSTALL_OPTIONS) \ + --namespace $(deploy_namespace) diff --git a/make/_shared/helm/helm.mk b/make/_shared/helm/helm.mk new file mode 100644 index 0000000..7a0cc90 --- /dev/null +++ b/make/_shared/helm/helm.mk @@ -0,0 +1,126 @@ +# Copyright 2023 The cert-manager 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. + +ifndef bin_dir +$(error bin_dir is not set) +endif + +ifndef repo_name +$(error repo_name is not set) +endif + +ifndef helm_chart_source_dir +$(error helm_chart_source_dir is not set) +endif + +ifndef helm_chart_name +$(error helm_chart_name is not set) +endif + +ifndef helm_chart_version +$(error helm_chart_version is not set) +endif + +ifndef helm_values_mutation_function +$(error helm_values_mutation_function is not set) +endif + +########################################## + +helm_chart_sources := $(shell find $(helm_chart_source_dir) -maxdepth 1 -type f) $(shell find $(helm_chart_source_dir)/templates -type f) +helm_chart_archive := $(bin_dir)/scratch/image/$(helm_chart_name)-$(helm_chart_version).tgz + +$(helm_chart_archive): $(helm_chart_sources) | $(NEEDS_HELM) $(NEEDS_YQ) $(bin_dir)/scratch/image + $(eval helm_chart_source_dir_versioned := $@.tmp) + rm -rf $(helm_chart_source_dir_versioned) + mkdir -p $(dir $(helm_chart_source_dir_versioned)) + cp -a $(helm_chart_source_dir) $(helm_chart_source_dir_versioned) + + $(call helm_values_mutation_function,$(helm_chart_source_dir_versioned)/values.yaml) + + @if ! $(YQ) -oy '.name' $(helm_chart_source_dir_versioned)/Chart.yaml | grep -q '^$(helm_chart_name)$$'; then \ + echo "Chart name does not match the name in the helm_chart_name variable"; \ + exit 1; \ + fi + + $(YQ) '.annotations."artifacthub.io/prerelease" = "$(IS_PRERELEASE)"' \ + --inplace $(helm_chart_source_dir_versioned)/Chart.yaml + + mkdir -p $(dir $@) + $(HELM) package $(helm_chart_source_dir_versioned) \ + --app-version $(helm_chart_version) \ + --version $(helm_chart_version) \ + --destination $(dir $@) + +.PHONY: helm-chart +## Create a helm chart +## @category [shared] Helm Chart +helm-chart: $(helm_chart_archive) + +ifdef helm_docs_use_helm_tool + +helm_tool_header_search ?= ^ +helm_tool_footer_search ?= ^ + +.PHONY: generate-helm-docs +## Generate Helm chart documentation. +## @category [shared] Generate/ Verify +generate-helm-docs: | $(NEEDS_HELM-TOOL) + $(HELM-TOOL) inject -i $(helm_chart_source_dir)/values.yaml -o $(helm_chart_source_dir)/README.md --header-search "$(helm_tool_header_search)" --footer-search "$(helm_tool_footer_search)" +else +.PHONY: generate-helm-docs +## Generate Helm chart documentation. +## @category [shared] Generate/ Verify +generate-helm-docs: | $(NEEDS_HELM-DOCS) + $(HELM-DOCS) $(helm_chart_source_dir)/ +endif + +shared_generate_targets += generate-helm-docs + +ifdef helm_generate_schema +.PHONY: generate-helm-schema +## Generate Helm chart schema. +## @category [shared] Generate/ Verify +generate-helm-schema: | $(NEEDS_HELM-TOOL) $(NEEDS_GOJQ) + $(HELM-TOOL) schema -i $(helm_chart_source_dir)/values.yaml | $(GOJQ) > $(helm_chart_source_dir)/values.schema.json + +shared_generate_targets += generate-helm-schema +endif + +ifdef helm_verify_values +.PHONY: verify-helm-values +## Verify Helm chart values using helm-tool. +## @category [shared] Generate/ Verify +verify-helm-values: | $(NEEDS_HELM-TOOL) $(NEEDS_GOJQ) + $(HELM-TOOL) lint -i $(helm_chart_source_dir)/values.yaml -d $(helm_chart_source_dir)/templates -e $(helm_chart_source_dir)/values.linter.exceptions + +shared_verify_targets += verify-helm-values +endif + +.PHONY: verify-pod-security-standards +## Verify that the Helm chart complies with the pod security standards. +## @category [shared] Generate/ Verify +verify-pod-security-standards: $(helm_chart_archive) | $(NEEDS_KYVERNO) $(NEEDS_KUSTOMIZE) $(NEEDS_HELM) + $(KYVERNO) apply <($(KUSTOMIZE) build https://github.com/kyverno/policies/pod-security/enforce) \ + --resource <($(HELM) template $(helm_chart_archive)) 2>/dev/null + +shared_verify_targets_dirty += verify-pod-security-standards + +.PHONY: verify-helm-lint +## Verify that the Helm chart is linted. +## @category [shared] Generate/ Verify +verify-helm-lint: $(helm_chart_archive) | $(NEEDS_HELM) + $(HELM) lint $(helm_chart_archive) + +shared_verify_targets_dirty += verify-helm-lint diff --git a/make/_shared/help/01_mod.mk b/make/_shared/help/01_mod.mk new file mode 100644 index 0000000..1a6a3b4 --- /dev/null +++ b/make/_shared/help/01_mod.mk @@ -0,0 +1,22 @@ +# Copyright 2023 The cert-manager 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. + + +help_sh := $(dir $(lastword $(MAKEFILE_LIST)))/help.sh + +.PHONY: help +help: + @MAKEFILE_LIST="$(MAKEFILE_LIST)" \ + MAKE="$(MAKE)" \ + $(help_sh) diff --git a/make/_shared/help/help.sh b/make/_shared/help/help.sh new file mode 100755 index 0000000..d9c831f --- /dev/null +++ b/make/_shared/help/help.sh @@ -0,0 +1,115 @@ +#!/usr/bin/env bash + +# Copyright 2023 The cert-manager 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. + +set -o errexit +set -o nounset +set -o pipefail + +## 1. Build set of extracted line items + +EMPTYLINE_REGEX="^[[:space:]]*$" +DOCBLOCK_REGEX="^##[[:space:]]*(.*)$" +CATEGORY_REGEX="^##[[:space:]]*@category[[:space:]]*(.*)$" +TARGET_REGEX="^(([a-zA-Z0-9\_\/\%\$\(\)]|-)+):.*$" + +EMPTY_ITEM="" + +# shellcheck disable=SC2086 +raw_lines=$(cat ${MAKEFILE_LIST} | tr '\t' ' ' | grep -E "($TARGET_REGEX|$DOCBLOCK_REGEX|$EMPTYLINE_REGEX)") +extracted_lines="" +extracted_current="$EMPTY_ITEM" +max_target_length=0 + +## Extract all the commented targets from the Makefile +while read -r line; do + if [[ $line =~ $EMPTYLINE_REGEX ]]; then + # Reset current item. + extracted_current="$EMPTY_ITEM" + elif [[ $line =~ $CATEGORY_REGEX ]]; then + extracted_current=${extracted_current///${BASH_REMATCH[1]}} + elif [[ $line =~ $TARGET_REGEX ]]; then + # only keep the target if there is a comment + if [[ $extracted_current != *""* ]]; then + max_target_length=$(( ${#BASH_REMATCH[1]} > max_target_length ? ${#BASH_REMATCH[1]} : max_target_length )) + extracted_current=${extracted_current///${BASH_REMATCH[1]}} + extracted_lines="$extracted_lines\n$extracted_current" + fi + + extracted_current="$EMPTY_ITEM" + elif [[ $line =~ $DOCBLOCK_REGEX ]]; then + extracted_current=${extracted_current///${BASH_REMATCH[1]}} + fi +done <<< "$raw_lines" + +## 2. Build mapping for expanding targets + +ASSIGNMENT_REGEX="^(([a-zA-Z0-9\_\/\%\$\(\)]|-)+)[[:space:]]*:=[[:space:]]*(.*)$" + +raw_expansions=$(${MAKE} --dry-run --print-data-base noop | tr '\t' ' ' | grep -E "$ASSIGNMENT_REGEX") +extracted_expansions="" + +while read -r line; do + if [[ $line =~ $ASSIGNMENT_REGEX ]]; then + target=${BASH_REMATCH[1]} + expansion=${BASH_REMATCH[3]// /, } + extracted_expansions="$extracted_expansions\n$target$expansion" + fi +done <<< "$raw_expansions" + +## 3. Sort and print the extracted line items + +RULE_COLOR="$(tput setaf 6)" +CATEGORY_COLOR="$(tput setaf 3)" +CLEAR_STYLE="$(tput sgr0)" +PURPLE=$(tput setaf 125) + +extracted_lines=$(echo -e "$extracted_lines" | LC_ALL=C sort -r) +current_category="" + +## Print the help +echo "Usage: make [target1] [target2] ..." + +IFS=$'\n'; for line in $extracted_lines; do + category=$([[ $line =~ \(.*)\ ]] && echo "${BASH_REMATCH[1]}") + target=$([[ $line =~ \(.*)\ ]] && echo "${BASH_REMATCH[1]}") + comment=$([[ $line =~ \(.*)\ ]] && echo -e "${BASH_REMATCH[1]///\\n}") + + # Print the category header if it's changed + if [[ "$current_category" != "$category" ]]; then + current_category=$category + echo -e "\n${CATEGORY_COLOR}${current_category}${CLEAR_STYLE}" + fi + + # replace any $(...) with the actual value + if [[ $target =~ \$\((.*)\) ]]; then + new_target=$(echo -e "$extracted_expansions" | grep "${BASH_REMATCH[1]}" || true) + if [[ -n "$new_target" ]]; then + target=$([[ $new_target =~ \(.*)\ ]] && echo -e "${BASH_REMATCH[1]}") + fi + fi + + # Print the target and its multiline comment + is_first_line=true + while read -r comment_line; do + if [[ "$is_first_line" == true ]]; then + is_first_line=false + padding=$(( max_target_length - ${#target} )) + printf " %s%${padding}s ${PURPLE}>${CLEAR_STYLE} %s\n" "${RULE_COLOR}${target}${CLEAR_STYLE}" "" "${comment_line}" + else + printf " %${max_target_length}s %s\n" "" "${comment_line}" + fi + done <<< "$comment" +done diff --git a/make/_shared/kind/00_mod.mk b/make/_shared/kind/00_mod.mk new file mode 100644 index 0000000..576d33e --- /dev/null +++ b/make/_shared/kind/00_mod.mk @@ -0,0 +1,28 @@ +# Copyright 2023 The cert-manager 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. + +images_amd64 ?= +images_arm64 ?= + +kind_k8s_version := v1.29.4 + +# Goto https://github.com/kubernetes-sigs/kind/releases/tag/ and find the +# multi-arch digest for the image you want to use. Then use crane to get the platform +# specific digest. For example (digest is the multi-arch digest from the release page): +# digest="sha256:51a1434a5397193442f0be2a297b488b6c919ce8a3931be0ce822606ea5ca245" +# crane digest --platform=linux/amd64 docker.io/kindest/node@$digest +# crane digest --platform=linux/arm64 docker.io/kindest/node@$digest + +images_amd64 += docker.io/kindest/node:$(kind_k8s_version)@sha256:ea40a6bd365a17f71fd3883a1d34a0791d7d6b0eb75832c6d85b6f2326827f1e +images_arm64 += docker.io/kindest/node:$(kind_k8s_version)@sha256:e63a7f74e80b746328fbaa70be406639d0c31c8c8cf0a3d57efdd23c64fe4bba diff --git a/make/_shared/kind/01_mod.mk b/make/_shared/kind/01_mod.mk new file mode 100644 index 0000000..a7eb1b2 --- /dev/null +++ b/make/_shared/kind/01_mod.mk @@ -0,0 +1,16 @@ +# Copyright 2023 The cert-manager 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. + +include $(dir $(lastword $(MAKEFILE_LIST)))/kind.mk +include $(dir $(lastword $(MAKEFILE_LIST)))/kind-image-preload.mk diff --git a/make/_shared/kind/kind-image-preload.mk b/make/_shared/kind/kind-image-preload.mk new file mode 100644 index 0000000..a157ad2 --- /dev/null +++ b/make/_shared/kind/kind-image-preload.mk @@ -0,0 +1,56 @@ +# Copyright 2023 The cert-manager 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. + +ifndef bin_dir +$(error bin_dir is not set) +endif + +ifndef images_amd64 +$(error images_amd64 is not set) +endif + +ifndef images_arm64 +$(error images_arm64 is not set) +endif + +########################################## + +images := $(images_$(HOST_ARCH)) +images_files := $(foreach image,$(images),$(subst :,+,$(image))) + +images_tar_dir := $(bin_dir)/downloaded/containers/$(HOST_ARCH) +images_tars := $(images_files:%=$(images_tar_dir)/%.tar) + +$(images_tars): $(images_tar_dir)/%.tar: | $(NEEDS_CRANE) + @$(eval image=$(subst +,:,$*)) + @$(eval image_without_digest=$(shell cut -d@ -f1 <<<"$(image)")) + @$(eval digest=$(subst $(image_without_digest)@,,$(image))) + @mkdir -p $(dir $@) + diff <(echo "$(digest) -" | cut -d: -f2) <($(CRANE) manifest --platform=linux/$(HOST_ARCH) $(image_without_digest) | sha256sum) + $(CRANE) pull $(image_without_digest) $@ --platform=linux/$(HOST_ARCH) + +images_tar_envs := $(images_files:%=env-%) + +.PHONY: $(images_tar_envs) +$(images_tar_envs): env-%: $(images_tar_dir)/%.tar | $(NEEDS_GOJQ) + @$(eval image_without_tag=$(shell cut -d+ -f1 <<<"$*")) + @$(eval $(image_without_tag).TAR="$(images_tar_dir)/$*.tar") + @$(eval $(image_without_tag).REPO=$(shell tar xfO "$(images_tar_dir)/$*.tar" manifest.json | $(GOJQ) '.[0].RepoTags[0]' -r | cut -d: -f1)) + @$(eval $(image_without_tag).TAG=$(shell tar xfO "$(images_tar_dir)/$*.tar" manifest.json | $(GOJQ) '.[0].RepoTags[0]' -r | cut -d: -f2)) + @$(eval $(image_without_tag).FULL=$($(image_without_tag).REPO):$($(image_without_tag).TAG)) + +.PHONY: images-preload +## Preload images. +## @category [shared] Kind cluster +images-preload: | $(images_tar_envs) diff --git a/make/_shared/kind/kind.mk b/make/_shared/kind/kind.mk new file mode 100644 index 0000000..c573420 --- /dev/null +++ b/make/_shared/kind/kind.mk @@ -0,0 +1,79 @@ +# Copyright 2023 The cert-manager 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. + +ifndef bin_dir +$(error bin_dir is not set) +endif + +ifndef kind_cluster_name +$(error kind_cluster_name is not set) +endif + +ifndef kind_cluster_config +$(error kind_cluster_config is not set) +endif + +########################################## + +kind_kubeconfig := $(bin_dir)/scratch/kube.config +absolute_kubeconfig := $(CURDIR)/$(kind_kubeconfig) + +$(bin_dir)/scratch/cluster-check: FORCE | $(NEEDS_KIND) $(bin_dir)/scratch + @if ! $(KIND) get clusters -q | grep -q "^$(kind_cluster_name)\$$"; then \ + echo "❌ cluster $(kind_cluster_name) not found. Starting ..."; \ + echo "trigger" > $@; \ + else \ + echo "✅ existing cluster $(kind_cluster_name) found"; \ + fi + $(eval export KUBECONFIG=$(absolute_kubeconfig)) + +kind_post_create_hook ?= +$(kind_kubeconfig): $(kind_cluster_config) $(bin_dir)/scratch/cluster-check | images-preload $(bin_dir)/scratch $(NEEDS_KIND) $(NEEDS_KUBECTL) + @[ -f "$(bin_dir)/scratch/cluster-check" ] && ( \ + $(KIND) delete cluster --name $(kind_cluster_name); \ + $(CTR) load -i $(docker.io/kindest/node.TAR); \ + $(KIND) create cluster \ + --image $(docker.io/kindest/node.FULL) \ + --name $(kind_cluster_name) \ + --config "$<"; \ + $(CTR) exec $(kind_cluster_name)-control-plane find /mounted_images/ -name "*.tar" -exec echo {} \; -exec ctr --namespace=k8s.io images import --all-platforms --no-unpack --digests {} \; ; \ + $(MAKE) --no-print-directory noop $(kind_post_create_hook); \ + $(KUBECTL) config use-context kind-$(kind_cluster_name); \ + ) || true + + $(KIND) get kubeconfig --name $(kind_cluster_name) > $@ + +.PHONY: kind-cluster +## Create Kind cluster and wait for nodes to be ready +## @category [shared] Kind cluster +kind-cluster: $(kind_kubeconfig) | $(NEEDS_KUBECTL) + mkdir -p ~/.kube + KUBECONFIG=~/.kube/config:$(kind_kubeconfig) $(KUBECTL) config view --flatten > ~/.kube/config + $(KUBECTL) config use-context kind-$(kind_cluster_name) + +.PHONY: kind-cluster-clean +## Delete the Kind cluster +## @category [shared] Kind cluster +kind-cluster-clean: $(NEEDS_KIND) + $(KIND) delete cluster --name $(kind_cluster_name) + rm -rf $(kind_kubeconfig) + $(MAKE) --no-print-directory noop $(kind_post_create_hook) + +.PHONY: kind-logs +## Get the Kind cluster +## @category [shared] Kind cluster +kind-logs: | kind-cluster $(NEEDS_KIND) $(bin_dir)/artifacts + rm -rf $(bin_dir)/artifacts/e2e-logs + mkdir -p $(bin_dir)/artifacts/e2e-logs + $(KIND) export logs $(bin_dir)/artifacts/e2e-logs --name=$(kind_cluster_name) diff --git a/make/_shared/klone/01_mod.mk b/make/_shared/klone/01_mod.mk new file mode 100644 index 0000000..a3d07dd --- /dev/null +++ b/make/_shared/klone/01_mod.mk @@ -0,0 +1,27 @@ +# Copyright 2023 The cert-manager 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. + +.PHONY: generate-klone +## Generate klone shared Makefiles +## @category [shared] Generate/ Verify +generate-klone: | $(NEEDS_KLONE) + $(KLONE) sync + +shared_generate_targets += generate-klone + +.PHONY: upgrade-klone +## Upgrade klone Makefile modules to latest version +## @category [shared] Self-upgrade +upgrade-klone: | $(NEEDS_KLONE) + $(KLONE) upgrade diff --git a/make/_shared/oci-build/00_mod.mk b/make/_shared/oci-build/00_mod.mk new file mode 100644 index 0000000..11a09ed --- /dev/null +++ b/make/_shared/oci-build/00_mod.mk @@ -0,0 +1,125 @@ +# Copyright 2023 The cert-manager 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. + +oci_platforms ?= linux/amd64,linux/arm/v7,linux/arm64,linux/ppc64le + +# Use distroless as minimal base image to package the manager binary +# To get latest SHA run "crane digest quay.io/jetstack/base-static:latest" +base_image_static := quay.io/jetstack/base-static@sha256:23631cd1be9a63515cb5975e783284b209f7f9a449c02bb117f2a15413e13bfa + +# Use custom apko-built image as minimal base image to package the manager binary +# To get latest SHA run "crane digest quay.io/jetstack/base-static-csi:latest" +base_image_csi-static := quay.io/jetstack/base-static-csi@sha256:95b33b948da3790ac09f112486a1e9f10e3e705cfacc159cb7b12429b874c78f + +# Utility functions +fatal_if_undefined = $(if $(findstring undefined,$(origin $1)),$(error $1 is not set)) + +# Validate globals that are required +$(call fatal_if_undefined,bin_dir) +$(call fatal_if_undefined,build_names) + +# Set default config values +CGO_ENABLED ?= 0 +GOEXPERIMENT ?= # empty by default + +# Default variables per build_names entry +# +# $1 - build_name +define default_per_build_variables +cgo_enabled_$1 ?= $(CGO_ENABLED) +goexperiment_$1 ?= $(GOEXPERIMENT) +oci_additional_layers_$1 ?= +endef + +$(foreach build_name,$(build_names),$(eval $(call default_per_build_variables,$(build_name)))) + +# Validate variables per build_names entry +# +# $1 - build_name +define check_per_build_variables +# Validate required config exists +$(call fatal_if_undefined,go_$1_ldflags) +$(call fatal_if_undefined,go_$1_main_dir) +$(call fatal_if_undefined,go_$1_mod_dir) +$(call fatal_if_undefined,oci_$1_base_image_flavor) +$(call fatal_if_undefined,oci_$1_image_name_development) + +# Validate we have valid base image config +ifeq ($(oci_$1_base_image_flavor),static) + oci_$1_base_image := $(base_image_static) +else ifeq ($(oci_$1_base_image_flavor),csi-static) + oci_$1_base_image := $(base_image_csi-static) +else ifeq ($(oci_$1_base_image_flavor),custom) + $$(call fatal_if_undefined,oci_$1_base_image) +else + $$(error oci_$1_base_image_flavor has unknown value "$(oci_$1_base_image_flavor)") +endif + +# Validate the config required to build the golang based images +ifneq ($(go_$1_main_dir:.%=.),.) +$$(error go_$1_main_dir "$(go_$1_main_dir)" should be a directory path that DOES start with ".") +endif +ifeq ($(go_$1_main_dir:%/=/),/) +$$(error go_$1_main_dir "$(go_$1_main_dir)" should be a directory path that DOES NOT end with "/") +endif +ifeq ($(go_$1_main_dir:%.go=.go),.go) +$$(error go_$1_main_dir "$(go_$1_main_dir)" should be a directory path that DOES NOT end with ".go") +endif +ifneq ($(go_$1_mod_dir:.%=.),.) +$$(error go_$1_mod_dir "$(go_$1_mod_dir)" should be a directory path that DOES start with ".") +endif +ifeq ($(go_$1_mod_dir:%/=/),/) +$$(error go_$1_mod_dir "$(go_$1_mod_dir)" should be a directory path that DOES NOT end with "/") +endif +ifeq ($(go_$1_mod_dir:%.go=.go),.go) +$$(error go_$1_mod_dir "$(go_$1_mod_dir)" should be a directory path that DOES NOT end with ".go") +endif +ifeq ($(wildcard $(go_$1_mod_dir)/go.mod),) +$$(error go_$1_mod_dir "$(go_$1_mod_dir)" does not contain a go.mod file) +endif +ifeq ($(wildcard $(go_$1_mod_dir)/$(go_$1_main_dir)/main.go),) +$$(error go_$1_main_dir "$(go_$1_mod_dir)" does not contain a main.go file) +endif + +# Validate the config required to build OCI images +ifneq ($(words $(oci_$1_image_name_development)),1) +$$(error oci_$1_image_name_development "$(oci_$1_image_name_development)" should be a single image name) +endif + +endef + +$(foreach build_name,$(build_names),$(eval $(call check_per_build_variables,$(build_name)))) + +# Create variables holding targets +# +# We create the following targets for each $(build_names) +# - oci-build-$(build_name) = build the oci directory +# - oci-load-$(build_name) = load the image into docker using the oci_$(build_name)_image_name_development variable +# - docker-tarball-$(build_name) = build a "docker load" compatible tarball of the image +# - ko-config-$(build_name) = generate "ko" config for a given build +oci_build_targets := $(build_names:%=oci-build-%) +oci_load_targets := $(build_names:%=oci-load-%) +docker_tarball_targets := $(build_names:%=docker-tarball-%) +ko_config_targets := $(build_names:%=ko-config-%) + +# Derive config based on user config +# +# - oci_layout_path_$(build_name) = path that the OCI image will be saved in OCI layout directory format +# - oci_digest_path_$(build_name) = path to the file that will contain the digests +# - ko_config_path_$(build_name) = path to the ko config file +# - docker_tarball_path_$(build_name) = path that the docker tarball that the docker-tarball-$(build_name) will produce +$(foreach build_name,$(build_names),$(eval oci_layout_path_$(build_name) := $(bin_dir)/scratch/image/oci-layout-$(build_name).$(oci_$(build_name)_image_tag))) +$(foreach build_name,$(build_names),$(eval oci_digest_path_$(build_name) := $(CURDIR)/$(oci_layout_path_$(build_name)).digests)) +$(foreach build_name,$(build_names),$(eval ko_config_path_$(build_name) := $(CURDIR)/$(oci_layout_path_$(build_name)).ko_config.yaml)) +$(foreach build_name,$(build_names),$(eval docker_tarball_path_$(build_name) := $(CURDIR)/$(oci_layout_path_$(build_name)).docker.tar)) diff --git a/make/_shared/oci-build/01_mod.mk b/make/_shared/oci-build/01_mod.mk new file mode 100644 index 0000000..ca6fc92 --- /dev/null +++ b/make/_shared/oci-build/01_mod.mk @@ -0,0 +1,90 @@ +# Copyright 2023 The cert-manager 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. + +# Utility variables +current_makefile = $(lastword $(MAKEFILE_LIST)) +current_makefile_directory = $(dir $(current_makefile)) + +# Build the image tool +image_tool_dir := $(current_makefile_directory:/=)/image_tool +IMAGE_TOOL := $(CURDIR)/$(bin_dir)/tools/image_tool +NEEDS_IMAGE_TOOL := $(bin_dir)/tools/image_tool +$(NEEDS_IMAGE_TOOL): $(wildcard $(image_tool_dir)/*.go) | $(NEEDS_GO) + cd $(image_tool_dir) && GOWORK=off GOBIN=$(CURDIR)/$(dir $@) $(GO) install . + +define ko_config_target +.PHONY: $(ko_config_path_$1:$(CURDIR)/%=%) +$(ko_config_path_$1:$(CURDIR)/%=%): | $(NEEDS_YQ) $(bin_dir)/scratch/image + echo '{}' | \ + $(YQ) '.defaultBaseImage = "$(oci_$1_base_image)"' | \ + $(YQ) '.builds[0].id = "$1"' | \ + $(YQ) '.builds[0].dir = "$(go_$1_mod_dir)"' | \ + $(YQ) '.builds[0].main = "$(go_$1_main_dir)"' | \ + $(YQ) '.builds[0].env[0] = "CGO_ENABLED=$(cgo_enabled_$1)"' | \ + $(YQ) '.builds[0].env[1] = "GOEXPERIMENT=$(goexperiment_$1)"' | \ + $(YQ) '.builds[0].ldflags[0] = "-s"' | \ + $(YQ) '.builds[0].ldflags[1] = "-w"' | \ + $(YQ) '.builds[0].ldflags[2] = "{{.Env.LDFLAGS}}"' \ + > $(CURDIR)/$(oci_layout_path_$1).ko_config.yaml + +ko-config-$1: $(ko_config_path_$1:$(CURDIR)/%=%) +endef + +.PHONY: $(ko_config_targets) +$(foreach build_name,$(build_names),$(eval $(call ko_config_target,$(build_name)))) + +.PHONY: $(oci_build_targets) +## Build the OCI image. +## @category [shared] Build +$(oci_build_targets): oci-build-%: ko-config-% | $(NEEDS_KO) $(NEEDS_GO) $(NEEDS_YQ) $(NEEDS_IMAGE_TOOL) $(bin_dir)/scratch/image + rm -rf $(CURDIR)/$(oci_layout_path_$*) + GOWORK=off \ + KO_DOCKER_REPO=$(oci_$*_image_name_development) \ + KOCACHE=$(CURDIR)/$(bin_dir)/scratch/image/ko_cache \ + KO_CONFIG_PATH=$(ko_config_path_$*) \ + SOURCE_DATE_EPOCH=$(GITEPOCH) \ + KO_GO_PATH=$(GO) \ + LDFLAGS="$(go_$*_ldflags)" \ + $(KO) build $(go_$*_mod_dir)/$(go_$*_main_dir) \ + --platform=$(oci_platforms) \ + --oci-layout-path=$(oci_layout_path_$*) \ + --sbom-dir=$(CURDIR)/$(oci_layout_path_$*).sbom \ + --sbom=spdx \ + --push=false \ + --bare + + $(IMAGE_TOOL) append-layers \ + $(CURDIR)/$(oci_layout_path_$*) \ + $(oci_additional_layers_$*) + + $(IMAGE_TOOL) list-digests \ + $(CURDIR)/$(oci_layout_path_$*) \ + > $(oci_digest_path_$*) + +# Only include the oci-load target if kind is provided by the kind makefile-module +ifdef kind_cluster_name +.PHONY: $(oci_load_targets) +## Build OCI image for the local architecture and load +## it into the $(kind_cluster_name) kind cluster. +## @category [shared] Build +$(oci_load_targets): oci-load-%: docker-tarball-% | kind-cluster $(NEEDS_KIND) + $(KIND) load image-archive --name $(kind_cluster_name) $(docker_tarball_path_$*) +endif + +## Build Docker tarball image for the local architecture +## @category [shared] Build +.PHONY: $(docker_tarball_targets) +$(docker_tarball_targets): oci_platforms := "linux/$(HOST_ARCH)" +$(docker_tarball_targets): docker-tarball-%: oci-build-% | $(NEEDS_GO) $(NEEDS_IMAGE_TOOL) + $(IMAGE_TOOL) convert-to-docker-tar $(CURDIR)/$(oci_layout_path_$*) $(docker_tarball_path_$*) $(oci_$*_image_name_development):$(oci_$*_image_tag) \ No newline at end of file diff --git a/make/_shared/oci-build/image_tool/append_layers.go b/make/_shared/oci-build/image_tool/append_layers.go new file mode 100644 index 0000000..6af65e8 --- /dev/null +++ b/make/_shared/oci-build/image_tool/append_layers.go @@ -0,0 +1,220 @@ +/* +Copyright 2023 The cert-manager 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 ( + "archive/tar" + "bytes" + "io" + "io/fs" + "log/slog" + "os" + "path/filepath" + + v1 "github.com/google/go-containerregistry/pkg/v1" + "github.com/google/go-containerregistry/pkg/v1/layout" + "github.com/google/go-containerregistry/pkg/v1/match" + "github.com/google/go-containerregistry/pkg/v1/mutate" + "github.com/google/go-containerregistry/pkg/v1/tarball" + "github.com/google/go-containerregistry/pkg/v1/types" + "github.com/spf13/cobra" +) + +var CommandAppendLayers = cobra.Command{ + Use: "append-layers oci-path [path-to-tarball...]", + Short: "Appends a tarball or directory to every image in an OCI index.", + Args: cobra.MinimumNArgs(1), + Run: func(cmd *cobra.Command, args []string) { + oci := args[0] + extra := args[1:] + + if len(extra) == 0 { + return + } + + path, err := layout.FromPath(oci) + must("could not load oci directory", err) + + index, err := path.ImageIndex() + must("could not load oci image index", err) + + layers := []untypedLayer{} + for _, path := range extra { + layers = append(layers, newUntypedLayerFromPath(path)) + } + + index = mutateImage(index, func(img v1.Image) v1.Image { + imgMediaType, err := img.MediaType() + must("could not get image media type", err) + + layerType := types.DockerLayer + if imgMediaType == types.OCIManifestSchema1 { + layerType = types.OCILayer + } + + for _, untypedLayer := range layers { + layer, err := untypedLayer.ToLayer(layerType) + must("could not load image layer", err) + + img, err = mutate.AppendLayers(img, layer) + must("could not append layer", err) + } + + return img + }) + + _, err = layout.Write(oci, index) + must("could not write image", err) + }, +} + +type untypedLayer struct { + tarball tarball.Opener +} + +func newUntypedLayer(tarball tarball.Opener) untypedLayer { + return untypedLayer{tarball: tarball} +} + +func newUntypedLayerFromPath(path string) untypedLayer { + stat, err := os.Stat(path) + must("could not open directory or tarball", err) + + var layer untypedLayer + if stat.IsDir() { + var buf bytes.Buffer + + tw := tar.NewWriter(&buf) + + filepath.Walk(path, func(target string, info fs.FileInfo, err error) error { + must("walk error", err) + + header, err := tar.FileInfoHeader(info, info.Name()) + must("could not create tar header", err) + + name, err := filepath.Rel(path, target) + must("could not build relative path", err) + + // Write simplified header, this removes all fields that would cause + // the build to be non-reproducible (like modtime for example) + err = tw.WriteHeader(&tar.Header{ + Typeflag: header.Typeflag, + Name: name, + Mode: header.Mode, + Linkname: header.Linkname, + Size: header.Size, + }) + + must("could not write tar header", err) + + if !info.IsDir() { + file, err := os.Open(target) + must("could not write tar contents", err) + + defer file.Close() + + _, err = io.Copy(tw, file) + must("could not write tar contents", err) + } + + return nil + }) + + tw.Close() + + byts := buf.Bytes() + + layer = newUntypedLayer( + func() (io.ReadCloser, error) { + return io.NopCloser(bytes.NewReader(byts)), nil + }, + ) + } else { + layer = newUntypedLayer( + func() (io.ReadCloser, error) { + return os.Open(path) + }, + ) + } + + return layer +} + +func (ul untypedLayer) ToLayer(mediaType types.MediaType) (v1.Layer, error) { + return tarball.LayerFromOpener(ul.tarball, tarball.WithMediaType(mediaType)) +} + +type imageMutateFn func(index v1.Image) v1.Image + +func mutateImage(index v1.ImageIndex, fn imageMutateFn) v1.ImageIndex { + manifest, err := index.IndexManifest() + must("could not load oci image manifest", err) + + for _, descriptor := range manifest.Manifests { + switch { + case descriptor.MediaType.IsImage(): + slog.Info("found image", "digest", descriptor.Digest, "platform", descriptor.Platform) + + img, err := index.Image(descriptor.Digest) + must("could not load oci image with digest", err) + + img = fn(img) + + digest, err := img.Digest() + must("could not get image digest", err) + + size, err := img.Size() + must("could not get image size", err) + + slog.Info("appended layers to image", "old_digest", descriptor.Digest, "digest", digest, "platform", descriptor.Platform) + + index = mutate.RemoveManifests(index, match.Digests(descriptor.Digest)) + + descriptor.Digest = digest + descriptor.Size = size + index = mutate.AppendManifests(index, mutate.IndexAddendum{ + Add: img, + Descriptor: descriptor, + }) + + case descriptor.MediaType.IsIndex(): + slog.Info("found image index", "digest", descriptor.Digest) + + child, err := index.ImageIndex(descriptor.Digest) + must("could not load oci index manifest", err) + + child = mutateImage(child, fn) + + digest, err := child.Digest() + must("could not get index digest", err) + + size, err := child.Size() + must("could not get index size", err) + + index = mutate.RemoveManifests(index, match.Digests(descriptor.Digest)) + + descriptor.Digest = digest + descriptor.Size = size + index = mutate.AppendManifests(index, mutate.IndexAddendum{ + Add: child, + Descriptor: descriptor, + }) + } + } + + return index +} diff --git a/make/_shared/oci-build/image_tool/convert_to_docker_tar.go b/make/_shared/oci-build/image_tool/convert_to_docker_tar.go new file mode 100644 index 0000000..c6e1e26 --- /dev/null +++ b/make/_shared/oci-build/image_tool/convert_to_docker_tar.go @@ -0,0 +1,97 @@ +/* +Copyright 2023 The cert-manager 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 ( + "runtime" + + "github.com/google/go-containerregistry/pkg/name" + v1 "github.com/google/go-containerregistry/pkg/v1" + "github.com/google/go-containerregistry/pkg/v1/layout" + "github.com/google/go-containerregistry/pkg/v1/match" + "github.com/google/go-containerregistry/pkg/v1/tarball" + "github.com/spf13/cobra" +) + +var CommandConvertToDockerTar = cobra.Command{ + Use: "convert-to-docker-tar oci-path output image-name", + Short: "Reads the OCI directory and outputs a tarball that is compatible with \"docker load\"", + Args: cobra.ExactArgs(3), + Run: func(cmd *cobra.Command, args []string) { + path := args[0] + output := args[1] + imageName := args[2] + + ociLayout, err := layout.FromPath(path) + must("could not load oci directory", err) + + index, err := ociLayout.ImageIndex() + must("could not load oci image index", err) + + images := getImagesFromIndex(index, func(desc v1.Descriptor) bool { + return desc.Platform != nil && desc.Platform.Architecture == runtime.GOARCH + }) + + switch { + case len(images) == 0: + fail("no matching images found") + case len(images) > 1: + fail("multiple matching images found") + } + + ref, err := name.ParseReference(imageName) + must("invalid image name", err) + + err = tarball.WriteToFile(output, ref, images[0]) + must("could not write tarball", err) + }, +} + +func getImagesFromIndex(index v1.ImageIndex, matcher match.Matcher) (images []v1.Image) { + manifest, err := index.IndexManifest() + must("could not load oci index manifest", err) + + for _, descriptor := range manifest.Manifests { + switch { + case descriptor.MediaType.IsImage(): + // If the platform is not part of the index manifest, attempt to + // load it from the image config + if descriptor.Platform == nil { + img, err := index.Image(descriptor.Digest) + must("could not load image", err) + + cfg, err := img.ConfigFile() + must("could not load image config", err) + + descriptor.Platform = cfg.Platform() + } + + if matcher(descriptor) { + img, err := index.Image(descriptor.Digest) + must("could not load image", err) + images = append(images, img) + } + + case descriptor.MediaType.IsIndex(): + idx, err := index.ImageIndex(descriptor.Digest) + must("could not load image index", err) + images = append(images, getImagesFromIndex(idx, matcher)...) + } + } + + return +} diff --git a/make/_shared/oci-build/image_tool/go.mod b/make/_shared/oci-build/image_tool/go.mod new file mode 100644 index 0000000..84c8b86 --- /dev/null +++ b/make/_shared/oci-build/image_tool/go.mod @@ -0,0 +1,19 @@ +module image_tool + +go 1.21 + +require ( + github.com/google/go-containerregistry v0.19.1 + github.com/spf13/cobra v1.8.0 +) + +require ( + github.com/containerd/stargz-snapshotter/estargz v0.14.3 // indirect + github.com/inconshreveable/mousetrap v1.1.0 // indirect + github.com/klauspost/compress v1.16.5 // indirect + github.com/opencontainers/go-digest v1.0.0 // indirect + github.com/opencontainers/image-spec v1.1.0-rc3 // indirect + github.com/spf13/pflag v1.0.5 // indirect + github.com/vbatts/tar-split v0.11.3 // indirect + golang.org/x/sync v0.2.0 // indirect +) diff --git a/make/_shared/oci-build/image_tool/go.sum b/make/_shared/oci-build/image_tool/go.sum new file mode 100644 index 0000000..a36acd3 --- /dev/null +++ b/make/_shared/oci-build/image_tool/go.sum @@ -0,0 +1,60 @@ +github.com/BurntSushi/toml v1.2.1/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= +github.com/containerd/stargz-snapshotter/estargz v0.14.3 h1:OqlDCK3ZVUO6C3B/5FSkDwbkEETK84kQgEeFwDC+62k= +github.com/containerd/stargz-snapshotter/estargz v0.14.3/go.mod h1:KY//uOCIkSuNAHhJogcZtrNHdKrA99/FCCRjE3HD36o= +github.com/cpuguy83/go-md2man/v2 v2.0.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.3/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/docker/cli v24.0.0+incompatible h1:0+1VshNwBQzQAx9lOl+OYCTCEAD8fKs/qeXMx3O0wqM= +github.com/docker/cli v24.0.0+incompatible/go.mod h1:JLrzqnKDaYBop7H2jaqPtU4hHvMKP+vjCwu2uszcLI8= +github.com/docker/distribution v2.8.2+incompatible h1:T3de5rq0dB1j30rp0sA2rER+m322EBzniBPB6ZIzuh8= +github.com/docker/distribution v2.8.2+incompatible/go.mod h1:J2gT2udsDAN96Uj4KfcMRqY0/ypR+oyYUYmja8H+y+w= +github.com/docker/docker v24.0.0+incompatible h1:z4bf8HvONXX9Tde5lGBMQ7yCJgNahmJumdrStZAbeY4= +github.com/docker/docker v24.0.0+incompatible/go.mod h1:eEKB0N0r5NX/I1kEveEz05bcu8tLC/8azJZsviup8Sk= +github.com/docker/docker-credential-helpers v0.7.0 h1:xtCHsjxogADNZcdv1pKUHXryefjlVRqWqIhk/uXJp0A= +github.com/docker/docker-credential-helpers v0.7.0/go.mod h1:rETQfLdHNT3foU5kuNkFR1R1V12OJRRO5lzt2D1b5X0= +github.com/google/go-cmp v0.5.9 h1:O2Tfq5qg4qc4AmwVlvv0oLiVAGB7enBSJ2x2DqQFi38= +github.com/google/go-cmp v0.5.9/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-containerregistry v0.19.1 h1:yMQ62Al6/V0Z7CqIrrS1iYoA5/oQCm88DeNujc7C1KY= +github.com/google/go-containerregistry v0.19.1/go.mod h1:YCMFNQeeXeLF+dnhhWkqDItx/JSkH01j1Kis4PsjzFI= +github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8= +github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/klauspost/compress v1.16.5 h1:IFV2oUNUzZaz+XyusxpLzpzS8Pt5rh0Z16For/djlyI= +github.com/klauspost/compress v1.16.5/go.mod h1:ntbaceVETuRiXiv4DpjP66DpAtAGkEQskQzEyD//IeE= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= +github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= +github.com/opencontainers/image-spec v1.1.0-rc3 h1:fzg1mXZFj8YdPeNkRXMg+zb88BFV0Ys52cJydRwBkb8= +github.com/opencontainers/image-spec v1.1.0-rc3/go.mod h1:X4pATf0uXsnn3g5aiGIsVnJBR4mxhKzfwmvK/B2NTm8= +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= +github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/sirupsen/logrus v1.9.1 h1:Ou41VVR3nMWWmTiEUnj0OlsgOSCUFgsPAOl6jRIcVtQ= +github.com/sirupsen/logrus v1.9.1/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= +github.com/spf13/cobra v1.8.0 h1:7aJaZx1B85qltLMc546zn58BxxfZdR/W22ej9CFoEf0= +github.com/spf13/cobra v1.8.0/go.mod h1:WXLWApfZ71AjXPya3WOlMsY9yMs7YeiHhFVlvLyhcho= +github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= +github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= +github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= +github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= +github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= +github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= +github.com/urfave/cli v1.22.12/go.mod h1:sSBEIC79qR6OvcmsD4U3KABeOTxDqQtdDnaFuUN30b8= +github.com/vbatts/tar-split v0.11.3 h1:hLFqsOLQ1SsppQNTMpkpPXClLDfC2A3Zgy9OUU+RVck= +github.com/vbatts/tar-split v0.11.3/go.mod h1:9QlHN18E+fEH7RdG+QAJJcuya3rqT7eXSTY7wGrAokY= +golang.org/x/sync v0.2.0 h1:PUR+T4wwASmuSTYdKjYHI5TD22Wy5ogLU5qZCOLxBrI= +golang.org/x/sync v0.2.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220906165534-d0df966e6959/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.15.0 h1:h48lPFYpsTvQJZF4EKyI4aLHaev3CxivZmv7yZig9pc= +golang.org/x/sys v0.15.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/make/_shared/oci-build/image_tool/list_digests.go b/make/_shared/oci-build/image_tool/list_digests.go new file mode 100644 index 0000000..e08d948 --- /dev/null +++ b/make/_shared/oci-build/image_tool/list_digests.go @@ -0,0 +1,46 @@ +/* +Copyright 2023 The cert-manager 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" + + "github.com/google/go-containerregistry/pkg/v1/layout" + "github.com/spf13/cobra" +) + +var CommandListDigests = cobra.Command{ + Use: "list-digests oci-path", + Short: "Outputs the digests for images found inside the tarball", + Args: cobra.ExactArgs(1), + Run: func(cmd *cobra.Command, args []string) { + path := args[0] + + ociLayout, err := layout.FromPath(path) + must("could not load oci directory", err) + + imageIndex, err := ociLayout.ImageIndex() + must("could not load oci image index", err) + + indexManifest, err := imageIndex.IndexManifest() + must("could not load oci index manifest", err) + + for _, man := range indexManifest.Manifests { + fmt.Println(man.Digest) + } + }, +} diff --git a/make/_shared/oci-build/image_tool/main.go b/make/_shared/oci-build/image_tool/main.go new file mode 100644 index 0000000..507281e --- /dev/null +++ b/make/_shared/oci-build/image_tool/main.go @@ -0,0 +1,46 @@ +/* +Copyright 2023 The cert-manager 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" + + "github.com/spf13/cobra" +) + +var CommandRoot = cobra.Command{ + Use: "image-tool", +} + +func main() { + CommandRoot.AddCommand(&CommandAppendLayers) + CommandRoot.AddCommand(&CommandConvertToDockerTar) + CommandRoot.AddCommand(&CommandListDigests) + must("error running command", CommandRoot.Execute()) +} + +func must(msg string, err error) { + if err != nil { + fail(msg+": %w", err) + } +} + +func fail(msg string, a ...any) { + fmt.Fprintf(os.Stderr, msg+"\n", a...) + os.Exit(1) +} diff --git a/make/_shared/oci-publish/00_mod.mk b/make/_shared/oci-publish/00_mod.mk new file mode 100644 index 0000000..f27062a --- /dev/null +++ b/make/_shared/oci-publish/00_mod.mk @@ -0,0 +1,58 @@ +# Copyright 2023 The cert-manager 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. + +# Push names is equivilent to build_names, additional names can be added for +# pushing images that are not build with the oci-build module +push_names ?= +push_names += $(build_names) + +# Sometimes we need to push to one registry, but pull from another. This allows +# that. +# +# The lines should be in the format a=b +# +# The value on the left is the domain you include in your oci__image_name +# variable, the one on the right is the domain that is actually pushed to. +# +# For example, if we set up a vanity domain for the current quay: +# +# oci_controller_image_name = registry.cert-manager.io/cert-manager-controller` +# image_registry_rewrite += registry.cert-manager.io=quay.io/jetstack +# +# This would push to quay.io/jetstack/cert-manager-controller. +# +# The general idea is oci__image_name contains the final image name, after replication, after vanity domains etc. + +image_registry_rewrite ?= + +# Utilities for extracting the key and value from a foo=bar style line +kv_key = $(word 1,$(subst =, ,$1)) +kv_value = $(word 2,$(subst =, ,$1)) + +# Apply the image_registry_rewrite rules, if no rules match an image then the +# image name is not changed. Any rules that match will be applied. +# +# For example, if there was a rule vanity-domain.com=real-registry.com/foo +# then any references to vanity-domain.com/image would be rewritten to +# real-registry.com/foo/image +image_registry_rewrite_rules_for_image = $(strip $(sort $(foreach rule,$(image_registry_rewrite),$(if $(findstring $(call kv_key,$(rule)),$1),$(rule))))) +apply_image_registry_rewrite_rules_to_image = $(if $(call image_registry_rewrite_rules_for_image,$1),\ + $(foreach rule,$(call image_registry_rewrite_rules_for_image,$1),$(subst $(call kv_key,$(rule)),$(call kv_value,$(rule)),$1)),\ + $1) +apply_image_registry_rewrite_rules = $(foreach image_name,$1,$(call apply_image_registry_rewrite_rules_to_image,$(image_name))) + +# This is a helper function to return the image names for a given build_name. +# It will apply all rewrite rules to the image names +oci_image_names_for = $(call apply_image_registry_rewrite_rules,$(oci_$1_image_name)) +oci_image_tag_for = $(oci_$1_image_tag) \ No newline at end of file diff --git a/make/_shared/oci-publish/01_mod.mk b/make/_shared/oci-publish/01_mod.mk new file mode 100644 index 0000000..348490c --- /dev/null +++ b/make/_shared/oci-publish/01_mod.mk @@ -0,0 +1,127 @@ +# Copyright 2023 The cert-manager 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. + +# Utility functions +fatal_if_undefined = $(if $(findstring undefined,$(origin $1)),$(error $1 is not set)) +oci_digest = $(shell head -1 $(oci_digest_path_$1) 2> /dev/null) +sanitize_target = $(subst :,-,$1) +registry_for = $(firstword $(subst /, ,$1)) + +# Utility variables +current_makefile_directory := $(dir $(lastword $(MAKEFILE_LIST))) +image_exists_script := $(current_makefile_directory)/image-exists.sh + +# Validate globals that are required +$(call fatal_if_undefined,bin_dir) +$(call fatal_if_undefined,push_names) + +# Set default config values +RELEASE_DRYRUN ?= false +CRANE_FLAGS ?= # empty by default +COSIGN_FLAGS ?= # empty by default +OCI_SIGN_ON_PUSH ?= true + +# Default variables per push_names entry +# +# $1 - build_name +define default_per_build_variables +release_dryrun_$1 ?= $(RELEASE_DRYRUN) +crane_flags_$1 ?= $(CRANE_FLAGS) +cosign_flags_$1 ?= $(COSIGN_FLAGS) +oci_sign_on_push_$1 ?= $(OCI_SIGN_ON_PUSH) +endef + +$(foreach build_name,$(push_names),$(eval $(call default_per_build_variables,$(build_name)))) + +# Validate variables per push_names entry +# +# $1 - build_name +define check_per_build_variables +$(call fatal_if_undefined,oci_digest_path_$1) +$(call fatal_if_undefined,oci_layout_path_$1) +$(call fatal_if_undefined,oci_$1_image_name) +$(call fatal_if_undefined,oci_$1_image_tag) +endef + +$(foreach build_name,$(push_names),$(eval $(call check_per_build_variables,$(build_name)))) + +# Create variables holding targets +# +# We create the following targets for each $(push_names) +# - oci-build-$(build_name) = build the oci directory +# - oci-load-$(build_name) = load the image into docker using the oci_$(build_name)_image_name_development variable +# - docker-tarball-$(build_name) = build a "docker load" compatible tarball of the image +# - ko-config-$(build_name) = generate "ko" config for a given build +oci_push_targets := $(push_names:%=oci-push-%) +oci_sign_targets := $(push_names:%=oci-sign-%) +oci_maybe_push_targets := $(push_names:%=oci-maybe-push-%) + +# Define push target +# $1 - build_name +# $2 - image_name +define oci_push_target +.PHONY: $(call sanitize_target,oci-push-$2) +$(call sanitize_target,oci-push-$2): oci-build-$1 | $(NEEDS_CRANE) + $$(CRANE) $(crane_flags_$1) push "$(oci_layout_path_$1)" "$2:$(call oci_image_tag_for,$1)" + $(if $(filter true,$(oci_sign_on_push_$1)),$(MAKE) $(call sanitize_target,oci-sign-$2)) + +.PHONY: $(call sanitize_target,oci-maybe-push-$2) +$(call sanitize_target,oci-maybe-push-$2): oci-build-$1 | $(NEEDS_CRANE) + CRANE="$$(CRANE) $(crane_flags_$1)" \ + source $(image_exists_script) $2:$(call oci_image_tag_for,$1); \ + $$(CRANE) $(crane_flags_$1) push "$(oci_layout_path_$1)" "$2:$(call oci_image_tag_for,$1)"; \ + $(if $(filter true,$(oci_sign_on_push_$1)),$(MAKE) $(call sanitize_target,oci-sign-$2)) + +oci-push-$1: $(call sanitize_target,oci-push-$2) +oci-maybe-push-$1: $(call sanitize_target,oci-maybe-push-$2) +endef + +oci_push_target_per_image = $(foreach image_name,$2,$(eval $(call oci_push_target,$1,$(image_name)))) +$(foreach build_name,$(push_names),$(eval $(call oci_push_target_per_image,$(build_name),$(call oci_image_names_for,$(build_name))))) + +.PHONY: $(oci_push_targets) +## Build and push OCI image. +## If the tag already exists, this target will overwrite it. +## If an identical image was already built before, we will add a new tag to it, but we will not sign it again. +## Expected pushed images: +## - :v1.2.3, @sha256:0000001 +## - :v1.2.3.sig, :sha256-0000001.sig +## @category [shared] Publish +$(oci_push_targets): + +.PHONY: $(oci_maybe_push_targets) +## Push image if tag does not already exist in registry. +## @category [shared] Publish +$(oci_maybe_push_targets): + +# Define sign target +# $1 - build_name +# $2 - image_name +define oci_sign_target +.PHONY: $(call sanitize_target,oci-sign-$2) +$(call sanitize_target,oci-sign-$2): $(oci_digest_path_$1) | $(NEEDS_CRANE) $(NEEDS_COSIGN) + $$(CRANE) $(crane_flags_$1) manifest $2:$$(subst :,-,$$(call oci_digest,$1)).sig > /dev/null 2>&1 || \ + $$(COSIGN) sign --yes=true $(cosign_flags_$1) "$2@$$(call oci_digest,$1)" + +oci-sign-$1: $(call sanitize_target,oci-sign-$2) +endef + +oci_sign_target_per_image = $(foreach image_name,$2,$(eval $(call oci_sign_target,$1,$(image_name)))) +$(foreach build_name,$(push_names),$(eval $(call oci_sign_target_per_image,$(build_name),$(call oci_image_names_for,$(build_name))))) + +.PHONY: $(oci_sign_targets) +## Sign an OCI image. +## If a signature already exists, this will not overwrite it. +## @category [shared] Publish +$(oci_sign_targets): \ No newline at end of file diff --git a/make/_shared/oci-publish/image-exists.sh b/make/_shared/oci-publish/image-exists.sh new file mode 100755 index 0000000..9ecbb61 --- /dev/null +++ b/make/_shared/oci-publish/image-exists.sh @@ -0,0 +1,70 @@ +#!/usr/bin/env bash + +# Copyright 2022 The cert-manager 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. + +set -o errexit +set -o nounset +set -o pipefail + +# This script checks if a given image exists in the upstream registry, and if it +# does, whether it contains all the expected architectures. + +crane=${CRANE:-} + +FULL_IMAGE=${1:-} + +function print_usage() { + echo "usage: $0 [commands...]" +} + +if [[ -z $FULL_IMAGE ]]; then + print_usage + echo "Missing full-image" + exit 1 +fi + +if [[ -z $crane ]]; then + echo "CRANE environment variable must be set to the path of the crane binary" + exit 1 +fi + +shift 1 + +manifest=$(mktemp) +trap 'rm -f "$manifest"' EXIT SIGINT + +manifest_error=$(mktemp) +trap 'rm -f "$manifest_error"' EXIT SIGINT + +echo "+++ searching for $FULL_IMAGE in upstream registry" + +set +o errexit +$crane manifest "$FULL_IMAGE" > "$manifest" 2> "$manifest_error" +exit_code=$? +set -o errexit + +manifest_error_data=$(cat "$manifest_error") +if [[ $exit_code -eq 0 ]]; then + echo "+++ upstream registry appears to contain $FULL_IMAGE, exiting" + exit 0 + +elif [[ "$manifest_error_data" == *"MANIFEST_UNKNOWN"* ]]; then + echo "+++ upstream registry does not contain $FULL_IMAGE, will build and push" + # fall through to run the commands passed to this script + +else + echo "FATAL: upstream registry returned an unexpected error: $manifest_error_data, exiting" + exit 1 +fi diff --git a/make/_shared/repository-base/01_mod.mk b/make/_shared/repository-base/01_mod.mk new file mode 100644 index 0000000..aa6b7ee --- /dev/null +++ b/make/_shared/repository-base/01_mod.mk @@ -0,0 +1,33 @@ +# Copyright 2023 The cert-manager 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. + +base_dir := $(dir $(lastword $(MAKEFILE_LIST)))/base/ +base_dependabot_dir := $(dir $(lastword $(MAKEFILE_LIST)))/base-dependabot/ + +ifdef repository_base_no_dependabot +.PHONY: generate-base +## Generate base files in the repository +## @category [shared] Generate/ Verify +generate-base: + cp -r $(base_dir)/. ./ +else +.PHONY: generate-base +## Generate base files in the repository +## @category [shared] Generate/ Verify +generate-base: + cp -r $(base_dir)/. ./ + cp -r $(base_dependabot_dir)/. ./ +endif + +shared_generate_targets += generate-base diff --git a/make/_shared/repository-base/base-dependabot/.github/dependabot.yaml b/make/_shared/repository-base/base-dependabot/.github/dependabot.yaml new file mode 100644 index 0000000..81b9297 --- /dev/null +++ b/make/_shared/repository-base/base-dependabot/.github/dependabot.yaml @@ -0,0 +1,20 @@ +# THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. +# Edit https://github.com/cert-manager/makefile-modules/blob/main/modules/repository-base/base/.github/dependabot.yaml instead. + +# Update Go dependencies and GitHub Actions dependencies daily. +version: 2 +updates: +- package-ecosystem: gomod + directory: / + schedule: + interval: daily + groups: + all: + patterns: ["*"] +- package-ecosystem: github-actions + directory: / + schedule: + interval: daily + groups: + all: + patterns: ["*"] diff --git a/make/_shared/repository-base/base/.github/workflows/make-self-upgrade.yaml b/make/_shared/repository-base/base/.github/workflows/make-self-upgrade.yaml new file mode 100644 index 0000000..93beedf --- /dev/null +++ b/make/_shared/repository-base/base/.github/workflows/make-self-upgrade.yaml @@ -0,0 +1,90 @@ +# THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. +# Edit https://github.com/cert-manager/makefile-modules/blob/main/modules/repository-base/base/.github/workflows/make-self-upgrade.yaml instead. + +name: make-self-upgrade +concurrency: make-self-upgrade +on: + workflow_dispatch: {} + schedule: + - cron: '0 0 * * *' + +jobs: + self_upgrade: + runs-on: ubuntu-latest + + permissions: + contents: write + pull-requests: write + + env: + SOURCE_BRANCH: "${{ github.ref_name }}" + SELF_UPGRADE_BRANCH: "self-upgrade-${{ github.ref_name }}" + + steps: + - name: Fail if branch is not head of branch. + if: ${{ !startsWith(github.ref, 'refs/heads/') && env.SOURCE_BRANCH != '' && env.SELF_UPGRADE_BRANCH != '' }} + run: | + echo "This workflow should not be run on a non-branch-head." + exit 1 + + - uses: actions/checkout@v4 + + - id: go-version + run: | + make print-go-version >> "$GITHUB_OUTPUT" + + - uses: actions/setup-go@v5 + with: + go-version: ${{ steps.go-version.outputs.result }} + + - run: | + git checkout -B "$SELF_UPGRADE_BRANCH" + + - run: | + make -j upgrade-klone + make -j generate + + - id: is-up-to-date + shell: bash + run: | + git_status=$(git status -s) + is_up_to_date="true" + if [ -n "$git_status" ]; then + is_up_to_date="false" + echo "The following changes will be committed:" + echo "$git_status" + fi + echo "result=$is_up_to_date" >> "$GITHUB_OUTPUT" + + - if: ${{ steps.is-up-to-date.outputs.result != 'true' }} + run: | + git config --global user.name "cert-manager-bot" + git config --global user.email "cert-manager-bot@users.noreply.github.com" + git add -A && git commit -m "BOT: run 'make upgrade-klone' and 'make generate'" --signoff + git push -f origin "$SELF_UPGRADE_BRANCH" + + - if: ${{ steps.is-up-to-date.outputs.result != 'true' }} + uses: actions/github-script@v7 + with: + script: | + const { repo, owner } = context.repo; + const pulls = await github.rest.pulls.list({ + owner: owner, + repo: repo, + head: owner + ':' + process.env.SELF_UPGRADE_BRANCH, + base: process.env.SOURCE_BRANCH, + state: 'open', + }); + + if (pulls.data.length < 1) { + await github.rest.pulls.create({ + title: '[CI] Merge ' + process.env.SELF_UPGRADE_BRANCH + ' into ' + process.env.SOURCE_BRANCH, + owner: owner, + repo: repo, + head: process.env.SELF_UPGRADE_BRANCH, + base: process.env.SOURCE_BRANCH, + body: [ + 'This PR is auto-generated to bump the Makefile modules.', + ].join('\n'), + }); + } diff --git a/make/_shared/repository-base/base/LICENSE b/make/_shared/repository-base/base/LICENSE new file mode 100644 index 0000000..261eeb9 --- /dev/null +++ b/make/_shared/repository-base/base/LICENSE @@ -0,0 +1,201 @@ + Apache License + Version 2.0, January 2004 + http://www.apache.org/licenses/ + + TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION + + 1. Definitions. + + "License" shall mean the terms and conditions for use, reproduction, + and distribution as defined by Sections 1 through 9 of this document. + + "Licensor" shall mean the copyright owner or entity authorized by + the copyright owner that is granting the License. + + "Legal Entity" shall mean the union of the acting entity and all + other entities that control, are controlled by, or are under common + control with that entity. For the purposes of this definition, + "control" means (i) the power, direct or indirect, to cause the + direction or management of such entity, whether by contract or + otherwise, or (ii) ownership of fifty percent (50%) or more of the + outstanding shares, or (iii) beneficial ownership of such entity. + + "You" (or "Your") shall mean an individual or Legal Entity + exercising permissions granted by this License. + + "Source" form shall mean the preferred form for making modifications, + including but not limited to software source code, documentation + source, and configuration files. + + "Object" form shall mean any form resulting from mechanical + transformation or translation of a Source form, including but + not limited to compiled object code, generated documentation, + and conversions to other media types. + + "Work" shall mean the work of authorship, whether in Source or + Object form, made available under the License, as indicated by a + copyright notice that is included in or attached to the work + (an example is provided in the Appendix below). + + "Derivative Works" shall mean any work, whether in Source or Object + form, that is based on (or derived from) the Work and for which the + editorial revisions, annotations, elaborations, or other modifications + represent, as a whole, an original work of authorship. For the purposes + of this License, Derivative Works shall not include works that remain + separable from, or merely link (or bind by name) to the interfaces of, + the Work and Derivative Works thereof. + + "Contribution" shall mean any work of authorship, including + the original version of the Work and any modifications or additions + to that Work or Derivative Works thereof, that is intentionally + submitted to Licensor for inclusion in the Work by the copyright owner + or by an individual or Legal Entity authorized to submit on behalf of + the copyright owner. For the purposes of this definition, "submitted" + means any form of electronic, verbal, or written communication sent + to the Licensor or its representatives, including but not limited to + communication on electronic mailing lists, source code control systems, + and issue tracking systems that are managed by, or on behalf of, the + Licensor for the purpose of discussing and improving the Work, but + excluding communication that is conspicuously marked or otherwise + designated in writing by the copyright owner as "Not a Contribution." + + "Contributor" shall mean Licensor and any individual or Legal Entity + on behalf of whom a Contribution has been received by Licensor and + subsequently incorporated within the Work. + + 2. Grant of Copyright License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + copyright license to reproduce, prepare Derivative Works of, + publicly display, publicly perform, sublicense, and distribute the + Work and such Derivative Works in Source or Object form. + + 3. Grant of Patent License. Subject to the terms and conditions of + this License, each Contributor hereby grants to You a perpetual, + worldwide, non-exclusive, no-charge, royalty-free, irrevocable + (except as stated in this section) patent license to make, have made, + use, offer to sell, sell, import, and otherwise transfer the Work, + where such license applies only to those patent claims licensable + by such Contributor that are necessarily infringed by their + Contribution(s) alone or by combination of their Contribution(s) + with the Work to which such Contribution(s) was submitted. If You + institute patent litigation against any entity (including a + cross-claim or counterclaim in a lawsuit) alleging that the Work + or a Contribution incorporated within the Work constitutes direct + or contributory patent infringement, then any patent licenses + granted to You under this License for that Work shall terminate + as of the date such litigation is filed. + + 4. Redistribution. You may reproduce and distribute copies of the + Work or Derivative Works thereof in any medium, with or without + modifications, and in Source or Object form, provided that You + meet the following conditions: + + (a) You must give any other recipients of the Work or + Derivative Works a copy of this License; and + + (b) You must cause any modified files to carry prominent notices + stating that You changed the files; and + + (c) You must retain, in the Source form of any Derivative Works + that You distribute, all copyright, patent, trademark, and + attribution notices from the Source form of the Work, + excluding those notices that do not pertain to any part of + the Derivative Works; and + + (d) If the Work includes a "NOTICE" text file as part of its + distribution, then any Derivative Works that You distribute must + include a readable copy of the attribution notices contained + within such NOTICE file, excluding those notices that do not + pertain to any part of the Derivative Works, in at least one + of the following places: within a NOTICE text file distributed + as part of the Derivative Works; within the Source form or + documentation, if provided along with the Derivative Works; or, + within a display generated by the Derivative Works, if and + wherever such third-party notices normally appear. The contents + of the NOTICE file are for informational purposes only and + do not modify the License. You may add Your own attribution + notices within Derivative Works that You distribute, alongside + or as an addendum to the NOTICE text from the Work, provided + that such additional attribution notices cannot be construed + as modifying the License. + + You may add Your own copyright statement to Your modifications and + may provide additional or different license terms and conditions + for use, reproduction, or distribution of Your modifications, or + for any such Derivative Works as a whole, provided Your use, + reproduction, and distribution of the Work otherwise complies with + the conditions stated in this License. + + 5. Submission of Contributions. Unless You explicitly state otherwise, + any Contribution intentionally submitted for inclusion in the Work + by You to the Licensor shall be under the terms and conditions of + this License, without any additional terms or conditions. + Notwithstanding the above, nothing herein shall supersede or modify + the terms of any separate license agreement you may have executed + with Licensor regarding such Contributions. + + 6. Trademarks. This License does not grant permission to use the trade + names, trademarks, service marks, or product names of the Licensor, + except as required for reasonable and customary use in describing the + origin of the Work and reproducing the content of the NOTICE file. + + 7. Disclaimer of Warranty. Unless required by applicable law or + agreed to in writing, Licensor provides the Work (and each + Contributor provides its Contributions) on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or + implied, including, without limitation, any warranties or conditions + of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A + PARTICULAR PURPOSE. You are solely responsible for determining the + appropriateness of using or redistributing the Work and assume any + risks associated with Your exercise of permissions under this License. + + 8. Limitation of Liability. In no event and under no legal theory, + whether in tort (including negligence), contract, or otherwise, + unless required by applicable law (such as deliberate and grossly + negligent acts) or agreed to in writing, shall any Contributor be + liable to You for damages, including any direct, indirect, special, + incidental, or consequential damages of any character arising as a + result of this License or out of the use or inability to use the + Work (including but not limited to damages for loss of goodwill, + work stoppage, computer failure or malfunction, or any and all + other commercial damages or losses), even if such Contributor + has been advised of the possibility of such damages. + + 9. Accepting Warranty or Additional Liability. While redistributing + the Work or Derivative Works thereof, You may choose to offer, + and charge a fee for, acceptance of support, warranty, indemnity, + or other liability obligations and/or rights consistent with this + License. However, in accepting such obligations, You may act only + on Your own behalf and on Your sole responsibility, not on behalf + of any other Contributor, and only if You agree to indemnify, + defend, and hold each Contributor harmless for any liability + incurred by, or claims asserted against, such Contributor by reason + of your accepting any such warranty or additional liability. + + END OF TERMS AND CONDITIONS + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + 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. diff --git a/make/_shared/repository-base/base/Makefile b/make/_shared/repository-base/base/Makefile new file mode 100644 index 0000000..6c5aa12 --- /dev/null +++ b/make/_shared/repository-base/base/Makefile @@ -0,0 +1,116 @@ +# Copyright 2023 The cert-manager 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. + +# THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. +# Edit https://github.com/cert-manager/makefile-modules/blob/main/modules/repository-base/base/Makefile instead. + +# NOTE FOR DEVELOPERS: "How do the Makefiles work and how can I extend them?" +# +# Shared Makefile logic lives in the make/_shared/ directory. The source of truth for these files +# lies outside of this repository, eg. in the cert-manager/makefile-modules repository. +# +# Logic specific to this repository must be defined in the make/00_mod.mk and make/02_mod.mk files: +# - The make/00_mod.mk file is included first and contains variable definitions needed by +# the shared Makefile logic. +# - The make/02_mod.mk file is included later, it can make use of most of the shared targets +# defined in the make/_shared/ directory (all targets defined in 00_mod.mk and 01_mod.mk). +# This file should be used to define targets specific to this repository. + +################################## + +# Some modules build their dependencies from variables, we want these to be +# evalutated at the last possible moment. For this we use second expansion to +# re-evaluate the generate and verify targets a second time. +# +# See https://www.gnu.org/software/make/manual/html_node/Secondary-Expansion.html +.SECONDEXPANSION: + +# For details on some of these "prelude" settings, see: +# https://clarkgrubb.com/makefile-style-guide +MAKEFLAGS += --warn-undefined-variables --no-builtin-rules +SHELL := /usr/bin/env bash +.SHELLFLAGS := -uo pipefail -c +.DEFAULT_GOAL := help +.DELETE_ON_ERROR: +.SUFFIXES: +FORCE: + +noop: # do nothing + +# Set empty value for MAKECMDGOALS to prevent the "warning: undefined variable 'MAKECMDGOALS'" +# warning from happening when running make without arguments +MAKECMDGOALS ?= + +################################## +# Host OS and architecture setup # +################################## + +# The reason we don't use "go env GOOS" or "go env GOARCH" is that the "go" +# binary may not be available in the PATH yet when the Makefiles are +# evaluated. HOST_OS and HOST_ARCH only support Linux, *BSD and macOS (M1 +# and Intel). +host_os := $(shell uname -s | tr A-Z a-z) +host_arch := $(shell uname -m) +HOST_OS ?= $(host_os) +HOST_ARCH ?= $(host_arch) + +ifeq (x86_64, $(HOST_ARCH)) + HOST_ARCH = amd64 +else ifeq (aarch64, $(HOST_ARCH)) + # linux reports the arm64 arch as aarch64 + HOST_ARCH = arm64 +endif + +################################## +# Git and versioning information # +################################## + +git_version := $(shell git describe --tags --always --match='v*' --abbrev=14 --dirty) +VERSION ?= $(git_version) +IS_PRERELEASE := $(shell git describe --tags --always --match='v*' --abbrev=0 | grep -q '-' && echo true || echo false) +GITCOMMIT := $(shell git rev-parse HEAD) +GITEPOCH := $(shell git show -s --format=%ct HEAD) + +################################## +# Global variables and dirs # +################################## + +bin_dir := _bin + +# The ARTIFACTS environment variable is set by the CI system to a directory +# where artifacts should be placed. These artifacts are then uploaded to a +# storage bucket by the CI system (https://docs.prow.k8s.io/docs/components/pod-utilities/). +# An example of such an artifact is a jUnit XML file containing test results. +# If the ARTIFACTS environment variable is not set, we default to a local +# directory in the _bin directory. +ARTIFACTS ?= $(bin_dir)/artifacts + +$(bin_dir) $(ARTIFACTS) $(bin_dir)/scratch: + mkdir -p $@ + +.PHONY: clean +## Clean all temporary files +## @category [shared] Tools +clean: + rm -rf $(bin_dir) + +################################## +# Include all the Makefiles # +################################## + +-include make/00_mod.mk +-include make/_shared/*/00_mod.mk +-include make/_shared/*/01_mod.mk +-include make/02_mod.mk +-include make/_shared/*/02_mod.mk diff --git a/make/_shared/repository-base/base/OWNERS_ALIASES b/make/_shared/repository-base/base/OWNERS_ALIASES new file mode 100644 index 0000000..10d1279 --- /dev/null +++ b/make/_shared/repository-base/base/OWNERS_ALIASES @@ -0,0 +1,14 @@ +# THIS FILE IS AUTOMATICALLY GENERATED. DO NOT EDIT. +# Edit https://github.com/cert-manager/makefile-modules/blob/main/modules/repository-base/base/OWNERS_ALIASES instead. + +aliases: + cm-maintainers: + - munnerz + - joshvanl + - wallrj + - jakexks + - maelvls + - irbekrm + - sgtcodfish + - inteon + - thatsmrtalbot diff --git a/make/_shared/tools/00_mod.mk b/make/_shared/tools/00_mod.mk new file mode 100644 index 0000000..39caa7a --- /dev/null +++ b/make/_shared/tools/00_mod.mk @@ -0,0 +1,649 @@ +# Copyright 2023 The cert-manager 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. + +ifndef bin_dir +$(error bin_dir is not set) +endif + +########################################## + +export DOWNLOAD_DIR ?= $(CURDIR)/$(bin_dir)/downloaded +export GOVENDOR_DIR ?= $(CURDIR)/$(bin_dir)/go_vendor + +$(bin_dir)/scratch/image $(bin_dir)/tools $(DOWNLOAD_DIR)/tools: + @mkdir -p $@ + +checkhash_script := $(dir $(lastword $(MAKEFILE_LIST)))/util/checkhash.sh +lock_script := $(dir $(lastword $(MAKEFILE_LIST)))/util/lock.sh + +# $outfile is a variable in the lock script +outfile := $$outfile + +for_each_kv = $(foreach item,$2,$(eval $(call $1,$(word 1,$(subst =, ,$(item))),$(word 2,$(subst =, ,$(item)))))) + +# To make sure we use the right version of each tool, we put symlink in +# $(bin_dir)/tools, and the actual binaries are in $(bin_dir)/downloaded. When bumping +# the version of the tools, this symlink gets updated. + +# Let's have $(bin_dir)/tools in front of the PATH so that we don't inavertedly +# pick up the wrong binary somewhere. Watch out, $(shell echo $$PATH) will +# still print the original PATH, since GNU make does not honor exported +# variables: https://stackoverflow.com/questions/54726457 +export PATH := $(CURDIR)/$(bin_dir)/tools:$(PATH) + +CTR=docker + +tools := +# https://github.com/helm/helm/releases +tools += helm=v3.14.4 +# https://dl.k8s.io/release/$(curl -L -s https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl +tools += kubectl=v1.30.0 +# https://github.com/kubernetes-sigs/kind/releases +tools += kind=v0.23.0 +# https://www.vaultproject.io/downloads +tools += vault=1.16.2 +# https://github.com/Azure/azure-workload-identity/releases +tools += azwi=v1.2.2 +# https://github.com/kyverno/kyverno/releases +tools += kyverno=v1.12.1 +# https://github.com/mikefarah/yq/releases +tools += yq=v4.43.1 +# https://github.com/ko-build/ko/releases +tools += ko=0.15.2 +# https://github.com/protocolbuffers/protobuf/releases +tools += protoc=26.1 +# https://github.com/aquasecurity/trivy/releases +tools += trivy=v0.50.4 +# https://github.com/vmware-tanzu/carvel-ytt/releases +tools += ytt=v0.49.0 +# https://github.com/rclone/rclone/releases +tools += rclone=v1.66.0 + +### go packages +# https://pkg.go.dev/sigs.k8s.io/controller-tools/cmd/controller-gen?tab=versions +tools += controller-gen=v0.15.0 +# https://pkg.go.dev/golang.org/x/tools/cmd/goimports?tab=versions +tools += goimports=v0.20.0 +# https://pkg.go.dev/github.com/google/go-licenses/licenses?tab=versions +tools += go-licenses=706b9c60edd424a8b6d253fe10dfb7b8e942d4a5 +# https://pkg.go.dev/gotest.tools/gotestsum?tab=versions +tools += gotestsum=v1.11.0 +# https://pkg.go.dev/sigs.k8s.io/kustomize/kustomize/v4?tab=versions +tools += kustomize=v4.5.7 +# https://pkg.go.dev/github.com/itchyny/gojq?tab=versions +tools += gojq=v0.12.15 +# https://pkg.go.dev/github.com/google/go-containerregistry/pkg/crane?tab=versions +tools += crane=v0.19.1 +# https://pkg.go.dev/google.golang.org/protobuf/cmd/protoc-gen-go?tab=versions +tools += protoc-gen-go=v1.34.0 +# https://pkg.go.dev/github.com/norwoodj/helm-docs/cmd/helm-docs?tab=versions +tools += helm-docs=v1.13.1 +# https://pkg.go.dev/github.com/sigstore/cosign/v2/cmd/cosign?tab=versions +tools += cosign=v2.2.4 +# https://pkg.go.dev/github.com/cert-manager/boilersuite?tab=versions +tools += boilersuite=v0.1.0 +# https://pkg.go.dev/github.com/princjef/gomarkdoc/cmd/gomarkdoc?tab=versions +tools += gomarkdoc=v1.1.0 +# https://pkg.go.dev/oras.land/oras/cmd/oras?tab=versions +tools += oras=v1.1.0 +# https://pkg.go.dev/github.com/onsi/ginkgo/v2/ginkgo?tab=versions +# The gingko version should be kept in sync with the version used in code. +# If there is no go.mod file (which is only the case for the makefile-modules +# repo), then we default to a version that we know exists. We have to do this +# because otherwise the awk failure renders the whole makefile unusable. +detected_ginkgo_version := $(shell [[ -f go.mod ]] && awk '/ginkgo\/v2/ {print $$2}' go.mod || echo "v2.13.2") +tools += ginkgo=$(detected_ginkgo_version) +# https://pkg.go.dev/github.com/cert-manager/klone?tab=versions +tools += klone=v0.0.5 +# https://pkg.go.dev/github.com/goreleaser/goreleaser?tab=versions +tools += goreleaser=v1.25.1 +# https://pkg.go.dev/github.com/anchore/syft/cmd/syft?tab=versions +tools += syft=v0.100.0 +# https://github.com/cert-manager/helm-tool +tools += helm-tool=v0.5.1 +# https://github.com/cert-manager/cmctl +tools += cmctl=v2.0.0 +# https://pkg.go.dev/github.com/cert-manager/release/cmd/cmrel?tab=versions +tools += cmrel=e4c3a4dc07df5c7c0379d334c5bb00e172462551 +# https://github.com/golangci/golangci-lint/releases +tools += golangci-lint=v1.57.2 +# https://pkg.go.dev/golang.org/x/vuln?tab=versions +tools += govulncheck=v1.1.0 +# https://pkg.go.dev/github.com/operator-framework/operator-sdk/cmd/operator-sdk?tab=versions +tools += operator-sdk=v1.34.1 +# https://pkg.go.dev/github.com/cli/cli/v2?tab=versions +tools += gh=v2.49.0 +# https:///github.com/redhat-openshift-ecosystem/openshift-preflight/releases +tools += preflight=1.9.2 +# https://github.com/daixiang0/gci/releases +tools += gci=v0.13.4 +# https://github.com/google/yamlfmt/releases +tools += yamlfmt=v0.12.1 + +# https://pkg.go.dev/k8s.io/code-generator/cmd?tab=versions +K8S_CODEGEN_VERSION := v0.30.1 +tools += client-gen=$(K8S_CODEGEN_VERSION) +tools += deepcopy-gen=$(K8S_CODEGEN_VERSION) +tools += informer-gen=$(K8S_CODEGEN_VERSION) +tools += lister-gen=$(K8S_CODEGEN_VERSION) +tools += applyconfiguration-gen=$(K8S_CODEGEN_VERSION) +tools += defaulter-gen=$(K8S_CODEGEN_VERSION) +tools += conversion-gen=$(K8S_CODEGEN_VERSION) +# https://github.com/kubernetes/kube-openapi +tools += openapi-gen=f0e62f92d13f418e2732b21c952fd17cab771c75 + +# https://raw.githubusercontent.com/kubernetes-sigs/controller-tools/master/envtest-releases.yaml +KUBEBUILDER_ASSETS_VERSION := v1.30.0 +tools += etcd=$(KUBEBUILDER_ASSETS_VERSION) +tools += kube-apiserver=$(KUBEBUILDER_ASSETS_VERSION) + +# Additional tools can be defined to reuse the tooling in this file +ADDITIONAL_TOOLS ?= +tools += $(ADDITIONAL_TOOLS) + +# https://go.dev/dl/ +VENDORED_GO_VERSION := 1.22.4 + +# Print the go version which can be used in GH actions +.PHONY: print-go-version +print-go-version: + @echo result=$(VENDORED_GO_VERSION) + +# When switching branches which use different versions of the tools, we +# need a way to re-trigger the symlinking from $(bin_dir)/downloaded to $(bin_dir)/tools. +$(bin_dir)/scratch/%_VERSION: FORCE | $(bin_dir)/scratch + @test "$($*_VERSION)" == "$(shell cat $@ 2>/dev/null)" || echo $($*_VERSION) > $@ + +# --silent = don't print output like progress meters +# --show-error = but do print errors when they happen +# --fail = exit with a nonzero error code without the response from the server when there's an HTTP error +# --location = follow redirects from the server +# --retry = the number of times to retry a failed attempt to connect +# --retry-connrefused = retry even if the initial connection was refused +CURL := curl --silent --show-error --fail --location --retry 10 --retry-connrefused + +# LN is expected to be an atomic action, meaning that two Make processes +# can run the "link $(DOWNLOAD_DIR)/tools/xxx@$(XXX_VERSION)_$(HOST_OS)_$(HOST_ARCH) +# to $(bin_dir)/tools/xxx" operation simulatiously without issues (both +# will perform the action and the second time the link will be overwritten). +LN := ln -fs + +upper_map := a:A b:B c:C d:D e:E f:F g:G h:H i:I j:J k:K l:L m:M n:N o:O p:P q:Q r:R s:S t:T u:U v:V w:W x:X y:Y z:Z +uc = $(strip \ + $(eval __upper := $1) \ + $(foreach p,$(upper_map), \ + $(eval __upper := $(subst $(word 1,$(subst :, ,$p)),$(word 2,$(subst :, ,$p)),$(__upper))) \ + ) \ + )$(__upper) + +tool_names := + +# for each item `xxx` in the tools variable: +# - a $(XXX_VERSION) variable is generated +# -> this variable contains the version of the tool +# - a $(NEEDS_XXX) variable is generated +# -> this variable contains the target name for the tool, +# which is the relative path of the binary, this target +# should be used when adding the tool as a dependency to +# your target, you can't use $(XXX) as a dependency because +# make does not support an absolute path as a dependency +# - a $(XXX) variable is generated +# -> this variable contains the absolute path of the binary, +# the absolute path should be used when executing the binary +# in targets or in scripts, because it is agnostic to the +# working directory +# - an unversioned target $(bin_dir)/tools/xxx is generated that +# creates a link to the corresponding versioned target: +# $(DOWNLOAD_DIR)/tools/xxx@$(XXX_VERSION)_$(HOST_OS)_$(HOST_ARCH) +define tool_defs +tool_names += $1 + +$(call uc,$1)_VERSION ?= $2 +NEEDS_$(call uc,$1) := $$(bin_dir)/tools/$1 +$(call uc,$1) := $$(CURDIR)/$$(bin_dir)/tools/$1 + +$$(bin_dir)/tools/$1: $$(bin_dir)/scratch/$(call uc,$1)_VERSION | $$(DOWNLOAD_DIR)/tools/$1@$$($(call uc,$1)_VERSION)_$$(HOST_OS)_$$(HOST_ARCH) $$(bin_dir)/tools + @cd $$(dir $$@) && $$(LN) $$(patsubst $$(bin_dir)/%,../%,$$(word 1,$$|)) $$(notdir $$@) + @touch $$@ # making sure the target of the symlink is newer than *_VERSION +endef + +$(foreach tool,$(tools),$(eval $(call tool_defs,$(word 1,$(subst =, ,$(tool))),$(word 2,$(subst =, ,$(tool)))))) + +tools_paths := $(tool_names:%=$(bin_dir)/tools/%) + +###### +# Go # +###### + +# $(NEEDS_GO) is a target that is set as an order-only prerequisite in +# any target that calls $(GO), e.g.: +# +# $(bin_dir)/tools/crane: $(NEEDS_GO) +# $(GO) build -o $(bin_dir)/tools/crane +# +# $(NEEDS_GO) is empty most of the time, except when running "make vendor-go" +# or when "make vendor-go" was previously run, in which case $(NEEDS_GO) is set +# to $(bin_dir)/tools/go, since $(bin_dir)/tools/go is a prerequisite of +# any target depending on Go when "make vendor-go" was run. + +detected_vendoring := $(findstring vendor-go,$(MAKECMDGOALS))$(shell [ -f $(bin_dir)/tools/go ] && echo yes) +export VENDOR_GO ?= $(detected_vendoring) + +ifeq ($(VENDOR_GO),) +GO := go +NEEDS_GO := # +else +export GOROOT := $(CURDIR)/$(bin_dir)/tools/goroot +export PATH := $(CURDIR)/$(bin_dir)/tools/goroot/bin:$(PATH) +GO := $(CURDIR)/$(bin_dir)/tools/go +NEEDS_GO := $(bin_dir)/tools/go +MAKE := $(MAKE) vendor-go +endif + +.PHONY: vendor-go +## By default, this Makefile uses the system's Go. You can use a "vendored" +## version of Go that will get downloaded by running this command once. To +## disable vendoring, run "make unvendor-go". When vendoring is enabled, +## you will want to set the following: +## +## export PATH="$PWD/$(bin_dir)/tools:$PATH" +## export GOROOT="$PWD/$(bin_dir)/tools/goroot" +## @category [shared] Tools +vendor-go: $(bin_dir)/tools/go + +.PHONY: unvendor-go +unvendor-go: $(bin_dir)/tools/go + rm -rf $(bin_dir)/tools/go $(bin_dir)/tools/goroot + +.PHONY: which-go +## Print the version and path of go which will be used for building and +## testing in Makefile commands. Vendored go will have a path in ./bin +## @category [shared] Tools +which-go: | $(NEEDS_GO) + @$(GO) version + @echo "go binary used for above version information: $(GO)" + +$(bin_dir)/tools/go: $(bin_dir)/scratch/VENDORED_GO_VERSION | $(bin_dir)/tools/goroot $(bin_dir)/tools + @cd $(dir $@) && $(LN) ./goroot/bin/go $(notdir $@) + @touch $@ # making sure the target of the symlink is newer than *_VERSION + +# The "_" in "_bin" prevents "go mod tidy" from trying to tidy the vendored goroot. +$(bin_dir)/tools/goroot: $(bin_dir)/scratch/VENDORED_GO_VERSION | $(GOVENDOR_DIR)/go@$(VENDORED_GO_VERSION)_$(HOST_OS)_$(HOST_ARCH)/goroot $(bin_dir)/tools + @cd $(dir $@) && $(LN) $(patsubst $(bin_dir)/%,../%,$(word 1,$|)) $(notdir $@) + @touch $@ # making sure the target of the symlink is newer than *_VERSION + +# Extract the tar to the $(GOVENDOR_DIR) directory, this directory is not cached across CI runs. +$(GOVENDOR_DIR)/go@$(VENDORED_GO_VERSION)_$(HOST_OS)_$(HOST_ARCH)/goroot: | $(DOWNLOAD_DIR)/tools/go@$(VENDORED_GO_VERSION)_$(HOST_OS)_$(HOST_ARCH).tar.gz + @source $(lock_script) $@; \ + mkdir -p $(outfile).dir; \ + tar xzf $| -C $(outfile).dir; \ + mv $(outfile).dir/go $(outfile); \ + rm -rf $(outfile).dir + +################### +# go dependencies # +################### + +go_dependencies := +go_dependencies += ginkgo=github.com/onsi/ginkgo/v2/ginkgo +go_dependencies += controller-gen=sigs.k8s.io/controller-tools/cmd/controller-gen +go_dependencies += goimports=golang.org/x/tools/cmd/goimports +go_dependencies += go-licenses=github.com/google/go-licenses +go_dependencies += gotestsum=gotest.tools/gotestsum +go_dependencies += kustomize=sigs.k8s.io/kustomize/kustomize/v4 +go_dependencies += gojq=github.com/itchyny/gojq/cmd/gojq +go_dependencies += crane=github.com/google/go-containerregistry/cmd/crane +go_dependencies += protoc-gen-go=google.golang.org/protobuf/cmd/protoc-gen-go +go_dependencies += helm-docs=github.com/norwoodj/helm-docs/cmd/helm-docs +go_dependencies += cosign=github.com/sigstore/cosign/v2/cmd/cosign +go_dependencies += boilersuite=github.com/cert-manager/boilersuite +go_dependencies += gomarkdoc=github.com/princjef/gomarkdoc/cmd/gomarkdoc +go_dependencies += oras=oras.land/oras/cmd/oras +go_dependencies += klone=github.com/cert-manager/klone +go_dependencies += goreleaser=github.com/goreleaser/goreleaser +go_dependencies += syft=github.com/anchore/syft/cmd/syft +go_dependencies += client-gen=k8s.io/code-generator/cmd/client-gen +go_dependencies += deepcopy-gen=k8s.io/code-generator/cmd/deepcopy-gen +go_dependencies += informer-gen=k8s.io/code-generator/cmd/informer-gen +go_dependencies += lister-gen=k8s.io/code-generator/cmd/lister-gen +go_dependencies += applyconfiguration-gen=k8s.io/code-generator/cmd/applyconfiguration-gen +go_dependencies += defaulter-gen=k8s.io/code-generator/cmd/defaulter-gen +go_dependencies += conversion-gen=k8s.io/code-generator/cmd/conversion-gen +go_dependencies += openapi-gen=k8s.io/kube-openapi/cmd/openapi-gen +go_dependencies += helm-tool=github.com/cert-manager/helm-tool +go_dependencies += cmctl=github.com/cert-manager/cmctl/v2 +go_dependencies += cmrel=github.com/cert-manager/release/cmd/cmrel +go_dependencies += golangci-lint=github.com/golangci/golangci-lint/cmd/golangci-lint +go_dependencies += govulncheck=golang.org/x/vuln/cmd/govulncheck +go_dependencies += operator-sdk=github.com/operator-framework/operator-sdk/cmd/operator-sdk +go_dependencies += gh=github.com/cli/cli/v2/cmd/gh +go_dependencies += gci=github.com/daixiang0/gci +go_dependencies += yamlfmt=github.com/google/yamlfmt/cmd/yamlfmt + +################# +# go build tags # +################# + +go_tags := + +# Additional Go dependencies can be defined to re-use the tooling in this file +ADDITIONAL_GO_DEPENDENCIES ?= +ADDITIONAL_GO_TAGS ?= +go_dependencies += $(ADDITIONAL_GO_DEPENDENCIES) +go_tags += $(ADDITIONAL_GO_TAGS) + +go_tags_init = go_tags_$1 := +$(call for_each_kv,go_tags_init,$(go_dependencies)) + +go_tags_defs = go_tags_$1 += $2 +$(call for_each_kv,go_tags_defs,$(go_tags)) + +define go_dependency +$$(DOWNLOAD_DIR)/tools/$1@$($(call uc,$1)_VERSION)_$(HOST_OS)_$(HOST_ARCH): | $$(NEEDS_GO) $$(DOWNLOAD_DIR)/tools + @source $$(lock_script) $$@; \ + mkdir -p $$(outfile).dir; \ + GOWORK=off GOBIN=$$(outfile).dir $$(GO) install --tags "$(strip $(go_tags_$1))" $2@$($(call uc,$1)_VERSION); \ + mv $$(outfile).dir/$1 $$(outfile); \ + rm -rf $$(outfile).dir +endef +$(call for_each_kv,go_dependency,$(go_dependencies)) + +################## +# File downloads # +################## + +go_linux_amd64_SHA256SUM=ba79d4526102575196273416239cca418a651e049c2b099f3159db85e7bade7d +go_linux_arm64_SHA256SUM=a8e177c354d2e4a1b61020aca3562e27ea3e8f8247eca3170e3fa1e0c2f9e771 +go_darwin_amd64_SHA256SUM=c95967f50aa4ace34af0c236cbdb49a9a3e80ee2ad09d85775cb4462a5c19ed3 +go_darwin_arm64_SHA256SUM=242b78dc4c8f3d5435d28a0d2cec9b4c1aa999b601fb8aa59fb4e5a1364bf827 + +.PRECIOUS: $(DOWNLOAD_DIR)/tools/go@$(VENDORED_GO_VERSION)_$(HOST_OS)_$(HOST_ARCH).tar.gz +$(DOWNLOAD_DIR)/tools/go@$(VENDORED_GO_VERSION)_$(HOST_OS)_$(HOST_ARCH).tar.gz: | $(DOWNLOAD_DIR)/tools + @source $(lock_script) $@; \ + $(CURL) https://go.dev/dl/go$(VENDORED_GO_VERSION).$(HOST_OS)-$(HOST_ARCH).tar.gz -o $(outfile); \ + $(checkhash_script) $(outfile) $(go_$(HOST_OS)_$(HOST_ARCH)_SHA256SUM) + +helm_linux_amd64_SHA256SUM=a5844ef2c38ef6ddf3b5a8f7d91e7e0e8ebc39a38bb3fc8013d629c1ef29c259 +helm_linux_arm64_SHA256SUM=113ccc53b7c57c2aba0cd0aa560b5500841b18b5210d78641acfddc53dac8ab2 +helm_darwin_amd64_SHA256SUM=73434aeac36ad068ce2e5582b8851a286dc628eae16494a26e2ad0b24a7199f9 +helm_darwin_arm64_SHA256SUM=61e9c5455f06b2ad0a1280975bf65892e707adc19d766b0cf4e9006e3b7b4b6c + +.PRECIOUS: $(DOWNLOAD_DIR)/tools/helm@$(HELM_VERSION)_$(HOST_OS)_$(HOST_ARCH) +$(DOWNLOAD_DIR)/tools/helm@$(HELM_VERSION)_$(HOST_OS)_$(HOST_ARCH): | $(DOWNLOAD_DIR)/tools + @source $(lock_script) $@; \ + $(CURL) https://get.helm.sh/helm-$(HELM_VERSION)-$(HOST_OS)-$(HOST_ARCH).tar.gz -o $(outfile).tar.gz; \ + $(checkhash_script) $(outfile).tar.gz $(helm_$(HOST_OS)_$(HOST_ARCH)_SHA256SUM); \ + tar xfO $(outfile).tar.gz $(HOST_OS)-$(HOST_ARCH)/helm > $(outfile); \ + chmod +x $(outfile); \ + rm -f $(outfile).tar.gz + +kubectl_linux_amd64_SHA256SUM=7c3807c0f5c1b30110a2ff1e55da1d112a6d0096201f1beb81b269f582b5d1c5 +kubectl_linux_arm64_SHA256SUM=669af0cf520757298ea60a8b6eb6b719ba443a9c7d35f36d3fb2fd7513e8c7d2 +kubectl_darwin_amd64_SHA256SUM=bcfa57d020b8d07d0ea77235ce8012c2c28fefdfd7cb9738f33674a7b16cef08 +kubectl_darwin_arm64_SHA256SUM=45cfa208151320153742062824398f22bb6bfb5a142bf6238476d55dacbd1bdd + +.PRECIOUS: $(DOWNLOAD_DIR)/tools/kubectl@$(KUBECTL_VERSION)_$(HOST_OS)_$(HOST_ARCH) +$(DOWNLOAD_DIR)/tools/kubectl@$(KUBECTL_VERSION)_$(HOST_OS)_$(HOST_ARCH): | $(DOWNLOAD_DIR)/tools + @source $(lock_script) $@; \ + $(CURL) https://dl.k8s.io/release/$(KUBECTL_VERSION)/bin/$(HOST_OS)/$(HOST_ARCH)/kubectl -o $(outfile); \ + $(checkhash_script) $(outfile) $(kubectl_$(HOST_OS)_$(HOST_ARCH)_SHA256SUM); \ + chmod +x $(outfile) + +kind_linux_amd64_SHA256SUM=1d86e3069ffbe3da9f1a918618aecbc778e00c75f838882d0dfa2d363bc4a68c +kind_linux_arm64_SHA256SUM=a416d6c311882337f0e56910e4a2e1f8c106ec70c22cbf0ac1dd8f33c1e284fe +kind_darwin_amd64_SHA256SUM=81c77f104b4b668812f7930659dc01ad88fa4d1cfc56900863eacdfb2731c457 +kind_darwin_arm64_SHA256SUM=68ec87c1e1ea2a708df883f4b94091150d19552d7b344e80ca59f449b301c2a0 + +.PRECIOUS: $(DOWNLOAD_DIR)/tools/kind@$(KIND_VERSION)_$(HOST_OS)_$(HOST_ARCH) +$(DOWNLOAD_DIR)/tools/kind@$(KIND_VERSION)_$(HOST_OS)_$(HOST_ARCH): | $(DOWNLOAD_DIR)/tools + @source $(lock_script) $@; \ + $(CURL) https://github.com/kubernetes-sigs/kind/releases/download/$(KIND_VERSION)/kind-$(HOST_OS)-$(HOST_ARCH) -o $(outfile); \ + $(checkhash_script) $(outfile) $(kind_$(HOST_OS)_$(HOST_ARCH)_SHA256SUM); \ + chmod +x $(outfile) + +vault_linux_amd64_SHA256SUM=688ce462b70cb674f84fddb731f75bb710db5ad9e4e5a17659e90e1283a8b4b7 +vault_linux_arm64_SHA256SUM=d5bd42227d295b1dcc4a5889c37e6a8ca945ece4795819718eaf54db87aa6d4f +vault_darwin_amd64_SHA256SUM=e4886d22273dedc579dc2382e114e7be29341049a48592f8f7be8a0020310731 +vault_darwin_arm64_SHA256SUM=ca59c85e7e3d67e25b6bfa505f7e7717b418452e8bfcd602a2a717bc06d5b1ee + +.PRECIOUS: $(DOWNLOAD_DIR)/tools/vault@$(VAULT_VERSION)_$(HOST_OS)_$(HOST_ARCH) +$(DOWNLOAD_DIR)/tools/vault@$(VAULT_VERSION)_$(HOST_OS)_$(HOST_ARCH): | $(DOWNLOAD_DIR)/tools + @source $(lock_script) $@; \ + $(CURL) https://releases.hashicorp.com/vault/$(VAULT_VERSION)/vault_$(VAULT_VERSION)_$(HOST_OS)_$(HOST_ARCH).zip -o $(outfile).zip; \ + $(checkhash_script) $(outfile).zip $(vault_$(HOST_OS)_$(HOST_ARCH)_SHA256SUM); \ + unzip -qq -c $(outfile).zip > $(outfile); \ + chmod +x $(outfile); \ + rm -f $(outfile).zip + +azwi_linux_amd64_SHA256SUM=d33aaedbcbcc0ef61d845b3704ab336deaafc192c854e887896e163b99097871 +azwi_linux_arm64_SHA256SUM=7c4b55ef83e62f4b597885e66fbbdf0720cf0e2be3f1a16212f9b41d4b61b454 +azwi_darwin_amd64_SHA256SUM=47a9e99a7e02e531967d1c9a8abf12e73134f88ce3363007f411ba9b83497fd0 +azwi_darwin_arm64_SHA256SUM=19c5cf9fe4e1a7394bc01456d5e314fd898162d2d360c585fc72e46dae930659 + +.PRECIOUS: $(DOWNLOAD_DIR)/tools/azwi@$(AZWI_VERSION)_$(HOST_OS)_$(HOST_ARCH) +$(DOWNLOAD_DIR)/tools/azwi@$(AZWI_VERSION)_$(HOST_OS)_$(HOST_ARCH): | $(DOWNLOAD_DIR)/tools + @source $(lock_script) $@; \ + $(CURL) https://github.com/Azure/azure-workload-identity/releases/download/$(AZWI_VERSION)/azwi-$(AZWI_VERSION)-$(HOST_OS)-$(HOST_ARCH).tar.gz -o $(outfile).tar.gz; \ + $(checkhash_script) $(outfile).tar.gz $(azwi_$(HOST_OS)_$(HOST_ARCH)_SHA256SUM); \ + tar xfO $(outfile).tar.gz azwi > $(outfile) && chmod 775 $(outfile); \ + rm -f $(outfile).tar.gz + +kubebuilder_tools_linux_amd64_SHA256SUM=2a9792cb5f1403f524543ce94c3115e3c4a4229f0e86af55fd26c078da448164 +kubebuilder_tools_linux_arm64_SHA256SUM=39cc7274a3075a650a20fcd24b9e2067375732bebaf5356088a8efb35155f068 +kubebuilder_tools_darwin_amd64_SHA256SUM=85890b864330baec88f53aabfc1d5d94a8ca8c17483f34f4823dec0fae7c6e3a +kubebuilder_tools_darwin_arm64_SHA256SUM=849362d26105b64193b4142982c710306d90248272731a81fb83efac27c5a750 + +.PRECIOUS: $(DOWNLOAD_DIR)/tools/kubebuilder_tools_$(KUBEBUILDER_ASSETS_VERSION)_$(HOST_OS)_$(HOST_ARCH).tar.gz +$(DOWNLOAD_DIR)/tools/kubebuilder_tools_$(KUBEBUILDER_ASSETS_VERSION)_$(HOST_OS)_$(HOST_ARCH).tar.gz: | $(DOWNLOAD_DIR)/tools + @source $(lock_script) $@; \ + $(CURL) https://github.com/kubernetes-sigs/controller-tools/releases/download/envtest-$(KUBEBUILDER_ASSETS_VERSION)/envtest-$(KUBEBUILDER_ASSETS_VERSION)-$(HOST_OS)-$(HOST_ARCH).tar.gz -o $(outfile); \ + $(checkhash_script) $(outfile) $(kubebuilder_tools_$(HOST_OS)_$(HOST_ARCH)_SHA256SUM) + +$(DOWNLOAD_DIR)/tools/etcd@$(KUBEBUILDER_ASSETS_VERSION)_$(HOST_OS)_$(HOST_ARCH): $(DOWNLOAD_DIR)/tools/kubebuilder_tools_$(KUBEBUILDER_ASSETS_VERSION)_$(HOST_OS)_$(HOST_ARCH).tar.gz | $(DOWNLOAD_DIR)/tools + @source $(lock_script) $@; \ + tar xfO $< controller-tools/envtest/etcd > $(outfile) && chmod 775 $(outfile) + +$(DOWNLOAD_DIR)/tools/kube-apiserver@$(KUBEBUILDER_ASSETS_VERSION)_$(HOST_OS)_$(HOST_ARCH): $(DOWNLOAD_DIR)/tools/kubebuilder_tools_$(KUBEBUILDER_ASSETS_VERSION)_$(HOST_OS)_$(HOST_ARCH).tar.gz | $(DOWNLOAD_DIR)/tools + @source $(lock_script) $@; \ + tar xfO $< controller-tools/envtest/kube-apiserver > $(outfile) && chmod 775 $(outfile) + +kyverno_linux_amd64_SHA256SUM=a5f6e9070c17acc47168c8ce4db78e45258376551b8bf68ad2d5ed27454cf666 +kyverno_linux_arm64_SHA256SUM=007e828d622e73614365f5f7e8e107e36ae686e97e8982b1eeb53511fb2363c3 +kyverno_darwin_amd64_SHA256SUM=20786eebf45238e8b4a35f4146c3f8dfea35968cf8ef6ca6d6727559f5c0156e +kyverno_darwin_arm64_SHA256SUM=3a454fb0b2bfbca6225d46ff4cc0b702fd4a63e978718c50225472b9631a8015 + +.PRECIOUS: $(DOWNLOAD_DIR)/tools/kyverno@$(KYVERNO_VERSION)_$(HOST_OS)_$(HOST_ARCH) +$(DOWNLOAD_DIR)/tools/kyverno@$(KYVERNO_VERSION)_$(HOST_OS)_$(HOST_ARCH): | $(DOWNLOAD_DIR)/tools + $(eval ARCH := $(subst amd64,x86_64,$(HOST_ARCH))) + + @source $(lock_script) $@; \ + $(CURL) https://github.com/kyverno/kyverno/releases/download/$(KYVERNO_VERSION)/kyverno-cli_$(KYVERNO_VERSION)_$(HOST_OS)_$(ARCH).tar.gz -o $(outfile).tar.gz; \ + $(checkhash_script) $(outfile).tar.gz $(kyverno_$(HOST_OS)_$(HOST_ARCH)_SHA256SUM); \ + tar xfO $(outfile).tar.gz kyverno > $(outfile); \ + chmod +x $(outfile); \ + rm -f $(outfile).tar.gz + +yq_linux_amd64_SHA256SUM=cfbbb9ba72c9402ef4ab9d8f843439693dfb380927921740e51706d90869c7e1 +yq_linux_arm64_SHA256SUM=a8186efb079673293289f8c31ee252b0d533c7bb8b1ada6a778ddd5ec0f325b6 +yq_darwin_amd64_SHA256SUM=fdc42b132ac460037f4f0f48caea82138772c651d91cfbb735210075ddfdbaed +yq_darwin_arm64_SHA256SUM=9f1063d910698834cb9176593aa288471898031929138d226c2c2de9f262f8e5 + +.PRECIOUS: $(DOWNLOAD_DIR)/tools/yq@$(YQ_VERSION)_$(HOST_OS)_$(HOST_ARCH) +$(DOWNLOAD_DIR)/tools/yq@$(YQ_VERSION)_$(HOST_OS)_$(HOST_ARCH): | $(DOWNLOAD_DIR)/tools + @source $(lock_script) $@; \ + $(CURL) https://github.com/mikefarah/yq/releases/download/$(YQ_VERSION)/yq_$(HOST_OS)_$(HOST_ARCH) -o $(outfile); \ + $(checkhash_script) $(outfile) $(yq_$(HOST_OS)_$(HOST_ARCH)_SHA256SUM); \ + chmod +x $(outfile) + +ko_linux_amd64_SHA256SUM=d11f03f23261d16f9e7802291e9d098e84f5daecc7931e8573bece9025b6a2c5 +ko_linux_arm64_SHA256SUM=8294849c0f12138006cd149dd02bb580c0eea41a6031473705cbf825e021a688 +ko_darwin_amd64_SHA256SUM=314c33154de941bfc4ede5e7283eb182028459bac36eb4223859e0b778254936 +ko_darwin_arm64_SHA256SUM=b6ecd62eb4f9238a0ed0512d7a34648b881aea0774c3830e3e5159370eb6834f + +.PRECIOUS: $(DOWNLOAD_DIR)/tools/ko@$(KO_VERSION)_$(HOST_OS)_$(HOST_ARCH) +$(DOWNLOAD_DIR)/tools/ko@$(KO_VERSION)_$(HOST_OS)_$(HOST_ARCH): | $(DOWNLOAD_DIR)/tools + $(eval OS := $(subst linux,Linux,$(subst darwin,Darwin,$(HOST_OS)))) + $(eval ARCH := $(subst amd64,x86_64,$(HOST_ARCH))) + + @source $(lock_script) $@; \ + $(CURL) https://github.com/ko-build/ko/releases/download/v$(KO_VERSION)/ko_$(KO_VERSION)_$(OS)_$(ARCH).tar.gz -o $(outfile).tar.gz; \ + $(checkhash_script) $(outfile).tar.gz $(ko_$(HOST_OS)_$(HOST_ARCH)_SHA256SUM); \ + tar xfO $(outfile).tar.gz ko > $(outfile); \ + chmod +x $(outfile); \ + rm -f $(outfile).tar.gz + +protoc_linux_amd64_SHA256SUM=a7be2928c0454f132c599e25b79b7ad1b57663f2337d7f7e468a1d59b98ec1b0 +protoc_linux_arm64_SHA256SUM=64a3b3b5f7dac0c8f9cf1cb85b2b1a237eb628644f6bcb0fb8f23db6e0d66181 +protoc_darwin_amd64_SHA256SUM=febd8821c3a2a23f72f4641471e0ab6486f4fb07b68111490a27a31681465b3c +protoc_darwin_arm64_SHA256SUM=26a29befa8891ecc48809958c909d284f2b9539a2eb47f22cadc631fe6abe8fd + +.PRECIOUS: $(DOWNLOAD_DIR)/tools/protoc@$(PROTOC_VERSION)_$(HOST_OS)_$(HOST_ARCH) +$(DOWNLOAD_DIR)/tools/protoc@$(PROTOC_VERSION)_$(HOST_OS)_$(HOST_ARCH): | $(DOWNLOAD_DIR)/tools + $(eval OS := $(subst darwin,osx,$(HOST_OS))) + $(eval ARCH := $(subst arm64,aarch_64,$(subst amd64,x86_64,$(HOST_ARCH)))) + + @source $(lock_script) $@; \ + $(CURL) https://github.com/protocolbuffers/protobuf/releases/download/v$(PROTOC_VERSION)/protoc-$(PROTOC_VERSION)-$(OS)-$(ARCH).zip -o $(outfile).zip; \ + $(checkhash_script) $(outfile).zip $(protoc_$(HOST_OS)_$(HOST_ARCH)_SHA256SUM); \ + unzip -qq -c $(outfile).zip bin/protoc > $(outfile); \ + chmod +x $(outfile); \ + rm -f $(outfile).zip + +trivy_linux_amd64_SHA256SUM=b0d135815867246baba52f608f4af84beca90cfeb17a9ce407a21acca760ace1 +trivy_linux_arm64_SHA256SUM=1be1dee3a5e013528374f25391d6ba84e2a10fda59f4e98431e30d9c4975762b +trivy_darwin_amd64_SHA256SUM=744f5e8c5c09c1e5ec6ec6a0570f779d89964c0a91ab60b4e59b284cdd3e1576 +trivy_darwin_arm64_SHA256SUM=e78a0db86f6364e756d5e058316c7815a747fc7fd8e8e984e3baf5830166ec63 + +.PRECIOUS: $(DOWNLOAD_DIR)/tools/trivy@$(TRIVY_VERSION)_$(HOST_OS)_$(HOST_ARCH) +$(DOWNLOAD_DIR)/tools/trivy@$(TRIVY_VERSION)_$(HOST_OS)_$(HOST_ARCH): | $(DOWNLOAD_DIR)/tools + $(eval OS := $(subst linux,Linux,$(subst darwin,macOS,$(HOST_OS)))) + $(eval ARCH := $(subst amd64,64bit,$(subst arm64,ARM64,$(HOST_ARCH)))) + + @source $(lock_script) $@; \ + $(CURL) https://github.com/aquasecurity/trivy/releases/download/$(TRIVY_VERSION)/trivy_$(patsubst v%,%,$(TRIVY_VERSION))_$(OS)-$(ARCH).tar.gz -o $(outfile).tar.gz; \ + $(checkhash_script) $(outfile).tar.gz $(trivy_$(HOST_OS)_$(HOST_ARCH)_SHA256SUM); \ + tar xfO $(outfile).tar.gz trivy > $(outfile); \ + chmod +x $(outfile); \ + rm $(outfile).tar.gz + +ytt_linux_amd64_SHA256SUM=357ec754446b1eda29dd529e088f617e85809726c686598ab03cfc1c79f43b56 +ytt_linux_arm64_SHA256SUM=a2d195b058884c0e36a918936076965b8efb426f7e00f6b7d7b99b82737c7299 +ytt_darwin_amd64_SHA256SUM=71b5ea38bfc7a9748c35ce0735fd6f806dce46bd5c9039d527050c7682e62a70 +ytt_darwin_arm64_SHA256SUM=0658db4af8263ca091ca31e4b599cb40c324b75934660a4c0ed98ad9b701f7e9 + +.PRECIOUS: $(DOWNLOAD_DIR)/tools/ytt@$(YTT_VERSION)_$(HOST_OS)_$(HOST_ARCH) +$(DOWNLOAD_DIR)/tools/ytt@$(YTT_VERSION)_$(HOST_OS)_$(HOST_ARCH): | $(DOWNLOAD_DIR)/tools + @source $(lock_script) $@; \ + $(CURL) -sSfL https://github.com/vmware-tanzu/carvel-ytt/releases/download/$(YTT_VERSION)/ytt-$(HOST_OS)-$(HOST_ARCH) -o $(outfile); \ + $(checkhash_script) $(outfile) $(ytt_$(HOST_OS)_$(HOST_ARCH)_SHA256SUM); \ + chmod +x $(outfile) + +rclone_linux_amd64_SHA256SUM=b4d304b1dc76001b1d3bb820ae8d1ae60a072afbd3296be904a3ee00b3d4fab9 +rclone_linux_arm64_SHA256SUM=c50a3ab93082f21788f9244393b19f2426edeeb896eec2e3e05ffb2e8727e075 +rclone_darwin_amd64_SHA256SUM=5adb4c5fe0675627461000a63156001301ec7cade966c55c8c4ebcfaeb62c5ae +rclone_darwin_arm64_SHA256SUM=b5f4c4d06ff3d426aee99870ad437276c9ddaad55442f2df6a58b918115fe4cf + +.PRECIOUS: $(DOWNLOAD_DIR)/tools/rclone@$(RCLONE_VERSION)_$(HOST_OS)_$(HOST_ARCH) +$(DOWNLOAD_DIR)/tools/rclone@$(RCLONE_VERSION)_$(HOST_OS)_$(HOST_ARCH): | $(DOWNLOAD_DIR)/tools + $(eval OS := $(subst darwin,osx,$(HOST_OS))) + + @source $(lock_script) $@; \ + $(CURL) https://github.com/rclone/rclone/releases/download/$(RCLONE_VERSION)/rclone-$(RCLONE_VERSION)-$(OS)-$(HOST_ARCH).zip -o $(outfile).zip; \ + $(checkhash_script) $(outfile).zip $(rclone_$(HOST_OS)_$(HOST_ARCH)_SHA256SUM); \ + unzip -p $(outfile).zip rclone-$(RCLONE_VERSION)-$(OS)-$(HOST_ARCH)/rclone > $(outfile); \ + chmod +x $(outfile); \ + rm -f $(outfile).zip + +preflight_linux_amd64_SHA256SUM=20f31e4af2004e8e3407844afea4e973975069169d69794e0633f0cb91d45afd +preflight_linux_arm64_SHA256SUM=c42cf4132027d937da88da07760e8fd9b1a8836f9c7795a1b60513d99c6939fe + +# Currently there are no offical releases for darwin, you cannot submit results +# on non-official binaries, but we can still run tests. +# +# Once https://github.com/redhat-openshift-ecosystem/openshift-preflight/pull/942 is merged +# we can remove this darwin specific hack +.PRECIOUS: $(DOWNLOAD_DIR)/tools/preflight@$(PREFLIGHT_VERSION)_darwin_$(HOST_ARCH) +$(DOWNLOAD_DIR)/tools/preflight@$(PREFLIGHT_VERSION)_darwin_$(HOST_ARCH): | $(DOWNLOAD_DIR)/tools + @source $(lock_script) $@; \ + mkdir -p $(outfile).dir; \ + GOWORK=off GOBIN=$(outfile).dir $(GO) install github.com/redhat-openshift-ecosystem/openshift-preflight/cmd/preflight@$(PREFLIGHT_VERSION); \ + mv $(outfile).dir/preflight $(outfile); \ + rm -rf $(outfile).dir + +.PRECIOUS: $(DOWNLOAD_DIR)/tools/preflight@$(PREFLIGHT_VERSION)_linux_$(HOST_ARCH) +$(DOWNLOAD_DIR)/tools/preflight@$(PREFLIGHT_VERSION)_linux_$(HOST_ARCH): | $(DOWNLOAD_DIR)/tools + @source $(lock_script) $@; \ + $(CURL) https://github.com/redhat-openshift-ecosystem/openshift-preflight/releases/download/$(PREFLIGHT_VERSION)/preflight-linux-$(HOST_ARCH) -o $(outfile); \ + $(checkhash_script) $(outfile) $(preflight_linux_$(HOST_ARCH)_SHA256SUM); \ + chmod +x $(outfile) + +################# +# Other Targets # +################# + +# Although we "vendor" most tools in $(bin_dir)/tools, we still require some binaries +# to be available on the system. The vendor-go MAKECMDGOALS trick prevents the +# check for the presence of Go when 'make vendor-go' is run. + +# Gotcha warning: MAKECMDGOALS only contains what the _top level_ make invocation used, and doesn't look at target dependencies +# i.e. if we have a target "abc: vendor-go test" and run "make abc", we'll get an error +# about go being missing even though abc itself depends on vendor-go! +# That means we need to pass vendor-go at the top level if go is not installed (i.e. "make vendor-go abc") + +missing=$(shell (command -v curl >/dev/null || echo curl) \ + && (command -v sha256sum >/dev/null || command -v shasum >/dev/null || echo sha256sum) \ + && (command -v git >/dev/null || echo git) \ + && (command -v rsync >/dev/null || echo rsync) \ + && ([ -n "$(findstring vendor-go,$(MAKECMDGOALS),)" ] \ + || command -v $(GO) >/dev/null || echo "$(GO) (or run 'make vendor-go')") \ + && (command -v $(CTR) >/dev/null || echo "$(CTR) (or set CTR to a docker-compatible tool)")) +ifneq ($(missing),) +$(error Missing required tools: $(missing)) +endif + +.PHONY: tools +## Download and setup all tools +## @category [shared] Tools +tools: $(tools_paths) + +self_file := $(dir $(lastword $(MAKEFILE_LIST)))/00_mod.mk + +# see https://stackoverflow.com/a/53408233 +sed_inplace := sed -i'' +ifeq ($(HOST_OS),darwin) + sed_inplace := sed -i '' +endif + +# This target is used to learn the sha256sum of the tools. It is used only +# in the makefile-modules repo, and should not be used in any other repo. +.PHONY: tools-learn-sha +tools-learn-sha: | $(bin_dir) + rm -rf ./$(bin_dir)/ + mkdir -p ./$(bin_dir)/scratch/ + $(eval export LEARN_FILE=$(CURDIR)/$(bin_dir)/scratch/learn_tools_file) + echo -n "" > "$(LEARN_FILE)" + + HOST_OS=linux HOST_ARCH=amd64 $(MAKE) tools + HOST_OS=linux HOST_ARCH=arm64 $(MAKE) tools + HOST_OS=darwin HOST_ARCH=amd64 $(MAKE) tools + HOST_OS=darwin HOST_ARCH=arm64 $(MAKE) tools + + HOST_OS=linux HOST_ARCH=amd64 $(MAKE) vendor-go + HOST_OS=linux HOST_ARCH=arm64 $(MAKE) vendor-go + HOST_OS=darwin HOST_ARCH=amd64 $(MAKE) vendor-go + HOST_OS=darwin HOST_ARCH=arm64 $(MAKE) vendor-go + + while read p; do \ + $(sed_inplace) "$$p" $(self_file); \ + done <"$(LEARN_FILE)" diff --git a/make/_shared/tools/util/checkhash.sh b/make/_shared/tools/util/checkhash.sh new file mode 100755 index 0000000..62e5489 --- /dev/null +++ b/make/_shared/tools/util/checkhash.sh @@ -0,0 +1,58 @@ +#!/usr/bin/env bash + +# Copyright 2023 The cert-manager 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. + +set -o errexit +set -o nounset +set -o pipefail + +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" + +# This script takes the hash of its first argument and verifies it against the +# hex hash given in its second argument + +function usage_and_exit() { + echo "usage: $0 " + echo "or: LEARN_FILE= $0 " + exit 1 +} + +HASH_TARGET=${1:-} +EXPECTED_HASH=${2:-} + +if [[ -z $HASH_TARGET ]]; then + usage_and_exit +fi + +if [[ -z $EXPECTED_HASH ]]; then + usage_and_exit +fi + +SHASUM=$("${SCRIPT_DIR}/hash.sh" "$HASH_TARGET") + +if [[ "$SHASUM" == "$EXPECTED_HASH" ]]; then + exit 0 +fi + +# When running 'make learn-sha-tools', we don't want this script to fail. +# Instead we log what sha values are wrong, so the make.mk file can be updated. + +if [ "${LEARN_FILE:-}" != "" ]; then + echo "s/$EXPECTED_HASH/$SHASUM/g" >> "${LEARN_FILE:-}" + exit 0 +fi + +echo "invalid checksum for \"$HASH_TARGET\": wanted \"$EXPECTED_HASH\" but got \"$SHASUM\"" +exit 1 diff --git a/make/_shared/tools/util/hash.sh b/make/_shared/tools/util/hash.sh new file mode 100755 index 0000000..21d006f --- /dev/null +++ b/make/_shared/tools/util/hash.sh @@ -0,0 +1,27 @@ +#!/usr/bin/env bash + +# Copyright 2023 The cert-manager 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. + +set -o errexit +set -o nounset +set -o pipefail + +# This script is a wrapper for outputting purely the sha256 hash of the input file, +# ideally in a portable way. + +case "$(uname -s)" in + Darwin*) shasum -a 256 "$1";; + *) sha256sum "$1" +esac | cut -d" " -f1 \ No newline at end of file diff --git a/make/_shared/tools/util/lock.sh b/make/_shared/tools/util/lock.sh new file mode 100755 index 0000000..22564f7 --- /dev/null +++ b/make/_shared/tools/util/lock.sh @@ -0,0 +1,70 @@ +#!/usr/bin/env bash + +# Copyright 2023 The cert-manager 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. + +set -o errexit +set -o nounset +set -o pipefail + +# This script is used to lock a file while it is being downloaded. It prevents +# multiple processes from downloading the same file at the same time or from reading +# a half-downloaded file. +# We need this solution because we have recursive $(MAKE) calls in our makefile +# which each will try to download a set of tools. To prevent them from all downloading +# the same files, we re-use the same downloads folder for all $(MAKE) invocations and +# use this script to deduplicate the download processes. + +finalfile="$1" +lockfile="$finalfile.lock" + +# On OSX, flock is not installed, we just skip locking in that case, +# this means that running verify in parallel without downloading all +# tools first will not work. +flock_installed=$(command -v flock >/dev/null && echo "yes" || echo "no") + +if [[ "$flock_installed" == "yes" ]]; then + mkdir -p "$(dirname "$lockfile")" + touch "$lockfile" + exec {FD}<>"$lockfile" + + # wait for the file to be unlocked + if ! flock -x $FD; then + echo "Failed to obtain a lock for $lockfile" + exit 1 + fi +fi + +# now that we have the lock, check if file is already there +if [[ -e "$finalfile" ]]; then + exit 0 +fi + +# use a temporary file to prevent Make from thinking the file is ready +# while in reality is is only a partial download +# shellcheck disable=SC2034 +outfile="$finalfile.tmp" + +finish() { + rv=$? + if [[ $rv -eq 0 ]]; then + mv "$outfile" "$finalfile" + echo "[info]: downloaded $finalfile" + else + rm -rf "$outfile" || true + rm -rf "$finalfile" || true + fi + rm -rf "$lockfile" || true +} +trap finish EXIT SIGINT diff --git a/make/config/kind/cluster.yaml b/make/config/kind/cluster.yaml new file mode 100644 index 0000000..507f1f9 --- /dev/null +++ b/make/config/kind/cluster.yaml @@ -0,0 +1,19 @@ +apiVersion: kind.x-k8s.io/v1alpha4 +kind: Cluster +kubeadmConfigPatches: + - | + kind: ClusterConfiguration + metadata: + name: config + etcd: + local: + extraArgs: + unsafe-no-fsync: "true" + networking: + serviceSubnet: 10.0.0.0/16 +nodes: +- role: control-plane + + extraMounts: + - hostPath: {{KIND_IMAGES}} + containerPath: /mounted_images diff --git a/make/test-unit.mk b/make/test-unit.mk new file mode 100644 index 0000000..26ac73b --- /dev/null +++ b/make/test-unit.mk @@ -0,0 +1,26 @@ +# Copyright 2023 The cert-manager 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. + +.PHONY: test-unit +## Unit tests +## @category Testing +test-unit: | $(NEEDS_GOTESTSUM) $(ARTIFACTS) + $(GOTESTSUM) \ + --junitfile=$(ARTIFACTS)/junit-go-e2e.xml \ + -- \ + -coverprofile=$(ARTIFACTS)/filtered.cov \ + ./internal/... \ + -- \ + -ldflags $(go_manager_ldflags) \ + -test.timeout 2m