#!/bin/bash # ============================================================================= # create.client.sh # ============================================================================= # # DESCRIPTION: # Creates a new client in the Query Orchestration API using a JWT token # from a file for authentication. After creation, verifies the client exists. # # USAGE: # ./create.client.sh # # ARGUMENTS: # base_url - The URL of the Query Orchestration API (e.g., http://localhost:8080) # token_file - Path to a file containing the JWT auth token # client_name - The name to assign to the new client # # EXAMPLES: # ./create.client.sh http://localhost:8080 ./token.txt "My Client" # ./create.client.sh http://localhost:8080 test/token.txt "Demo Client" # # EXIT CODES: # 0 - Client created successfully # 1 - Missing dependencies or invalid arguments # 2 - API call failed # 3 - Authentication failed # # ============================================================================= set -e # ============================================================================= # CONFIGURATION # ============================================================================= # Colors for output (disable if not a terminal) if [[ -t 1 ]]; then RED='\033[0;31m' GREEN='\033[0;32m' YELLOW='\033[1;33m' BLUE='\033[0;34m' NC='\033[0m' else RED='' GREEN='' YELLOW='' BLUE='' NC='' fi # Generate unique external ID for this client TIMESTAMP=$(date +%s) CLIENT_EXTERNAL_ID="client-${TIMESTAMP}" # Variables set by api_call HTTP_CODE="" RESPONSE_BODY="" # ============================================================================= # HELPER FUNCTIONS # ============================================================================= # print_success - Prints a success message # Parameters: # $1 - Message print_success() { echo -e "${GREEN} OK: $1${NC}" } # print_error - Prints an error message and exits # Parameters: # $1 - Message print_error() { echo -e "${RED} ERROR: $1${NC}" exit 2 } # print_info - Prints an informational message # Parameters: # $1 - Message print_info() { echo -e " $1" } # check_response - Checks if the HTTP response code indicates success # Parameters: # $1 - Expected HTTP status code(s) (comma-separated, e.g., "200,201") # $2 - Actual HTTP status code # $3 - Response body (for error messages) # $4 - Endpoint description check_response() { local expected="$1" local actual="$2" local body="$3" local desc="$4" IFS=',' read -ra CODES <<< "$expected" for code in "${CODES[@]}"; do if [[ "$actual" == "$code" ]]; then return 0 fi done if [[ "$actual" == "401" ]]; then echo -e "${RED} AUTHENTICATION FAILED: $desc${NC}" echo " Token may be expired or invalid" echo " Response: $body" exit 3 fi if [[ "$actual" == "403" ]]; then echo -e "${RED} AUTHORIZATION FAILED: $desc${NC}" echo " User does not have permission for this operation" echo " Response: $body" exit 3 fi echo -e "${RED} FAILED: $desc${NC}" echo " Expected: $expected, Got: $actual" echo " Response: $body" exit 2 } # api_call - Makes an authenticated API call and captures response # Parameters: # $1 - HTTP method (GET, POST, PATCH, DELETE) # $2 - Endpoint path (e.g., "/client") # $3 - Request body (optional, empty string for none) # $4 - Content-Type header (optional, defaults to application/json) # Sets globals: HTTP_CODE, RESPONSE_BODY api_call() { local method="$1" local endpoint="$2" local body="$3" local content_type="${4:-application/json}" local url="${BASE_URL}${endpoint}" local curl_opts=(-s -k -w "\n%{http_code}") curl_opts+=(-X "$method") if [[ -n "$AUTH_TOKEN" ]]; then curl_opts+=(-H "Authorization: Bearer ${AUTH_TOKEN}") fi if [[ -n "$body" ]]; then curl_opts+=(-H "Content-Type: $content_type") curl_opts+=(-d "$body") fi local response local retries=3 local delay=1 for ((i=1; i<=retries; i++)); do if ! response=$(curl --connect-timeout 5 --max-time 30 "${curl_opts[@]}" "$url" 2>&1); then echo -e "${RED} CONNECTION FAILED: Could not reach ${url}${NC}" echo " curl error: $response" exit 2 fi HTTP_CODE=$(echo "$response" | tail -n1) RESPONSE_BODY=$(echo "$response" | sed '$d') if [[ "$HTTP_CODE" != "429" ]]; then break fi if [[ $i -lt $retries ]]; then print_info "Rate limited (429), waiting ${delay}s before retry $((i+1))/$retries..." sleep "$delay" delay=$((delay * 2)) fi done sleep 0.1 } # ============================================================================= # ARGUMENT VALIDATION # ============================================================================= if [[ $# -lt 3 ]]; then echo "Usage: $0 " echo "" echo "Arguments:" echo " base_url - The URL of the Query Orchestration API" echo " token_file - Path to a file containing the JWT auth token" echo " client_name - The name to assign to the new client" echo "" echo "Examples:" echo " $0 http://localhost:8080 ./token.txt \"My Client\"" echo " $0 http://localhost:8080 test/token.txt \"Demo Client\"" exit 1 fi # Check dependencies for cmd in curl jq; do if ! command -v "$cmd" &> /dev/null; then echo -e "${RED}ERROR: Required command '$cmd' not found${NC}" exit 1 fi done BASE_URL="${1%/}" TOKEN_FILE="$2" CLIENT_NAME="$3" if [[ ! -f "$TOKEN_FILE" ]]; then echo -e "${RED}ERROR: Token file not found: $TOKEN_FILE${NC}" exit 1 fi AUTH_TOKEN=$(cat "$TOKEN_FILE" | tr -d '[:space:]') if [[ -z "$AUTH_TOKEN" ]]; then echo -e "${RED}ERROR: Token file is empty: $TOKEN_FILE${NC}" exit 1 fi # ============================================================================= # MAIN # ============================================================================= echo -e "${BLUE}========================================${NC}" echo -e "${BLUE}Create Client${NC}" echo -e "${BLUE}========================================${NC}" echo "" echo "Base URL: ${BASE_URL}" echo "Token File: ${TOKEN_FILE}" echo "Client Name: ${CLIENT_NAME}" echo "External ID: ${CLIENT_EXTERNAL_ID}" echo "" # Step 1: Create client via POST /client echo -e "${BLUE}--- Creating client ---${NC}" body=$(cat << EOF { "id": "${CLIENT_EXTERNAL_ID}", "name": "${CLIENT_NAME}" } EOF ) print_info "Request: POST /client" print_info "Body: $body" api_call "POST" "/client" "$body" check_response "201" "$HTTP_CODE" "$RESPONSE_BODY" "Create client" CLIENT_ID=$(echo "$RESPONSE_BODY" | jq -r '.id') print_success "Client created successfully" print_info "Client ID: $CLIENT_ID" # Step 2: Verify client via GET /client/{id} echo "" echo -e "${BLUE}--- Verifying client ---${NC}" print_info "Request: GET /client/${CLIENT_ID}" api_call "GET" "/client/${CLIENT_ID}" "" check_response "200" "$HTTP_CODE" "$RESPONSE_BODY" "Get client" name=$(echo "$RESPONSE_BODY" | jq -r '.name') can_sync=$(echo "$RESPONSE_BODY" | jq -r '.can_sync') print_success "Client verified" print_info "Name: $name" print_info "Can Sync: $can_sync" # Summary echo "" echo -e "${GREEN}========================================${NC}" echo -e "${GREEN}Client created and verified${NC}" echo -e "${GREEN}========================================${NC}" echo " ID: $CLIENT_ID" echo " External ID: $CLIENT_EXTERNAL_ID" echo " Name: $CLIENT_NAME"