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
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,6 @@
*.iml
out
gen

# VSCode project files
.vscode/
162 changes: 162 additions & 0 deletions endpoint-exposer/configure
Original file line number Diff line number Diff line change
@@ -0,0 +1,162 @@
#!/bin/bash

set -euo pipefail

# Colors
GREEN="\033[0;32m"
BLUE="\033[0;34m"
YELLOW="\033[1;33m"
RED="\033[0;31m"
NC="\033[0m"

# Spinner state
SPINNER_PID=""
SPINNER_MSG=""

start_spinner() {
SPINNER_MSG="$1"
echo -ne "${BLUE}==>${NC} $SPINNER_MSG..."
(
while true; do
for c in / - \\ \|; do
echo -ne "\r${BLUE}==>${NC} $SPINNER_MSG... $c"
sleep 0.1
done
done
) &
SPINNER_PID=$!
disown
}

stop_spinner_success() {
kill "$SPINNER_PID" >/dev/null 2>&1 || true
wait "$SPINNER_PID" 2>/dev/null || true
echo -ne "\r\033[K"
echo -e "${GREEN}✔${NC} $SPINNER_MSG"
}

stop_spinner_error() {
kill "$SPINNER_PID" >/dev/null 2>&1 || true
wait "$SPINNER_PID" 2>/dev/null || true
echo -ne "\r\033[K"
echo -e "${RED}✖${NC} $SPINNER_MSG"
exit 1
}

# --- Step 1: Environment Validation ---

start_spinner "Validating that the NRN has been loaded into the environment."
if [ -z "${NRN:-}" ]; then
stop_spinner_error "NRN is not set. Please export the NRN environment variable before running this script."
fi
stop_spinner_success "NRN found and loaded successfully."

start_spinner "Validating that the ENVIRONMENT has been loaded into the environment."
if [ -z "${ENVIRONMENT:-}" ]; then
stop_spinner_error "ENVIRONMENT is not set. Please export the ENVIRONMENT environment variable before running this script."
fi
stop_spinner_success "ENVIRONMENT found and loaded successfully."

start_spinner "Validating that the REPO_PATH has been loaded into the environment."
if [ -z "${REPO_PATH:-}" ]; then
stop_spinner_error "REPO_PATH is not set. Please export the REPO_PATH environment variable before running this script."
fi
stop_spinner_success "REPO_PATH found and loaded successfully."

# --- Step 2: Generate and Create Service Specification ---

SERVICE_SPEC_PATH="specs/service-spec.json"
LINK_SPEC_PATH="specs/link-spec.json"
LINK_ACTION_DIR="specs/link-actions"
SERVICE_ACTION_DIR="specs/service-actions"

gomplate --file "$SERVICE_SPEC_PATH.tpl" --out "$SERVICE_SPEC_PATH"

start_spinner "Creating the service specification in the platform."
{
SERVICE_SPEC_BODY=$(cat "$SERVICE_SPEC_PATH")
SERVICE_SPEC=$(np service specification create --body "$SERVICE_SPEC_BODY" --format json)
SERVICE_SPECIFICATION_ID=$(echo "$SERVICE_SPEC" | jq -r .id)
SERVICE_SLUG=$(echo "$SERVICE_SPEC" | jq -r .slug)
} || stop_spinner_error "Failed to create or parse the service specification."
stop_spinner_success "Service specification created successfully (id=$SERVICE_SPECIFICATION_ID, slug=$SERVICE_SLUG)."

rm "$SERVICE_SPEC_PATH"
export SERVICE_SPECIFICATION_ID
export SERVICE_SLUG

# --- Step 3: Generate and Create Link Specification ---
gomplate --file "$LINK_SPEC_PATH.tpl" --out "$LINK_SPEC_PATH"

start_spinner "Creating the link specification in the platform."
{
LINK_SPEC_BODY=$(cat "$LINK_SPEC_PATH")
LINK_SPEC=$(np link specification create --body "$LINK_SPEC_BODY" --format json)
LINK_SPECIFICATION_ID=$(echo "$LINK_SPEC" | jq -r .id)
LINK_SLUG=$(echo "$LINK_SPEC" | jq -r .slug)
} || stop_spinner_error "Failed to create or parse the service specification."
stop_spinner_success "Link specification created successfully (id=$LINK_SPECIFICATION_ID, slug=$LINK_SLUG)."

rm "$LINK_SPEC_PATH"
export LINK_SPECIFICATION_ID
export LINK_SLUG

# --- Step 4: Create Action Specifications ---

find "$LINK_ACTION_DIR" -type f -name "*.tpl" | while read -r TEMPLATE_FILE; do
REL_PATH="${TEMPLATE_FILE#$LINK_ACTION_DIR/}"
OUTPUT_PATH="$LINK_ACTION_DIR/${REL_PATH%.tpl}"

gomplate --file "$TEMPLATE_FILE" --out "$OUTPUT_PATH"

ACTION_SPEC_BODY=$(cat "$OUTPUT_PATH")

start_spinner "Registering action specification: ${REL_PATH%.json.tpl}."
{
ACTION_SPEC=$(np link specification action specification create \
--linkSpecificationId "$LINK_SPECIFICATION_ID" \
--body "$ACTION_SPEC_BODY" \
--format json)
ACTION_SPEC_ID=$(echo "$ACTION_SPEC" | jq -r .id)
} || stop_spinner_error "Failed to create action specification: $REL_PATH."

rm "$OUTPUT_PATH"
stop_spinner_success "Action specification created successfully (id=$ACTION_SPEC_ID)."
done

find "$SERVICE_ACTION_DIR" -type f -name "*.tpl" | while read -r TEMPLATE_FILE; do
REL_PATH="${TEMPLATE_FILE#$SERVICE_ACTION_DIR/}"
OUTPUT_PATH="$SERVICE_ACTION_DIR/${REL_PATH%.tpl}"

gomplate --file "$TEMPLATE_FILE" --out "$OUTPUT_PATH"

ACTION_SPEC_BODY=$(cat "$OUTPUT_PATH")

start_spinner "Registering action specification: ${REL_PATH%.json.tpl}."
{
ACTION_SPEC=$(np service specification action specification create \
--serviceSpecificationId "$SERVICE_SPECIFICATION_ID" \
--body "$ACTION_SPEC_BODY" \
--format json)
ACTION_SPEC_ID=$(echo "$ACTION_SPEC" | jq -r .id)
} || stop_spinner_error "Failed to create action specification: $REL_PATH."

rm "$OUTPUT_PATH"
stop_spinner_success "Action specification created successfully (id=$ACTION_SPEC_ID)."
done

# --- Step 5: Create Notification Channel ---

NOTIFICATION_CHANNEL_PATH="specs/notification-channel.json"

gomplate --file "$NOTIFICATION_CHANNEL_PATH.tpl" --out "$NOTIFICATION_CHANNEL_PATH"

start_spinner "Creating the notification channel."
{
NOTIFICATION_CHANNEL_BODY=$(cat "$NOTIFICATION_CHANNEL_PATH")
NOTIFICATION_CHANNEL=$(np notification channel create --format json --body "$NOTIFICATION_CHANNEL_BODY")
NOTIFICATION_CHANNEL_ID=$(echo "$NOTIFICATION_CHANNEL" | jq -r .id)
} || stop_spinner_error "Failed to create the notification channel."

rm "$NOTIFICATION_CHANNEL_PATH"
stop_spinner_success "Notification channel created successfully (id=$NOTIFICATION_CHANNEL_ID)."
172 changes: 172 additions & 0 deletions endpoint-exposer/container-scope-override/deployment/sync_exposer
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
#!/bin/bash

echo "=== DEBUG: Starting sync_exposer script ==="

APPLICATION_NRN=$(jq -r .application.nrn <<< "$CONTEXT")

echo "SERVICE SPECIFICATION SLUG: $SERVICE_SPECIFICATION_SLUG, APPLICATION_NRN: $APPLICATION_NRN"

# Step 1: Get service specification by slug
echo "DEBUG: Fetching service specifications..."
SERVICE_SPECS=$(np service specification list --nrn "$APPLICATION_NRN" --type dependency --format json)
SERVICE_SPEC=$(jq -c --arg slug "$SERVICE_SPECIFICATION_SLUG" '
.results
| map(select(.slug == $slug))
| .[0]
' <<< "$SERVICE_SPECS")

SERVICE_SPEC_ID=$(jq -r .id <<< "$SERVICE_SPEC")

if [[ -z "$SERVICE_SPEC_ID" || "$SERVICE_SPEC_ID" == "null" ]]; then
echo "Error: Could not find service specification with slug '$SERVICE_SPECIFICATION_SLUG'"
exit 1
fi

echo "DEBUG: SERVICE_SPEC_ID=$SERVICE_SPEC_ID"

# Step 2: Get service instance that matches the SERVICE_SPEC_ID
echo "DEBUG: Fetching services for application..."
SERVICES=$(np service list --nrn "$APPLICATION_NRN" --format json)

SERVICE=$(jq -c --arg spec_id "$SERVICE_SPEC_ID" '
.results
| map(select(.specification_id == $spec_id))
| .[0]
' <<< "$SERVICES")

SERVICE_ID=$(jq -r .id <<< "$SERVICE")

if [[ -z "$SERVICE_ID" || "$SERVICE_ID" == "null" ]]; then
echo "Could not find service instance for specification '$SERVICE_SPEC_ID', skipping exposer sync"
exit 0
fi

echo "DEBUG: SERVICE_ID=$SERVICE_ID"

# Step 3: Get service attributes as parameters
echo "DEBUG: Reading service attributes..."
SERVICE_DATA=$(np service read --id "$SERVICE_ID" --format json)
export PARAMETERS=$(jq -c .attributes <<< "$SERVICE_DATA")

echo "DEBUG: PARAMETERS=$PARAMETERS"

# Step 4: Get action specification with slug "update-<service-spec-slug>"
ACTION_SLUG="update-$SERVICE_SPECIFICATION_SLUG"
echo "DEBUG: Fetching action specifications (looking for slug: $ACTION_SLUG)..."
SERVICE_ACTIONS=$(np service specification action specification list --serviceSpecificationId "$SERVICE_SPEC_ID" --format json)

ACTION_SPEC=$(jq -c --arg slug "$ACTION_SLUG" '
.results
| map(select(.slug == $slug))
| .[0]
' <<< "$SERVICE_ACTIONS")

ACTION_SPEC_ID=$(jq -r .id <<< "$ACTION_SPEC")

if [[ -z "$ACTION_SPEC_ID" || "$ACTION_SPEC_ID" == "null" ]]; then
echo "Error: Could not find action specification with slug '$ACTION_SLUG' for service specification '$SERVICE_SPEC_ID'"
exit 1
fi

echo "DEBUG: ACTION_SPEC_ID=$ACTION_SPEC_ID"

# Step 5: Create service action with parameters (with retry for concurrency)
echo "DEBUG: Creating service action..."

MAX_CREATE_RETRIES=10
RETRY_DELAY=5
create_attempt=0
ACTION_ID=""

while [[ -z "$ACTION_ID" || "$ACTION_ID" == "null" ]]; do
((create_attempt++))
echo "DEBUG: Create attempt $create_attempt/$MAX_CREATE_RETRIES"

if [ "$create_attempt" -gt $MAX_CREATE_RETRIES ]; then
echo "Error: Maximum number of create attempts (${MAX_CREATE_RETRIES}) reached. Could not create action."
exit 1
fi

# Add delay before retry (except on first attempt)
if [ "$create_attempt" -gt 1 ]; then
echo "DEBUG: Waiting ${RETRY_DELAY} seconds before retry..."
sleep $RETRY_DELAY
fi

# Try to create the action
ACTION_RESPONSE=$(np service action create --serviceId "$SERVICE_ID" --body "$(jq -n --argjson params "$PARAMETERS" --arg spec_id "$ACTION_SPEC_ID" '{name: "update", parameters: $params, specification_id: $spec_id}')" --format json 2>&1 || true)

# Check if response contains an error about action already in progress
if echo "$ACTION_RESPONSE" | grep -q "already an action with status.*in_progress"; then
echo "DEBUG: Action already in progress detected"

# Try to find the existing in_progress action
echo "DEBUG: Attempting to find existing in_progress action..."
EXISTING_ACTIONS=$(np service action list --serviceId "$SERVICE_ID" --format json)
EXISTING_ACTION=$(echo "$EXISTING_ACTIONS" | jq -c --arg spec_id "$ACTION_SPEC_ID" '
.results
| map(select(.specification_id == $spec_id and .status == "in_progress"))
| .[0]
')

EXISTING_ACTION_ID=$(echo "$EXISTING_ACTION" | jq -r '.id // empty')

if [[ -n "$EXISTING_ACTION_ID" && "$EXISTING_ACTION_ID" != "null" ]]; then
echo "DEBUG: Found existing in_progress action with ID: $EXISTING_ACTION_ID"
ACTION_ID="$EXISTING_ACTION_ID"
echo "Using existing action instead of creating new one"
break
fi

echo "DEBUG: No existing action found, will retry..."
elif echo "$ACTION_RESPONSE" | grep -q '"error"'; then
echo "ERROR: Failed to create action: $ACTION_RESPONSE"
echo "DEBUG: Will retry after delay..."
else
# Success - extract action ID
ACTION_ID=$(echo "$ACTION_RESPONSE" | jq -r '.id // empty')

if [[ -n "$ACTION_ID" && "$ACTION_ID" != "null" ]]; then
echo "DEBUG: ACTION_ID=$ACTION_ID"
echo "Created endpoint exposer update action[id=$ACTION_ID], waiting for its completion"
break
else
echo "DEBUG: Could not extract ACTION_ID from response: $ACTION_RESPONSE"
echo "DEBUG: Will retry after delay..."
fi
fi
done

# Step 6: Wait for action to complete
MAX_ITERATIONS=20
iteration=0

echo "DEBUG: Starting polling loop for action status..."
while true; do
((iteration++))
echo "DEBUG: Iteration $iteration/$MAX_ITERATIONS"

if [ "$iteration" -gt $MAX_ITERATIONS ]; then
echo "Error: Maximum number of iterations (${MAX_ITERATIONS}) reached. Could not update the endpoint exposer."
exit 1
fi

echo "DEBUG: Reading action status..."
ACTION_RESPONSE=$(np service action read --serviceId "$SERVICE_ID" --id "$ACTION_ID" --format json)
ACTION_STATUS=$(jq -r .status <<< "$ACTION_RESPONSE")

echo "Checking endpoint exposer update action[id=$ACTION_ID, status=$ACTION_STATUS]"

if [[ "$ACTION_STATUS" == "success" ]]; then
echo "✅ Endpoint exposer successfully updated"
break
elif [[ "$ACTION_STATUS" == "failed" ]]; then
echo "❌ Could not update endpoint exposer, deployment will be rollbacked"
exit 1
fi

echo "DEBUG: Sleeping for 5 seconds..."
sleep 5
done

echo "=== DEBUG: sync_exposer script completed successfully ==="
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
steps:
- name: sync_exposer
type: script
file: "$OVERRIDES_PATH/deployment/sync_exposer"
after: apply
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
steps:
- name: sync_exposer
type: script
file: "$OVERRIDES_PATH/deployment/sync_exposer"
after: apply traffic
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
steps:
- name: sync_exposer
type: script
file: "$OVERRIDES_PATH/deployment/sync_exposer"
after: apply
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
steps:
- name: sync_exposer
type: script
file: "$OVERRIDES_PATH/deployment/sync_exposer"
after: apply
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
steps:
- name: sync_exposer
type: script
file: "$OVERRIDES_PATH/deployment/sync_exposer"
after: apply
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
steps:
- name: sync_exposer
type: script
file: "$OVERRIDES_PATH/deployment/sync_exposer"
after: apply
3 changes: 3 additions & 0 deletions endpoint-exposer/container-scope-override/values.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
configuration:
SERVICE_SPECIFICATION_SLUG: endpoint-exposer

Loading