mirror of
https://github.com/juspay/hyperswitch.git
synced 2026-03-13 09:02:06 +08:00
fix: Unified scarf setup (#8238)
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -120,6 +120,7 @@ fabric.properties
|
||||
|
||||
### dotenv ###
|
||||
.env
|
||||
.oneclick-setup.env
|
||||
|
||||
### Linux ###
|
||||
*~
|
||||
@@ -145,7 +146,6 @@ fabric.properties
|
||||
# Icon must end with two \r
|
||||
Icon
|
||||
|
||||
|
||||
# Thumbnails
|
||||
._*
|
||||
|
||||
|
||||
@@ -11,6 +11,8 @@ services:
|
||||
prestart-hook:
|
||||
image: curlimages/curl-base:latest
|
||||
container_name: prestart-hook
|
||||
environment:
|
||||
- ONE_CLICK_SETUP=${ONE_CLICK_SETUP:-false}
|
||||
entrypoint:
|
||||
[
|
||||
"/bin/sh",
|
||||
@@ -29,7 +31,7 @@ services:
|
||||
networks:
|
||||
- router_net
|
||||
volumes:
|
||||
- pg_data:/VAR/LIB/POSTGRESQL/DATA
|
||||
- pg_data:/var/lib/postgresql/data
|
||||
environment:
|
||||
- POSTGRES_USER=db_user
|
||||
- POSTGRES_PASSWORD=db_pass
|
||||
@@ -108,23 +110,6 @@ services:
|
||||
start_period: 5s
|
||||
timeout: 5s
|
||||
|
||||
poststart-hook:
|
||||
image: curlimages/curl-base:latest
|
||||
container_name: poststart-hook
|
||||
depends_on:
|
||||
hyperswitch-server:
|
||||
condition: service_healthy # Ensures it only starts when `hyperswitch-server` is healthy
|
||||
entrypoint:
|
||||
[
|
||||
"/bin/sh",
|
||||
"-c",
|
||||
"apk add --no-cache bash jq && /bin/bash /poststart_hook.sh",
|
||||
]
|
||||
volumes:
|
||||
- ./scripts/poststart_hook.sh:/poststart_hook.sh
|
||||
networks:
|
||||
- router_net
|
||||
|
||||
hyperswitch-producer:
|
||||
image: docker.juspay.io/juspaydotin/hyperswitch-producer:standalone
|
||||
pull_policy: always
|
||||
@@ -223,6 +208,49 @@ services:
|
||||
labels:
|
||||
logs: "promtail"
|
||||
|
||||
create-default-user:
|
||||
image: curlimages/curl-base:latest
|
||||
container_name: create-default-user
|
||||
depends_on:
|
||||
hyperswitch-server:
|
||||
condition: service_healthy
|
||||
hyperswitch-control-center:
|
||||
condition: service_started
|
||||
environment:
|
||||
- HYPERSWITCH_SERVER_URL=http://hyperswitch-server:8080
|
||||
- HYPERSWITCH_CONTROL_CENTER_URL=http://hyperswitch-control-center:9000
|
||||
entrypoint:
|
||||
[
|
||||
"/bin/sh",
|
||||
"-c",
|
||||
"apk add --no-cache bash jq && /bin/bash /create_default_user.sh",
|
||||
]
|
||||
volumes:
|
||||
- ./scripts/create_default_user.sh:/create_default_user.sh
|
||||
networks:
|
||||
- router_net
|
||||
|
||||
poststart-hook:
|
||||
image: curlimages/curl-base:latest
|
||||
container_name: poststart-hook
|
||||
depends_on:
|
||||
create-default-user:
|
||||
condition: service_completed_successfully
|
||||
hyperswitch-server:
|
||||
condition: service_healthy # Ensures it only starts when `hyperswitch-server` is healthy
|
||||
environment:
|
||||
- ONE_CLICK_SETUP=${ONE_CLICK_SETUP:-false}
|
||||
entrypoint:
|
||||
[
|
||||
"/bin/sh",
|
||||
"-c",
|
||||
"apk add --no-cache bash jq && /bin/bash /poststart_hook.sh",
|
||||
]
|
||||
volumes:
|
||||
- ./scripts/poststart_hook.sh:/poststart_hook.sh
|
||||
networks:
|
||||
- router_net
|
||||
|
||||
### Clustered Redis setup
|
||||
redis-cluster:
|
||||
image: redis:7
|
||||
@@ -476,4 +504,4 @@ services:
|
||||
- HYPERSWITCH_CLIENT_URL=http://localhost:9050
|
||||
- HYPERSWITCH_SERVER_URL=http://localhost:8080
|
||||
labels:
|
||||
logs: "promtail"
|
||||
logs: "promtail"
|
||||
138
scripts/create_default_user.sh
Normal file
138
scripts/create_default_user.sh
Normal file
@@ -0,0 +1,138 @@
|
||||
#! /usr/bin/env bash
|
||||
EMAIL="demo@hyperswitch.com"
|
||||
PASSWORD="Hyperswitch@123"
|
||||
# Initialize merchant_id and profile_id to empty strings
|
||||
merchant_id=""
|
||||
profile_id=""
|
||||
|
||||
# Test the health endpoint first to ensure the API is responsive
|
||||
health_response=$(curl -s -w "\\nStatus_Code:%{http_code}" "${HYPERSWITCH_SERVER_URL}/health")
|
||||
health_status_code=$(echo "${health_response}" | grep "Status_Code:" | cut -d':' -f2)
|
||||
health_response_body=$(echo "${health_response}" | head -n1)
|
||||
|
||||
# Try signin first
|
||||
signin_payload="{\"email\":\"${EMAIL}\",\"password\":\"${PASSWORD}\"}"
|
||||
signin_response=$(curl -s -X POST -H "Content-Type: application/json" -H "api-key: hyperswitch" -H "User-Agent: HyperSwitch-Shell-Client/1.0" -H "Referer: ${HYPERSWITCH_CONTROL_CENTER_URL}/" -d "${signin_payload}" "${HYPERSWITCH_SERVER_URL}/user/signin")
|
||||
|
||||
# Check if user needs to be created
|
||||
if [[ $(
|
||||
echo "${signin_response}" | grep -q "error"
|
||||
echo $?
|
||||
) -eq 0 ]]; then
|
||||
# User doesn't exist or login failed, create new account
|
||||
signup_payload="{\"email\":\"${EMAIL}\",\"password\":\"${PASSWORD}\",\"country\":\"IN\"}"
|
||||
|
||||
# Only try signing up once - using exact headers from browser
|
||||
# For making signup request without verbose logging
|
||||
signup_cmd="curl -s -X POST '${HYPERSWITCH_SERVER_URL}/user/signup' \
|
||||
-H 'Accept: */*' \
|
||||
-H 'Accept-Language: en-GB,en-US;q=0.9,en;q=0.8' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-H 'Origin: ${HYPERSWITCH_CONTROL_CENTER_URL}' \
|
||||
-H 'Referer: ${HYPERSWITCH_CONTROL_CENTER_URL}/' \
|
||||
-H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36' \
|
||||
-H 'api-key: hyperswitch' \
|
||||
-d '${signup_payload}'"
|
||||
|
||||
signup_response=$(eval "${signup_cmd}")
|
||||
|
||||
# Extract token from signup response
|
||||
token=$(echo "${signup_response}" | grep -o '"token":"[^"]*"' | cut -d'"' -f4)
|
||||
token_type=$(echo "${signup_response}" | grep -o '"token_type":"[^"]*"' | cut -d'"' -f4)
|
||||
is_new_user=true
|
||||
else
|
||||
auth_response="${signin_response}"
|
||||
token=$(echo "${auth_response}" | grep -o '"token":"[^"]*"' | cut -d'"' -f4)
|
||||
token_type=$(echo "${auth_response}" | grep -o '"token_type":"[^"]*"' | cut -d'"' -f4)
|
||||
is_new_user=false
|
||||
fi
|
||||
|
||||
# Handle 2FA if needed
|
||||
if [ "${token_type}" = "totp" ]; then
|
||||
MAX_RETRIES=3
|
||||
for i in $(seq 1 ${MAX_RETRIES}); do
|
||||
terminate_response=$(curl -s -X GET -H "Content-Type: application/json" -H "api-key: hyperswitch" -H "authorization: Bearer ${token}" "${HYPERSWITCH_SERVER_URL}/user/2fa/terminate?skip_two_factor_auth=true")
|
||||
|
||||
new_token=$(echo "${terminate_response}" | grep -o '"token":"[^"]*"' | cut -d'"' -f4)
|
||||
if [ -n "${new_token}" ]; then
|
||||
token="${new_token}"
|
||||
break
|
||||
else
|
||||
if [ $i -lt ${MAX_RETRIES} ]; then
|
||||
sleep 1
|
||||
fi
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# Get user info
|
||||
if [ -n "${token}" ]; then
|
||||
user_info_cmd="curl -s -X GET -H 'Content-Type: application/json' -H 'api-key: hyperswitch' -H 'authorization: Bearer ${token}' '${HYPERSWITCH_SERVER_URL}/user'"
|
||||
user_info=$(eval "${user_info_cmd}")
|
||||
else
|
||||
user_info="{}"
|
||||
fi
|
||||
|
||||
merchant_id=$(echo "${user_info}" | grep -o '"merchant_id":"[^"]*"' | cut -d'"' -f4 || echo "")
|
||||
profile_id=$(echo "${user_info}" | grep -o '"profile_id":"[^"]*"' | cut -d'"' -f4 || echo "")
|
||||
|
||||
# Configure account for new users
|
||||
if [ "${is_new_user}" = true ] && [ -n "${merchant_id}" ] && [ -n "${token}" ]; then
|
||||
# Create merchant account
|
||||
merchant_payload="{\"merchant_id\":\"${merchant_id}\",\"merchant_name\":\"Test\"}"
|
||||
merchant_response=$(curl -s -X POST -H "Content-Type: application/json" -H "api-key: hyperswitch" -H "authorization: Bearer ${token}" -d "${merchant_payload}" "${HYPERSWITCH_SERVER_URL}/accounts/${merchant_id}")
|
||||
|
||||
# Configure connector
|
||||
connector_payload=$(
|
||||
cat <<EOF
|
||||
{
|
||||
"connector_type": "payment_processor",
|
||||
"profile_id": "${profile_id}",
|
||||
"connector_name": "paypal_test",
|
||||
"connector_label": "paypal_test_default",
|
||||
"disabled": false,
|
||||
"test_mode": true,
|
||||
"payment_methods_enabled": [
|
||||
{
|
||||
"payment_method": "card",
|
||||
"payment_method_types": [
|
||||
{
|
||||
"payment_method_type": "debit",
|
||||
"card_networks": [
|
||||
"Mastercard"
|
||||
],
|
||||
"minimum_amount": 0,
|
||||
"maximum_amount": 68607706,
|
||||
"recurring_enabled": true,
|
||||
"installment_payment_enabled": false
|
||||
},
|
||||
{
|
||||
"payment_method_type": "credit",
|
||||
"card_networks": [
|
||||
"Visa"
|
||||
],
|
||||
"minimum_amount": 0,
|
||||
"maximum_amount": 68607706,
|
||||
"recurring_enabled": true,
|
||||
"installment_payment_enabled": false
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {},
|
||||
"connector_account_details": {
|
||||
"api_key": "test_key",
|
||||
"auth_type": "HeaderKey"
|
||||
},
|
||||
"status": "active"
|
||||
}
|
||||
EOF
|
||||
)
|
||||
connector_response=$(curl -s -X POST -H "Content-Type: application/json" -H "api-key: hyperswitch" -H "authorization: Bearer ${token}" -d "${connector_payload}" "${HYPERSWITCH_SERVER_URL}/account/${merchant_id}/connectors")
|
||||
|
||||
# Silently check if configuration was successful without printing messages
|
||||
if [ -z "$(echo "${merchant_response}" | grep -o 'merchant_id')" ] || [ -z "$(echo "${connector_response}" | grep -o 'connector_id')" ]; then
|
||||
# Only log to debug log if we want to troubleshoot later
|
||||
: # No-op command
|
||||
fi
|
||||
fi
|
||||
24
scripts/notify_scarf.sh
Executable file
24
scripts/notify_scarf.sh
Executable file
@@ -0,0 +1,24 @@
|
||||
#! /usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
# Define the URL and parameters
|
||||
SCARF_URL="https://hyperswitch.gateway.scarf.sh/docker"
|
||||
VERSION=$1
|
||||
INSTALLATION_STATUS=$2
|
||||
|
||||
CURL_COMMAND=("curl" "--get" "${SCARF_URL}" "--data-urlencode" "${VERSION}" "--data-urlencode" "${INSTALLATION_STATUS}")
|
||||
|
||||
# Calculate number of arguments and process remaining args (if any)
|
||||
if [ $# -gt 2 ]; then
|
||||
# Starting from the 3rd argument (index 2 in $@)
|
||||
for param in "${@:3}"; do
|
||||
CURL_COMMAND+=("--data-urlencode" "${param}")
|
||||
done
|
||||
fi
|
||||
|
||||
# Execute the curl command
|
||||
echo "Executing: ${CURL_COMMAND[@]}"
|
||||
"${CURL_COMMAND[@]}"
|
||||
|
||||
# Print confirmation
|
||||
echo "Request sent to ${SCARF_URL} with ${VERSION} and ${INSTALLATION_STATUS}"
|
||||
@@ -7,7 +7,13 @@ STATUS=""
|
||||
SERVER_BASE_URL="http://hyperswitch-server:8080"
|
||||
HYPERSWITCH_HEALTH_URL="${SERVER_BASE_URL}/health"
|
||||
HYPERSWITCH_DEEP_HEALTH_URL="${SERVER_BASE_URL}/health/ready"
|
||||
WEBHOOK_URL="https://hyperswitch.gateway.scarf.sh/docker"
|
||||
ONE_CLICK_SETUP="${ONE_CLICK_SETUP:-false}"
|
||||
|
||||
if [[ "${ONE_CLICK_SETUP}" == "true" ]]; then
|
||||
SCARF_URL="https://hyperswitch.gateway.scarf.sh/docker"
|
||||
else
|
||||
SCARF_URL="https://hyperswitch.gateway.scarf.sh/only-docker"
|
||||
fi
|
||||
|
||||
# Fetch health status
|
||||
echo "Fetching app server health status..."
|
||||
@@ -15,12 +21,12 @@ HEALTH_RESPONSE=$(curl --silent --fail "${HYPERSWITCH_HEALTH_URL}") || HEALTH_RE
|
||||
|
||||
if [[ "${HEALTH_RESPONSE}" == "connection_error" ]]; then
|
||||
STATUS="error"
|
||||
ERROR_MESSAGE="404 response"
|
||||
ERROR_MESSAGE="500 response"
|
||||
|
||||
curl --get "${WEBHOOK_URL}" \
|
||||
curl --get "${SCARF_URL}" \
|
||||
--data-urlencode "version=${VERSION}" \
|
||||
--data-urlencode "status=${STATUS}" \
|
||||
--data-urlencode "error_message=${ERROR_MESSAGE}"
|
||||
--data-urlencode "error_message='${ERROR_MESSAGE}'"
|
||||
|
||||
echo "Webhook sent with connection error."
|
||||
exit 0
|
||||
@@ -33,10 +39,10 @@ echo "Fetching Hyperswitch health status..."
|
||||
HEALTH_RESPONSE=$(curl --silent "${HYPERSWITCH_DEEP_HEALTH_URL}")
|
||||
|
||||
# Prepare curl command
|
||||
CURL_COMMAND=("curl" "--get" "${WEBHOOK_URL}" "--data-urlencode" "version=${VERSION}")
|
||||
CURL_COMMAND=("curl" "--get" "${SCARF_URL}" "--data-urlencode" "version=${VERSION}")
|
||||
|
||||
# Check if the response contains an error
|
||||
if [[ "$(echo "${HEALTH_RESPONSE}" | jq --raw-output '.error')" != 'null' ]]; then
|
||||
if [[ "$(echo "${HEALTH_RESPONSE}" | jq --raw-output '.error')" != "null" ]]; then
|
||||
STATUS="error"
|
||||
ERROR_TYPE=$(echo "${HEALTH_RESPONSE}" | jq --raw-output '.error.type')
|
||||
ERROR_MESSAGE=$(echo "${HEALTH_RESPONSE}" | jq --raw-output '.error.message')
|
||||
@@ -48,17 +54,19 @@ if [[ "$(echo "${HEALTH_RESPONSE}" | jq --raw-output '.error')" != 'null' ]]; th
|
||||
"--data-urlencode" "error_message='${ERROR_MESSAGE}'"
|
||||
"--data-urlencode" "error_code='${ERROR_CODE}'"
|
||||
)
|
||||
else
|
||||
"${CURL_COMMAND[@]}"
|
||||
echo "Webhook sent with error status."
|
||||
exit 0
|
||||
elif [[ "${ONE_CLICK_SETUP}" == "false" ]]; then
|
||||
STATUS="success"
|
||||
CURL_COMMAND+=("--data-urlencode" "status=${STATUS}")
|
||||
|
||||
for key in $(echo "${HEALTH_RESPONSE}" | jq --raw-output 'keys_unsorted[]'); do
|
||||
value=$(echo "${HEALTH_RESPONSE}" | jq --raw-output --arg key "${key}" '.[$key]')
|
||||
CURL_COMMAND+=("--data-urlencode" "'${key}=${value}'")
|
||||
CURL_COMMAND+=("--data-urlencode" "${key}=${value}")
|
||||
done
|
||||
"${CURL_COMMAND[@]}"
|
||||
echo "Webhook notification sent for success status."
|
||||
else
|
||||
echo "ONE_CLICK_SETUP=true and status=success, skipping webhook call."
|
||||
fi
|
||||
|
||||
# Send the webhook request
|
||||
bash -c "${CURL_COMMAND[*]}"
|
||||
|
||||
echo "Webhook notification sent."
|
||||
|
||||
@@ -1,13 +1,21 @@
|
||||
#! /usr/bin/env bash
|
||||
set -euo pipefail
|
||||
|
||||
ONE_CLICK_SETUP="${ONE_CLICK_SETUP:-false}"
|
||||
|
||||
# Check if ONE_CLICK_SETUP is set to true; if so, skip execution
|
||||
if [ "${ONE_CLICK_SETUP}" = "true" ]; then
|
||||
echo "ONE_CLICK_SETUP is true; skipping script execution."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Define the URL and parameters
|
||||
WEBHOOK_URL="https://hyperswitch.gateway.scarf.sh/docker"
|
||||
SCARF_URL="https://hyperswitch.gateway.scarf.sh/only-docker"
|
||||
VERSION="unknown"
|
||||
STATUS="initiated"
|
||||
|
||||
# Send the GET request
|
||||
curl --get "${WEBHOOK_URL}" --data-urlencode "version=${VERSION}" --data-urlencode "status=${STATUS}"
|
||||
curl --get "${SCARF_URL}" --data-urlencode "version=${VERSION}" --data-urlencode "status=${STATUS}"
|
||||
|
||||
# Print confirmation
|
||||
echo "Request sent to ${WEBHOOK_URL} with version=${VERSION} and status=${STATUS}"
|
||||
echo "Request sent to ${SCARF_URL} with version=${VERSION} and status=${STATUS}"
|
||||
|
||||
498
scripts/setup.sh
498
scripts/setup.sh
@@ -1,5 +1,82 @@
|
||||
#!/usr/bin/env bash
|
||||
set -euo pipefail
|
||||
set -Eeuo pipefail
|
||||
|
||||
# Set up error logging - redirect stderr to both log file and console
|
||||
ERROR_LOG="error.log"
|
||||
exec 2> >(tee -a "${ERROR_LOG}" >&2)
|
||||
|
||||
# Set traps for errors and interruptions
|
||||
trap 'handle_error "$LINENO" "$BASH_COMMAND" "$?"' ERR
|
||||
trap 'handle_interrupt' INT TERM
|
||||
|
||||
# Variables for installation status
|
||||
VERSION="unknown"
|
||||
INSTALLATION_STATUS="initiated"
|
||||
SCARF_PARAMS=()
|
||||
|
||||
# Trap and handle any errors that occur during the script execution
|
||||
handle_error() {
|
||||
local lineno=$1
|
||||
local last_command=$2
|
||||
local exit_code=$3
|
||||
|
||||
# Capture recent error log content if available
|
||||
local log_content=""
|
||||
if [ -f "${ERROR_LOG}" ] && [ -s "${ERROR_LOG}" ]; then
|
||||
# Get last 5 lines of error log, escape for URL encoding
|
||||
log_content=$(tail -n 1 "${ERROR_LOG}" | tr '\n' '|' | sed 's/|$//')
|
||||
fi
|
||||
|
||||
# Set global vars used by scarf_call
|
||||
INSTALLATION_STATUS="error"
|
||||
ERROR_MESSAGE="Command '\$ ${last_command}' failed at line ${lineno} with exit code ${exit_code} and error logs: ${log_content:-'not available'}"
|
||||
|
||||
SCARF_PARAMS+=(
|
||||
"error_type=script_error"
|
||||
"error_message=${ERROR_MESSAGE}"
|
||||
"error_code=${exit_code}"
|
||||
)
|
||||
|
||||
scarf_call
|
||||
cleanup
|
||||
exit $exit_code
|
||||
}
|
||||
|
||||
# Handle user interruptions
|
||||
handle_interrupt() {
|
||||
echo ""
|
||||
echo_warning "Script interrupted by user"
|
||||
# Set appropriate error information for user abort
|
||||
INSTALLATION_STATUS="user_interrupt"
|
||||
|
||||
# Call scarf to report the interruption
|
||||
scarf_call
|
||||
cleanup
|
||||
exit 130
|
||||
}
|
||||
|
||||
cleanup() {
|
||||
# Clean up any started containers if we've selected a profile
|
||||
if [ -n "${PROFILE:-}" ]; then
|
||||
echo_info "Cleaning up any started containers..."
|
||||
case $PROFILE in
|
||||
standalone)
|
||||
$DOCKER_COMPOSE down >/dev/null 2>&1 || true
|
||||
;;
|
||||
standard)
|
||||
$DOCKER_COMPOSE down >/dev/null 2>&1 || true
|
||||
;;
|
||||
full)
|
||||
$DOCKER_COMPOSE --profile scheduler --profile monitoring --profile olap --profile full_setup down >/dev/null 2>&1 || true
|
||||
;;
|
||||
esac
|
||||
fi
|
||||
|
||||
# Optionally remove error log if it's empty or on successful completion
|
||||
if [ -f "${ERROR_LOG}" ]; then
|
||||
rm -f "${ERROR_LOG}"
|
||||
fi
|
||||
}
|
||||
|
||||
# ANSI color codes for pretty output
|
||||
RED='\033[0;31m'
|
||||
@@ -9,21 +86,6 @@ BLUE='\033[0;34m'
|
||||
BOLD='\033[1m'
|
||||
NC='\033[0m' # No Color
|
||||
|
||||
# Global cleanup function to handle error conditions and graceful exit
|
||||
cleanup() {
|
||||
# Restore strict error checking
|
||||
set -e
|
||||
# Remove any temporary files if needed
|
||||
# Add any necessary cleanup operations here
|
||||
|
||||
# The exit status passed to the function
|
||||
exit $1
|
||||
}
|
||||
|
||||
# Set up trap to call cleanup function on script exit or interruptions
|
||||
trap 'cleanup $?' EXIT
|
||||
trap 'cleanup 1' INT TERM
|
||||
|
||||
# Function to print colorful messages
|
||||
echo_info() {
|
||||
printf "${BLUE}[INFO]${NC} %s\n" "$1"
|
||||
@@ -43,7 +105,7 @@ echo_error() {
|
||||
|
||||
show_banner() {
|
||||
printf "${BLUE}${BOLD}\n"
|
||||
printf "\n"
|
||||
printf "\n"
|
||||
printf " # \n"
|
||||
printf " # # # #### ##### ## # # \n"
|
||||
printf " # # # # # # # # # # \n"
|
||||
@@ -51,15 +113,15 @@ show_banner() {
|
||||
printf " # # # # # ##### ###### # \n"
|
||||
printf " # # # # # # # # # # \n"
|
||||
printf " ##### #### #### # # # # \n"
|
||||
printf "\n"
|
||||
printf "\n"
|
||||
printf "\n"
|
||||
printf "\n"
|
||||
printf " # # # # ##### ###### ##### #### # # # ##### #### # # \n"
|
||||
printf " # # # # # # # # # # # # # # # # # # \n"
|
||||
printf " # # # # # ##### # # #### # # # # # ###### \n"
|
||||
printf " ####### # ##### # ##### # # ## # # # # # # \n"
|
||||
printf " # # # # # # # # # ## ## # # # # # # \n"
|
||||
printf " # # # # ###### # # #### # # # # #### # # \n"
|
||||
printf "\n"
|
||||
printf "\n"
|
||||
sleep 1
|
||||
printf "${NC}\n"
|
||||
printf "🚀 ${BLUE}One-Click Docker Setup${NC} 🚀\n"
|
||||
@@ -68,11 +130,11 @@ show_banner() {
|
||||
# Detect Docker Compose version
|
||||
detect_docker_compose() {
|
||||
# Check Docker or Podman
|
||||
if command -v docker &> /dev/null; then
|
||||
if command -v docker &>/dev/null; then
|
||||
CONTAINER_ENGINE="docker"
|
||||
echo_success "Docker is installed."
|
||||
echo ""
|
||||
elif command -v podman &> /dev/null; then
|
||||
elif command -v podman &>/dev/null; then
|
||||
CONTAINER_ENGINE="podman"
|
||||
echo_success "Podman is installed."
|
||||
echo ""
|
||||
@@ -85,17 +147,17 @@ detect_docker_compose() {
|
||||
fi
|
||||
|
||||
# Check Docker Compose or Podman Compose
|
||||
if $CONTAINER_ENGINE compose version &> /dev/null; then
|
||||
DOCKER_COMPOSE="$CONTAINER_ENGINE compose"
|
||||
echo_success "Compose is installed for $CONTAINER_ENGINE."
|
||||
if $CONTAINER_ENGINE compose version &>/dev/null; then
|
||||
DOCKER_COMPOSE="${CONTAINER_ENGINE} compose"
|
||||
echo_success "Compose is installed for ${CONTAINER_ENGINE}."
|
||||
echo ""
|
||||
else
|
||||
echo_error "Compose is not installed for $CONTAINER_ENGINE. Please install $CONTAINER_ENGINE compose to proceed."
|
||||
echo_error "Compose is not installed for ${CONTAINER_ENGINE}. Please install ${CONTAINER_ENGINE} compose to proceed."
|
||||
echo ""
|
||||
if [ "$CONTAINER_ENGINE" = "docker" ]; then
|
||||
if [ "${CONTAINER_ENGINE}" = "docker" ]; then
|
||||
echo_info "Visit https://docs.docker.com/compose/install/ for installation instructions."
|
||||
echo ""
|
||||
elif [ "$CONTAINER_ENGINE" = "podman" ]; then
|
||||
echo ""
|
||||
elif [ "${CONTAINER_ENGINE}" = "podman" ]; then
|
||||
echo_info "Visit https://podman-desktop.io/docs/compose/setting-up-compose for installation instructions."
|
||||
echo ""
|
||||
fi
|
||||
@@ -107,25 +169,25 @@ detect_docker_compose() {
|
||||
|
||||
check_prerequisites() {
|
||||
# Check curl
|
||||
if ! command -v curl &> /dev/null; then
|
||||
if ! command -v curl &>/dev/null; then
|
||||
echo_error "curl is not installed. Please install curl to proceed."
|
||||
echo ""
|
||||
exit 1
|
||||
fi
|
||||
echo_success "curl is installed."
|
||||
echo ""
|
||||
|
||||
|
||||
# Check ports
|
||||
required_ports=(8080 9000 9050 5432 6379 9060)
|
||||
unavailable_ports=()
|
||||
|
||||
|
||||
for port in "${required_ports[@]}"; do
|
||||
if command -v nc &> /dev/null; then
|
||||
if command -v nc &>/dev/null; then
|
||||
if nc -z localhost "$port" 2>/dev/null; then
|
||||
unavailable_ports+=("$port")
|
||||
fi
|
||||
elif command -v lsof &> /dev/null; then
|
||||
if lsof -i :"$port" &> /dev/null; then
|
||||
elif command -v lsof &>/dev/null; then
|
||||
if lsof -i :"$port" &>/dev/null; then
|
||||
unavailable_ports+=("$port")
|
||||
fi
|
||||
else
|
||||
@@ -134,7 +196,7 @@ check_prerequisites() {
|
||||
break
|
||||
fi
|
||||
done
|
||||
|
||||
|
||||
if [ ${#unavailable_ports[@]} -ne 0 ]; then
|
||||
echo_warning "The following ports are already in use: ${unavailable_ports[*]}"
|
||||
echo_warning "This might cause conflicts with Hyperswitch services."
|
||||
@@ -155,10 +217,19 @@ setup_config() {
|
||||
echo_error "Configuration file 'config/docker_compose.toml' not found. Please ensure the file exists and is correctly configured."
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Create an .env file for one-click setup
|
||||
local env_file=".oneclick-setup.env"
|
||||
echo "# One-Click Setup configuration" >"${env_file}"
|
||||
echo "# Generated on $(date)" >>"${env_file}"
|
||||
echo "" >>"${env_file}"
|
||||
|
||||
# Enable one-click setup mode
|
||||
echo "ONE_CLICK_SETUP=true" >>"${env_file}"
|
||||
}
|
||||
|
||||
select_profile() {
|
||||
printf "\n"
|
||||
select_profile() {
|
||||
printf "\n"
|
||||
printf "Select a setup option:\n"
|
||||
printf "1) ${YELLOW}Standard Setup${NC}: ${BLUE}[Recommended]${NC} Ideal for quick trial.\n"
|
||||
printf " Services included: ${BLUE}App Server, Control Center, PostgreSQL and Redis${NC}\n"
|
||||
@@ -170,283 +241,82 @@ select_profile() {
|
||||
printf " Services included: ${BLUE}App Server, PostgreSQL and Redis)${NC}\n"
|
||||
echo ""
|
||||
local profile_selected=false
|
||||
while [ "$profile_selected" = false ]; do
|
||||
while [ "${profile_selected}" = "false" ]; do
|
||||
echo -n "Enter your choice (1-3): "
|
||||
read -n 1 profile_choice
|
||||
echo
|
||||
|
||||
|
||||
case $profile_choice in
|
||||
1)
|
||||
PROFILE="standard"
|
||||
profile_selected=true
|
||||
;;
|
||||
2)
|
||||
PROFILE="full"
|
||||
profile_selected=true
|
||||
;;
|
||||
3)
|
||||
PROFILE="standalone"
|
||||
profile_selected=true
|
||||
;;
|
||||
*)
|
||||
echo_error "Invalid choice. Please enter 1, 2, or 3."
|
||||
;;
|
||||
1)
|
||||
PROFILE="standard"
|
||||
profile_selected=true
|
||||
;;
|
||||
2)
|
||||
PROFILE="full"
|
||||
profile_selected=true
|
||||
;;
|
||||
3)
|
||||
PROFILE="standalone"
|
||||
profile_selected=true
|
||||
;;
|
||||
*)
|
||||
echo_error "Invalid choice. Please enter 1, 2, or 3."
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
echo "Selected setup: $PROFILE"
|
||||
|
||||
echo "Selected setup: ${PROFILE}"
|
||||
}
|
||||
|
||||
scarf_call() {
|
||||
# Call the Scarf webhook endpoint with the provided parameters
|
||||
chmod +x scripts/notify_scarf.sh
|
||||
if [ ${#SCARF_PARAMS[@]} -eq 0 ]; then
|
||||
scripts/notify_scarf.sh "version=${VERSION}" "status=${INSTALLATION_STATUS}" >/dev/null 2>&1
|
||||
else
|
||||
scripts/notify_scarf.sh "version=${VERSION}" "status=${INSTALLATION_STATUS}" "${SCARF_PARAMS[@]}" >/dev/null 2>&1
|
||||
fi
|
||||
# Reset SCARF_PARAMS for the next call
|
||||
SCARF_PARAMS=()
|
||||
}
|
||||
|
||||
start_services() {
|
||||
|
||||
|
||||
case $PROFILE in
|
||||
standalone)
|
||||
$DOCKER_COMPOSE up -d pg redis-standalone migration_runner hyperswitch-server
|
||||
;;
|
||||
standard)
|
||||
$DOCKER_COMPOSE up -d
|
||||
;;
|
||||
full)
|
||||
$DOCKER_COMPOSE --profile scheduler --profile monitoring --profile olap --profile full_setup up -d
|
||||
;;
|
||||
standalone)
|
||||
$DOCKER_COMPOSE --env-file .oneclick-setup.env up -d pg redis-standalone migration_runner hyperswitch-server
|
||||
;;
|
||||
standard)
|
||||
$DOCKER_COMPOSE --env-file .oneclick-setup.env up -d
|
||||
;;
|
||||
full)
|
||||
$DOCKER_COMPOSE --env-file .oneclick-setup.env --profile scheduler --profile monitoring --profile olap --profile full_setup up -d
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
check_services_health() {
|
||||
# Wait for the hyperswitch-server to be healthy
|
||||
MAX_RETRIES=30
|
||||
RETRY_INTERVAL=5
|
||||
RETRIES=0
|
||||
|
||||
while [ $RETRIES -lt $MAX_RETRIES ]; do
|
||||
response=$(curl -s -w "\\nStatus_Code:%{http_code}" http://localhost:8080/health)
|
||||
status_code=$(echo "$response" | grep "Status_Code:" | cut -d':' -f2)
|
||||
response_body=$(echo "$response" | head -n1)
|
||||
|
||||
if [ "$status_code" = "200" ] && [ "$response_body" = "health is good" ]; then
|
||||
print_access_info
|
||||
return
|
||||
fi
|
||||
|
||||
RETRIES=$((RETRIES+1))
|
||||
if [ $RETRIES -eq $MAX_RETRIES ]; then
|
||||
printf "\n"
|
||||
echo_error "${RED}${BOLD}Hyperswitch server did not become healthy in the expected time."
|
||||
printf "Check logs with: $DOCKER_COMPOSE logs hyperswitch-server, Or reach out to us on slack(https://hyperswitch-io.slack.com/) for help.\n"
|
||||
printf "\n"
|
||||
else
|
||||
printf "Waiting for server to become healthy... (%d/%d)\n" $RETRIES $MAX_RETRIES
|
||||
sleep $RETRY_INTERVAL
|
||||
fi
|
||||
done
|
||||
}
|
||||
HYPERSWITCH_BASE_URL="http://localhost:8080"
|
||||
HYPERSWITCH_HEALTH_URL="${HYPERSWITCH_BASE_URL}/health"
|
||||
HYPERSWITCH_DEEP_HEALTH_URL="${HYPERSWITCH_BASE_URL}/health/ready"
|
||||
|
||||
configure_account() {
|
||||
# Temporarily disable strict error checking to prevent premature exit
|
||||
set +e
|
||||
local show_credentials_flag=false
|
||||
|
||||
BASE_URL="http://localhost:8080"
|
||||
EMAIL="demo@hyperswitch.com"
|
||||
PASSWORD="Hyperswitch@123"
|
||||
# Initialize merchant_id and profile_id to empty strings
|
||||
merchant_id=""
|
||||
profile_id=""
|
||||
|
||||
# Function to make API calls with proper headers
|
||||
make_api_call() {
|
||||
local method=$1
|
||||
local endpoint=$2
|
||||
local data=$3
|
||||
local auth_header=${4:-}
|
||||
|
||||
# Ensure endpoint starts with /user if it doesn't already
|
||||
if [[ ! $endpoint =~ ^/user && ! $endpoint =~ ^/health && ! $endpoint =~ ^/accounts && ! $endpoint =~ ^/account ]]; then
|
||||
endpoint="/user$endpoint"
|
||||
fi
|
||||
|
||||
local headers=(-H "Content-Type: application/json" -H "api-key: hyperswitch" -H "User-Agent: HyperSwitch-Shell-Client/1.0" -H "Referer: http://localhost:9000/")
|
||||
|
||||
if [ -n "$auth_header" ]; then
|
||||
headers+=(-H "authorization: Bearer $auth_header")
|
||||
fi
|
||||
|
||||
if [ -n "$merchant_id" ]; then
|
||||
headers+=(-H "X-Merchant-Id: $merchant_id")
|
||||
fi
|
||||
|
||||
if [ -n "$profile_id" ]; then
|
||||
headers+=(-H "X-Profile-Id: $profile_id")
|
||||
fi
|
||||
|
||||
local curl_cmd
|
||||
if [ "$method" = "GET" ]; then
|
||||
curl_cmd=(curl -s -X "$method" "${headers[@]}" "$BASE_URL$endpoint")
|
||||
else
|
||||
curl_cmd=(curl -s -X "$method" "${headers[@]}" -d "$data" "$BASE_URL$endpoint")
|
||||
fi
|
||||
|
||||
local retries=3
|
||||
local i=0
|
||||
while [ $i -lt $retries ]; do
|
||||
response=$("${curl_cmd[@]}")
|
||||
local response_code=$("${curl_cmd[@]}" -o /dev/null -s -w "%{http_code}")
|
||||
|
||||
if [ $response_code -lt 400 ]; then
|
||||
echo "$response"
|
||||
return 0
|
||||
fi
|
||||
|
||||
i=$((i+1))
|
||||
done
|
||||
return 1
|
||||
}
|
||||
|
||||
# Test the health endpoint first to ensure the API is responsive
|
||||
health_response=$(curl -s -w "\\nStatus_Code:%{http_code}" "$BASE_URL/health")
|
||||
health_status_code=$(echo "$health_response" | grep "Status_Code:" | cut -d':' -f2)
|
||||
health_response_body=$(echo "$health_response" | head -n1)
|
||||
|
||||
# Try signin first
|
||||
signin_payload="{\"email\":\"$EMAIL\",\"password\":\"$PASSWORD\"}"
|
||||
signin_response=$(make_api_call "POST" "/signin" "$signin_payload")
|
||||
status_code=$?
|
||||
|
||||
# Check if user needs to be created
|
||||
if [[ $status_code -ne 0 || $(echo "$signin_response" | grep -q "error"; echo $?) -eq 0 ]]; then
|
||||
# User doesn't exist or login failed, create new account
|
||||
signup_payload="{\"email\":\"$EMAIL\",\"password\":\"$PASSWORD\",\"country\":\"IN\"}"
|
||||
|
||||
# Only try signing up once - using exact headers from browser
|
||||
# For making signup request without verbose logging
|
||||
signup_cmd="curl -s -X POST '$BASE_URL/user/signup' \
|
||||
-H 'Accept: */*' \
|
||||
-H 'Accept-Language: en-GB,en-US;q=0.9,en;q=0.8' \
|
||||
-H 'Content-Type: application/json' \
|
||||
-H 'Origin: http://localhost:9000' \
|
||||
-H 'Referer: http://localhost:9000/' \
|
||||
-H 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/136.0.0.0 Safari/537.36' \
|
||||
-H 'api-key: hyperswitch' \
|
||||
-d '$signup_payload'"
|
||||
|
||||
signup_response=$(eval "$signup_cmd")
|
||||
|
||||
# Extract token from signup response
|
||||
token=$(echo "$signup_response" | grep -o '"token":"[^"]*"' | cut -d'"' -f4)
|
||||
token_type=$(echo "$signup_response" | grep -o '"token_type":"[^"]*"' | cut -d'"' -f4)
|
||||
|
||||
if [ -n "$token" ]; then
|
||||
show_credentials_flag=true
|
||||
fi
|
||||
is_new_user=true
|
||||
else
|
||||
auth_response="$signin_response"
|
||||
token=$(echo "$auth_response" | grep -o '"token":"[^"]*"' | cut -d'"' -f4)
|
||||
token_type=$(echo "$auth_response" | grep -o '"token_type":"[^"]*"' | cut -d'"' -f4)
|
||||
if [ -n "$token" ]; then
|
||||
show_credentials_flag=true
|
||||
fi
|
||||
is_new_user=false
|
||||
# Basic health check
|
||||
health_response=$(curl --silent --fail "${HYPERSWITCH_HEALTH_URL}") || exit 0
|
||||
if [ "${health_response}" != "health is good" ]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Handle 2FA if needed
|
||||
if [ "$token_type" = "totp" ]; then
|
||||
MAX_RETRIES=3
|
||||
for i in $(seq 1 $MAX_RETRIES); do
|
||||
terminate_response=$(curl -s -X GET -H "Content-Type: application/json" -H "api-key: hyperswitch" -H "authorization: Bearer $token" "$BASE_URL/user/2fa/terminate?skip_two_factor_auth=true")
|
||||
|
||||
new_token=$(echo "$terminate_response" | grep -o '"token":"[^"]*"' | cut -d'"' -f4)
|
||||
if [ -n "$new_token" ]; then
|
||||
token="$new_token"
|
||||
break
|
||||
else
|
||||
if [ $i -lt $MAX_RETRIES ]; then
|
||||
sleep 1
|
||||
fi
|
||||
fi
|
||||
done
|
||||
# Deep health check
|
||||
deep_health_response=$(curl --silent "${HYPERSWITCH_DEEP_HEALTH_URL}") || exit 0
|
||||
if [[ "$(echo "${deep_health_response}" | jq --raw-output '.error')" != "null" ]]; then
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Get user info
|
||||
if [ -n "$token" ]; then
|
||||
user_info_cmd="curl -s -X GET -H 'Content-Type: application/json' -H 'api-key: hyperswitch' -H 'authorization: Bearer $token' '$BASE_URL/user'"
|
||||
user_info=$(eval "$user_info_cmd")
|
||||
else
|
||||
user_info="{}"
|
||||
fi
|
||||
|
||||
merchant_id=$(echo "$user_info" | grep -o '"merchant_id":"[^"]*"' | cut -d'"' -f4 || echo "")
|
||||
profile_id=$(echo "$user_info" | grep -o '"profile_id":"[^"]*"' | cut -d'"' -f4 || echo "")
|
||||
|
||||
# Configure account for new users
|
||||
if [ "$is_new_user" = true ] && [ -n "$merchant_id" ] && [ -n "$token" ]; then
|
||||
# Create merchant account
|
||||
merchant_payload="{\"merchant_id\":\"$merchant_id\",\"merchant_name\":\"Test\"}"
|
||||
merchant_response=$(curl -s -X POST -H "Content-Type: application/json" -H "api-key: hyperswitch" -H "authorization: Bearer $token" -d "$merchant_payload" "$BASE_URL/accounts/$merchant_id")
|
||||
|
||||
# Configure connector
|
||||
connector_payload=$(cat <<EOF
|
||||
{
|
||||
"connector_type": "payment_processor",
|
||||
"profile_id": "$profile_id",
|
||||
"connector_name": "paypal_test",
|
||||
"connector_label": "paypal_test_default",
|
||||
"disabled": false,
|
||||
"test_mode": true,
|
||||
"payment_methods_enabled": [
|
||||
{
|
||||
"payment_method": "card",
|
||||
"payment_method_types": [
|
||||
{
|
||||
"payment_method_type": "debit",
|
||||
"card_networks": [
|
||||
"Mastercard"
|
||||
],
|
||||
"minimum_amount": 0,
|
||||
"maximum_amount": 68607706,
|
||||
"recurring_enabled": true,
|
||||
"installment_payment_enabled": false
|
||||
},
|
||||
{
|
||||
"payment_method_type": "credit",
|
||||
"card_networks": [
|
||||
"Visa"
|
||||
],
|
||||
"minimum_amount": 0,
|
||||
"maximum_amount": 68607706,
|
||||
"recurring_enabled": true,
|
||||
"installment_payment_enabled": false
|
||||
}
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {},
|
||||
"connector_account_details": {
|
||||
"api_key": "test_key",
|
||||
"auth_type": "HeaderKey"
|
||||
},
|
||||
"status": "active"
|
||||
}
|
||||
EOF
|
||||
)
|
||||
connector_response=$(curl -s -X POST -H "Content-Type: application/json" -H "api-key: hyperswitch" -H "authorization: Bearer $token" -d "$connector_payload" "$BASE_URL/account/$merchant_id/connectors")
|
||||
|
||||
# Silently check if configuration was successful without printing messages
|
||||
if [ -z "$(echo "$merchant_response" | grep -o 'merchant_id')" ] || [ -z "$(echo "$connector_response" | grep -o 'connector_id')" ]; then
|
||||
# Only log to debug log if we want to troubleshoot later
|
||||
: # No-op command
|
||||
fi
|
||||
fi
|
||||
|
||||
# Provide helpful information to the user regardless of success/failure
|
||||
if [ "$show_credentials_flag" = true ]; then
|
||||
printf " Use the following credentials:\n"
|
||||
printf " Email: $EMAIL\n"
|
||||
printf " Password: $PASSWORD\n"
|
||||
fi
|
||||
|
||||
# Restore strict error checking
|
||||
set -e
|
||||
# Extract version
|
||||
VERSION=$(curl --silent --output /dev/null --request GET --write-out '%header{x-hyperswitch-version}' "${HYPERSWITCH_BASE_URL}" | sed 's/-dirty$//')
|
||||
INSTALLATION_STATUS="success"
|
||||
print_access_info
|
||||
scarf_call
|
||||
}
|
||||
|
||||
print_access_info() {
|
||||
@@ -457,41 +327,49 @@ print_access_info() {
|
||||
printf "${NC}\n"
|
||||
|
||||
printf "${GREEN}${BOLD}Setup complete! You can now access Hyperswitch services at:${NC}\n"
|
||||
|
||||
|
||||
if [ "$PROFILE" != "standalone" ]; then
|
||||
printf " • ${GREEN}${BOLD}Control Center${NC}: ${BLUE}${BOLD}http://localhost:9000${NC}\n"
|
||||
configure_account || true
|
||||
fi
|
||||
|
||||
|
||||
printf " • ${GREEN}${BOLD}App Server${NC}: ${BLUE}${BOLD}http://localhost:8080${NC}\n"
|
||||
|
||||
|
||||
if [ "$PROFILE" = "full" ]; then
|
||||
printf " • ${GREEN}${BOLD}Monitoring (Grafana)${NC}: ${BLUE}${BOLD}http://localhost:3000${NC}\n"
|
||||
fi
|
||||
printf "\n"
|
||||
|
||||
# Default user credentials
|
||||
printf " Use the following credentials:\n"
|
||||
printf " Email: demo@hyperswitch.com\n"
|
||||
printf " Password: Hyperswitch@123\n"
|
||||
|
||||
printf "\n"
|
||||
|
||||
# Provide the stop command based on the selected profile
|
||||
echo_info "To stop all services, run the following command:"
|
||||
case $PROFILE in
|
||||
standalone)
|
||||
printf "${BLUE}$DOCKER_COMPOSE down${NC}\n"
|
||||
;;
|
||||
standard)
|
||||
printf "${BLUE}$DOCKER_COMPOSE down${NC}\n"
|
||||
;;
|
||||
full)
|
||||
printf "${BLUE}$DOCKER_COMPOSE --profile scheduler --profile monitoring --profile olap --profile full_setup down${NC}\n"
|
||||
;;
|
||||
standalone)
|
||||
printf "${BLUE}$DOCKER_COMPOSE down${NC}\n"
|
||||
;;
|
||||
standard)
|
||||
printf "${BLUE}$DOCKER_COMPOSE down${NC}\n"
|
||||
;;
|
||||
full)
|
||||
printf "${BLUE}$DOCKER_COMPOSE --profile scheduler --profile monitoring --profile olap --profile full_setup down${NC}\n"
|
||||
;;
|
||||
esac
|
||||
printf "\n"
|
||||
printf "Reach out to us on ${BLUE}https://hyperswitch-io.slack.com${NC} in case you face any issues.\n"
|
||||
}
|
||||
|
||||
# Main execution flow
|
||||
scarf_call
|
||||
show_banner
|
||||
detect_docker_compose
|
||||
check_prerequisites
|
||||
source .oneclick-setup.env
|
||||
setup_config
|
||||
select_profile
|
||||
start_services
|
||||
check_services_health # This will call print_access_info if the server is healthy
|
||||
check_services_health
|
||||
|
||||
Reference in New Issue
Block a user