Skip to content

Commit

Permalink
tools
Browse files Browse the repository at this point in the history
Signed-off-by: Per Goncalves da Silva <[email protected]>
  • Loading branch information
Per Goncalves da Silva committed Aug 24, 2024
1 parent d2241b0 commit c706ebc
Show file tree
Hide file tree
Showing 10 changed files with 841 additions and 0 deletions.
126 changes: 126 additions & 0 deletions hack/tools/catalogs/bundle-manifests
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
#!/usr/bin/env bash

# Get the directory of the current script
SCRIPT_ROOT=$(dirname "$(realpath "$0")")

source "${SCRIPT_ROOT}/lib/unpack.sh"
source "${SCRIPT_ROOT}/lib/collect-rbac.sh"

# Set the container runtime, default to docker
CONTAINER_RUNTIME=${CONTAINER_RUNTIME:-docker}

function usage() {
script_name=$(basename "$0")
echo "Usage:"
echo "./${script_name} install <package-name> <package-version> [-n namespace] [-e cluster-extension-name] [-cr cluster-role-name] [-r role-name] [-s service-account-name] [--use-defaults]"
echo "./${script_name} rbac <package-name> <package-version> [-n namespace] [-e cluster-extension-name] [-cr cluster-role-name] [-r role-name] [-s service-account-name] [--use-defaults]"
echo ""
echo "Note: If --use-defaults is not set, the unset optional parameters will appear as template variables in the resulting manifests, i.e.:"
echo "\${NAMESPACE}, \${EXTENSION_NAME}, \${CLUSTER_ROLE_NAME}, \${ROLE_NAME}, \${SERVICE_ACCOUNT_NAME}."
echo "If --use-defaults is set, the defaults will be applied only to optional parameters that are not set."
echo "Defaults: cluster-extension-name => <package-name>, namespace => <cluster-extension-name>-system, "
echo "service-account => <package-name>-installer, cluster role => <service-account>-cluster-role,"
echo "role => <service-account>-installer-role."
echo "NOTE: The role and cluster-role bindings always follow the format <[cluster-]role-name>-binding."
}

# Check for at least 3 arguments
if [ "$#" -lt 3 ]; then
usage
exit 1
fi

# Command and package details
COMMAND=$1
export PACKAGE_NAME=$2
export PACKAGE_VERSION=$3

# Initialize environment variables with template defaults
export NAMESPACE="\${NAMESPACE}"
export EXTENSION_NAME="\${EXTENSION-NAME}"
export CLUSTER_ROLE_NAME="\${CLUSTER_ROLE_NAME}"
export ROLE_NAME="\${ROLE_NAME}"
export SERVICE_ACCOUNT_NAME="\${SERVICE_ACCOUNT_NAME}"
use_defaults=false

# Parse optional arguments
shift 3
while [[ $# -gt 0 ]]; do
key="$1"

case $key in
-n)
export NAMESPACE="$2"
shift 2
;;
-e)
export EXTENSION_NAME="$2"
shift 2
;;
-cr)
export CLUSTER_ROLE_NAME="$2"
shift 2
;;
-r)
export ROLE_NAME="$2"
shift 2
;;
-s)
export SERVICE_ACCOUNT_NAME="$2"
shift 2
;;
--use-defaults)
use_defaults=true
shift
;;
*)
echo "Unknown option $1"
usage
exit 1
;;
esac
done

# Apply default values only to unset parameters if --use-defaults is set
if [ "$use_defaults" = true ]; then
[ "$EXTENSION_NAME" == "\${EXTENSION-NAME}" ] && export EXTENSION_NAME="${PACKAGE_NAME}"
[ "$NAMESPACE" == "\${NAMESPACE}" ] && export NAMESPACE="${EXTENSION_NAME}-system"
[ "$SERVICE_ACCOUNT_NAME" == "\${SERVICE_ACCOUNT_NAME}" ] && export SERVICE_ACCOUNT_NAME="${PACKAGE_NAME}-installer"
[ "$CLUSTER_ROLE_NAME" == "\${CLUSTER_ROLE_NAME}" ] && export CLUSTER_ROLE_NAME="${SERVICE_ACCOUNT_NAME}-cluster-role"
[ "$ROLE_NAME" == "\${ROLE_NAME}" ] && export ROLE_NAME="${SERVICE_ACCOUNT_NAME}-installer-role"
fi

# Output the set environment variables for confirmation
debug "Environment variables set:"
debug "NAMESPACE=${NAMESPACE}"
debug "EXTENSION_NAME=${EXTENSION_NAME}"
debug "CLUSTER_ROLE_NAME=${CLUSTER_ROLE_NAME}"
debug "ROLE_NAME=${ROLE_NAME}"
debug "SERVICE_ACCOUNT_NAME=${SERVICE_ACCOUNT_NAME}"

# Find bundle image
image="$(cat - | get-bundle-image "${PACKAGE_NAME}" "${PACKAGE_VERSION}")"

# Unpack and close container
bundle_manifest_dir="$(unpack "$(create_container "${image}")")"

# Derive rbac from bundle manifests
collect_installer_rbac "${bundle_manifest_dir}"

# Example output or further processing based on command
case "${COMMAND}" in
install)
generate_install_manifests | envsubst
;;
rbac)
generate_rbac_manifests | envsubst
;;
*)
echo "Unknown command $command"
usage
exit 1
;;
esac

# Clean up manifest directory
rm -rf "${bundle_manifest_dir}"
61 changes: 61 additions & 0 deletions hack/tools/catalogs/download-catalog
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
#!/bin/bash

# Constants
SERVICE_NAMESPACE="olmv1-system"
SERVICE_NAME="catalogd-catalogserver"
LOCAL_PORT=8001
SERVICE_PORT=443 # Assuming the service uses HTTPS on port 443

# Function to display usage
usage() {
echo "Usage: $0 <catalog-name>"
exit 1
}

# Check if catalog name is provided
if [ -z "$1" ]; then
usage
fi

CATALOG_NAME="$1"

# Check if the clustercatalog resource exists
echo "Checking if ClusterCatalog $CATALOG_NAME exists..."
CLUSTER_CATALOG=$(kubectl get clustercatalog "$CATALOG_NAME" -o json 2>/dev/null)
if [ -z "$CLUSTER_CATALOG" ]; then
echo "ClusterCatalog $CATALOG_NAME does not exist."
exit 1
fi

# Check if the Unpacked condition is true
UNPACKED_CONDITION=$(echo "$CLUSTER_CATALOG" | jq -r '.status.conditions[] | select(.type=="Unpacked") | .status')
if [ "$UNPACKED_CONDITION" != "True" ]; then
echo "ClusterCatalog $CATALOG_NAME is not unpacked yet."
exit 1
fi

# Get the contentURL
CONTENT_URL=$(echo "$CLUSTER_CATALOG" | jq -r '.status.contentURL')
if [ -z "$CONTENT_URL" ]; then
echo "Content URL not found for ClusterCatalog $CATALOG_NAME."
exit 1
fi

# Start port forwarding
echo "Starting kubectl port-forward to $SERVICE_NAME on port $LOCAL_PORT..."
kubectl port-forward -n "$SERVICE_NAMESPACE" svc/"$SERVICE_NAME" $LOCAL_PORT:$SERVICE_PORT &>/dev/null &
PORT_FORWARD_PID=$!
sleep 2 # Wait for the port-forwarding to start

# Modify the contentURL to hit localhost:<port>
LOCAL_CONTENT_URL=$(echo "$CONTENT_URL" | sed "s|https://[^/]*|https://localhost:$LOCAL_PORT|")

# Download the catalog using wget
echo "Downloading catalog from $LOCAL_CONTENT_URL..."
wget --no-check-certificate "$LOCAL_CONTENT_URL" -O "${CATALOG_NAME}-catalog.json"

# Stop the port forwarding
echo "Stopping kubectl port-forward..."
kill $PORT_FORWARD_PID

echo "Catalog downloaded to ${CATALOG_NAME}-catalog.json"
117 changes: 117 additions & 0 deletions hack/tools/catalogs/lib/bundle.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
source "${SCRIPT_ROOT}/lib/hash.sh"

# Given package and version grabs the bundle image from stdin FBC stream
function get-bundle-image(){
local package_name="${1}"
local package_version="${2}"
local image=$(jq -r --arg pkg "$package_name" --arg ver "$package_version" \
'select(.schema == "olm.bundle" and (.properties[] | select(.type == "olm.package" and .value.packageName == $pkg and .value.version == $ver))) | .image')

if [ -z "$image" ]; then
echo "No matching image found for package '$package_name' with version '$package_version'."
exit 1
fi

echo "${image}"
}

# Function to validate the bundle is supported
function check-bundle-supported() {
local csv="${1}"
local valid=$(yq eval '
(.spec.installModes[] | select(.type == "AllNamespaces" and .supported == true)) and
((.spec.webhookdefinitions == null) or (.spec.webhookdefinitions | length == 0)) and
((.spec.customresourcedefinitions.required == null) or (.spec.customresourcedefinitions.required | length == 0))
' "${csv}")

# Check if the result is 'true'
if [ "$valid" != "true" ]; then
echo "Bundles with dependencies, or that don't support AllNamespaces mode, or with webhookdefinitions, are not supported."
exit 1
fi

}

# Function to get all resource names for a particular kind
# from the manifest directory
function collect_resource_names() {
local manifest_dir="${1}"
local kind="${2}"
local resource_names=()
while IFS= read -r resource_file; do
name=$(yq eval -r '.metadata.name' "$resource_file")
if [ -n "$name" ]; then
resource_names+=("$name")
fi
done < <(find "${manifest_dir}" -type f -exec grep -l "^kind: ${kind}" {} \;)
echo "${resource_names[@]}"
}

# Function that collects all the rules for all the ClusterRole manifests
# shipped with the bundle
function collect_manifest_cluster_role_perms() {
local manifest_dir="${1}"
local kind="ClusterRole"
local all_cr_rules="[]"

while IFS= read -r resource_file; do
# Extract the entire rules array from the current file and ensure it's treated as a valid JSON array
cr_rules=$(yq eval -o=json -r '.rules // []' "$resource_file")
# Validate and merge the current rules array with the cumulative rules array
if jq -e . >/dev/null 2>&1 <<<"$cr_rules"; then
all_cr_rules=$(jq -c --argjson existing "$all_cr_rules" --argjson new "$cr_rules" '$existing + $new' <<<"$all_cr_rules")
fi
done < <(find "${manifest_dir}" -type f -exec grep -l "^kind: ${kind}" {} \;)
echo "$all_cr_rules"
}

# Function that collects all the rules for all the Role manifests
# shipped with the bundle
function collect_manifest_role_perms() {
local manifest_dir="${1}"
local kind="Role"
local all_cr_rules="[]"

while IFS= read -r resource_file; do
# Extract the entire rules array from the current file and ensure it's treated as a valid JSON array
cr_rules=$(yq eval -o=json -r '.rules // []' "$resource_file")
# Validate and merge the current rules array with the cumulative rules array
if jq -e . >/dev/null 2>&1 <<<"$cr_rules"; then
all_cr_rules=$(jq -c --argjson existing "$all_cr_rules" --argjson new "$cr_rules" '$existing + $new' <<<"$all_cr_rules")
fi
done < <(find "${manifest_dir}" -type f -exec grep -l "^kind: ${kind}" {} \;)
echo "$all_cr_rules"
}

# Function to get the apiGroup for a named resource of a given kind
# from the manifests dir
function get_api_group() {
local dir_path="$1"
local kind="$2"
local name="$3"

# Find the file containing the specified kind and name
local file=$(grep -rl "kind: $kind" "$dir_path" | xargs grep -l "name: $name")

# Extract the apiGroup from the found file
if [ -n "$file" ]; then
local api_group=$(yq eval '.apiVersion' "$file" | awk -F'/' '{print $1}')
echo "$api_group"
fi
}

# Function to get the generated clusterrole resource names
function generated_cluster_role_names() {
local csvFile="${1}"
local generated_cluster_role_names=()
csv_name=$(yq eval -r '.metadata.name' "${csvFile}")
cperms=$(yq eval -o=json -r '.spec.install.spec.clusterPermissions?' "$csvFile" | jq -c '.[] | {serviceAccountName, rules: [.rules[] | {verbs, apiGroups, resources, resourceNames, nonResourceURLs} | with_entries(select(.value != null and .value != []))]}')
rbacPerms=$(yq eval -o=json -r '.spec.install.spec.permissions?' "$csvFile" | jq -c '.[] | {serviceAccountName, rules: [.rules[] | {verbs, apiGroups, resources, resourceNames, nonResourceURLs} | with_entries(select(.value != null and .value != []))]}')
allPerms=("${cperms[@]}" "${rbacPerms[@]}")
for perm in ${allPerms[@]}; do
local sa=$(echo $perm | yq eval -r '.serviceAccountName')
local generated_name=$(generate_name "${csv_name}-${sa}" "${perm}")
generated_cluster_role_names+=("${generated_name}")
done
echo "${generated_cluster_role_names[@]}"
}
Loading

0 comments on commit c706ebc

Please sign in to comment.