mirror of
https://github.com/vmware-tanzu/pinniped.git
synced 2025-12-23 06:15:47 +00:00
Also fixes some kubectl client-side validation errors, which also uses the generated openapi docs served by Pinniped.
366 lines
16 KiB
Bash
Executable File
366 lines
16 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
|
|
# Copyright 2020-2025 the Pinniped contributors. All Rights Reserved.
|
|
# SPDX-License-Identifier: Apache-2.0
|
|
set -euo pipefail
|
|
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
|
|
KUBE_VERSIONS=("$@")
|
|
BASE_PKG="go.pinniped.dev"
|
|
export GO111MODULE="on"
|
|
|
|
# Note that you can change this value to 10 to debug the Kubernetes code generator shell scripts used below.
|
|
debug_level="${CODEGEN_LOG_LEVEL:-1}"
|
|
|
|
# If we're not running in a container, assume that we want to loop over and run each build
|
|
# in a container.
|
|
if [[ -z "${CONTAINED:-}" ]]; then
|
|
for kubeVersion in "${KUBE_VERSIONS[@]}"; do
|
|
# CODEGEN_IMAGE is the container image to use when running
|
|
CODEGEN_IMAGE="ghcr.io/pinniped-ci-bot/k8s-code-generator-$(echo "$kubeVersion" | cut -d"." -f1-2):latest"
|
|
|
|
echo "generating code for ${kubeVersion} using ${CODEGEN_IMAGE}..."
|
|
docker run --rm \
|
|
--pull always \
|
|
--env CONTAINED=1 \
|
|
--env CODEGEN_LOG_LEVEL="$debug_level" \
|
|
--volume "${ROOT}:/work" \
|
|
--workdir "/work" \
|
|
"${CODEGEN_IMAGE}" \
|
|
"/work/hack/lib/$(basename "${BASH_SOURCE[0]}")" \
|
|
"${kubeVersion}" \
|
|
| sed "s|^|${kubeVersion} > |"
|
|
done
|
|
exit 0
|
|
fi
|
|
|
|
# Now that we know we are running in the nested container, expect there to be only
|
|
# a single Kubernetes version
|
|
if [[ "${#KUBE_VERSIONS[@]}" -ne 1 ]]; then
|
|
echo "when running in a container, we can only generate for a single kubernetes version" >&2
|
|
exit 1
|
|
fi
|
|
|
|
# Add this to the git config inside the container to avoid permission errors when running this script on linux.
|
|
git config --global --add safe.directory /work
|
|
|
|
# Link the root directory into GOPATH since that is where output ends up.
|
|
GOPATH_ROOT="${GOPATH}/src/${BASE_PKG}"
|
|
mkdir -p "$(dirname "${GOPATH_ROOT}")"
|
|
ln -s "${ROOT}" "${GOPATH_ROOT}"
|
|
ROOT="${GOPATH_ROOT}"
|
|
cd "${ROOT}"
|
|
|
|
# KUBE_VERSION is the full version (e.g., '1.28.0-rc.0').
|
|
KUBE_VERSION="${KUBE_VERSIONS[0]}"
|
|
export KUBE_VERSION
|
|
|
|
# KUBE_MINOR_VERSION is just the major/minor version (e.g., '1.28').
|
|
KUBE_MINOR_VERSION="$(echo "${KUBE_VERSION}" | cut -d"." -f1-2)"
|
|
export KUBE_MINOR_VERSION
|
|
|
|
# Check if it is a recent version of Kube.
|
|
KUBE_MAJOR_NUMBER="$(echo "${KUBE_VERSION}" | cut -d"." -f1)" # (e.g. '1')
|
|
KUBE_MINOR_NUMBER="$(echo "${KUBE_VERSION}" | cut -d"." -f2)" # (e.g. '28')
|
|
KUBE_1_29_OR_NEWER="no"
|
|
if [[ "$KUBE_MAJOR_NUMBER" -gt "1" || ( "$KUBE_MAJOR_NUMBER" == "1" && "$KUBE_MINOR_NUMBER" -ge "29" ) ]]; then
|
|
KUBE_1_29_OR_NEWER="yes"
|
|
fi
|
|
KUBE_1_30_OR_NEWER="no"
|
|
if [[ "$KUBE_MAJOR_NUMBER" -gt "1" || ( "$KUBE_MAJOR_NUMBER" == "1" && "$KUBE_MINOR_NUMBER" -ge "30" ) ]]; then
|
|
KUBE_1_30_OR_NEWER="yes"
|
|
fi
|
|
KUBE_1_35_OR_NEWER="no"
|
|
if [[ "$KUBE_MAJOR_NUMBER" -gt "1" || ( "$KUBE_MAJOR_NUMBER" == "1" && "$KUBE_MINOR_NUMBER" -ge "35" ) ]]; then
|
|
KUBE_1_35_OR_NEWER="yes"
|
|
fi
|
|
|
|
# KUBE_MODULE_VERSION is just version of client libraries (e.g., 'v0.28.9-rc-0').
|
|
KUBE_MODULE_VERSION="v0.$(echo "${KUBE_VERSION}" | cut -d '.' -f 2-)"
|
|
export KUBE_MODULE_VERSION
|
|
|
|
# Start by picking an output directory and deleting any previously-generated code.
|
|
OUTPUT_DIR="${ROOT}/generated/${KUBE_MINOR_VERSION}"
|
|
rm -rf "${OUTPUT_DIR}"
|
|
mkdir -p "${OUTPUT_DIR}"
|
|
cd "${OUTPUT_DIR}"
|
|
|
|
echo "running in container to generate ${KUBE_VERSION} into ${OUTPUT_DIR}..."
|
|
|
|
# Next, copy in the base definitions of our APIs from ./apis into the generated directory, substituting some
|
|
# variables in the template files and renaming them to strip the `.tmpl` extension.
|
|
cp -R "${ROOT}/apis" "${OUTPUT_DIR}/apis"
|
|
find "${OUTPUT_DIR}" -type f -exec sed -i "s|GENERATED_PKG|generated/${KUBE_MINOR_VERSION}|g" {} \;
|
|
find "${OUTPUT_DIR}" -type f -not -name '*.tmpl' -exec rm {} \;
|
|
find "${OUTPUT_DIR}" -type f -name '*.tmpl' -exec bash -c 'mv "$0" "${0%.tmpl}"' {} \;
|
|
|
|
# Starting in Kube 1.29, we need to use language level 1.21.
|
|
GO_LANG_LEVEL="1.13"
|
|
if [[ "$KUBE_1_29_OR_NEWER" == "yes" ]]; then
|
|
GO_LANG_LEVEL="1.21"
|
|
fi
|
|
|
|
# Make the generated API code its own Go module.
|
|
echo "generating ${OUTPUT_DIR}/apis/go.mod..."
|
|
cat << EOF > "${OUTPUT_DIR}/apis/go.mod"
|
|
// This go.mod file is generated by ./hack/update.sh.
|
|
module ${BASE_PKG}/generated/${KUBE_MINOR_VERSION}/apis
|
|
|
|
go $GO_LANG_LEVEL
|
|
|
|
require (
|
|
k8s.io/apimachinery ${KUBE_MODULE_VERSION}
|
|
k8s.io/api ${KUBE_MODULE_VERSION}
|
|
)
|
|
EOF
|
|
|
|
# Create a Go file that declares the package or else we can't use "go mod tidy" in the client subdirectory.
|
|
# Without this, go mod tidy complains that this directory "but does not contain package".
|
|
# We will delete this at the end of the script.
|
|
cat << EOF > "${OUTPUT_DIR}/apis/placeholder.go"
|
|
package apis
|
|
EOF
|
|
|
|
echo "Showing initial apis/go.mod..."
|
|
cat "${OUTPUT_DIR}/apis/go.mod" | sed "s|^|cat-go-mod > |"
|
|
|
|
# Generate a go.sum without changing the go.mod by running go mod download.
|
|
echo "running go mod download in ${OUTPUT_DIR}/apis/go.mod to generate a go.sum file..."
|
|
(cd "${OUTPUT_DIR}/apis" && go mod download all 2>&1 | sed "s|^|go-mod-download > |")
|
|
|
|
# Starting in Kube 1.29, the code generator complains that we need to run go mod tidy first.
|
|
if [[ "$KUBE_1_29_OR_NEWER" == "yes" ]]; then
|
|
echo "running go mod tidy in ${OUTPUT_DIR}/apis..."
|
|
(cd "${OUTPUT_DIR}/apis" && go mod tidy 2>&1 | sed "s|^|go-mod-tidy > |")
|
|
echo "Showing updated apis/go.mod..."
|
|
cat "${OUTPUT_DIR}/apis/go.mod" | sed "s|^|cat-updated-go-mod > |"
|
|
fi
|
|
|
|
# Make the generated client code its own Go module.
|
|
echo "generating ${OUTPUT_DIR}/client/go.mod..."
|
|
mkdir client
|
|
mkdir client/concierge
|
|
mkdir client/supervisor
|
|
|
|
# Create a tools.go just to prevent "go mod tidy" from deleting these packages from the go.mod as unused deps.
|
|
# We will delete this at the end of the script.
|
|
cat << EOF > "${OUTPUT_DIR}/client/tools.go"
|
|
//go:build tools
|
|
|
|
package tools
|
|
|
|
import (
|
|
_ "k8s.io/api"
|
|
_ "k8s.io/apimachinery"
|
|
_ "k8s.io/client-go"
|
|
_ "${BASE_PKG}/generated/${KUBE_MINOR_VERSION}/apis"
|
|
)
|
|
EOF
|
|
|
|
# Create client/go.mod.
|
|
cat << EOF > "${OUTPUT_DIR}/client/go.mod"
|
|
// This go.mod file is generated by ./hack/update.sh.
|
|
module ${BASE_PKG}/generated/${KUBE_MINOR_VERSION}/client
|
|
|
|
go $GO_LANG_LEVEL
|
|
|
|
replace ${BASE_PKG}/generated/${KUBE_MINOR_VERSION}/apis => ../apis
|
|
|
|
require (
|
|
k8s.io/api ${KUBE_MODULE_VERSION}
|
|
k8s.io/apimachinery ${KUBE_MODULE_VERSION}
|
|
k8s.io/client-go ${KUBE_MODULE_VERSION}
|
|
${BASE_PKG}/generated/${KUBE_MINOR_VERSION}/apis v0.0.0
|
|
)
|
|
EOF
|
|
|
|
echo "Showing initial client/go.mod..."
|
|
cat "${OUTPUT_DIR}/client/go.mod" | sed "s|^|cat-go-mod > |"
|
|
|
|
# Generate a go.sum without changing the go.mod by running go mod download.
|
|
echo "running go mod download in ${OUTPUT_DIR}/client/go.mod to generate a go.sum file..."
|
|
(cd "${OUTPUT_DIR}/client" && go mod download all 2>&1 | sed "s|^|go-mod-download > |")
|
|
|
|
# Starting in Kube 1.29, the code generator complains that we need to run go mod tidy first.
|
|
if [[ "$KUBE_1_29_OR_NEWER" == "yes" ]]; then
|
|
echo "running go mod tidy in ${OUTPUT_DIR}/client..."
|
|
(cd "${OUTPUT_DIR}/client" && go mod tidy 2>&1 | sed "s|^|go-mod-tidy > |")
|
|
echo "Showing updated client/go.mod..."
|
|
cat "${OUTPUT_DIR}/client/go.mod" | sed "s|^|cat-updated-go-mod > |"
|
|
fi
|
|
|
|
# These files were only created above to satisfy the above usages of "go mod tidy" in this script.
|
|
# We don't need to commit them. Delete them before the final "go mod tidy" so that unused
|
|
# imports can be deleted by the usages of "go mod tidy" below.
|
|
rm -f apis/placeholder.go client/tools.go
|
|
|
|
chmod -R +x "${GOPATH}/src/k8s.io/code-generator/"
|
|
|
|
if [[ "$KUBE_1_30_OR_NEWER" == "yes" ]]; then
|
|
# Use the new code generator scripts from Kubernetes.
|
|
# The old scripts were deprecated in 1.28 and removed in Kube 1.30.
|
|
# The new script is called kube_codegen.sh.
|
|
echo "Using new codegen tooling from kube_codegen.sh ..."
|
|
|
|
# This is a dirty hack to avoid needing to rework much of this script.
|
|
# Without this, kube::codegen::gen_client will resolve our symlink to its true path and then cause an error.
|
|
# With this change, it will use whatever path we give it, so we can use our path which contains a symlink.
|
|
# Once we are not using the old Kube codegen scripts anymore, we should probably consider rewriting this
|
|
# whole script instead of using this dirty hack.
|
|
sed -i -E -e 's/--input-base.*/--input-base "${in_dir}" \\/g' "${GOPATH}/src/k8s.io/code-generator/kube_codegen.sh"
|
|
|
|
source "${GOPATH}/src/k8s.io/code-generator/kube_codegen.sh"
|
|
|
|
# The functions from kube_codegen.sh pay attention to this env var.
|
|
export KUBE_VERBOSE="$debug_level"
|
|
|
|
echo "generating API helpers..."
|
|
|
|
# In the old codegen scripts, you would specify which generators you want to run as arguments.
|
|
# In this new codegen script, you instead specify the source code directory and it decides
|
|
# which generators to run for each package entirely by looking for "+k8s:*-gen" annotations
|
|
# in our source code.
|
|
pushd "${OUTPUT_DIR}/apis" > /dev/null
|
|
kube::codegen::gen_helpers . \
|
|
--boilerplate "${ROOT}/hack/boilerplate.go.txt" 2>&1 | sed "s|^|gen-helpers > |"
|
|
popd > /dev/null
|
|
|
|
# Tidy the apis module after codegen.
|
|
echo "tidying ${OUTPUT_DIR}/apis/go.mod..."
|
|
(cd apis && go mod tidy 2>&1 | sed "s|^|go-mod-tidy > |")
|
|
|
|
echo "generating API clients and openapi..."
|
|
|
|
# Note that --extra-pkgs can be set to generate openapi docs for other k8s APIs that our types depend upon
|
|
# aside from the default k8s packages that are already added automatically by the kube::codegen::gen_openapi script
|
|
# (meta/v1, runtime, and version). E.g. TokenCredentialRequestSpec uses corev1.TypedLocalObjectReference, so we
|
|
# add core/v1 when running codegen for the Pinniped aggregated APIs here.
|
|
concierge_gen_openapi_args=(
|
|
"${OUTPUT_DIR}/apis/concierge"
|
|
--update-report
|
|
--extra-pkgs "k8s.io/api/core/v1"
|
|
--output-dir "${OUTPUT_DIR}/client/concierge/openapi"
|
|
--output-pkg "${BASE_PKG}/generated/${KUBE_MINOR_VERSION}/client/concierge"
|
|
--boilerplate "${ROOT}/hack/boilerplate.go.txt"
|
|
)
|
|
supervisor_gen_openapi_args=(
|
|
"${OUTPUT_DIR}/apis/supervisor"
|
|
--update-report
|
|
--extra-pkgs "k8s.io/api/core/v1"
|
|
--output-dir "${OUTPUT_DIR}/client/supervisor/openapi"
|
|
--output-pkg "${BASE_PKG}/generated/${KUBE_MINOR_VERSION}/client/supervisor"
|
|
--boilerplate "${ROOT}/hack/boilerplate.go.txt"
|
|
)
|
|
if [[ "$KUBE_1_35_OR_NEWER" == "yes" ]]; then
|
|
concierge_gen_openapi_args+=(--output-model-name-file "zz_generated.model_name.go")
|
|
supervisor_gen_openapi_args+=(--output-model-name-file "zz_generated.model_name.go")
|
|
fi
|
|
|
|
pushd "${OUTPUT_DIR}/apis/concierge" > /dev/null
|
|
kube::codegen::gen_client "${OUTPUT_DIR}/apis/concierge" \
|
|
--with-watch \
|
|
--output-dir "${OUTPUT_DIR}/client/concierge" \
|
|
--output-pkg "${BASE_PKG}/generated/${KUBE_MINOR_VERSION}/client/concierge" \
|
|
--boilerplate "${ROOT}/hack/boilerplate.go.txt" 2>&1 | sed "s|^|gen-client-concierge > |"
|
|
kube::codegen::gen_openapi "${concierge_gen_openapi_args[@]}" 2>&1 | sed "s|^|gen-openapi-concierge > |"
|
|
popd > /dev/null
|
|
|
|
pushd "${OUTPUT_DIR}/apis/supervisor" > /dev/null
|
|
kube::codegen::gen_client "${OUTPUT_DIR}/apis/supervisor" \
|
|
--with-watch \
|
|
--output-dir "${OUTPUT_DIR}/client/supervisor" \
|
|
--output-pkg "${BASE_PKG}/generated/${KUBE_MINOR_VERSION}/client/supervisor" \
|
|
--boilerplate "${ROOT}/hack/boilerplate.go.txt" 2>&1 | sed "s|^|gen-client-supervisor > |"
|
|
kube::codegen::gen_openapi "${supervisor_gen_openapi_args[@]}" 2>&1 | sed "s|^|gen-openapi-supervisor > |"
|
|
popd > /dev/null
|
|
|
|
# Tidy the client module after codegen.
|
|
echo "tidying ${OUTPUT_DIR}/client/go.mod..."
|
|
(cd client && go mod tidy 2>&1 | sed "s|^|go-mod-tidy > |")
|
|
|
|
else
|
|
# For older Kube versions, use the old code generator scripts from Kubernetes: generate-groups.sh and generate-groups-internal.sh.
|
|
# The old scripts were deprecated in 1.28 and removed in Kube 1.30, but for older versions we can still use them.
|
|
|
|
# Generate API-related code for our public API groups
|
|
echo "generating API-related code for our public API groups..."
|
|
|
|
(cd apis &&
|
|
bash "${GOPATH}/src/k8s.io/code-generator/generate-groups.sh" \
|
|
"deepcopy" \
|
|
"${BASE_PKG}/generated/${KUBE_MINOR_VERSION}/apis" \
|
|
"${BASE_PKG}/generated/${KUBE_MINOR_VERSION}/apis" \
|
|
"supervisor/config:v1alpha1 supervisor/idp:v1alpha1 supervisor/clientsecret:v1alpha1 concierge/config:v1alpha1 concierge/authentication:v1alpha1 concierge/login:v1alpha1 concierge/identity:v1alpha1" \
|
|
--go-header-file "${ROOT}/hack/boilerplate.go.txt" -v "$debug_level" 2>&1 | sed "s|^|gen-api > |"
|
|
)
|
|
|
|
# Generate API-related code for our internal API groups.
|
|
# Note that OPENAPI_EXTRA_PACKAGES can be set to generate openapi docs for other k8s APIs that our types depend upon
|
|
# aside from the default k8s packages that are already added automatically by the generate-internal-groups.sh script
|
|
# (meta/v1, runtime, and version). E.g. TokenCredentialRequestSpec uses corev1.TypedLocalObjectReference, so we
|
|
# add core/v1 when running codegen for the Concierge aggregated APIs here.
|
|
echo "generating API-related code for our internal API groups..."
|
|
(cd apis &&
|
|
OPENAPI_EXTRA_PACKAGES="k8s.io/api/core/v1" \
|
|
bash "${GOPATH}/src/k8s.io/code-generator/generate-internal-groups.sh" \
|
|
"deepcopy,defaulter,conversion,openapi" \
|
|
"${BASE_PKG}/generated/${KUBE_MINOR_VERSION}/client/concierge" \
|
|
"${BASE_PKG}/generated/${KUBE_MINOR_VERSION}/apis" \
|
|
"${BASE_PKG}/generated/${KUBE_MINOR_VERSION}/apis" \
|
|
"concierge/login:v1alpha1 concierge/identity:v1alpha1" \
|
|
--go-header-file "${ROOT}/hack/boilerplate.go.txt" -v "$debug_level" 2>&1 | sed "s|^|gen-concierge-int-api > |"
|
|
)
|
|
(cd apis &&
|
|
bash "${GOPATH}/src/k8s.io/code-generator/generate-internal-groups.sh" \
|
|
"deepcopy,defaulter,conversion,openapi" \
|
|
"${BASE_PKG}/generated/${KUBE_MINOR_VERSION}/client/supervisor" \
|
|
"${BASE_PKG}/generated/${KUBE_MINOR_VERSION}/apis" \
|
|
"${BASE_PKG}/generated/${KUBE_MINOR_VERSION}/apis" \
|
|
"supervisor/clientsecret:v1alpha1" \
|
|
--go-header-file "${ROOT}/hack/boilerplate.go.txt" -v "$debug_level" 2>&1 | sed "s|^|gen-supervisor-int-api > |"
|
|
)
|
|
|
|
# Tidy the apis module after codegen.
|
|
echo "tidying ${OUTPUT_DIR}/apis/go.mod..."
|
|
(cd apis && go mod tidy 2>&1 | sed "s|^|go-mod-tidy > |")
|
|
|
|
# Generate client code for our public API groups
|
|
echo "generating client code for our public API groups..."
|
|
(cd client &&
|
|
bash "${GOPATH}/src/k8s.io/code-generator/generate-groups.sh" \
|
|
"client,lister,informer" \
|
|
"${BASE_PKG}/generated/${KUBE_MINOR_VERSION}/client/concierge" \
|
|
"${BASE_PKG}/generated/${KUBE_MINOR_VERSION}/apis" \
|
|
"concierge/config:v1alpha1 concierge/authentication:v1alpha1 concierge/login:v1alpha1 concierge/identity:v1alpha1" \
|
|
--go-header-file "${ROOT}/hack/boilerplate.go.txt" -v "$debug_level" 2>&1 | sed "s|^|gen-concierge-client > |"
|
|
)
|
|
(cd client &&
|
|
bash "${GOPATH}/src/k8s.io/code-generator/generate-groups.sh" \
|
|
"client,lister,informer" \
|
|
"${BASE_PKG}/generated/${KUBE_MINOR_VERSION}/client/supervisor" \
|
|
"${BASE_PKG}/generated/${KUBE_MINOR_VERSION}/apis" \
|
|
"supervisor/config:v1alpha1 supervisor/idp:v1alpha1 supervisor/clientsecret:v1alpha1" \
|
|
--go-header-file "${ROOT}/hack/boilerplate.go.txt" -v "$debug_level" 2>&1 | sed "s|^|gen-supervisor-client > |"
|
|
)
|
|
|
|
# Tidy the client module after codegen.
|
|
echo "tidying ${OUTPUT_DIR}/client/go.mod..."
|
|
(cd client && go mod tidy 2>&1 | sed "s|^|go-mod-tidy > |")
|
|
fi
|
|
|
|
# Generate API documentation
|
|
sed "s|KUBE_MINOR_VERSION|${KUBE_MINOR_VERSION}|g" < "${ROOT}/hack/lib/docs/config.yaml" > /tmp/docs-config.yaml
|
|
crd-ref-docs \
|
|
--source-path="${ROOT}/generated/${KUBE_MINOR_VERSION}/apis" \
|
|
--config=/tmp/docs-config.yaml \
|
|
--renderer=asciidoctor \
|
|
--templates-dir="${ROOT}/hack/lib/docs/templates" \
|
|
--output-path="${ROOT}/generated/${KUBE_MINOR_VERSION}/README.adoc"
|
|
|
|
# Generate CRD YAML
|
|
(cd apis &&
|
|
controller-gen paths=./supervisor/config/v1alpha1 crd output:crd:artifacts:config=../crds &&
|
|
controller-gen paths=./supervisor/idp/v1alpha1 crd output:crd:artifacts:config=../crds &&
|
|
controller-gen paths=./concierge/config/v1alpha1 crd output:crd:artifacts:config=../crds &&
|
|
controller-gen paths=./concierge/authentication/v1alpha1 crd output:crd:artifacts:config=../crds
|
|
)
|