diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..b6b36c3 --- /dev/null +++ b/Makefile @@ -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 diff --git a/Makefile-common b/Makefile-common new file mode 100644 index 0000000..79bcf80 --- /dev/null +++ b/Makefile-common @@ -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\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 diff --git a/ansible.cfg b/ansible.cfg new file mode 100644 index 0000000..528a8cb --- /dev/null +++ b/ansible.cfg @@ -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 diff --git a/pattern.sh b/pattern.sh new file mode 100755 index 0000000..e7f16e5 --- /dev/null +++ b/pattern.sh @@ -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" \ + "$@" diff --git a/values-global.yaml b/values-global.yaml new file mode 100644 index 0000000..c0c0751 --- /dev/null +++ b/values-global.yaml @@ -0,0 +1,9 @@ +global: + pattern: quarter + secretLoader: + disabled: true +main: + clusterGroupName: prod + multiSourceConfig: + enabled: true + clusterGroupChartVersion: 0.9.* diff --git a/values-prod.yaml b/values-prod.yaml new file mode 100644 index 0000000..46fa71a --- /dev/null +++ b/values-prod.yaml @@ -0,0 +1,6 @@ +clusterGroup: + name: prod + namespaces: + - quarter + subscriptions: {} + applications: {}