feat: Initial commit, empty from template.
This commit is contained in:
144
scripts/bootstrap-apps.sh
Executable file
144
scripts/bootstrap-apps.sh
Executable file
@@ -0,0 +1,144 @@
|
||||
#!/usr/bin/env bash
|
||||
set -Eeuo pipefail
|
||||
|
||||
source "$(dirname "${0}")/lib/common.sh"
|
||||
|
||||
export LOG_LEVEL="debug"
|
||||
export ROOT_DIR="$(git rev-parse --show-toplevel)"
|
||||
|
||||
# Talos requires the nodes to be 'Ready=False' before applying resources
|
||||
function wait_for_nodes() {
|
||||
log debug "Waiting for nodes to be available"
|
||||
|
||||
# Skip waiting if all nodes are 'Ready=True'
|
||||
if kubectl wait nodes --for=condition=Ready=True --all --timeout=10s &>/dev/null; then
|
||||
log info "Nodes are available and ready, skipping wait for nodes"
|
||||
return
|
||||
fi
|
||||
|
||||
# Wait for all nodes to be 'Ready=False'
|
||||
until kubectl wait nodes --for=condition=Ready=False --all --timeout=10s &>/dev/null; do
|
||||
log info "Nodes are not available, waiting for nodes to be available. Retrying in 10 seconds..."
|
||||
sleep 10
|
||||
done
|
||||
}
|
||||
|
||||
# Namespaces to be applied before the SOPS secrets are installed
|
||||
function apply_namespaces() {
|
||||
log debug "Applying namespaces"
|
||||
|
||||
local -r apps_dir="${ROOT_DIR}/kubernetes/apps"
|
||||
|
||||
if [[ ! -d "${apps_dir}" ]]; then
|
||||
log error "Directory does not exist" "directory=${apps_dir}"
|
||||
fi
|
||||
|
||||
for app in "${apps_dir}"/*/; do
|
||||
namespace=$(basename "${app}")
|
||||
|
||||
# Check if the namespace resources are up-to-date
|
||||
if kubectl get namespace "${namespace}" &>/dev/null; then
|
||||
log info "Namespace resource is up-to-date" "resource=${namespace}"
|
||||
continue
|
||||
fi
|
||||
|
||||
# Apply the namespace resources
|
||||
if kubectl create namespace "${namespace}" --dry-run=client --output=yaml \
|
||||
| kubectl apply --server-side --filename - &>/dev/null;
|
||||
then
|
||||
log info "Namespace resource applied" "resource=${namespace}"
|
||||
else
|
||||
log error "Failed to apply namespace resource" "resource=${namespace}"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# SOPS secrets to be applied before the helmfile charts are installed
|
||||
function apply_sops_secrets() {
|
||||
log debug "Applying secrets"
|
||||
|
||||
local -r secrets=(
|
||||
"${ROOT_DIR}/bootstrap/github-deploy-key.sops.yaml"
|
||||
"${ROOT_DIR}/bootstrap/sops-age.sops.yaml"
|
||||
"${ROOT_DIR}/kubernetes/components/sops/cluster-secrets.sops.yaml"
|
||||
)
|
||||
|
||||
for secret in "${secrets[@]}"; do
|
||||
if [ ! -f "${secret}" ]; then
|
||||
log warn "File does not exist" "file=${secret}"
|
||||
continue
|
||||
fi
|
||||
|
||||
# Check if the secret resources are up-to-date
|
||||
if sops exec-file "${secret}" "kubectl --namespace flux-system diff --filename {}" &>/dev/null; then
|
||||
log info "Secret resource is up-to-date" "resource=$(basename "${secret}" ".sops.yaml")"
|
||||
continue
|
||||
fi
|
||||
|
||||
# Apply secret resources
|
||||
if sops exec-file "${secret}" "kubectl --namespace flux-system apply --server-side --filename {}" &>/dev/null; then
|
||||
log info "Secret resource applied successfully" "resource=$(basename "${secret}" ".sops.yaml")"
|
||||
else
|
||||
log error "Failed to apply secret resource" "resource=$(basename "${secret}" ".sops.yaml")"
|
||||
fi
|
||||
done
|
||||
}
|
||||
|
||||
# CRDs to be applied before the helmfile charts are installed
|
||||
function apply_crds() {
|
||||
log debug "Applying CRDs"
|
||||
|
||||
local -r helmfile_file="${ROOT_DIR}/bootstrap/helmfile.d/00-crds.yaml"
|
||||
|
||||
if [[ ! -f "${helmfile_file}" ]]; then
|
||||
log fatal "File does not exist" "file" "${helmfile_file}"
|
||||
fi
|
||||
|
||||
if ! crds=$(helmfile --file "${helmfile_file}" template --quiet | yq eval-all --exit-status 'select(.kind == "CustomResourceDefinition")') || [[ -z "${crds}" ]]; then
|
||||
log fatal "Failed to render CRDs from Helmfile" "file" "${helmfile_file}"
|
||||
fi
|
||||
|
||||
if echo "${crds}" | kubectl diff --filename - &>/dev/null; then
|
||||
log info "CRDs are up-to-date"
|
||||
return
|
||||
fi
|
||||
|
||||
if ! echo "${crds}" | kubectl apply --server-side --filename - &>/dev/null; then
|
||||
log fatal "Failed to apply crds from Helmfile" "file" "${helmfile_file}"
|
||||
fi
|
||||
|
||||
log info "CRDs applied successfully"
|
||||
}
|
||||
|
||||
# Sync Helm releases
|
||||
function sync_helm_releases() {
|
||||
log debug "Syncing Helm releases"
|
||||
|
||||
local -r helmfile_file="${ROOT_DIR}/bootstrap/helmfile.d/01-apps.yaml"
|
||||
|
||||
if [[ ! -f "${helmfile_file}" ]]; then
|
||||
log error "File does not exist" "file=${helmfile_file}"
|
||||
fi
|
||||
|
||||
if ! helmfile --file "${helmfile_file}" sync --hide-notes; then
|
||||
log error "Failed to sync Helm releases"
|
||||
fi
|
||||
|
||||
log info "Helm releases synced successfully"
|
||||
}
|
||||
|
||||
function main() {
|
||||
check_env KUBECONFIG TALOSCONFIG
|
||||
check_cli helmfile kubectl kustomize sops talhelper yq
|
||||
|
||||
# Apply resources and Helm releases
|
||||
wait_for_nodes
|
||||
apply_namespaces
|
||||
apply_sops_secrets
|
||||
apply_crds
|
||||
sync_helm_releases
|
||||
|
||||
log info "Congrats! The cluster is bootstrapped and Flux is syncing the Git repository"
|
||||
}
|
||||
|
||||
main "$@"
|
||||
107
scripts/lib/common.sh
Executable file
107
scripts/lib/common.sh
Executable file
@@ -0,0 +1,107 @@
|
||||
#!/usr/bin/env bash
|
||||
set -Eeuo pipefail
|
||||
|
||||
# Log messages with different levels
|
||||
function log() {
|
||||
local level="${1:-info}"
|
||||
shift
|
||||
|
||||
# Define log levels with their priorities
|
||||
local -A level_priority=(
|
||||
[debug]=1
|
||||
[info]=2
|
||||
[warn]=3
|
||||
[error]=4
|
||||
)
|
||||
|
||||
# Get the current log level's priority
|
||||
local current_priority=${level_priority[$level]:-2} # Default to "info" priority
|
||||
|
||||
# Get the configured log level from the environment, default to "info"
|
||||
local configured_level=${LOG_LEVEL:-info}
|
||||
local configured_priority=${level_priority[$configured_level]:-2}
|
||||
|
||||
# Skip log messages below the configured log level
|
||||
if ((current_priority < configured_priority)); then
|
||||
return
|
||||
fi
|
||||
|
||||
# Define log colors
|
||||
local -A colors=(
|
||||
[debug]="\033[1m\033[38;5;63m" # Blue
|
||||
[info]="\033[1m\033[38;5;87m" # Cyan
|
||||
[warn]="\033[1m\033[38;5;192m" # Yellow
|
||||
[error]="\033[1m\033[38;5;198m" # Red
|
||||
)
|
||||
|
||||
# Fallback to "info" if the color for the given level is not defined
|
||||
local color="${colors[$level]:-${colors[info]}}"
|
||||
local msg="$1"
|
||||
shift
|
||||
|
||||
# Prepare additional data
|
||||
local data=
|
||||
if [[ $# -gt 0 ]]; then
|
||||
for item in "$@"; do
|
||||
if [[ "${item}" == *=* ]]; then
|
||||
data+="\033[1m\033[38;5;236m${item%%=*}=\033[0m\"${item#*=}\" "
|
||||
else
|
||||
data+="${item} "
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# Determine output stream based on log level
|
||||
local output_stream="/dev/stdout"
|
||||
if [[ "$level" == "error" ]]; then
|
||||
output_stream="/dev/stderr"
|
||||
fi
|
||||
|
||||
# Print the log message
|
||||
printf "%s %b%s%b %s %b\n" "$(date -u +"%Y-%m-%dT%H:%M:%SZ")" \
|
||||
"${color}" "${level^^}" "\033[0m" "${msg}" "${data}" >"${output_stream}"
|
||||
|
||||
# Exit if the log level is error
|
||||
if [[ "$level" == "error" ]]; then
|
||||
exit 1
|
||||
fi
|
||||
}
|
||||
|
||||
# Check if required environment variables are set
|
||||
function check_env() {
|
||||
local envs=("${@}")
|
||||
local missing=()
|
||||
local values=()
|
||||
|
||||
for env in "${envs[@]}"; do
|
||||
if [[ -z "${!env-}" ]]; then
|
||||
missing+=("${env}")
|
||||
else
|
||||
values+=("${env}=${!env}")
|
||||
fi
|
||||
done
|
||||
|
||||
if [ ${#missing[@]} -ne 0 ]; then
|
||||
log error "Missing required env variables" "envs=${missing[*]}"
|
||||
fi
|
||||
|
||||
log debug "Env variables are set" "envs=${values[*]}"
|
||||
}
|
||||
|
||||
# Check if required CLI tools are installed
|
||||
function check_cli() {
|
||||
local deps=("${@}")
|
||||
local missing=()
|
||||
|
||||
for dep in "${deps[@]}"; do
|
||||
if ! command -v "${dep}" &>/dev/null; then
|
||||
missing+=("${dep}")
|
||||
fi
|
||||
done
|
||||
|
||||
if [ ${#missing[@]} -ne 0 ]; then
|
||||
log error "Missing required deps" "deps=${missing[*]}"
|
||||
fi
|
||||
|
||||
log debug "Deps are installed" "deps=${deps[*]}"
|
||||
}
|
||||
Reference in New Issue
Block a user