Skip to content
Open
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
5 changes: 5 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Generated by patternizer
# This Makefile includes the common pattern targets from Makefile-common
# You can add custom targets above or below the include line

include Makefile-common
54 changes: 54 additions & 0 deletions Makefile-common
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
MAKEFLAGS += --no-print-directory
ANSIBLE_STDOUT_CALLBACK ?= rhvp.cluster_utils.readable
ANSIBLE_RUN ?= ANSIBLE_STDOUT_CALLBACK=$(ANSIBLE_STDOUT_CALLBACK) ansible-playbook $(EXTRA_PLAYBOOK_OPTS)
DOCS_URL := https://validatedpatterns.io/blog/2025-08-29-new-common-makefile-structure/

.PHONY: help
help: ## Print this help message
@echo "For a complete guide to these targets and the available overrides, please visit $(DOCS_URL)"
@awk 'BEGIN {FS = ":.*##"; printf "\nUsage:\n make \033[36m<target>\033[0m\n"} /^(\s|[a-zA-Z_0-9-])+:.*?##/ { printf " \033[36m%-35s\033[0m %s\n", $$1, $$2 } /^##@/ { printf "\n\033[1m%s\033[0m\n", substr($$0, 5) } ' $(MAKEFILE_LIST)

##@ Pattern Install Tasks
.PHONY: show
show: ## Shows the template that would be applied by the `make install` target
@$(ANSIBLE_RUN) rhvp.cluster_utils.show

.PHONY: operator-deploy
operator-deploy operator-upgrade: ## Installs/updates the pattern on a cluster (DOES NOT load secrets)
@$(ANSIBLE_RUN) rhvp.cluster_utils.operator_deploy

.PHONY: install
install: pattern-install ## Installs the pattern onto a cluster (Loads secrets as well if configured)

.PHONY: uninstall
uninstall: ## (EXPERIMENTAL) See https://validatedpatterns.io/blog/2026-02-16-pattern-uninstall/.
@$(ANSIBLE_RUN) rhvp.cluster_utils.uninstall

.PHONY: pattern-install
pattern-install:
@$(ANSIBLE_RUN) rhvp.cluster_utils.install

.PHONY: load-secrets
load-secrets: ## Loads secrets onto the cluster (unless explicitly disabled in values-global.yaml)
@$(ANSIBLE_RUN) rhvp.cluster_utils.load_secrets

##@ Validation Tasks
.PHONY: validate-prereq
validate-prereq: ## verify pre-requisites
@$(ANSIBLE_RUN) rhvp.cluster_utils.validate_prereq

.PHONY: validate-origin
validate-origin: ## verify the git origin is available
@$(ANSIBLE_RUN) rhvp.cluster_utils.validate_origin

.PHONY: validate-cluster
validate-cluster: ## Do some cluster validations before installing
@$(ANSIBLE_RUN) rhvp.cluster_utils.validate_cluster

.PHONY: validate-schema
validate-schema: ## validates values files against schema in common/clustergroup
@$(ANSIBLE_RUN) rhvp.cluster_utils.validate_schema

.PHONY: argo-healthcheck
argo-healthcheck: ## Checks if all argo applications are synced
@$(ANSIBLE_RUN) rhvp.cluster_utils.argo_healthcheck
15 changes: 15 additions & 0 deletions ansible.cfg
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
[defaults]
localhost_warning=False
retry_files_enabled=False
# Retry files disabled to avoid cluttering CI/CD environments
interpreter_python=auto_silent
timeout=30
library=~/.ansible/plugins/modules:./ansible/plugins/modules:/usr/share/ansible/plugins/modules
roles_path=~/.ansible/roles:./ansible/roles:/usr/share/ansible/roles:/etc/ansible/roles
filter_plugins=~/.ansible/plugins/filter:./ansible/plugins/filter:/usr/share/ansible/plugins/filter
# use the collections from the util. container,
# change below if you want to test local collections
collections_path=/usr/share/ansible/collections

[inventory]
inventory_unparsed_warning=False
125 changes: 125 additions & 0 deletions pattern.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
#!/bin/bash
set -euo pipefail

function is_available {
command -v "$1" >/dev/null 2>&1 || { echo >&2 "$1 is required but it's not installed. Aborting."; exit 1; }
}

function version {
echo "$1" | awk -F. '{ printf("%d%03d%03d%03d\n", $1,$2,$3,$4); }'
}

if [ -z "${PATTERN_UTILITY_CONTAINER:-}" ]; then
PATTERN_UTILITY_CONTAINER="quay.io/validatedpatterns/utility-container"
fi
# If PATTERN_DISCONNECTED_HOME is set it will be used to populate both PATTERN_UTILITY_CONTAINER
# and PATTERN_INSTALL_CHART automatically
if [ -n "${PATTERN_DISCONNECTED_HOME:-}" ]; then
PATTERN_UTILITY_CONTAINER="${PATTERN_DISCONNECTED_HOME}/utility-container"
PATTERN_INSTALL_CHART="oci://${PATTERN_DISCONNECTED_HOME}/pattern-install"
echo "PATTERN_DISCONNECTED_HOME is set to ${PATTERN_DISCONNECTED_HOME}"
echo "Setting the following variables:"
echo " PATTERN_UTILITY_CONTAINER: ${PATTERN_UTILITY_CONTAINER}"
echo " PATTERN_INSTALL_CHART: ${PATTERN_INSTALL_CHART}"
fi

readonly commands=(podman)
for cmd in "${commands[@]}"; do is_available "$cmd"; done

UNSUPPORTED_PODMAN_VERSIONS="1.6 1.5"
PODMAN_VERSION_STR=$(podman --version) || { echo "Failed to get podman version"; exit 1; }
for i in ${UNSUPPORTED_PODMAN_VERSIONS}; do
# We add a space
if echo "${PODMAN_VERSION_STR}" | grep -q -E "\b${i}"; then
echo "Unsupported podman version. We recommend > 4.3.0"
podman --version
exit 1
fi
done

# podman --version outputs:
# podman version 4.8.2
PODMAN_VERSION=$(echo "${PODMAN_VERSION_STR}" | awk '{ print $NF }')

# podman < 4.3.0 do not support keep-id:uid=...
PODMAN_ARGS=()
if [ "$(version "${PODMAN_VERSION}")" -lt "$(version "4.3.0")" ]; then
PODMAN_ARGS=(-v "${HOME}:/root")
else
# We do not rely on bash's $UID and $GID because on MacOSX $GID is not set
MYNAME=$(id -n -u)
MYUID=$(id -u)
MYGID=$(id -g)
PODMAN_ARGS=(--passwd-entry "${MYNAME}:x:${MYUID}:${MYGID}::/pattern-home:/bin/bash" --user "${MYUID}:${MYGID}" --userns "keep-id:uid=${MYUID},gid=${MYGID}")
fi

if [ -n "${KUBECONFIG:-}" ]; then
# Check if KUBECONFIG path starts with HOME directory
if [[ ! "${KUBECONFIG}" =~ ^"${HOME}" ]]; then
echo "${KUBECONFIG} is pointing outside of the HOME folder, this will make it unavailable from the container."
echo "Please move it somewhere inside your $HOME folder, as that is what gets bind-mounted inside the container"
exit 1
fi
fi

# Detect if we use podman machine. If we do not then we bind mount local host ssl folders
# if we are using podman machine then we do not bind mount anything (for now!)
REMOTE_PODMAN=$(podman system connection list | tail -n +2 | wc -l) || REMOTE_PODMAN=0
PKI_HOST_MOUNT_ARGS=()
if [ "${REMOTE_PODMAN}" -eq 0 ]; then # If we are not using podman machine we check the hosts folders
# We check /etc/pki/tls because on ubuntu /etc/pki/fwupd sometimes
# exists but not /etc/pki/tls and we do not want to bind mount in such a case
# as it would find no certificates at all.
if [ -d /etc/pki/tls ]; then
PKI_HOST_MOUNT_ARGS=(-v /etc/pki:/etc/pki:ro)
elif [ -d /etc/ssl ]; then
PKI_HOST_MOUNT_ARGS=(-v /etc/ssl:/etc/ssl:ro)
else
PKI_HOST_MOUNT_ARGS=(-v /usr/share/ca-certificates:/usr/share/ca-certificates:ro)
fi
fi

# Parse EXTRA_ARGS into an array if set
EXTRA_ARGS_ARRAY=()
if [ -n "${EXTRA_ARGS:-}" ]; then
# shellcheck disable=SC2206
EXTRA_ARGS_ARRAY=(${EXTRA_ARGS})
fi

# Copy Kubeconfig from current environment. The utilities will pick up ~/.kube/config if set so it's not mandatory
# $HOME is mounted as itself for any files that are referenced with absolute paths
# $HOME is mounted to /root because the UID in the container is 0 and that's where SSH looks for credentials

podman run -it --rm --pull=newer \
--security-opt label=disable \
-e ANSIBLE_STDOUT_CALLBACK \
-e DISABLE_VALIDATE_ORIGIN \
-e EXTRA_HELM_OPTS \
-e EXTRA_PLAYBOOK_OPTS \
-e K8S_AUTH_HOST \
-e K8S_AUTH_PASSWORD \
-e K8S_AUTH_SSL_CA_CERT \
-e K8S_AUTH_TOKEN \
-e K8S_AUTH_USERNAME \
-e K8S_AUTH_VERIFY_SSL \
-e KUBECONFIG \
-e PATTERN_DIR \
-e PATTERN_DISCONNECTED_HOME \
-e PATTERN_INSTALL_CHART \
-e PATTERN_NAME \
-e TARGET_BRANCH \
-e TARGET_CLUSTERGROUP \
-e TARGET_ORIGIN \
-e TOKEN_NAMESPACE \
-e TOKEN_SECRET \
-e UUID_FILE \
-e VALUES_SECRET \
"${PKI_HOST_MOUNT_ARGS[@]}" \
-v "$(pwd -P)":"$(pwd -P)" \
-v "${HOME}":"${HOME}" \
-v "${HOME}":/pattern-home \
"${PODMAN_ARGS[@]}" \
"${EXTRA_ARGS_ARRAY[@]}" \
-w "$(pwd -P)" \
"$PATTERN_UTILITY_CONTAINER" \
"$@"
9 changes: 9 additions & 0 deletions values-global.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
global:
pattern: quarter
secretLoader:
disabled: true
main:
clusterGroupName: prod
multiSourceConfig:
enabled: true
clusterGroupChartVersion: 0.9.*
6 changes: 6 additions & 0 deletions values-prod.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
clusterGroup:
name: prod
namespaces:
- quarter
subscriptions: {}
applications: {}