|
#!/usr/bin/env bash |
|
|
|
#################################### |
|
######## General Variables ######### |
|
#################################### |
|
|
|
# The name of the owner of the github repository |
|
GITHUB_OWNER="" |
|
# The name of the github repository |
|
GITHUB_REPOSITORY="" |
|
# Helm charts repository URL |
|
HELM_REPOSITORY_URL="" |
|
# The name of the Helm repository to use to add charts repository |
|
HELM_REPOSITORY_NAME="" |
|
# The name of the Helm release |
|
HELM_RELEASE_NAME="" |
|
# Namespace we are going to use in kubernetes for deployment |
|
KUBERNETES_NAMESPACE="" |
|
# The name of the application under which deployment will be created |
|
KUBERNETES_APPLICATION_NAME="" |
|
# List of YAML files to be applied with kubectl |
|
# Add your file URLs or local paths to this list |
|
# For versions, substitute the version with the {version} placeholder |
|
ADDITIONAL_MANIFESTS=() |
|
|
|
|
|
#################################### |
|
######## Advanced Variables ######## |
|
#################################### |
|
|
|
# The script source directory (leave it as is) |
|
SCRIPT_DIRECTORY=$(dirname "$BASH_SOURCE") |
|
# The expected Helm version to be installed |
|
HELM_EXPECTED_VERSION="3" |
|
# The Kubernetes context we want to use |
|
KUBERNETES_CONTEXT="default" |
|
# The name of the values file to also be used during the install/upgrade process |
|
VALUES_FILE_NAME="values.yaml" |
|
|
|
# Function to fetch the latest release from a GitHub repository |
|
fetch_latest_release() { |
|
local owner_name="$1" |
|
local owner_repository="$2" |
|
|
|
local url="https://api.github.com/repos/${owner_name}/${owner_repository}/releases/latest" |
|
|
|
local data |
|
data=$(curl -s --fail "$url") |
|
|
|
if [[ $? -ne 0 ]]; then |
|
echo "Error fetching release data." >&2 |
|
return 1 |
|
fi |
|
|
|
local tag_name |
|
tag_name=$(echo "$data" | jq -r '.tag_name') |
|
|
|
if [[ $tag_name == v* ]]; then |
|
echo "$tag_name" |
|
else |
|
echo "" |
|
fi |
|
} |
|
|
|
# Function to check if there is a valid release |
|
has_valid_release() { |
|
local release_tag="$1" |
|
|
|
if [[ -z "$release_tag" ]]; then |
|
echo "No valid release found. Exiting." |
|
exit 1 |
|
fi |
|
} |
|
|
|
# Function to get the installed Helm chart version |
|
get_installed_release() { |
|
local namespace="$1" |
|
local release_name="$2" |
|
|
|
# Try to get the app_version |
|
local version=$(helm list -n "$namespace" --filter "$release_name" -o json | jq -r '.[0].app_version') |
|
|
|
# If app_version is empty or not found, fall back to extracting from chart |
|
if [[ -z "$version" || "$version" == "null" ]]; then |
|
version=$(helm list -n "$namespace" --filter "$release_name" -o json | jq -r '.[0].chart' | grep -oE "v?[0-9]+\.[0-9]+\.[0-9]+") |
|
fi |
|
|
|
version=${version#v} |
|
|
|
echo "$version" |
|
} |
|
|
|
|
|
# Function to check whether Helm chart is actually installed |
|
is_chart_installed() { |
|
local namespace="$1" |
|
local release_name="$2" |
|
|
|
if helm list -n "$namespace" --filter "$release_name" | grep -q "$release_name"; then |
|
return 0 # Chart is installed |
|
else |
|
return 1 # Chart is not installed |
|
fi |
|
} |
|
|
|
# Function to compare installed version with the latest release version |
|
compare_versions() { |
|
local installed_version="$1" |
|
local latest_version="${2#v}" |
|
|
|
if [[ "$installed_version" == "$latest_version" ]]; then |
|
echo "Installed version ($installed_version) is the latest. Exiting." |
|
exit 0 |
|
else |
|
echo "Installed version ($installed_version) differs from the latest ($latest_version)." |
|
fi |
|
} |
|
|
|
# Function to compare versions and check for patch update |
|
is_patch_update() { |
|
local installed_version="$1" |
|
local latest_version="$2" |
|
|
|
installed_version=${installed_version#v} |
|
latest_version=${latest_version#v} |
|
|
|
IFS='.' read -ra INSTALLED_VERSION_PARTS <<< "$installed_version" |
|
IFS='.' read -ra LATEST_VERSION_PARTS <<< "$latest_version" |
|
|
|
if [[ ${INSTALLED_VERSION_PARTS[0]} -eq ${LATEST_VERSION_PARTS[0]} ]] && [[ ${INSTALLED_VERSION_PARTS[1]} -eq ${LATEST_VERSION_PARTS[1]} ]]; then |
|
if [[ ${INSTALLED_VERSION_PARTS[2]} -eq ${LATEST_VERSION_PARTS[2]} ]]; then |
|
echo "No update required. Exiting." |
|
exit 0 |
|
fi |
|
else |
|
echo "Update is not a patch update. Potentially breaking changes. Exiting." |
|
exit 1 |
|
fi |
|
} |
|
|
|
# Function to check and add Helm repository if it doesn't exist |
|
check_and_add_helm_repository() { |
|
local repository_url="$1" |
|
local repository_name="$2" |
|
|
|
# Check if the Helm repository exists |
|
if ! helm repo list | grep -q "$repository_name"; then |
|
echo "Adding missing repository: $repository_name ($repository_url)." |
|
helm repo add "$repository_name" "$repository_url" > /dev/null 2>&1 |
|
fi |
|
} |
|
|
|
# Function to update Helm repositories |
|
update_helm_repository() { |
|
helm repo update > /dev/null 2>&1 |
|
} |
|
|
|
# Function to ensure a Kubernetes namespace exists |
|
ensure_namespace_exists() { |
|
local namespace="$1" |
|
|
|
if ! kubectl get namespace "$namespace" > /dev/null 2>&1; then |
|
echo "Creating namespace '$namespace'." |
|
kubectl create namespace "$namespace" > /dev/null 2>&1 |
|
fi |
|
} |
|
|
|
# Function to apply YAML manifests |
|
apply_additional_manifests() { |
|
for file in "${ADDITIONAL_MANIFESTS[@]}"; do |
|
echo "Applying $file" |
|
kubectl apply -f "$file" |
|
done |
|
} |
|
|
|
# Ensure we are in a valid Kubernetes context |
|
ensure_kubernetes_context() { |
|
local context="$1" |
|
current_context=$(kubectl config current-context) |
|
if [[ "$current_context" != "$context" ]]; then |
|
echo "Not in the expected Kubernetes context." |
|
echo "Expected to be in '${context}', but currently in '${current_context}'" |
|
echo "Exiting." |
|
exit 1 |
|
fi |
|
} |
|
|
|
# Ensure that we have the correct Helm version installed |
|
ensure_helm_version() { |
|
local required_version="$1" |
|
helm_version=$(helm version --short | cut -d '.' -f 1 | tr -dc '0-9') |
|
|
|
if [[ $helm_version -lt $required_version ]]; then |
|
echo "Requires Helm version $required_version or newer. Exiting." |
|
exit 1 |
|
fi |
|
} |
|
|
|
# Function to perform the Helm upgrade |
|
upgrade() { |
|
local release_name="$1" |
|
local chart="$2" |
|
local namespace="$3" |
|
local version="$4" |
|
|
|
local values_file="$SCRIPT_DIRECTORY/$VALUES_FILE_NAME" |
|
if [ -f "$values_file" ]; then |
|
has_values_file=true |
|
else |
|
has_values_file=false |
|
fi |
|
|
|
local upgrade_cmd="helm upgrade --version $version $release_name $chart --namespace $namespace" |
|
|
|
if [[ "$has_values_file" == "true" ]]; then |
|
upgrade_cmd+=" --values=$values_file" |
|
fi |
|
|
|
$upgrade_cmd |
|
} |
|
|
|
# Function to perform a Helm install |
|
install() { |
|
local release_name="$1" |
|
local chart="$2" |
|
local namespace="$3" |
|
local version="$4" |
|
|
|
local values_file="$SCRIPT_DIRECTORY/$VALUES_FILE_NAME" |
|
if [ -f "$values_file" ]; then |
|
has_values_file=true |
|
else |
|
has_values_file=false |
|
fi |
|
|
|
local install_cmd="helm install $release_name $chart --namespace $namespace --version $version" |
|
|
|
if [[ "$has_values_file" == "true" ]]; then |
|
install_cmd+=" --values=$values_file" |
|
fi |
|
|
|
$install_cmd |
|
} |
|
|
|
|
|
# Get the latest release version from Github |
|
latest_version=$(fetch_latest_release "$GITHUB_OWNER" "$GITHUB_REPOSITORY") || exit 1 |
|
|
|
# Loop through additional manifests and replace the version placeholder with actual vesion |
|
for i in "${!ADDITIONAL_MANIFESTS[@]}"; do |
|
ADDITIONAL_MANIFESTS[$i]=${ADDITIONAL_MANIFESTS[$i]//\{version\}/$latest_version} |
|
done |
|
|
|
# Check that we were able to successfully retrieve the latest release tag |
|
has_valid_release "$latest_version" |
|
# Check that we are working in a valid Kubernetes context |
|
ensure_kubernetes_context "$KUBERNETES_CONTEXT" |
|
# Check that we have required version of Helm installed |
|
ensure_helm_version "$HELM_EXPECTED_VERSION" |
|
# Get the installed chart version |
|
installed_version=$(get_installed_release "$KUBERNETES_NAMESPACE" "$KUBERNETES_APPLICATION_NAME") |
|
# Check if helm repository exists and add if not |
|
check_and_add_helm_repository "$HELM_REPOSITORY_URL" "$HELM_REPOSITORY_NAME" |
|
# Update helm repositories |
|
update_helm_repository |
|
|
|
# Check that Helm chart is actually installed |
|
if is_chart_installed "$KUBERNETES_NAMESPACE" "$KUBERNETES_APPLICATION_NAME"; then |
|
# Compare the installed chart version and latest version from Github |
|
compare_versions "$installed_version" "$latest_version" |
|
# Ensure that update is for the patch version, otherwise prompt user to check for breaking changes |
|
is_patch_update "$installed_version" "$latest_version" |
|
# Call the function to apply the YAML manifests |
|
apply_additional_manifests |
|
# Actually perform the upgrade of the Helm chart |
|
upgrade "$HELM_RELEASE_NAME" "$HELM_REPOSITORY_NAME/$GITHUB_REPOSITORY" "$KUBERNETES_NAMESPACE" "$latest_version" |
|
else |
|
# Ensure that kubernetes namespace exists |
|
ensure_namespace_exists "$KUBERNETES_NAMESPACE" |
|
# Call the function to apply the YAML manifests |
|
apply_additional_manifests |
|
# Actually perform the installation of the Helm chart |
|
install "$HELM_RELEASE_NAME" "$HELM_REPOSITORY_NAME/$GITHUB_REPOSITORY" "$KUBERNETES_NAMESPACE" "$latest_version" |
|
fi |