305 lines
7.7 KiB
Bash
305 lines
7.7 KiB
Bash
#!/usr/bin/env bash
|
|
|
|
set -euo pipefail
|
|
|
|
OUTPUT_DIR="./generated-helmops"
|
|
API_VERSION="fleet.cattle.io/v1alpha1"
|
|
RESOURCE_KIND="HelmOp"
|
|
VALUES_ARGS=()
|
|
WORKSPACE_NAMESPACE="fleet-local"
|
|
|
|
usage() {
|
|
cat <<'EOF'
|
|
Usage:
|
|
./generate-fleet-helmops-from-helm.sh [options]
|
|
|
|
Description:
|
|
Legge le release presenti con `helm list -A`, recupera metadata e values
|
|
per ogni release e genera un file YAML per release in formato HelmOp-style.
|
|
|
|
Options:
|
|
-o, --output-dir <dir> Directory di output (default: ./generated-helmops)
|
|
-w, --workspace-namespace <ns>
|
|
Namespace dove creare la risorsa HelmOp
|
|
(default: fleet-local)
|
|
--api-version <value> apiVersion del manifest generato
|
|
(default: fleet.cattle.io/v1alpha1)
|
|
--kind <value> kind del manifest generato (default: HelmOp)
|
|
-a, --all-values Usa `helm get values -a -o yaml`
|
|
-h, --help Mostra questo help
|
|
|
|
Examples:
|
|
./generate-fleet-helmops-from-helm.sh
|
|
./generate-fleet-helmops-from-helm.sh -o ./clusters/idc/imported
|
|
./generate-fleet-helmops-from-helm.sh -w fleet-default
|
|
./generate-fleet-helmops-from-helm.sh --kind HelmChart --api-version helm.cattle.io/v1
|
|
EOF
|
|
}
|
|
|
|
require_cmd() {
|
|
local cmd="$1"
|
|
if ! command -v "$cmd" >/dev/null 2>&1; then
|
|
echo "Errore: comando richiesto non trovato: $cmd" >&2
|
|
exit 1
|
|
fi
|
|
}
|
|
|
|
trim() {
|
|
local value="$1"
|
|
value="${value#"${value%%[![:space:]]*}"}"
|
|
value="${value%"${value##*[![:space:]]}"}"
|
|
printf '%s' "$value"
|
|
}
|
|
|
|
safe_file_name() {
|
|
printf '%s' "$1" | tr '/\\:' '---'
|
|
}
|
|
|
|
extract_yaml_scalar() {
|
|
local key="$1"
|
|
local content="$2"
|
|
|
|
printf '%s\n' "$content" \
|
|
| sed -n "s/^[[:space:]]*${key}:[[:space:]]*//p" \
|
|
| head -n 1 \
|
|
| sed 's/^"//; s/"$//; s/^\x27//; s/\x27$//'
|
|
}
|
|
|
|
extract_first_source() {
|
|
local content="$1"
|
|
|
|
awk '
|
|
/^sources:/ { in_sources=1; next }
|
|
in_sources && /^[^[:space:]-]/ { exit }
|
|
in_sources && /^[[:space:]]*-[[:space:]]*/ {
|
|
sub(/^[[:space:]]*-[[:space:]]*/, "")
|
|
print
|
|
exit
|
|
}
|
|
' <<< "$content"
|
|
}
|
|
|
|
extract_chart_name_from_ref() {
|
|
local chart_ref="$1"
|
|
|
|
if [[ "$chart_ref" =~ ^(.+)-([0-9][A-Za-z0-9.+_-]*)$ ]]; then
|
|
printf '%s' "${BASH_REMATCH[1]}"
|
|
else
|
|
printf '%s' "$chart_ref"
|
|
fi
|
|
}
|
|
|
|
extract_chart_version_from_ref() {
|
|
local chart_ref="$1"
|
|
|
|
if [[ "$chart_ref" =~ ^(.+)-([0-9][A-Za-z0-9.+_-]*)$ ]]; then
|
|
printf '%s' "${BASH_REMATCH[2]}"
|
|
fi
|
|
}
|
|
|
|
find_repo_url_from_local_cache() {
|
|
local chart_name="$1"
|
|
local chart_version="$2"
|
|
local search_json=""
|
|
local repo_alias=""
|
|
|
|
[[ -z "$chart_name" ]] && return 0
|
|
|
|
search_json="$(helm search repo "$chart_name" --versions -o json 2>/dev/null || true)"
|
|
[[ -z "$search_json" || "$search_json" == "[]" ]] && return 0
|
|
|
|
if [[ -n "$chart_version" ]]; then
|
|
repo_alias="$(jq -r --arg chart "$chart_name" --arg version "$chart_version" '
|
|
map(select((.name | split("/") | last) == $chart and .version == $version))
|
|
| .[0].name // empty
|
|
' <<< "$search_json")"
|
|
fi
|
|
|
|
if [[ -z "$repo_alias" ]]; then
|
|
repo_alias="$(jq -r --arg chart "$chart_name" '
|
|
map(select((.name | split("/") | last) == $chart))
|
|
| .[0].name // empty
|
|
' <<< "$search_json")"
|
|
fi
|
|
|
|
[[ -z "$repo_alias" ]] && return 0
|
|
|
|
repo_alias="${repo_alias%%/*}"
|
|
|
|
helm repo list -o json 2>/dev/null \
|
|
| jq -r --arg alias "$repo_alias" 'map(select(.name == $alias)) | .[0].url // empty'
|
|
}
|
|
|
|
indent_file() {
|
|
local file_path="$1"
|
|
sed 's/^/ /' "$file_path"
|
|
}
|
|
|
|
while [[ $# -gt 0 ]]; do
|
|
case "$1" in
|
|
-o|--output-dir)
|
|
OUTPUT_DIR="$2"
|
|
shift 2
|
|
;;
|
|
-w|--workspace-namespace)
|
|
WORKSPACE_NAMESPACE="$2"
|
|
shift 2
|
|
;;
|
|
--api-version)
|
|
API_VERSION="$2"
|
|
shift 2
|
|
;;
|
|
--kind)
|
|
RESOURCE_KIND="$2"
|
|
shift 2
|
|
;;
|
|
-a|--all-values)
|
|
VALUES_ARGS=(-a)
|
|
shift
|
|
;;
|
|
-h|--help)
|
|
usage
|
|
exit 0
|
|
;;
|
|
*)
|
|
echo "Opzione sconosciuta: $1" >&2
|
|
usage >&2
|
|
exit 1
|
|
;;
|
|
esac
|
|
done
|
|
|
|
require_cmd helm
|
|
require_cmd jq
|
|
|
|
mkdir -p "$OUTPUT_DIR"
|
|
|
|
releases_json="$(helm list -A -o json)"
|
|
release_count="$(jq 'length' <<< "$releases_json")"
|
|
|
|
if [[ "$release_count" -eq 0 ]]; then
|
|
echo "Nessuna release Helm trovata." >&2
|
|
exit 0
|
|
fi
|
|
|
|
echo "==> Release trovate: $release_count"
|
|
echo "==> Directory output: $OUTPUT_DIR"
|
|
|
|
generated_count=0
|
|
warning_count=0
|
|
|
|
while IFS= read -r release; do
|
|
name="$(jq -r '.name' <<< "$release")"
|
|
namespace="$(jq -r '.namespace' <<< "$release")"
|
|
chart_ref="$(jq -r '.chart // ""' <<< "$release")"
|
|
|
|
metadata_yaml="$(helm get metadata "$name" -n "$namespace" -o yaml 2>/dev/null || true)"
|
|
if [[ -z "$metadata_yaml" ]]; then
|
|
echo "! Impossibile leggere metadata per ${namespace}/${name}, salto." >&2
|
|
warning_count=$((warning_count + 1))
|
|
continue
|
|
fi
|
|
|
|
repo_url="$(trim "$(extract_yaml_scalar repo "$metadata_yaml")")"
|
|
if [[ -z "$repo_url" ]]; then
|
|
repo_url="$(trim "$(extract_yaml_scalar repository "$metadata_yaml")")"
|
|
fi
|
|
if [[ -z "$repo_url" ]]; then
|
|
repo_url="$(trim "$(extract_yaml_scalar repoURL "$metadata_yaml")")"
|
|
fi
|
|
if [[ -z "$repo_url" ]]; then
|
|
repo_url="$(trim "$(extract_first_source "$metadata_yaml")")"
|
|
fi
|
|
|
|
chart_name="$(trim "$(extract_yaml_scalar chart "$metadata_yaml")")"
|
|
chart_version="$(trim "$(extract_yaml_scalar version "$metadata_yaml")")"
|
|
|
|
if [[ -z "$chart_name" ]]; then
|
|
chart_name="$(extract_chart_name_from_ref "$chart_ref")"
|
|
fi
|
|
if [[ -z "$chart_version" ]]; then
|
|
chart_version="$(extract_chart_version_from_ref "$chart_ref")"
|
|
fi
|
|
|
|
if [[ -z "$repo_url" ]]; then
|
|
repo_url="$(trim "$(find_repo_url_from_local_cache "$chart_name" "$chart_version")")"
|
|
fi
|
|
|
|
if [[ -z "$repo_url" ]]; then
|
|
repo_url="REPO_URL_NOT_FOUND"
|
|
echo "! Repo URL non trovato in metadata o cache locale per ${namespace}/${name}" >&2
|
|
warning_count=$((warning_count + 1))
|
|
fi
|
|
|
|
if [[ -z "$chart_name" ]]; then
|
|
chart_name="CHART_NAME_NOT_FOUND"
|
|
echo "! Chart name non trovato per ${namespace}/${name}" >&2
|
|
warning_count=$((warning_count + 1))
|
|
fi
|
|
|
|
values_file="$(mktemp)"
|
|
if ! helm get values "$name" -n "$namespace" "${VALUES_ARGS[@]}" -o yaml > "$values_file" 2>/dev/null; then
|
|
printf '{}\n' > "$values_file"
|
|
echo "! Values non disponibili per ${namespace}/${name}, uso {}" >&2
|
|
warning_count=$((warning_count + 1))
|
|
fi
|
|
|
|
if [[ ! -s "$values_file" ]]; then
|
|
printf '{}\n' > "$values_file"
|
|
fi
|
|
|
|
values_compact="$(tr -d '[:space:]' < "$values_file")"
|
|
|
|
ns_dir="${OUTPUT_DIR}/${namespace}"
|
|
mkdir -p "$ns_dir"
|
|
|
|
safe_name="$(safe_file_name "$name")"
|
|
out_file="${ns_dir}/${safe_name}-helmop.yaml"
|
|
|
|
cat > "$out_file" <<EOF
|
|
apiVersion: ${API_VERSION}
|
|
kind: ${RESOURCE_KIND}
|
|
metadata:
|
|
name: ${safe_name}
|
|
namespace: ${WORKSPACE_NAMESPACE}
|
|
spec:
|
|
namespace: ${namespace}
|
|
helm:
|
|
releaseName: ${name}
|
|
repo: ${repo_url}
|
|
chart: ${chart_name}
|
|
EOF
|
|
|
|
if [[ -n "$chart_version" ]]; then
|
|
cat >> "$out_file" <<EOF
|
|
version: ${chart_version}
|
|
EOF
|
|
fi
|
|
|
|
if [[ "$values_compact" == "{}" ]]; then
|
|
cat >> "$out_file" <<EOF
|
|
values: {}
|
|
EOF
|
|
else
|
|
cat >> "$out_file" <<EOF
|
|
values:
|
|
$(indent_file "$values_file")
|
|
EOF
|
|
fi
|
|
|
|
rm -f "$values_file"
|
|
|
|
echo "+ Generato ${out_file} da ${namespace}/${name}"
|
|
generated_count=$((generated_count + 1))
|
|
done < <(jq -c '.[]' <<< "$releases_json")
|
|
|
|
echo ""
|
|
echo "=== Riepilogo ==="
|
|
echo "File generati: $generated_count"
|
|
echo "Warning: $warning_count"
|
|
echo "Output: $OUTPUT_DIR"
|
|
echo "Workspace namespace: $WORKSPACE_NAMESPACE"
|
|
echo ""
|
|
echo "Nota: il repo URL viene letto da 'helm get metadata' e, se assente,"
|
|
echo " viene cercato nella cache locale di 'helm repo list/search repo'."
|
|
echo "Se vedi REPO_URL_NOT_FOUND, completa il campo repo manualmente." |