|
| 1 | +#!/bin/bash |
| 2 | +# |
| 3 | +# This script verifies end-to-end connectivity for an example inference extension test environment based on |
| 4 | +# resources from the quickstart guide or e2e test framework. It can optionally launch a "curl" client pod to |
| 5 | +# run these tests within the cluster. |
| 6 | +# |
| 7 | +# USAGE: ./hack/e2e-test.sh |
| 8 | +# |
| 9 | +# OPTIONAL ENVIRONMENT VARIABLES: |
| 10 | +# - TIME: The duration (in seconds) for which the test will run. Defaults to 1 second. |
| 11 | +# - CURL_POD: If set to "true", the script will use a Kubernetes pod named "curl" for making requests. |
| 12 | +# - IP: Override the detected IP address. If not provided, the script attempts to use a Gateway based on |
| 13 | +# the quickstart guide or an Envoy service IP based on the e2e test framework. |
| 14 | +# - PORT: Override the detected port. If not provided, the script attempts to use a Gateway based on the |
| 15 | +# quickstart guide or an Envoy service IP based on the e2e test framework. |
| 16 | +# |
| 17 | +# WHAT THE SCRIPT DOES: |
| 18 | +# 1. Determines if there is a Gateway named "inference-gateway" in the "default" namespace. If found, it extracts the IP |
| 19 | +# address and port from the Gateway's "llm-gw" listener. Otherwise, it falls back to the Envoy service in the "default" namespace. |
| 20 | +# 2. Optionally checks for (or creates) a "curl" pod, ensuring it is ready to execute requests. |
| 21 | +# 3. Loops for $TIME seconds, sending requests every 5 seconds to the /v1/completions endpoint to confirm successful connectivity. |
| 22 | + |
| 23 | +set -euo pipefail |
| 24 | + |
| 25 | +# Determine the directory of this script and build an absolute path to client.yaml. |
| 26 | +SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )" |
| 27 | +CLIENT_YAML="$SCRIPT_DIR/../test/testdata/client.yaml" |
| 28 | + |
| 29 | +# TIME is the amount of time, in seconds, to run the test. |
| 30 | +TIME=${TIME:-1} |
| 31 | +# Optionally use a client curl pod for executing the curl command. |
| 32 | +CURL_POD=${CURL_POD:-false} |
| 33 | + |
| 34 | +check_resource_exists() { |
| 35 | + local type=$1 |
| 36 | + local name=$2 |
| 37 | + local namespace=$3 |
| 38 | + |
| 39 | + if kubectl get "$type" "$name" -n "$namespace" &>/dev/null; then |
| 40 | + return 0 |
| 41 | + else |
| 42 | + return 1 |
| 43 | + fi |
| 44 | +} |
| 45 | + |
| 46 | +check_pod_ready() { |
| 47 | + local pod_name=$1 |
| 48 | + local namespace=$2 |
| 49 | + # Check the Ready condition using jsonpath. Default to False if not found. |
| 50 | + local ready_status |
| 51 | + ready_status=$(kubectl get pod "$pod_name" -n "$namespace" -o jsonpath='{.status.conditions[?(@.type=="Ready")].status}' 2>/dev/null || echo "False") |
| 52 | + if [[ "$ready_status" == "True" ]]; then |
| 53 | + return 0 |
| 54 | + else |
| 55 | + return 1 |
| 56 | + fi |
| 57 | +} |
| 58 | + |
| 59 | +# Try to get the Gateway's IP and the port from the listener named "llm-gw" if it exists. |
| 60 | +if check_resource_exists "gateway" "inference-gateway" "default"; then |
| 61 | + GATEWAY_IP=$(kubectl get gateway inference-gateway -n default -o jsonpath='{.status.addresses[0].value}') |
| 62 | + # Use JSONPath to select the port from the listener with name "llm-gw" |
| 63 | + GATEWAY_PORT=$(kubectl get gateway inference-gateway -n default -o jsonpath='{.spec.listeners[?(@.name=="llm-gw")].port}') |
| 64 | +else |
| 65 | + GATEWAY_IP="" |
| 66 | + GATEWAY_PORT="" |
| 67 | +fi |
| 68 | + |
| 69 | +if [[ -n "$GATEWAY_IP" && -n "$GATEWAY_PORT" ]]; then |
| 70 | + echo "Using Gateway inference-gateway IP and port from listener 'llm-gw'." |
| 71 | + IP=${IP:-$GATEWAY_IP} |
| 72 | + PORT=${PORT:-$GATEWAY_PORT} |
| 73 | +else |
| 74 | + echo "Gateway inference-gateway not found or missing IP/port. Falling back to Envoy service." |
| 75 | + # Ensure the Envoy service exists. |
| 76 | + if ! check_resource_exists "svc" "envoy" "default"; then |
| 77 | + echo "Error: Envoy service not found in namespace 'default'." |
| 78 | + exit 1 |
| 79 | + fi |
| 80 | + IP=${IP:-$(kubectl get svc envoy -n default -o jsonpath='{.spec.clusterIP}')} |
| 81 | + PORT=${PORT:-$(kubectl get svc envoy -n default -o jsonpath='{.spec.ports[0].port}')} |
| 82 | +fi |
| 83 | + |
| 84 | +# Optionally verify that the curl pod exists and is ready. |
| 85 | +if [[ "$CURL_POD" == "true" ]]; then |
| 86 | + if ! check_resource_exists "pod" "curl" "default"; then |
| 87 | + echo "Pod 'curl' not found in namespace 'default'. Applying client.yaml from $CLIENT_YAML..." |
| 88 | + kubectl apply -f "$CLIENT_YAML" |
| 89 | + fi |
| 90 | + echo "Waiting for pod 'curl' to be ready..." |
| 91 | + # Retry every 5 seconds for up to 30 seconds (6 attempts) |
| 92 | + for i in {1..6}; do |
| 93 | + if check_pod_ready "curl" "default"; then |
| 94 | + echo "Pod 'curl' is now ready." |
| 95 | + break |
| 96 | + fi |
| 97 | + echo "Retry attempt $i: Pod 'curl' not ready; waiting 5 seconds..." |
| 98 | + sleep 5 |
| 99 | + done |
| 100 | + |
| 101 | + if ! check_pod_ready "curl" "default"; then |
| 102 | + echo "Error: Pod 'curl' is still not ready in namespace 'default' after 30 seconds." |
| 103 | + exit 1 |
| 104 | + fi |
| 105 | +fi |
| 106 | + |
| 107 | +# Validate that we have a non-empty IP and PORT. |
| 108 | +if [[ -z "$IP" ]]; then |
| 109 | + echo "Error: Unable to determine a valid IP from either Gateway or Envoy service." |
| 110 | + exit 1 |
| 111 | +fi |
| 112 | + |
| 113 | +if [[ -z "$PORT" ]]; then |
| 114 | + echo "Error: Unable to determine a valid port from either Gateway or Envoy service." |
| 115 | + exit 1 |
| 116 | +fi |
| 117 | + |
| 118 | +echo "Using IP: $IP" |
| 119 | +echo "Using PORT: $PORT" |
| 120 | + |
| 121 | +# Run the test for the specified duration. |
| 122 | +end=$((SECONDS + TIME)) |
| 123 | +if [[ "$CURL_POD" == "true" ]]; then |
| 124 | + while [ $SECONDS -lt $end ]; do |
| 125 | + kubectl exec po/curl -- curl -i "$IP:$PORT/v1/completions" \ |
| 126 | + -H 'Content-Type: application/json' \ |
| 127 | + -d '{"model": "tweet-summary","prompt": "Write as if you were a critic: San Francisco","max_tokens": 100,"temperature": 0}' |
| 128 | + sleep 5 |
| 129 | + done |
| 130 | +else |
| 131 | + while [ $SECONDS -lt $end ]; do |
| 132 | + curl -i "$IP:$PORT/v1/completions" \ |
| 133 | + -H 'Content-Type: application/json' \ |
| 134 | + -d '{"model": "tweet-summary","prompt": "Write as if you were a critic: San Francisco","max_tokens": 100,"temperature": 0}' |
| 135 | + sleep 5 |
| 136 | + done |
| 137 | +fi |
0 commit comments