|
#!/bin/bash |
|
|
|
# Load YAML config if provided |
|
CONFIG_FILE="" |
|
if [[ "$1" == "--config" ]]; then |
|
CONFIG_FILE="$2" |
|
shift 2 |
|
if [ ! -f "$CONFIG_FILE" ]; then |
|
echo "Error: Config file $CONFIG_FILE not found!" |
|
exit 1 |
|
fi |
|
# Load the YAML config into variables using `yq` |
|
CONFIG=$(yq eval '.' "$CONFIG_FILE") |
|
fi |
|
|
|
# Function to retrieve value from YAML config or use gum input if not provided |
|
get_input() { |
|
local yaml_key="$1" |
|
local prompt="$2" |
|
local placeholder="$3" |
|
local password="$4" |
|
|
|
if [[ -n "$CONFIG_FILE" ]]; then |
|
local value=$(echo "$CONFIG" | yq eval "$yaml_key" -) |
|
if [[ -n "$value" && "$value" != "null" ]]; then |
|
echo "$value" |
|
return |
|
fi |
|
fi |
|
|
|
if [[ "$password" == "true" ]]; then |
|
gum input --prompt "$prompt" --password |
|
else |
|
gum input --prompt "$prompt" --placeholder "$placeholder" |
|
fi |
|
} |
|
|
|
check_tools() { |
|
MISSING_TOOLS=() |
|
REQUIRED_TOOLS=("jq" "helm" "oras" "gum" "yq") |
|
|
|
for TOOL in "${REQUIRED_TOOLS[@]}"; do |
|
if ! command -v "$TOOL" &> /dev/null; then |
|
MISSING_TOOLS+=("$TOOL") |
|
fi |
|
done |
|
|
|
if [ ${#MISSING_TOOLS[@]} -ne 0 ]; then |
|
echo "The following tools are missing:" |
|
for TOOL in "${MISSING_TOOLS[@]}"; do |
|
echo "- $TOOL" |
|
done |
|
exit 1 |
|
fi |
|
} |
|
|
|
create_registry_layout() { |
|
gum style --bold --foreground 6 "Registry Configuration" |
|
REGISTRY_NAME=$(get_input ".registry.name" "Enter registry name: ") |
|
REGISTRY_FQDN=$(get_input ".registry.fqdn" "Enter registry FQDN: ") |
|
USERNAME=$(get_input ".registry.username" "Enter registry username: ") |
|
PASSWORD=$(get_input ".registry.password" "Enter registry password: " "" true) |
|
SUBPATH=$(get_input ".registry.subpath" "Enter registry sub-path/project name: ") |
|
mkdir -p "$REGISTRY_NAME/packs" |
|
cd "$REGISTRY_NAME" || exit 1 |
|
git init |
|
echo ".registry-config" > .gitignore |
|
cat <<EOF > ".registry-config" |
|
{ |
|
"fqdn": "$REGISTRY_FQDN", |
|
"subpath": "$SUBPATH", |
|
"username": "$USERNAME", |
|
"password": "$PASSWORD" |
|
} |
|
EOF |
|
gum style --foreground 2 "Registry layout created successfully at packs/$REGISTRY_NAME." |
|
} |
|
|
|
select_or_add_helm_repo() { |
|
gum style --bold --foreground 6 "Helm Repository Selection" |
|
if [[ -n "$CONFIG_FILE" ]]; then |
|
echo $CONFIG_FILE |
|
REPO_NAME=$(get_input ".pack.repo.name" "Enter Helm repository name: ") |
|
REPO_URL=$(get_input ".pack.repo.url" "Enter Helm repository URL: ") |
|
else |
|
if gum confirm "Is this an existing repository?"; then |
|
EXISTING_REPOS=($(helm repo list -o json | jq -r '.[].name')) |
|
if [ ${#EXISTING_REPOS[@]} -eq 0 ]; then |
|
gum style --foreground 1 "No existing repositories found. You need to add a new one." |
|
else |
|
REPO_NAME=$(gum choose "${EXISTING_REPOS[@]}") |
|
helm repo update "$REPO_NAME" |
|
return |
|
fi |
|
fi |
|
REPO_NAME=$(gum input --prompt "Enter new Helm repository name: ") |
|
REPO_URL=$(gum input --prompt "Enter Helm repository URL: ") |
|
fi |
|
|
|
if helm repo list | grep -q "$REPO_NAME"; then |
|
EXISTING_URL=$(helm repo list | grep "$REPO_NAME" | awk '{print $2}') |
|
if [ "$EXISTING_URL" != "$REPO_URL" ]; then |
|
echo "REPO NAME: $REPO_NAME" |
|
echo "$EXISTING_URL != $REPO_URL" |
|
gum style --foreground 1 "Repository name exists but with a different URL. Please choose a different name." |
|
exit 1 |
|
fi |
|
else |
|
helm repo add "$REPO_NAME" "$REPO_URL" || exit 1 |
|
fi |
|
} |
|
|
|
create_manifest_based_pack() { |
|
if [[ ! -d "packs" || ! -f ".registry-config" ]]; then |
|
echo "Error: This command must be run from within a specific pack registry folder. One can be created with the \"$(basename "$0") create registry-layout\" command" |
|
exit 1 |
|
fi |
|
gum style --bold --foreground 6 "Manifest based Pack Creation" |
|
PACK_NAME=$(get_input ".pack.name" "Enter pack name: ") |
|
PACK_VERSION=$(get_input ".pack.version" "Enter pack version: ") |
|
DISPLAY_NAME=$(get_input ".pack.display_name" "Enter display name (default: $PACK_NAME): " "$PACK_NAME") |
|
|
|
mkdir -p "packs/$PACK_NAME-$PACK_VERSION/$PACK_NAME/manifests" |
|
|
|
if [[ -n "$CONFIG_FILE" ]]; then |
|
MANIFEST_SOURCES_LENGTH=$(echo "$CONFIG" | yq eval '.pack.manifest_sources | length' -) |
|
for (( i=0; i<MANIFEST_SOURCES_LENGTH; i++ )); do |
|
SOURCE_TYPE=$(echo "$CONFIG" | yq eval ".pack.manifest_sources[$i].type" -) |
|
case $SOURCE_TYPE in |
|
"HTTP URL") |
|
URL=$(echo "$CONFIG" | yq eval ".pack.manifest_sources[$i].url" -) |
|
FILENAME=$(basename "$URL") |
|
curl -L "$URL" -o "packs/$PACK_NAME-$PACK_VERSION/$PACK_NAME/manifests/$FILENAME" || { gum style --foreground 1 "Error downloading $URL"; exit 1; } |
|
;; |
|
"Local File") |
|
FILE_PATH=$(echo "$CONFIG" | yq eval ".pack.manifest_sources[$i].path" -) |
|
if [[ -f "$FILE_PATH" ]]; then |
|
FILENAME=$(basename "$FILE_PATH") |
|
cp "$FILE_PATH" "packs/$PACK_NAME-$PACK_VERSION/$PACK_NAME/manifests/$FILENAME" |
|
else |
|
gum style --foreground 1 "Invalid file path: $FILE_PATH" |
|
exit 1 |
|
fi |
|
;; |
|
"Local Folder") |
|
FOLDER_PATH=$(echo "$CONFIG" | yq eval ".pack.manifest_sources[$i].path" -) |
|
if [[ -d "$FOLDER_PATH" ]]; then |
|
cp -r "$FOLDER_PATH"/* "packs/$PACK_NAME-$PACK_VERSION/$PACK_NAME/manifests/" |
|
else |
|
gum style --foreground 1 "Invalid folder path: $FOLDER_PATH" |
|
exit 1 |
|
fi |
|
;; |
|
"Git Repository") |
|
REPO_URL=$(echo "$CONFIG" | yq eval ".pack.manifest_sources[$i].url" -) |
|
BRANCH=$(echo "$CONFIG" | yq eval ".pack.manifest_sources[$i].branch" -) |
|
CONTENT_TYPE=$(echo "$CONFIG" | yq eval ".pack.manifest_sources[$i].content_type" -) |
|
FILE_PATH=$(echo "$CONFIG" | yq eval ".pack.manifest_sources[$i].file_path" -) |
|
SUB_FOLDER=$(echo "$CONFIG" | yq eval ".pack.manifest_sources[$i].sub_folder" -) |
|
BASE_DIRECTORY=$(pwd) |
|
TEMP_DIR=$(mktemp -d) |
|
git clone "$REPO_URL" "$TEMP_DIR" || { gum style --foreground 1 "Error cloning repository"; exit 1; } |
|
cd "$TEMP_DIR" || exit 1 |
|
git checkout "${BRANCH:-main}" || { gum style --foreground 1 "Error checking out branch"; exit 1; } |
|
cd "$BASE_DIRECTORY" || exit 1 |
|
case $CONTENT_TYPE in |
|
"Whole repository") |
|
cp -r "$TEMP_DIR"/* "packs/$PACK_NAME-$PACK_VERSION/$PACK_NAME/manifests/" |
|
;; |
|
"Sub-folder") |
|
if [[ -d "$TEMP_DIR/$SUB_FOLDER" ]]; then |
|
cp -r "$TEMP_DIR/$SUB_FOLDER"/* "packs/$PACK_NAME-$PACK_VERSION/$PACK_NAME/manifests/" |
|
else |
|
gum style --foreground 1 "Invalid sub-folder path: $SUB_FOLDER" |
|
exit 1 |
|
fi |
|
;; |
|
"Specific file") |
|
if [[ -f "$TEMP_DIR/$FILE_PATH" ]]; then |
|
FILENAME=$(basename "$FILE_PATH") |
|
cp "$TEMP_DIR/$FILE_PATH" "packs/$PACK_NAME-$PACK_VERSION/$PACK_NAME/manifests/$FILENAME" |
|
else |
|
gum style --foreground 1 "Invalid file path: $FILE_PATH" |
|
exit 1 |
|
fi |
|
;; |
|
esac |
|
rm -rf "$TEMP_DIR" |
|
;; |
|
*) |
|
gum style --foreground 1 "Unknown manifest source type: $SOURCE_TYPE" |
|
exit 1 |
|
;; |
|
esac |
|
done |
|
else |
|
while gum confirm "Do you want to add a manifest source?"; do |
|
SOURCE_TYPE=$(gum choose "HTTP URL" "Local File" "Local Folder" "Git Repository") |
|
case $SOURCE_TYPE in |
|
"HTTP URL") |
|
URL=$(gum input --prompt "Enter the HTTP URL to the manifest file: ") |
|
FILENAME=$(basename "$URL") |
|
curl -L "$URL" -o "packs/$PACK_NAME-$PACK_VERSION/$PACK_NAME/manifests/$FILENAME" || { gum style --foreground 1 "Error downloading $URL"; exit 1; } |
|
;; |
|
"Local File") |
|
FILE_PATH=$(gum input --prompt "Enter the full path to the local file: ") |
|
if [[ -f "$FILE_PATH" ]]; then |
|
FILENAME=$(basename "$FILE_PATH") |
|
cp "$FILE_PATH" "packs/$PACK_NAME-$PACK_VERSION/$PACK_NAME/manifests/$FILENAME" |
|
else |
|
gum style --foreground 1 "Invalid file path: $FILE_PATH" |
|
exit 1 |
|
fi |
|
;; |
|
"Local Folder") |
|
FOLDER_PATH=$(gum input --prompt "Enter the full path to the local folder: ") |
|
if [[ -d "$FOLDER_PATH" ]]; then |
|
cp -r "$FOLDER_PATH"/* "packs/$PACK_NAME-$PACK_VERSION/$PACK_NAME/manifests/" |
|
else |
|
gum style --foreground 1 "Invalid folder path: $FOLDER_PATH" |
|
exit 1 |
|
fi |
|
;; |
|
"Git Repository") |
|
REPO_URL=$(gum input --prompt "Enter the Git repository URL: ") |
|
BASE_DIRECTORY=$(pwd) |
|
TEMP_DIR=$(mktemp -d) |
|
git clone "$REPO_URL" "$TEMP_DIR" || { gum style --foreground 1 "Error cloning repository"; exit 1; } |
|
BRANCH=$(gum input --prompt "Enter the branch (default: main): " --placeholder "main") |
|
cd "$TEMP_DIR" |
|
git checkout "${BRANCH:-main}" || { gum style --foreground 1 "Error checking out branch"; exit 1; } |
|
cd $BASE_DIRECTORY |
|
CONTENT_TYPE=$(gum choose "Whole repository" "Sub-folder" "Specific file") |
|
case $CONTENT_TYPE in |
|
"Whole repository") |
|
cp -r "$TEMP_DIR"/* "packs/$PACK_NAME-$PACK_VERSION/$PACK_NAME/manifests/" |
|
;; |
|
"Sub-folder") |
|
SUB_FOLDER=$(gum input --prompt "Enter the path of the sub-folder: ") |
|
if [[ -d "$TEMP_DIR/$SUB_FOLDER" ]]; then |
|
pwd |
|
cp -r "$TEMP_DIR/$SUB_FOLDER"/* "packs/$PACK_NAME-$PACK_VERSION/$PACK_NAME/manifests/" |
|
else |
|
gum style --foreground 1 "Invalid sub-folder path: $SUB_FOLDER" |
|
exit 1 |
|
fi |
|
;; |
|
"Specific file") |
|
FILE_PATH=$(gum input --prompt "Enter the path of the file within the repository: ") |
|
if [[ -f "$TEMP_DIR/$FILE_PATH" ]]; then |
|
FILENAME=$(basename "$FILE_PATH") |
|
ls -lah |
|
pwd |
|
cp "$TEMP_DIR/$FILE_PATH" "packs/$PACK_NAME-$PACK_VERSION/$PACK_NAME/manifests/$FILENAME" |
|
else |
|
gum style --foreground 1 "Invalid file path: $FILE_PATH" |
|
exit 1 |
|
fi |
|
;; |
|
esac |
|
rm -rf "$TEMP_DIR" |
|
;; |
|
esac |
|
done |
|
fi |
|
|
|
BASE_DIRECTORY=$(pwd) |
|
cd "packs/$PACK_NAME-$PACK_VERSION/$PACK_NAME" || exit 1 |
|
MANIFEST_SOURCES=($(find "manifests" -type f \( -name "*.yaml" -o -name "*.yml" \))) |
|
cd "$BASE_DIRECTORY" || exit 1 |
|
if [[ -n "$CONFIG_FILE" ]]; then |
|
PACK_LAYER=$(get_input ".pack.layer" "Select pack layer: " "addon") |
|
else |
|
PACK_LAYER=$(gum choose "os" "k8s" "cni" "csi" "addon") |
|
fi |
|
|
|
if [ "$PACK_LAYER" == "addon" ]; then |
|
if [[ -n "$CONFIG_FILE" ]]; then |
|
ADDON_TYPE=$(get_input ".pack.addon_type" "Select addon type: ") |
|
else |
|
ADDON_TYPE=$(gum choose "logging" "monitoring" "load balancer" "authentication" "ingress" "security" "system app") |
|
fi |
|
fi |
|
|
|
MIN_K8S_VERSION=$(get_input ".pack.k8s_version.min" "Enter minimum K8s version (or leave empty for none): ") |
|
MAX_K8S_VERSION=$(get_input ".pack.k8s_version.max" "Enter maximum K8s version (or leave empty for none): ") |
|
|
|
DEPENDENCIES=() |
|
if [[ -n "$CONFIG_FILE" ]]; then |
|
DEPENDENCIES_LENGTH=$(echo "$CONFIG" | yq eval '.pack.dependencies | length' -) |
|
for (( i=0; i<DEPENDENCIES_LENGTH; i++ )); do |
|
DEP_PACK_NAME=$(echo "$CONFIG" | yq eval ".pack.dependencies[$i].name" -) |
|
DEP_LAYER=$(echo "$CONFIG" | yq eval ".pack.dependencies[$i].layer" -) |
|
DEP_MIN_VERSION=$(echo "$CONFIG" | yq eval ".pack.dependencies[$i].min_version" -) |
|
DEP_MAX_VERSION=$(echo "$CONFIG" | yq eval ".pack.dependencies[$i].max_version" -) |
|
DEP_TYPE=$(echo "$CONFIG" | yq eval ".pack.dependencies[$i].type" -) |
|
DEPENDENCIES+=("{\"packName\":\"$DEP_PACK_NAME\",\"layer\":\"$DEP_LAYER\",\"minVersion\":\"$DEP_MIN_VERSION\",\"maxVersion\":\"$DEP_MAX_VERSION\",\"type\":\"$DEP_TYPE\"}") |
|
done |
|
else |
|
while gum confirm "Does the pack have constraints regarding other packs?"; do |
|
DEP_PACK_NAME=$(gum input --prompt "Enter dependent pack name: ") |
|
DEP_LAYER=$(gum input --prompt "Enter dependent pack layer: ") |
|
DEP_MIN_VERSION=$(gum input --prompt "Enter dependent pack minVersion: ") |
|
DEP_MAX_VERSION=$(gum input --prompt "Enter dependent pack maxVersion: ") |
|
DEP_TYPE=$(gum choose "optional" "required" "notSupported") |
|
DEPENDENCIES+=("{\"packName\":\"$DEP_PACK_NAME\",\"layer\":\"$DEP_LAYER\",\"minVersion\":\"$DEP_MIN_VERSION\",\"maxVersion\":\"$DEP_MAX_VERSION\",\"type\":\"$DEP_TYPE\"}") |
|
done |
|
fi |
|
|
|
NAMESPACE=$(get_input ".pack.namespace" "Enter namespace for pack installation: ") |
|
|
|
VALUES_FILE="packs/$PACK_NAME-$PACK_VERSION/$PACK_NAME/values.yaml" |
|
cat <<EOF > "$VALUES_FILE" |
|
pack: |
|
namespace: $NAMESPACE |
|
EOF |
|
|
|
PACK_JSON_FILE="packs/$PACK_NAME-$PACK_VERSION/$PACK_NAME/pack.json" |
|
|
|
jq -n --arg source "community" \ |
|
--arg contributor "TeraSky" \ |
|
--arg displayName "$DISPLAY_NAME" \ |
|
--arg eol " " \ |
|
--arg group " " \ |
|
--argjson kubeManifests "$(printf '%s\n' "${MANIFEST_SOURCES[@]}" | jq -R . | jq -s '.')" \ |
|
--arg layer "$PACK_LAYER" \ |
|
--arg name "$PACK_NAME" \ |
|
--arg version "$PACK_VERSION" \ |
|
'{ |
|
annotations: { |
|
source: $source, |
|
contributor: $contributor |
|
}, |
|
ansibleRoles: [], |
|
cloudTypes: ["all"], |
|
displayName: $displayName, |
|
eol: $eol, |
|
group: $group, |
|
kubeManifests: $kubeManifests, |
|
layer: $layer, |
|
name: $name, |
|
version: $version |
|
}' > "$PACK_JSON_FILE" |
|
|
|
# Add "addonType" if it's an addon |
|
if [ "$PACK_LAYER" == "addon" ]; then |
|
jq --arg addonType "$ADDON_TYPE" '. + {addonType: $addonType}' "$PACK_JSON_FILE" > tmp.json && mv tmp.json "$PACK_JSON_FILE" |
|
fi |
|
|
|
# Add constraints if needed |
|
if [ -n "$MIN_K8S_VERSION" ] || [ -n "$MAX_K8S_VERSION" ] || [ ${#DEPENDENCIES[@]} -ne 0 ]; then |
|
constraints=$(jq -n '{dependencies: []}') |
|
|
|
# Add Kubernetes constraint if versions are provided |
|
if [ -n "$MIN_K8S_VERSION" ] || [ -n "$MAX_K8S_VERSION" ]; then |
|
kubeConstraint=$(jq -n --arg minVersion "$MIN_K8S_VERSION" --arg maxVersion "$MAX_K8S_VERSION" '[{ |
|
packName: "kubernetes", |
|
layer: "k8s", |
|
minVersion: $minVersion, |
|
maxVersion: $maxVersion, |
|
type: "optional" |
|
},{ |
|
packName: "kubernetes-eks", |
|
layer: "k8s", |
|
minVersion: $minVersion, |
|
maxVersion: $maxVersion, |
|
type: "optional" |
|
},{ |
|
packName: "kubernetes-aks", |
|
layer: "k8s", |
|
minVersion: $minVersion, |
|
maxVersion: $maxVersion, |
|
type: "optional" |
|
},{ |
|
packName: "kubernetes-gke", |
|
layer: "k8s", |
|
minVersion: $minVersion, |
|
maxVersion: $maxVersion, |
|
type: "optional" |
|
},{ |
|
packName: "kubernetes-rke2", |
|
layer: "k8s", |
|
minVersion: $minVersion, |
|
maxVersion: $maxVersion, |
|
type: "optional" |
|
},{ |
|
packName: "kubernetes-microk8s", |
|
layer: "k8s", |
|
minVersion: $minVersion, |
|
maxVersion: $maxVersion, |
|
type: "optional" |
|
},{ |
|
packName: "kubernetes-konvoy", |
|
layer: "k8s", |
|
minVersion: $minVersion, |
|
maxVersion: $maxVersion, |
|
type: "optional" |
|
},{ |
|
packName: "edge-k3s", |
|
layer: "k8s", |
|
minVersion: $minVersion, |
|
maxVersion: $maxVersion, |
|
type: "optional" |
|
},{ |
|
packName: "edge-k8s", |
|
layer: "k8s", |
|
minVersion: $minVersion, |
|
maxVersion: $maxVersion, |
|
type: "optional" |
|
},{ |
|
packName: "edge-rke2", |
|
layer: "k8s", |
|
minVersion: $minVersion, |
|
maxVersion: $maxVersion, |
|
type: "optional" |
|
},{ |
|
packName: "edge-microk8s", |
|
layer: "k8s", |
|
minVersion: $minVersion, |
|
maxVersion: $maxVersion, |
|
type: "optional" |
|
}]') |
|
constraints=$(echo "$constraints" | jq --argjson kubeConstraint "$kubeConstraint" '.dependencies += $kubeConstraint') |
|
fi |
|
|
|
# Add additional dependencies |
|
for DEP in "${DEPENDENCIES[@]}"; do |
|
constraints=$(echo "$constraints" | jq --argjson dep "$DEP" '.dependencies += [$dep]') |
|
done |
|
|
|
jq --argjson constraints "$constraints" '. + {constraints: $constraints}' "$PACK_JSON_FILE" > tmp.json && mv tmp.json "$PACK_JSON_FILE" |
|
fi |
|
|
|
gum style --foreground 2 "Pack $PACK_NAME-$PACK_VERSION created successfully under packs directory." |
|
} |
|
|
|
create_helm_based_pack() { |
|
if [[ ! -d "packs" || ! -f ".registry-config" ]]; then |
|
echo "Error: This command must be run from within a specific pack registry folder. One can be created with the \"$(basename "$0") create registry-layout\" command" |
|
exit 1 |
|
fi |
|
gum style --bold --foreground 6 "Helm-based Pack Creation" |
|
PACK_NAME=$(get_input ".pack.name" "Enter pack name: ") |
|
PACK_VERSION=$(get_input ".pack.version" "Enter pack version: ") |
|
DISPLAY_NAME=$(get_input ".pack.display_name" "Enter display name (default: $PACK_NAME): " "$PACK_NAME") |
|
|
|
select_or_add_helm_repo |
|
|
|
CHARTS=$(helm search repo "$REPO_NAME/" -o json | jq -r '.[].name') |
|
|
|
if [[ -n "$CONFIG_FILE" ]]; then |
|
SELECTED_CHARTS=($(echo "$CONFIG" | yq eval '.pack.charts[]' -)) |
|
else |
|
gum style --bold --foreground 6 "Select Charts" |
|
SELECTED_CHARTS=($(gum choose --no-limit "${CHARTS[@]}")) |
|
fi |
|
|
|
if [ ${#SELECTED_CHARTS[@]} -eq 0 ]; then |
|
gum style --foreground 1 "No charts selected. Exiting." |
|
exit 1 |
|
fi |
|
|
|
mkdir -p "packs/$PACK_NAME-$PACK_VERSION/$PACK_NAME/charts" |
|
|
|
for CHART in "${SELECTED_CHARTS[@]}"; do |
|
if [[ -n "$CONFIG_FILE" ]]; then |
|
CHART_VERSION=$(get_input ".pack.chart_versions.$CHART" "Enter version for chart '$CHART': ") |
|
else |
|
VERSIONS=$(helm search repo "$CHART" -o json --versions | jq -r '.[].version') |
|
CHART_VERSION=$(echo "$VERSIONS" | gum choose --header "Select version for chart '$CHART': ") |
|
fi |
|
helm pull "$CHART" --version "$CHART_VERSION" --destination "packs/$PACK_NAME-$PACK_VERSION/$PACK_NAME/charts" |
|
done |
|
|
|
PACK_LAYER=$(get_input ".pack.layer" "Select pack layer: " "addon") |
|
|
|
if [ "$PACK_LAYER" == "addon" ]; then |
|
if [[ -n "$CONFIG_FILE" ]]; then |
|
ADDON_TYPE=$(get_input ".pack.addon_type" "Select addon type: ") |
|
else |
|
ADDON_TYPE=$(gum choose "logging" "monitoring" "load balancer" "authentication" "ingress" "security" "system app") |
|
fi |
|
fi |
|
|
|
MIN_K8S_VERSION=$(get_input ".pack.k8s_version.min" "Enter minimum K8s version (or leave empty for none): ") |
|
MAX_K8S_VERSION=$(get_input ".pack.k8s_version.max" "Enter maximum K8s version (or leave empty for none): ") |
|
|
|
DEPENDENCIES=() |
|
if [[ -n "$CONFIG_FILE" ]]; then |
|
DEPENDENCIES_LENGTH=$(echo "$CONFIG" | yq eval '.pack.dependencies | length' -) |
|
for (( i=0; i<DEPENDENCIES_LENGTH; i++ )); do |
|
DEP_PACK_NAME=$(echo "$CONFIG" | yq eval ".pack.dependencies[$i].name" -) |
|
DEP_LAYER=$(echo "$CONFIG" | yq eval ".pack.dependencies[$i].layer" -) |
|
DEP_MIN_VERSION=$(echo "$CONFIG" | yq eval ".pack.dependencies[$i].min_version" -) |
|
DEP_MAX_VERSION=$(echo "$CONFIG" | yq eval ".pack.dependencies[$i].max_version" -) |
|
DEP_TYPE=$(echo "$CONFIG" | yq eval ".pack.dependencies[$i].type" -) |
|
DEPENDENCIES+=("{\"packName\":\"$DEP_PACK_NAME\",\"layer\":\"$DEP_LAYER\",\"minVersion\":\"$DEP_MIN_VERSION\",\"maxVersion\":\"$DEP_MAX_VERSION\",\"type\":\"$DEP_TYPE\"}") |
|
done |
|
else |
|
while gum confirm "Does the pack have constraints regarding other packs?"; do |
|
DEP_PACK_NAME=$(gum input --prompt "Enter dependent pack name: ") |
|
DEP_LAYER=$(gum input --prompt "Enter dependent pack layer: ") |
|
DEP_MIN_VERSION=$(gum input --prompt "Enter dependent pack minVersion: ") |
|
DEP_MAX_VERSION=$(gum input --prompt "Enter dependent pack maxVersion: ") |
|
DEP_TYPE=$(gum choose "optional" "required" "notSupported") |
|
DEPENDENCIES+=("{\"packName\":\"$DEP_PACK_NAME\",\"layer\":\"$DEP_LAYER\",\"minVersion\":\"$DEP_MIN_VERSION\",\"maxVersion\":\"$DEP_MAX_VERSION\",\"type\":\"$DEP_TYPE\"}") |
|
done |
|
fi |
|
|
|
NAMESPACE=$(get_input ".pack.namespace" "Enter namespace for pack installation: ") |
|
|
|
VALUES_FILE="packs/$PACK_NAME-$PACK_VERSION/$PACK_NAME/values.yaml" |
|
cat <<EOF > "$VALUES_FILE" |
|
pack: |
|
namespace: $NAMESPACE |
|
charts: |
|
EOF |
|
|
|
for CHART in "${SELECTED_CHARTS[@]}"; do |
|
DEFAULT_VALUES=$(helm show values "$CHART") |
|
CHART_SHORT_NAME="${CHART#*/}" |
|
echo " $CHART_SHORT_NAME:" >> "$VALUES_FILE" |
|
echo "$DEFAULT_VALUES" | sed 's/^/ /' >> "$VALUES_FILE" |
|
done |
|
|
|
PACK_JSON_FILE="packs/$PACK_NAME-$PACK_VERSION/$PACK_NAME/pack.json" |
|
|
|
# Create base JSON structure |
|
CHART_FILES=() |
|
for CHART in ./packs/$PACK_NAME-$PACK_VERSION/$PACK_NAME/charts/*; do |
|
CHART_FILE="charts/$(basename $CHART)" |
|
CHART_FILES+=("$CHART_FILE") |
|
done |
|
|
|
jq -n --arg source "community" \ |
|
--arg contributor "TeraSky" \ |
|
--arg displayName "$DISPLAY_NAME" \ |
|
--arg eol " " \ |
|
--arg group " " \ |
|
--argjson charts "$(printf '%s\n' "${CHART_FILES[@]}" | jq -R . | jq -s '.')" \ |
|
--arg layer "$PACK_LAYER" \ |
|
--arg name "$PACK_NAME" \ |
|
--arg version "$PACK_VERSION" \ |
|
'{ |
|
annotations: { |
|
source: $source, |
|
contributor: $contributor |
|
}, |
|
ansibleRoles: [], |
|
cloudTypes: ["all"], |
|
displayName: $displayName, |
|
eol: $eol, |
|
group: $group, |
|
kubeManifests: [], |
|
charts: $charts, |
|
layer: $layer, |
|
name: $name, |
|
version: $version |
|
}' > "$PACK_JSON_FILE" |
|
|
|
# Add "addonType" if it's an addon |
|
if [ "$PACK_LAYER" == "addon" ]; then |
|
jq --arg addonType "$ADDON_TYPE" '. + {addonType: $addonType}' "$PACK_JSON_FILE" > tmp.json && mv tmp.json "$PACK_JSON_FILE" |
|
fi |
|
|
|
# Add constraints if needed |
|
if [ -n "$MIN_K8S_VERSION" ] || [ -n "$MAX_K8S_VERSION" ] || [ ${#DEPENDENCIES[@]} -ne 0 ]; then |
|
constraints=$(jq -n '{dependencies: []}') |
|
|
|
# Add Kubernetes constraint if versions are provided |
|
if [ -n "$MIN_K8S_VERSION" ] || [ -n "$MAX_K8S_VERSION" ]; then |
|
kubeConstraint=$(jq -n --arg minVersion "$MIN_K8S_VERSION" --arg maxVersion "$MAX_K8S_VERSION" '[{ |
|
packName: "kubernetes", |
|
layer: "k8s", |
|
minVersion: $minVersion, |
|
maxVersion: $maxVersion, |
|
type: "optional" |
|
},{ |
|
packName: "kubernetes-eks", |
|
layer: "k8s", |
|
minVersion: $minVersion, |
|
maxVersion: $maxVersion, |
|
type: "optional" |
|
},{ |
|
packName: "kubernetes-aks", |
|
layer: "k8s", |
|
minVersion: $minVersion, |
|
maxVersion: $maxVersion, |
|
type: "optional" |
|
},{ |
|
packName: "kubernetes-gke", |
|
layer: "k8s", |
|
minVersion: $minVersion, |
|
maxVersion: $maxVersion, |
|
type: "optional" |
|
},{ |
|
packName: "kubernetes-rke2", |
|
layer: "k8s", |
|
minVersion: $minVersion, |
|
maxVersion: $maxVersion, |
|
type: "optional" |
|
},{ |
|
packName: "kubernetes-microk8s", |
|
layer: "k8s", |
|
minVersion: $minVersion, |
|
maxVersion: $maxVersion, |
|
type: "optional" |
|
},{ |
|
packName: "kubernetes-konvoy", |
|
layer: "k8s", |
|
minVersion: $minVersion, |
|
maxVersion: $maxVersion, |
|
type: "optional" |
|
},{ |
|
packName: "edge-k3s", |
|
layer: "k8s", |
|
minVersion: $minVersion, |
|
maxVersion: $maxVersion, |
|
type: "optional" |
|
},{ |
|
packName: "edge-k8s", |
|
layer: "k8s", |
|
minVersion: $minVersion, |
|
maxVersion: $maxVersion, |
|
type: "optional" |
|
},{ |
|
packName: "edge-rke2", |
|
layer: "k8s", |
|
minVersion: $minVersion, |
|
maxVersion: $maxVersion, |
|
type: "optional" |
|
},{ |
|
packName: "edge-microk8s", |
|
layer: "k8s", |
|
minVersion: $minVersion, |
|
maxVersion: $maxVersion, |
|
type: "optional" |
|
}]') |
|
constraints=$(echo "$constraints" | jq --argjson kubeConstraint "$kubeConstraint" '.dependencies += $kubeConstraint') |
|
fi |
|
|
|
# Add additional dependencies |
|
for DEP in "${DEPENDENCIES[@]}"; do |
|
constraints=$(echo "$constraints" | jq --argjson dep "$DEP" '.dependencies += [$dep]') |
|
done |
|
|
|
jq --argjson constraints "$constraints" '. + {constraints: $constraints}' "$PACK_JSON_FILE" > tmp.json && mv tmp.json "$PACK_JSON_FILE" |
|
fi |
|
|
|
gum style --foreground 2 "Pack $PACK_NAME-$PACK_VERSION created successfully under packs directory." |
|
} |
|
|
|
push_pack() { |
|
REGISTRY_CONFIG=".registry-config" |
|
if [ ! -f "$REGISTRY_CONFIG" ]; then |
|
gum style --foreground 1 "Registry configuration file not found!" |
|
exit 1 |
|
fi |
|
|
|
PACKS_DIR="packs" |
|
PACKS=($(find packs -maxdepth 1 -mindepth 1 -type d -exec basename {} \;)) |
|
if [[ -n "$CONFIG_FILE" ]]; then |
|
SELECTED_PACK=$(get_input ".pack.name" "Select pack to push: ") |
|
else |
|
SELECTED_PACK=$(gum choose "${PACKS[@]}") |
|
fi |
|
REGISTRY_FQDN=$(jq -r '.fqdn' "$REGISTRY_CONFIG") |
|
REGISTRY_SUBPATH=$(jq -r '.subpath' "$REGISTRY_CONFIG") |
|
USERNAME=$(jq -r '.username' "$REGISTRY_CONFIG") |
|
PASSWORD=$(jq -r '.password' "$REGISTRY_CONFIG") |
|
|
|
oras login -u "$USERNAME" -p "$PASSWORD" "$REGISTRY_FQDN" --insecure |
|
|
|
PACK_ARCHIVE="${SELECTED_PACK##*/}.tar.gz" |
|
PACK_NAME=$(echo "${SELECTED_PACK%-*}" | tr '[:upper:]' '[:lower:]') |
|
PACK_VERSION="${SELECTED_PACK##*-}" |
|
cd "packs/$SELECTED_PACK" || exit 1 |
|
tar -czvf "$PACK_ARCHIVE" "$PACK_NAME" |
|
oras push "$REGISTRY_FQDN/$REGISTRY_SUBPATH/spectro-packs/archive/$PACK_NAME:$PACK_VERSION" "$PACK_ARCHIVE" |
|
cd ../../ |
|
mkdir -p pack-bundles |
|
mv "packs/$SELECTED_PACK/$PACK_ARCHIVE" pack-bundles/ |
|
gum style --foreground 2 "Pack pushed and archived successfully." |
|
} |
|
|
|
install_dependencies() { |
|
TOOLS=("jq" "helm" "oras" "gum" "yq") |
|
|
|
# Function to check if a command exists |
|
command_exists() { |
|
command -v "$1" >/dev/null 2>&1 |
|
} |
|
|
|
# Check if all required tools are installed |
|
missing_tools=() |
|
for tool in "${TOOLS[@]}"; do |
|
if ! command_exists "$tool"; then |
|
missing_tools+=("$tool") |
|
fi |
|
done |
|
|
|
# If all tools are installed, exit |
|
if [ ${#missing_tools[@]} -eq 0 ]; then |
|
echo "All required tools are already installed." |
|
exit 0 |
|
fi |
|
|
|
# Check if Homebrew is installed |
|
if ! command_exists "brew"; then |
|
echo "Error: The following tools are missing: ${missing_tools[*]}" |
|
echo "Homebrew is required to install these tools. Please install Homebrew first." |
|
exit 1 |
|
fi |
|
|
|
# Install missing tools using Homebrew |
|
for tool in "${missing_tools[@]}"; do |
|
case $tool in |
|
jq) |
|
echo "Installing jq..." |
|
brew install jq |
|
;; |
|
helm) |
|
echo "Installing helm..." |
|
brew install helm |
|
;; |
|
oras) |
|
echo "Installing oras..." |
|
brew install oras |
|
;; |
|
yq) |
|
echo "Installing YQ..." |
|
brew install yq |
|
;; |
|
gum) |
|
echo "Installing gum 1.13.0..." |
|
wget https://raw.githubusercontent.com/charmbracelet/homebrew-tap/a8616717837d78b31484464cde92170b5570e20e/gum.rb |
|
brew install gum.rb |
|
rm -f gum.rb |
|
;; |
|
esac |
|
done |
|
|
|
echo "Installation complete for missing tools." |
|
} |
|
|
|
|
|
# Main script logic |
|
|
|
case "$1" in |
|
create) |
|
case "$2" in |
|
registry-layout) |
|
check_tools |
|
create_registry_layout |
|
;; |
|
pack) |
|
check_tools |
|
if [[ -n "$CONFIG_FILE" ]]; then |
|
PACK_TYPE=$(get_input ".pack.type" "Which type of pack do you want to create?" "Helm" "YAML Manifests") |
|
else |
|
PACK_TYPE=$(gum choose --header "Which type of pack do you want to create?" "Helm" "YAML Manifests") |
|
fi |
|
case "$PACK_TYPE" in |
|
"Helm") |
|
create_helm_based_pack |
|
;; |
|
"YAML Manifests") |
|
create_manifest_based_pack |
|
;; |
|
*) |
|
gum style --foreground 1 "Unknown pack type. Available: Helm, YAML Manifests" |
|
exit 1 |
|
;; |
|
esac |
|
;; |
|
*) |
|
gum style --foreground 1 "Unknown create subcommand. Available: registry-layout, pack" |
|
exit 1 |
|
;; |
|
esac |
|
;; |
|
push) |
|
case "$2" in |
|
pack) |
|
check_tools |
|
push_pack |
|
;; |
|
*) |
|
gum style --foreground 1 "Unknown push subcommand. Available: pack" |
|
exit 1 |
|
;; |
|
esac |
|
;; |
|
install-dependencies) |
|
install_dependencies |
|
;; |
|
*) |
|
gum style --foreground 1 "Unknown command. Available: create, push, install-dependencies" |
|
exit 1 |
|
;; |
|
esac |