Add new ./apis directory and codegen scripts.

Signed-off-by: Matt Moyer <moyerm@vmware.com>
This commit is contained in:
Matt Moyer
2020-08-24 14:09:35 -05:00
parent 142e9a1583
commit 1aef2f07d3
22 changed files with 596 additions and 167 deletions

View File

@@ -1,149 +0,0 @@
#!/usr/bin/env bash
# Copyright 2020 VMware, Inc.
# SPDX-License-Identifier: Apache-2.0
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
GOPATH="${GOPATH:-$(mktemp -d)}"
K8S_PKG_VERSION="${K8S_PKG_VERSION:-"1.19"}"
CODEGEN_IMAGE=${CODEGEN_IMAGE:-"gcr.io/tanzu-user-authentication/k8s-code-generator-${K8S_PKG_VERSION}:latest"}
BASE_PKG="github.com/suzerain-io/pinniped"
# This script assumes that your current working directory is the top of the module
# in which you would like to generate code.
MOD_DIR=$(pwd)
function codegen::ensure_module_in_gopath() {
# This should be something like "kubernetes/1.19/api".
local pkg_name="$(realpath "--relative-to=$ROOT" "$MOD_DIR")"
# Use --canonicalize-missing to since pkg_name could end up as "." - this would
# lead to a pkg_gosrc_path like "foo/bar/bat/." which ln(1) (below) does not like.
local pkg_gosrc_path="$(realpath --canonicalize-missing "${GOPATH}/src/${BASE_PKG}/${pkg_name}")"
if [[ ! -e "${pkg_gosrc_path}" ]]; then
mkdir -p "$(dirname "${pkg_gosrc_path}")"
ln -s "${ROOT}/${pkg_name}" "${pkg_gosrc_path}"
fi
}
function codegen::invoke_code_generator() {
local generator_command="${1}"
local mod_basename_for_version="${2}"
shift 2 # generator args are now in $@
if [ "${BASH_VERSINFO[0]}" -lt 5 ]; then
echo "ERROR: invalid BASH version"
echo " using v${BASH_VERSINFO[0]}.${BASH_VERSINFO[1]}.${BASH_VERSINFO[2]} @ ${BASH}"
echo " require v5.0.0+"
exit 1
fi
bash "${GOPATH}/src/k8s.io/code-generator/${generator_command}.sh" \
"$@" \
--go-header-file "${ROOT}/hack/boilerplate.go.txt" |
sed "s|^|${mod_basename_for_version} > ${generator_command} > |"
}
function codegen::generate_for_module() {
local mod_basename_for_version="${1}"
case "${mod_basename_for_version}" in
1.19/api)
echo "GENERATING CODE for $mod_basename_for_version"
codegen::invoke_code_generator generate-groups "${mod_basename_for_version}" \
deepcopy,defaulter \
"${BASE_PKG}/kubernetes/1.19/api/generated" \
"${BASE_PKG}/kubernetes/1.19/api/apis" \
"pinniped:v1alpha1 crdpinniped:v1alpha1"
codegen::invoke_code_generator generate-internal-groups "${mod_basename_for_version}" \
deepcopy,defaulter,conversion,openapi \
"${BASE_PKG}/kubernetes/1.19/api/generated" \
"${BASE_PKG}/kubernetes/1.19/api/apis" \
"${BASE_PKG}/kubernetes/1.19/api/apis" \
"pinniped:v1alpha1 crdpinniped:v1alpha1"
;;
1.19/client-go)
echo "GENERATING CODE for $mod_basename_for_version"
codegen::invoke_code_generator generate-groups "${mod_basename_for_version}" \
client,lister,informer \
"${BASE_PKG}/kubernetes/1.19/client-go" \
"${BASE_PKG}/kubernetes/1.19/api/apis" \
"pinniped:v1alpha1 crdpinniped:v1alpha1"
;;
*)
echo "Skipping $mod_basename_for_version because it does not contain any code to generate"
esac
}
function codegen::generate() {
local mod_basename_for_version
mod_basename_for_version="${K8S_PKG_VERSION}/$(basename "${MOD_DIR}")"
codegen::ensure_module_in_gopath
codegen::generate_for_module "${mod_basename_for_version}"
}
function codegen::verify() {
local have_stash=''
if [[ "$(git status --porcelain 2>/dev/null | wc -l | tr -d ' ')" -ne "0" ]]; then
# git stash requires the user.email and user.name to be set. We set these at
# a global scope so they don't overwrite the .git/config in the mounted repo
# from the host.
git config --global user.email "codegen_verify@whatever.com"
git config --global user.name "Codegen Verify"
git stash --all >/dev/null 2>&1 && have_stash=1
fi
codegen::generate
failure=0
if [[ "$(git status --porcelain 2>/dev/null | wc -l | tr -d ' ')" -eq "0" ]]; then
echo "Generated code in ${MOD_DIR} up to date."
else
echo "Generated code in ${MOD_DIR} is out of date."
echo "Please run hack/module.sh codegen"
git diff "${ROOT}"
git checkout "${ROOT}"
failure=1
fi
if [[ -n "${have_stash}" ]]; then
git stash pop >/dev/null 2>&1
fi
if [[ "$failure" -eq 1 ]]; then
exit 1
fi
}
function codegen::usage() {
echo "Error: <codegen command> must be specified"
echo " ${BASH_SOURCE[0]} <codegen command> [codegen::generate, codegen::verify]"
exit 1
}
function codegen::main() {
local codegen_command="${1}"
if [[ -n "${CONTAINED:-}" ]]; then
"${codegen_command}"
else
DOCKER_ROOT_DIR="/tmp/${RANDOM}/${BASE_PKG}"
DOCKER_MOD_DIR="${DOCKER_ROOT_DIR}/$(realpath "--relative-to=$ROOT" "$MOD_DIR")"
docker run --rm \
--env CONTAINED=1 \
--env MOD_DIR="${DOCKER_MOD_DIR}" \
--volume "${ROOT}:${DOCKER_ROOT_DIR}" \
--workdir "${DOCKER_MOD_DIR}" \
"${CODEGEN_IMAGE}" \
"${DOCKER_ROOT_DIR}/hack/lib/$(basename "${BASH_SOURCE[0]}")" \
"${codegen_command}"
fi
}
codegen::main "${1:-"codegen::usage"}"

View File

@@ -0,0 +1,3 @@
1.17.9
1.18.6
1.19.0-rc.0

137
hack/lib/update-codegen.sh Executable file
View File

@@ -0,0 +1,137 @@
#!/usr/bin/env bash
# Copyright 2020 VMware, Inc.
# SPDX-License-Identifier: Apache-2.0
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
KUBE_VERSIONS=("$@")
BASE_PKG="github.com/suzerain-io/pinniped"
export GO111MODULE="on"
# 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="gcr.io/tanzu-user-authentication/k8s-code-generator-$(echo "$kubeVersion" | cut -d"." -f1-2):latest"
echo "generating code for ${kubeVersion} using ${CODEGEN_IMAGE}..."
docker run --rm \
--env CONTAINED=1 \
--volume "${ROOT}:/go/src/${BASE_PKG}" \
--workdir "/go/src/${BASE_PKG}" \
"${CODEGEN_IMAGE}" \
"/go/src/${BASE_PKG}/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
# KUBE_VERSION is the full version (e.g., '1.19.0-rc.0').
KUBE_VERSION="${KUBE_VERSIONS[0]}"
export KUBE_VERSION
# KUBE_MINOR_VERSION is just the major/minor version (e.g., '1.19').
KUBE_MINOR_VERSION="$(echo "${KUBE_VERSION}" | cut -d"." -f1-2)"
export KUBE_MINOR_VERSION
# KUBE_MODULE_VERSION is just version of client libraries (e.g., 'v0.19.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 -name '*.tmpl' -exec bash -c 'mv "$0" "${0%.tmpl}"' {} \;
# 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/codegen.sh.
module ${BASE_PKG}/generated/${KUBE_MINOR_VERSION}/apis
go 1.13
require (
k8s.io/apimachinery ${KUBE_MODULE_VERSION}
)
EOF
# Make the generated client code its own Go module.
echo "generating ${OUTPUT_DIR}/client/go.mod..."
mkdir client
cat << EOF > "./client/go.mod"
// This go.mod file is generated by ./hack/codegen.sh.
module ${BASE_PKG}/generated/${KUBE_MINOR_VERSION}/client
go 1.13
require (
github.com/go-openapi/spec v0.19.9
k8s.io/api ${KUBE_MODULE_VERSION}
k8s.io/apimachinery ${KUBE_MODULE_VERSION}
k8s.io/client-go ${KUBE_MODULE_VERSION}
k8s.io/apimachinery ${KUBE_MODULE_VERSION}
)
replace ${BASE_PKG}/generated/${KUBE_MINOR_VERSION}/apis => ../apis
EOF
# 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" \
"pinniped:v1alpha1 crdpinniped:v1alpha1" \
--go-header-file "${ROOT}/hack/boilerplate.go.txt" 2>&1 | sed "s|^|gen-api > |"
)
# Generate API-related code for our internal API groups
echo "generating API-related code for our internal API groups..."
(cd apis &&
bash "${GOPATH}/src/k8s.io/code-generator/generate-internal-groups.sh" \
deepcopy,defaulter,conversion,openapi \
"${BASE_PKG}/generated/${KUBE_MINOR_VERSION}/client" \
"${BASE_PKG}/generated/${KUBE_MINOR_VERSION}/apis" \
"${BASE_PKG}/generated/${KUBE_MINOR_VERSION}/apis" \
"pinniped:v1alpha1 crdpinniped:v1alpha1" \
--go-header-file "${ROOT}/hack/boilerplate.go.txt" 2>&1 | sed "s|^|gen-int-api > |"
)
# Tidy up the .../apis module
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" \
"${BASE_PKG}/generated/${KUBE_MINOR_VERSION}/apis" \
"pinniped:v1alpha1 crdpinniped:v1alpha1" \
--go-header-file "${ROOT}/hack/boilerplate.go.txt" 2>&1 | sed "s|^|gen-client > |"
)
# Tidy up the .../client module
echo "tidying ${OUTPUT_DIR}/client/go.mod..."
(cd client && go mod tidy 2>&1 | sed "s|^|go-mod-tidy > |")

43
hack/lib/verify-codegen.sh Executable file
View File

@@ -0,0 +1,43 @@
#!/usr/bin/env bash
# Copyright 2020 VMware, Inc.
# SPDX-License-Identifier: Apache-2.0
set -euo pipefail
ROOT="$(cd "$(dirname "${BASH_SOURCE[0]}")/../.." && pwd)"
KUBE_VERSIONS=("$@")
GENERATED_DIR="${ROOT}/generated"
BACKUP_DIR="${GENERATED_DIR}.bak"
# Move the originally generated directory to a backup location
mv "${GENERATED_DIR}" "${BACKUP_DIR}"
mkdir "${GENERATED_DIR}"
# At exit (even on error), copy it back
cleanup() {
rm -r "${GENERATED_DIR}"
mv -f "${BACKUP_DIR}" "${GENERATED_DIR}"
}
trap "cleanup" EXIT SIGINT
# Run the code generation into a new empty `./generated` directory.
"${ROOT}/hack/lib/update-codegen.sh" "${KUBE_VERSIONS[@]}"
# Diff each of the chosen Kubernetes versions (but avoid comparing any other versions).
echo "diffing ${GENERATED_DIR} against freshly generated codegen"
ret=0
for kubeVersion in "${KUBE_VERSIONS[@]}"; do
kubeMinorVersion="$(echo "${kubeVersion}" | cut -d"." -f1-2)"
generatedVersionDir="${GENERATED_DIR}/${kubeMinorVersion}"
backupVersionDir="${BACKUP_DIR}/${kubeMinorVersion}"
diff -Naupr "${generatedVersionDir}" "${backupVersionDir}" || ret=$?
done
# If any of the versions differed, exit nonzero with an error message.
if [[ $ret -eq 0 ]]
then
echo "${GENERATED_DIR} up to date."
else
echo "${GENERATED_DIR} is out of date. Please run hack/update.sh"
exit 1
fi

View File

@@ -35,20 +35,12 @@ function unittest_cmd() {
echo "${cmd} -count 1 -short -race ./..."
}
function codegen_cmd() {
echo "${ROOT}/hack/lib/codegen.sh codegen::generate"
}
function codegen_verify_cmd() {
echo "${ROOT}/hack/lib/codegen.sh codegen::verify"
}
function with_modules() {
local cmd_function="${1}"
cmd="$(${cmd_function})"
pushd "${ROOT}" >/dev/null
for mod_file in $(find . -maxdepth 4 -name go.mod | sort); do
for mod_file in $(find . -maxdepth 4 -not -path "./generated/*" -name go.mod | sort); do
mod_dir="$(dirname "${mod_file}")"
(
echo "=> "
@@ -61,7 +53,7 @@ function with_modules() {
function usage() {
echo "Error: <task> must be specified"
echo " module.sh <task> [tidy, lint, test, unittest, codegen, codegen_verify]"
echo " module.sh <task> [tidy, lint, test, unittest]"
exit 1
}
@@ -79,12 +71,6 @@ function main() {
'unittest' | 'unittests' | 'units' | 'unit')
with_modules 'unittest_cmd'
;;
'codegen' | 'codegens')
with_modules 'codegen_cmd'
;;
'codegen_verify' | 'verify_codegen')
with_modules 'codegen_verify_cmd'
;;
*)
usage
;;

View File

@@ -5,5 +5,5 @@
set -euo pipefail
ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )/.." && pwd )"
xargs "$ROOT/hack/lib/update-codegen.sh" < "${ROOT}/hack/lib/kube-versions.txt"
"$ROOT/hack/module.sh" tidy
"$ROOT/hack/module.sh" codegen

View File

@@ -5,5 +5,5 @@
set -euo pipefail
ROOT="$( cd "$( dirname "${BASH_SOURCE[0]}" )/.." && pwd )"
xargs "$ROOT/hack/lib/verify-codegen.sh" < "${ROOT}/hack/lib/kube-versions.txt"
"$ROOT/hack/module.sh" lint
"$ROOT/hack/module.sh" codegen_verify