Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion installers/olm/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,9 @@ IMAGE_TAG_BASE ?= $(IMAGE_TAG_OWNER)/$(NAME)
CONTAINER ?= docker

# Bundle configuration
OPENSHIFT_VERSIONS ?= v4.18-v4.21
# OPENSHIFT_VERSIONS: optional. If unset, generate.sh derives v<min>-v<max>
# from OPENSHIFT_MIN/MAX in e2e-tests/release_versions (or @@RHEL_VERSIONS@@
# if that file is unavailable).
DOCKER_DEFAULT_PLATFORM ?= linux/amd64

# Image configuration
Expand Down
5 changes: 4 additions & 1 deletion installers/olm/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,10 @@ Common variables:

```text
VERSION Release version. Required.
OPENSHIFT_VERSIONS OpenShift range annotation. Default: v4.18-v4.21
OPENSHIFT_VERSIONS OpenShift range annotation. If unset, derived from
OPENSHIFT_MIN/MAX in e2e-tests/release_versions
(v<major.minor>-v<major.minor>). If that file is
missing, @@RHEL_VERSIONS@@.
IMAGE Community operator image.
REDHAT_OPERATOR_IMAGE Red Hat operator image.
BUNDLE_DISTRO Bundle to build: community or redhat.
Expand Down
3 changes: 2 additions & 1 deletion installers/olm/bundle.annotations.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,8 @@ annotations:
operators.operatorframework.io.bundle.channels.v1: v5
operators.operatorframework.io.bundle.channel.default.v1: v5

# This default is overwritten by generate.sh from OPENSHIFT_VERSIONS.
# Overwritten by generate.sh: OPENSHIFT_VERSIONS, else OPENSHIFT_MIN/MAX
# from e2e-tests/release_versions, else @@RHEL_VERSIONS@@.
# https://github.com/operator-framework/community-operators/blob/8a36a33/docs/packaging-required-criteria-ocp.md
# https://redhat-connect.gitbook.io/certified-operator-guide/ocp-deployment/operator-metadata/bundle-directory
com.redhat.delivery.operator.bundle: true
Expand Down
110 changes: 97 additions & 13 deletions installers/olm/distributions/redhat.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,15 @@
# shellcheck disable=SC2016,SC2155
set -euo pipefail

redhat_release="${VERSION}"

Check notice on line 6 in installers/olm/distributions/redhat.sh

View workflow job for this annotation

GitHub Actions / shellcheck

[shellcheck] installers/olm/distributions/redhat.sh#L6 <ShellCheck.SC2153>

Possible misspelling: VERSION may not be assigned. Did you mean version?
Raw output
./installers/olm/distributions/redhat.sh:6:17: info: Possible misspelling: VERSION may not be assigned. Did you mean version? (ShellCheck.SC2153)
redhat_registry="registry.connect.redhat.com"
redhat_catalog_api="${REDHAT_CATALOG_API:-https://catalog.redhat.com/api/containers/v1}"
redhat_catalog_curl_timeout="${REDHAT_CATALOG_CURL_TIMEOUT:-20}"
redhat_catalog_curl_timeout="${REDHAT_CATALOG_CURL_TIMEOUT:-90}"
redhat_operator_repository="percona/percona-postgresql-operator"
redhat_containers_repository="percona/percona-postgresql-operator-containers"
redhat_operator_tag="${REDHAT_OPERATOR_TAG:-${redhat_release}}"
redhat_upgrade_tag="${REDHAT_UPGRADE_TAG:-${redhat_release}-upgrade}"
redhat_logcollector_tag="${REDHAT_LOGCOLLECTOR_TAG:-${redhat_release}-logcollector}"
redhat_related_images="[]"

required_vars=(
Expand Down Expand Up @@ -133,9 +134,13 @@
# shellcheck source=/dev/null
source "${repo_root}/e2e-tests/release_versions"

# Official majors only (IMAGE_POSTGRESQL14). Flavor suffixes such as
# _UBI8 / _UBI10 / _UBI9_COMMUNITY are e2e matrix variants, not certified
# relatedImages.
pg_versions="$(
compgen -A variable IMAGE_POSTGRESQL \
| sed 's/^IMAGE_POSTGRESQL//' \
| grep -E '^[0-9]+$' \
| sort -rn
)"

Expand All @@ -162,6 +167,7 @@
"$(release_component_tag pgbouncer "$(image_version "${IMAGE_PGBOUNCER18}")")"

add_related_image "pmm" "${redhat_containers_repository}" "${redhat_release}-pmm3"
add_related_image "logcollector" "${redhat_containers_repository}" "${redhat_logcollector_tag}"
add_related_image "operator" "${redhat_operator_repository}" "${redhat_operator_tag}"
add_related_image "pgupgrade" "${redhat_containers_repository}" "${redhat_upgrade_tag}"

Expand All @@ -171,6 +177,7 @@
--arg pgbouncer_image "$(related_image_by_name pgbouncer)" \
--arg pgbackrest_image "$(related_image_by_name pgbackrest)" \
--arg pmm_image "$(related_image_by_name pmm)" \
--arg logcollector_image "$(related_image_by_name logcollector)" \
--arg upgrade_image "$(related_image_by_name pgupgrade)" \
--argjson related_images "${redhat_related_images}" \
'{
Expand All @@ -179,6 +186,7 @@
pgbouncerImage: $pgbouncer_image,
pgbackrestImage: $pgbackrest_image,
pmmImage: $pmm_image,
logcollectorImage: $logcollector_image,
upgradeImage: $upgrade_image,
relatedImages: $related_images
}'
Expand All @@ -192,14 +200,28 @@

log "Applying Red Hat certified CSV overrides"

# yq --yaml-roundtrip encodes preserved comments as "__yq_comment*" string
# entries inside sequences: guard .type lookups against them, then drop any
# that yq fails to turn back into comments (they would otherwise be emitted
# as literal list items and break the CSV schema). Sequences of real strings
# such as keywords, skips and RBAC verbs are left untouched.
yq --in-place --yaml-roundtrip \
'
.metadata.annotations.certified = "true"
| (
.spec.installModes[]
| select(.type == "MultiNamespace")
| select((type == "object") and (.type == "MultiNamespace"))
| .supported
) = true
| walk(
if type == "object" then
with_entries(select((.key | tostring | startswith("__yq_comment_")) | not))
elif type == "array" then
map(select((type == "string" and startswith("__yq_comment_")) | not))
else
.
end
)
' \
"${csv_file}"

Expand All @@ -221,25 +243,86 @@
log "Red Hat CSV overrides applied"
}

# True if $1 is strictly less than $2 using version sort (2.9.0 < 3.1.0).
version_lt() {
[[ $1 != "$2" ]] || return 1
[[ $(printf '%s\n%s\n' "$1" "$2" | sort -V) == "$1"$'\n'"$2" ]]
}

# Strip a leading "v" or "v." so v3.1.0, v.3.1.0, and 3.1.0 all become 3.1.0.
normalize_git_tag() {
sed -E 's/^v\.?//' <<<"$1"
}

fetch_remote_tags() {
local remote="https://github.com/percona/percona-postgresql-operator"

log "Fetching tags from ${remote}"

git -C "${repo_root}" fetch --tags --force "${remote}" \
|| abort "Failed to fetch tags from ${remote}"
}

# Tags strictly after the last seed version and strictly before VERSION.
# Seed entries such as 2.9.0-cw are kept as-is and never inferred from git.
discovered_skip_versions() {
local last_seed="$1"
local current="$2"
local tag version

fetch_remote_tags

while IFS= read -r tag; do
[[ -n ${tag} ]] || continue

version="$(normalize_git_tag "${tag}")"
[[ ${version} =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] || continue

if version_lt "${last_seed}" "${version}" && version_lt "${version}" "${current}"; then
printf '%s\n' "${version}"
fi
done < <(git -C "${repo_root}" tag --list) \
| sort -u -V
}

prepare_redhat_csv_vars() {
local file_name="$1"
local last_seed extra_versions extra_json

local seed_versions=(
"2.5.0"
"2.6.0"
"2.6.1"
"2.7.0"
"2.8.0"
"2.8.1"
"2.8.2"
"2.9.0"
"2.9.0-cw"
"3.0.0"
)

last_seed="${seed_versions[-1]}"
extra_versions="$(discovered_skip_versions "${last_seed}" "${VERSION}")"

if [[ -n ${extra_versions} ]]; then
log "Adding Red Hat skips from git tags after ${last_seed} and before ${VERSION}: ${extra_versions//$'\n'/, }"
extra_json="$(printf '%s\n' "${extra_versions}" | jq -R . | jq -s -c .)"
else
log "No git tags found between ${last_seed} and ${VERSION}; using the seed skip list"
extra_json='[]'
fi

redhat_skips="$(
jq -nc \
--arg file_name "${file_name}" \
--argjson extra "${extra_json}" \
--args \
'
[
"2.5.0",
"2.6.0",
"2.6.1",
"2.7.0",
"2.8.0",
"2.8.1",
"2.8.2",
"2.9.0"
]
$ARGS.positional + $extra
| map("\($file_name).v\(.)")
'
' \
-- "${seed_versions[@]}"
)"

printf '%s\n' "${redhat_skips}"
Expand Down Expand Up @@ -277,6 +360,7 @@
| .spec.proxy.pgBouncer.image = $images.pgbouncerImage
| .spec.backups.pgbackrest.image = $images.pgbackrestImage
| .spec.pmm.image = $images.pmmImage
| .spec.logcollector.image = $images.logcollectorImage

elif .kind == "PerconaPGUpgrade" then
.spec.image = $images.upgradeImage
Expand Down
95 changes: 88 additions & 7 deletions installers/olm/generate.sh
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,40 @@ require_env() {
fi
}

# OPENSHIFT_VERSIONS, if set, is used as-is for com.redhat.openshift.versions.
# Otherwise derive v<major.minor>-v<major.minor> from OPENSHIFT_MIN/MAX in
# e2e-tests/release_versions. If that file is missing or unreadable, use a
# placeholder so bundle generation can still run.
resolve_openshift_versions() {
local file="${repo_root}/e2e-tests/release_versions"
local min max

if [[ -n ${OPENSHIFT_VERSIONS:-} ]]; then
log "Using OPENSHIFT_VERSIONS=${OPENSHIFT_VERSIONS}"
return
fi

if [[ ! -r ${file} ]]; then
OPENSHIFT_VERSIONS='@@RHEL_VERSIONS@@'
log "${file} is not readable; using OPENSHIFT_VERSIONS=${OPENSHIFT_VERSIONS}"
return
fi

# shellcheck source=/dev/null
source "${file}"

if [[ -z ${OPENSHIFT_MIN:-} || -z ${OPENSHIFT_MAX:-} ]]; then
OPENSHIFT_VERSIONS='@@RHEL_VERSIONS@@'
log "OPENSHIFT_MIN/MAX missing in ${file}; using OPENSHIFT_VERSIONS=${OPENSHIFT_VERSIONS}"
return
fi

min="$(printf '%s' "${OPENSHIFT_MIN}" | awk -F. '{print "v"$1"."$2}')"
max="$(printf '%s' "${OPENSHIFT_MAX}" | awk -F. '{print "v"$1"."$2}')"
OPENSHIFT_VERSIONS="${min}-${max}"
log "Derived OPENSHIFT_VERSIONS=${OPENSHIFT_VERSIONS} from OPENSHIFT_MIN=${OPENSHIFT_MIN} OPENSHIFT_MAX=${OPENSHIFT_MAX}"
}

select_manifests() {
local kind="$1"
shift
Expand All @@ -53,6 +87,21 @@ select_manifests() {
"$@"
}

# kislyuk --yaml-roundtrip keeps scalar quote style ("" vs '') by encoding
# comments as __yq_comment_* keys in jq. Drop those keys so generated files
# do not copy template comments (bundle.csv.yaml, bundle.annotations.yaml).
yq_drop_comments='
walk(
if type == "object" then
with_entries(select((.key | tostring | startswith("__yq_comment_")) | not))
elif type == "array" then
map(select((type == "string" and startswith("__yq_comment_")) | not))
else
.
end
)
'

require() {
if [ $# -eq 1 ]; then
command -v "$1" >/dev/null 2>&1 \
Expand All @@ -69,6 +118,9 @@ check_tools() {
require kubectl
require operator-sdk
require jq
# --yaml-roundtrip keeps quote style and block scalars; comments are
# dropped in jq via yq_drop_comments (not --yaml-output, which rewrites
# "" to '' and unquotes scalars).
require bash -c "yq --help | grep -q -- '--yaml-roundtrip'"

log "All tools available"
Expand Down Expand Up @@ -149,6 +201,30 @@ render_operator_manifests() {
log "Extracted manifests: CRDs, Deployments, ServiceAccounts, Roles, ClusterRoles"
}

# operator-sdk init still runs `go mod tidy` after scaffolding, even with
# --fetch-deps=false. Bundle generation deletes go.mod immediately and never
# compiles the scaffold, so skip tidy (it fails when the Go checksum DB is unreachable).
run_operator_sdk_init() {
local real_go wrapper rc

real_go="$(command -v go)" || abort "go not found in PATH"
wrapper="$(mktemp -d)"
cat >"${wrapper}/go" <<EOF
#!/usr/bin/env bash
if [[ \${1:-} == mod && \${2:-} == tidy ]]; then
exit 0
fi
exec '${real_go}' "\$@"
EOF
chmod +x "${wrapper}/go"

PATH="${wrapper}:${PATH}" operator-sdk init \
--fetch-deps='false' \
--project-name="${bundle_project_name}" && rc=0 || rc=$?
rm -rf "${wrapper}"
return "${rc}"
}

create_sdk_workspace() {
local crd_gvks

Expand All @@ -162,9 +238,7 @@ create_sdk_workspace() {

log "Initializing operator-sdk project"

operator-sdk init \
--fetch-deps='false' \
--project-name="${bundle_project_name}" \
run_operator_sdk_init \
|| abort "Failed to init operator-sdk"

# operator-sdk init used to put main.go at the project root. Newer
Expand Down Expand Up @@ -232,7 +306,7 @@ render_scorecard_tests() {
render_bundle_metadata() {
log "Rendering bundle annotations for ${DISTRIBUTION}"

require_env OPENSHIFT_VERSIONS
resolve_openshift_versions

yq --yaml-roundtrip \
--arg distribution "${DISTRIBUTION}" \
Expand All @@ -250,6 +324,7 @@ render_bundle_metadata() {
else
.
end
| '"${yq_drop_comments}"'
' \
<bundle.annotations.yaml \
>"${bundle_directory}/metadata/annotations.yaml" \
Expand Down Expand Up @@ -293,7 +368,7 @@ write_crd_manifests() {
)" || abort "Failed to extract CRD names"

while IFS=$'\t' read -r index name; do
yq --yaml-roundtrip ".[${index}]" \
yq --yaml-roundtrip ".[${index}] | ${yq_drop_comments}" \
<<<"${operator_crds}" \
>"${bundle_directory}/manifests/${name}.crd.yaml" \
|| abort "Failed to write CRD ${name}"
Expand Down Expand Up @@ -409,6 +484,11 @@ rewrite_crd_examples() {
}

apply_operator_image_to_examples() {
if [[ ${DISTRIBUTION} != "redhat" ]]; then
log "Skipping initContainer image override for ${DISTRIBUTION}"
return
fi

crd_examples="$(
jq \
--arg operator_image "${operator_image}" \
Expand Down Expand Up @@ -462,6 +542,7 @@ render_csv() {
--argjson related_images "${related_images}" \
"${skips_arg}" skips "${skips}" \
--arg target_namespaces_field_path "metadata.annotations['olm.targetNamespaces']" \
--arg namespace_field_path "metadata.namespace" \
--arg timestamp "$(date -u '+%Y-%m-%dT%H:%M:%SZ')" \
'
.metadata.annotations["alm-examples"] = $examples
Expand Down Expand Up @@ -523,14 +604,14 @@ render_csv() {
.spec.template.spec.containers[].env[]?
| select(.name == "PGO_NAMESPACE")
| .valueFrom.fieldRef.fieldPath
) = $target_namespaces_field_path
) = $namespace_field_path
| {
name: .metadata.name,
spec
}
)
]
| .
| '"${yq_drop_comments}"'
' \
<bundle.csv.yaml \
>"${bundle_directory}/manifests/${bundle_filename}.clusterserviceversion.yaml" \
Expand Down
Loading