Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 30 additions & 8 deletions deploy-scripts/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,6 @@
# Kubernetes Configuration
NAMESPACE=hyperfleet-e2e

# Release Configuration
RELEASE_PREFIX=hyperfleet

# Provider Configuration
GCP_PROJECT_ID=hcm-hyperfleet
Expand All @@ -22,12 +20,36 @@ API_IMAGE_REPO=hyperfleet-api
API_IMAGE_TAG=latest
API_SERVICE_TYPE=LoadBalancer

# API Adapter Configuration (comma-separated list)
# NOTE: Adapters are auto-discovered from testdata/adapter-configs/
# WARNING: Auto-discovery will OVERRIDE these environment variables if adapters are found
# These values are only used if no adapter configs exist in testdata/adapter-configs/
# Example: API_ADAPTERS_CLUSTER="example1-namespace,validation,dns"
# API_ADAPTERS_CLUSTER=""
# ============================================================================
# Adapter Deployment Configuration
# ============================================================================
# REQUIRED: Specify which adapters to deploy (comma-separated list)
# These environment variables are REQUIRED - auto-discovery has been removed

# Cluster-level adapters to deploy
# Available adapters: cl-namespace, cl-job, cl-deployment, cl-maestro
CLUSTER_TIER0_ADAPTERS_DEPLOYMENT=cl-namespace,cl-job,cl-deployment

# NodePool-level adapters to deploy
# Available adapters: np-configmap
NODEPOOL_TIER0_ADAPTERS_DEPLOYMENT=np-configmap

# Base directory containing adapter test data folders
# Each adapter must have its own folder: ${ADAPTERS_FILE_DIR}/<adapter-name>/
# Note: Uses TESTDATA_DIR environment variable if not explicitly set
# ADAPTERS_FILE_DIR="${TESTDATA_DIR}/adapter-configs"

# ============================================================================
# API Adapter Configuration
# ============================================================================
# NOTE: These are SEPARATE from tier0 deployment configuration above
# These should be set based on specific test case requirements
# Leave empty by default, set per test case as needed

# Adapters for API cluster configuration
API_ADAPTERS_CLUSTER=cl-namespace,cl-job,cl-deployment

# Adapters for API nodepool configuration
# API_ADAPTERS_NODEPOOL=""
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also give it the default value np-configmap


# Sentinel Component Configuration
Expand Down
53 changes: 35 additions & 18 deletions deploy-scripts/deploy-clm.sh
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "${SCRIPT_DIR}/.." && pwd)"
WORK_DIR="${PROJECT_ROOT}/.deploy-work"
TESTDATA_DIR="${PROJECT_ROOT}/testdata"
TESTDATA_DIR="${TESTDATA_DIR:-${PROJECT_ROOT}/testdata}"

# ============================================================================
# Load Environment Variables from .env file
Expand Down Expand Up @@ -55,6 +55,11 @@ API_SERVICE_TYPE="${API_SERVICE_TYPE:-LoadBalancer}"
API_ADAPTERS_CLUSTER="${API_ADAPTERS_CLUSTER:-}"
API_ADAPTERS_NODEPOOL="${API_ADAPTERS_NODEPOOL:-}"

# Adapter Test Data Configuration
ADAPTERS_FILE_DIR="${ADAPTERS_FILE_DIR:-${TESTDATA_DIR}/adapter-configs}"
CLUSTER_TIER0_ADAPTERS_DEPLOYMENT="${CLUSTER_TIER0_ADAPTERS_DEPLOYMENT:-}"
NODEPOOL_TIER0_ADAPTERS_DEPLOYMENT="${NODEPOOL_TIER0_ADAPTERS_DEPLOYMENT:-}"

# Sentinel Component
SENTINEL_IMAGE_REPO="${SENTINEL_IMAGE_REPO:-hyperfleet-sentinel}"
SENTINEL_IMAGE_TAG="${SENTINEL_IMAGE_TAG:-latest}"
Expand All @@ -70,9 +75,6 @@ ADAPTER_GOOGLEPUBSUB_CREATE_SUBSCRIPTION_IF_MISSING="${ADAPTER_GOOGLEPUBSUB_CREA
# HyperFleet API Configuration
API_BASE_URL="${API_BASE_URL:-http://hyperfleet-api:8000}"

# Release name prefix
RELEASE_PREFIX="${RELEASE_PREFIX:-hyperfleet}"

# Helm Chart Sources
API_CHART_REPO="${API_CHART_REPO:-https://github.com/openshift-hyperfleet/hyperfleet-api.git}"
API_CHART_REF="${API_CHART_REF:-main}"
Expand Down Expand Up @@ -144,12 +146,13 @@ OPTIONAL FLAGS:
# API Configuration
--api-base-url <url> HyperFleet API base URL for Sentinel and Adapter
(default: http://hyperfleet-api.<namespace>.svc.cluster.local:8000)
--api-adapters-cluster <list> Comma-separated list of cluster adapters (e.g., "example1,validation")
--api-adapters-nodepool <list> Comma-separated list of nodepool adapters (e.g., "validation,hypershift")
--api-adapters-cluster <list> Comma-separated list of cluster adapters for API config (e.g., "cl-namespace,cl-job")
--api-adapters-nodepool <list> Comma-separated list of nodepool adapters for API config (e.g., "np-configmap")

# Release Configuration
--release-prefix <prefix> Release name prefix (default: hyperfleet)
Components will be named: <prefix>-api, <prefix>-sentinel, <prefix>-adapter
# Adapter Deployment Configuration
--cluster-tier0-adapters <list> Comma-separated list of cluster-level adapters to deploy (e.g., "cl-namespace,cl-job")
--nodepool-tier0-adapters <list> Comma-separated list of nodepool-level adapters to deploy (e.g., "np-configmap")
--adapters-file-dir <path> Base directory containing adapter test data folders (default: ${TESTDATA_DIR}/adapter-configs)

# Uninstall Options (only for --action uninstall)
--delete-k8s-resources Delete Kubernetes resources (Helm releases + namespace)
Expand All @@ -165,12 +168,18 @@ ENVIRONMENT VARIABLES:
All configuration can be set in the .env file located at: ${SCRIPT_DIR}/.env

Common variables:
- NAMESPACE Kubernetes namespace
- IMAGE_REGISTRY Container image registry
- API_IMAGE_TAG API image tag
- SENTINEL_IMAGE_TAG Sentinel image tag
- ADAPTER_IMAGE_TAG Adapter image tag
- GCP_PROJECT_ID Google Cloud Project ID for Pub/Sub
- NAMESPACE Kubernetes namespace
- IMAGE_REGISTRY Container image registry
- API_IMAGE_TAG API image tag
- SENTINEL_IMAGE_TAG Sentinel image tag
- ADAPTER_IMAGE_TAG Adapter image tag
- GCP_PROJECT_ID Google Cloud Project ID for Pub/Sub
- TESTDATA_DIR Base directory for test data (default: PROJECT_ROOT/testdata)
- CLUSTER_TIER0_ADAPTERS_DEPLOYMENT Cluster-level adapters to deploy (comma-separated)
- NODEPOOL_TIER0_ADAPTERS_DEPLOYMENT NodePool-level adapters to deploy (comma-separated)
- ADAPTERS_FILE_DIR Base directory for adapter test data (default: TESTDATA_DIR/adapter-configs)
- API_ADAPTERS_CLUSTER Adapters for API cluster config (set per test case)
- API_ADAPTERS_NODEPOOL Adapters for API nodepool config (set per test case)

EXAMPLES:
# Install all components with default settings
Expand Down Expand Up @@ -279,8 +288,16 @@ parse_arguments() {
API_ADAPTERS_NODEPOOL="$2"
shift 2
;;
--release-prefix)
RELEASE_PREFIX="$2"
--cluster-tier0-adapters)
CLUSTER_TIER0_ADAPTERS_DEPLOYMENT="$2"
shift 2
;;
--nodepool-tier0-adapters)
NODEPOOL_TIER0_ADAPTERS_DEPLOYMENT="$2"
shift 2
;;
--adapters-file-dir)
ADAPTERS_FILE_DIR="$2"
shift 2
;;
--delete-k8s-resources)
Expand Down Expand Up @@ -405,7 +422,7 @@ perform_install() {
# Display API external IP if available
if [[ "${INSTALL_API}" == "true" ]]; then
local external_ip
external_ip=$(kubectl get svc "${RELEASE_PREFIX}-api" -n "${NAMESPACE}" -o jsonpath='{.status.loadBalancer.ingress[0].ip}' 2>/dev/null)
external_ip=$(kubectl get svc "api-${NAMESPACE}" -n "${NAMESPACE}" -o jsonpath='{.status.loadBalancer.ingress[0].ip}' 2>/dev/null)
if [[ -n "${external_ip}" ]]; then
echo
log_info "HyperFleet API External IP: ${external_ip}"
Expand Down
155 changes: 78 additions & 77 deletions deploy-scripts/lib/adapter.sh
Original file line number Diff line number Diff line change
Expand Up @@ -3,31 +3,75 @@
# adapter.sh - HyperFleet Adapter component deployment functions
#
# This module handles discovery, installation, and uninstallation of adapters
# from the testdata/adapter-configs directory
# from the ${ADAPTERS_FILE_DIR} directory (defaults to ${TESTDATA_DIR}/adapter-configs)

# ============================================================================
# Adapter Discovery Functions
# ============================================================================

discover_adapters() {
local adapter_configs_dir="${TESTDATA_DIR}/adapter-configs"
# Use ADAPTERS_FILE_DIR env var, fallback to default
local adapter_configs_dir="${ADAPTERS_FILE_DIR:-${TESTDATA_DIR}/adapter-configs}"

if [[ ! -d "${adapter_configs_dir}" ]]; then
log_verbose "Adapter configs directory not found: ${adapter_configs_dir}" >&2
return 1
fi

# Find all directories matching clusters-* or nodepools-* pattern
# Read adapter names from environment variables
local cluster_adapters="${CLUSTER_TIER0_ADAPTERS_DEPLOYMENT:-}"
local nodepool_adapters="${NODEPOOL_TIER0_ADAPTERS_DEPLOYMENT:-}"

if [[ -z "${cluster_adapters}" && -z "${nodepool_adapters}" ]]; then
log_error "No adapters specified. Set CLUSTER_TIER0_ADAPTERS_DEPLOYMENT and/or NODEPOOL_TIER0_ADAPTERS_DEPLOYMENT" >&2
return 1
fi

# Build list of adapter directories from environment variables
local adapter_dirs=()
while IFS= read -r -d '' dir; do
local basename=$(basename "$dir")
if [[ "$basename" =~ ^(clusters|nodepools)- ]]; then
adapter_dirs+=("$basename")
fi
done < <(find "${adapter_configs_dir}" -mindepth 1 -maxdepth 1 -type d -print0)

# Add cluster adapters
if [[ -n "${cluster_adapters}" ]]; then
IFS=',' read -ra cluster_adapter_array <<< "${cluster_adapters}"
for adapter_name in "${cluster_adapter_array[@]}"; do
# Trim whitespace
adapter_name=$(echo "${adapter_name}" | xargs)
# Validate adapter name is not empty (prevents issues from trailing commas)
if [[ -z "${adapter_name}" ]]; then
log_error "Empty adapter name in CLUSTER_TIER0_ADAPTERS_DEPLOYMENT (check for trailing commas)" >&2
return 1
fi
if [[ -d "${adapter_configs_dir}/${adapter_name}" ]]; then
adapter_dirs+=("clusters|${adapter_name}")
else
log_error "Cluster adapter directory not found: ${adapter_configs_dir}/${adapter_name}" >&2
return 1
fi
done
fi

# Add nodepool adapters
if [[ -n "${nodepool_adapters}" ]]; then
IFS=',' read -ra nodepool_adapter_array <<< "${nodepool_adapters}"
for adapter_name in "${nodepool_adapter_array[@]}"; do
# Trim whitespace
adapter_name=$(echo "${adapter_name}" | xargs)
# Validate adapter name is not empty (prevents issues from trailing commas)
if [[ -z "${adapter_name}" ]]; then
log_error "Empty adapter name in NODEPOOL_TIER0_ADAPTERS_DEPLOYMENT (check for trailing commas)" >&2
return 1
fi
if [[ -d "${adapter_configs_dir}/${adapter_name}" ]]; then
adapter_dirs+=("nodepools|${adapter_name}")
else
log_error "NodePool adapter directory not found: ${adapter_configs_dir}/${adapter_name}" >&2
return 1
fi
done
fi

if [[ ${#adapter_dirs[@]} -eq 0 ]]; then
log_verbose "No adapter configurations found (no clusters-* or nodepools-* directories)" >&2
log_verbose "No adapter configurations found" >&2
return 1
fi

Expand All @@ -37,55 +81,10 @@ discover_adapters() {
done

# Export for use in other functions
# Format: resource_type|adapter_name (e.g., "clusters|cl-namespace")
printf '%s\n' "${adapter_dirs[@]}"
}

get_adapters_by_type() {
local resource_type="$1" # "clusters" or "nodepools"
local adapter_configs_dir="${TESTDATA_DIR}/adapter-configs"

if [[ ! -d "${adapter_configs_dir}" ]]; then
return 1
fi

# Find all directories matching the resource type pattern
local adapter_names=()
while IFS= read -r -d '' dir; do
local basename=$(basename "$dir")
if [[ "$basename" =~ ^${resource_type}-(.+)$ ]]; then
# Extract just the adapter name (everything after "clusters-" or "nodepools-")
local adapter_name="${BASH_REMATCH[1]}"
adapter_names+=("${adapter_name}")
fi
done < <(find "${adapter_configs_dir}" -mindepth 1 -maxdepth 1 -type d -print0)

if [[ ${#adapter_names[@]} -eq 0 ]]; then
return 1
fi

# Return comma-separated list
local IFS=','
echo "${adapter_names[*]}"
}

parse_adapter_name() {
local dir_name="$1"

# Extract resource_type and adapter_name
# Format: <resource_type>-<adapter_name>
# Examples: clusters-example1-namespace, nodepools-namespace

if [[ "$dir_name" =~ ^(clusters|nodepools)-(.+)$ ]]; then
local resource_type="${BASH_REMATCH[1]}"
local adapter_name="${BASH_REMATCH[2]}"

echo "${resource_type}|${adapter_name}"
else
log_error "Invalid adapter directory name format: ${dir_name}"
return 1
fi
}

# ============================================================================
# Adapter Installation Functions
# ============================================================================
Expand All @@ -95,25 +94,25 @@ install_adapter_instance() {

log_section "Installing Adapter: ${dir_name}"

# Parse adapter name
local parsed
if ! parsed=$(parse_adapter_name "${dir_name}"); then
log_error "Failed to parse adapter directory name: ${dir_name}"
# Extract resource_type and adapter_name from format: resource_type|adapter_name
local resource_type="${dir_name%%|*}"
local adapter_name="${dir_name##*|}"

# Validate the descriptor format and ensure both parts are non-empty
if [[ -z "${resource_type}" || -z "${adapter_name}" || "${dir_name}" != *"|"* ]]; then
log_error "Invalid adapter descriptor '${dir_name}'. Expected format: resource_type|adapter_name"
return 1
fi

local resource_type="${parsed%%|*}"
local adapter_name="${parsed##*|}"

log_info "Resource type: ${resource_type}"
log_info "Adapter name: ${adapter_name}"

# Construct release name
local release_name="${RELEASE_PREFIX}-adapter-${resource_type}-${adapter_name}"
local release_name="adapter-${NAMESPACE}-${adapter_name}"

# Source adapter config directory
local adapter_configs_dir="${TESTDATA_DIR}/adapter-configs"
local source_adapter_dir="${adapter_configs_dir}/${dir_name}"
# Source adapter config directory (using ADAPTERS_FILE_DIR env var)
local adapter_configs_dir="${ADAPTERS_FILE_DIR:-${TESTDATA_DIR}/adapter-configs}"
local source_adapter_dir="${adapter_configs_dir}/${adapter_name}"

if [[ ! -d "${source_adapter_dir}" ]]; then
log_error "Adapter config directory not found: ${source_adapter_dir}"
Expand All @@ -124,10 +123,15 @@ install_adapter_instance() {
local full_chart_path="${WORK_DIR}/adapter/${ADAPTER_CHART_PATH}"

# Copy adapter config folder to chart directory
local dest_adapter_dir="${full_chart_path}/${dir_name}"
local dest_adapter_dir="${full_chart_path}/${adapter_name}"
log_info "Copying adapter config from ${source_adapter_dir} to ${dest_adapter_dir}"

if [[ -d "${dest_adapter_dir}" ]]; then
# Safety check: ensure dest_adapter_dir contains adapter_name to prevent accidental deletion
if [[ "${dest_adapter_dir}" != *"${adapter_name}" || "${dest_adapter_dir}" == "/" || "${dest_adapter_dir}" == "${full_chart_path}" ]]; then
log_error "Safety check failed: refusing to delete suspicious path: ${dest_adapter_dir}"
return 1
fi
log_verbose "Removing existing adapter config directory: ${dest_adapter_dir}"
rm -rf "${dest_adapter_dir}"
fi
Expand Down Expand Up @@ -241,18 +245,15 @@ uninstall_adapter_instance() {

log_section "Uninstalling Adapter: ${dir_name}"

# Parse adapter name
local parsed
if ! parsed=$(parse_adapter_name "${dir_name}"); then
log_error "Failed to parse adapter directory name: ${dir_name}"
return 1
fi
# Extract resource_type and adapter_name from format: resource_type|adapter_name
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The old parse_adapter_name() call provided validation for both install and
uninstall. After the refactor, install_adapter_instance got inline validation
(L101-104), but uninstall_adapter_instance did not — the descriptor is parsed
without any check.

Should be straightforward to add the same guard here:

  # Extract resource_type and adapter_name from format:
  resource_type|adapter_name
  local resource_type="${dir_name%%|*}"
  local adapter_name="${dir_name##*|}"

  # Validate the descriptor format and ensure both parts are non-empty
  if [[ -z "${resource_type}" || -z "${adapter_name}" || "${dir_name}" != *"|"*
  ]]; then
      log_error "Invalid adapter descriptor '${dir_name}'. Expected format:
  resource_type|adapter_name"
      return 1
  fi

local resource_type="${dir_name%%|*}"
local adapter_name="${dir_name##*|}"

local resource_type="${parsed%%|*}"
local adapter_name="${parsed##*|}"
log_info "Resource type: ${resource_type}"
log_info "Adapter name: ${adapter_name}"

# Construct release name
local release_name="${RELEASE_PREFIX}-adapter-${resource_type}-${adapter_name}"
local release_name="adapter-${NAMESPACE}-${adapter_name}"

# Check if release exists
if ! helm list -n "${NAMESPACE}" 2>/dev/null | grep -q "^${release_name}"; then
Expand Down
Loading