chore: import upstream snapshot with attribution
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,11 @@
|
||||
# Preset helpers for setup-managed overrides.
|
||||
|
||||
apply_preset_overwrite() {
|
||||
local entry key value
|
||||
|
||||
for entry in "$@"; do
|
||||
key="${entry%%=*}"
|
||||
value="${entry#*=}"
|
||||
ENV_VALUES["$key"]="$value"
|
||||
done
|
||||
}
|
||||
@@ -0,0 +1,286 @@
|
||||
# Prompt helpers for interactive setup.
|
||||
|
||||
CLEAR_INPUT_SENTINEL="__LIGHTRAG_CLEAR__"
|
||||
|
||||
_truncate_for_display() {
|
||||
local value="$1"
|
||||
local max=50
|
||||
if [[ ${#value} -gt $max ]]; then
|
||||
printf '%s' "${value:0:$max}..."
|
||||
else
|
||||
printf '%s' "$value"
|
||||
fi
|
||||
}
|
||||
|
||||
mask_sensitive_input() {
|
||||
local prompt="$1"
|
||||
local value
|
||||
|
||||
read -r -p "$prompt" value
|
||||
printf '%s' "$value"
|
||||
}
|
||||
|
||||
prompt_secret_with_default() {
|
||||
local prompt="$1"
|
||||
local default="${2:-}"
|
||||
local value
|
||||
|
||||
if [[ -n "$default" ]]; then
|
||||
local display_default
|
||||
display_default="$(_truncate_for_display "$default")"
|
||||
read -r -p "$prompt [${display_default}]: " value
|
||||
else
|
||||
read -r -p "$prompt" value
|
||||
fi
|
||||
|
||||
if [[ -z "$value" ]]; then
|
||||
value="$default"
|
||||
fi
|
||||
|
||||
printf '%s' "$value"
|
||||
}
|
||||
|
||||
prompt_clearable_with_default() {
|
||||
local prompt="$1"
|
||||
local default="${2:-}"
|
||||
local value
|
||||
local prompt_text="$prompt"
|
||||
|
||||
if [[ -n "$default" ]]; then
|
||||
prompt_text="$prompt (Enter to keep, type 'clear' to remove)"
|
||||
else
|
||||
prompt_text="$prompt (type 'clear' to remove)"
|
||||
fi
|
||||
|
||||
value="$(prompt_with_default "$prompt_text" "$default")"
|
||||
if [[ "${value,,}" == "clear" ]]; then
|
||||
printf '%s' "$CLEAR_INPUT_SENTINEL"
|
||||
return 0
|
||||
fi
|
||||
|
||||
printf '%s' "$value"
|
||||
}
|
||||
|
||||
prompt_clearable_secret_with_default() {
|
||||
local prompt="$1"
|
||||
local default="${2:-}"
|
||||
local value
|
||||
local prompt_text="$prompt"
|
||||
|
||||
if [[ -n "$default" ]]; then
|
||||
prompt_text="$prompt (Enter to keep, type 'clear' to remove)"
|
||||
else
|
||||
prompt_text="$prompt (type 'clear' to remove)"
|
||||
fi
|
||||
|
||||
value="$(prompt_secret_with_default "$prompt_text" "$default")"
|
||||
if [[ "${value,,}" == "clear" ]]; then
|
||||
printf '%s' "$CLEAR_INPUT_SENTINEL"
|
||||
return 0
|
||||
fi
|
||||
|
||||
printf '%s' "$value"
|
||||
}
|
||||
|
||||
prompt_with_default() {
|
||||
local prompt="$1"
|
||||
local default="$2"
|
||||
local value
|
||||
|
||||
if [[ -n "$default" ]]; then
|
||||
read -r -p "$prompt [$default]: " value
|
||||
else
|
||||
read -r -p "$prompt: " value
|
||||
fi
|
||||
|
||||
if [[ -z "$value" ]]; then
|
||||
value="$default"
|
||||
fi
|
||||
|
||||
printf '%s' "$value"
|
||||
}
|
||||
|
||||
style_prompt_text() {
|
||||
local prompt="$1"
|
||||
|
||||
if [[ -n "${COLOR_YELLOW:-}" && "$prompt" == *Docker* ]]; then
|
||||
prompt="${prompt//Docker/${COLOR_YELLOW}Docker${COLOR_RESET}}"
|
||||
fi
|
||||
|
||||
printf '%s' "$prompt"
|
||||
}
|
||||
|
||||
confirm_default_no() {
|
||||
local prompt="$1"
|
||||
local response
|
||||
local styled_prompt
|
||||
|
||||
styled_prompt="$(style_prompt_text "$prompt")"
|
||||
while true; do
|
||||
read -r -n 1 -p "$styled_prompt [y/N]: " response
|
||||
echo
|
||||
case "$response" in
|
||||
y|Y) return 0 ;;
|
||||
n|N|"") return 1 ;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
confirm_default_yes() {
|
||||
local prompt="$1"
|
||||
local response
|
||||
local styled_prompt
|
||||
|
||||
styled_prompt="$(style_prompt_text "$prompt")"
|
||||
while true; do
|
||||
read -r -n 1 -p "$styled_prompt [Y/n]: " response
|
||||
echo
|
||||
case "$response" in
|
||||
y|Y|"") return 0 ;;
|
||||
n|N) return 1 ;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
confirm_required_yes_no() {
|
||||
local prompt="$1"
|
||||
local response
|
||||
local styled_prompt
|
||||
|
||||
styled_prompt="$(style_prompt_text "$prompt")"
|
||||
|
||||
while true; do
|
||||
printf '%b' "$styled_prompt [yes/no]: " >&2
|
||||
read -r response
|
||||
case "${response,,}" in
|
||||
yes) return 0 ;;
|
||||
no) return 1 ;;
|
||||
*)
|
||||
echo "Please type 'yes' or 'no'." >&2
|
||||
;;
|
||||
esac
|
||||
done
|
||||
}
|
||||
|
||||
prompt_until_valid() {
|
||||
local prompt="$1"
|
||||
local default="$2"
|
||||
local validator="$3"
|
||||
shift 3
|
||||
local value
|
||||
|
||||
while true; do
|
||||
value="$(prompt_with_default "$prompt" "$default")"
|
||||
if "$validator" "$value" "$@"; then
|
||||
printf '%s' "$value"
|
||||
return 0
|
||||
fi
|
||||
echo "Invalid value. Please try again."
|
||||
done
|
||||
}
|
||||
|
||||
prompt_secret_until_valid() {
|
||||
local prompt="$1"
|
||||
local validator="$2"
|
||||
shift 2
|
||||
local value
|
||||
|
||||
while true; do
|
||||
value="$(mask_sensitive_input "$prompt")"
|
||||
if "$validator" "$value" "$@"; then
|
||||
printf '%s' "$value"
|
||||
return 0
|
||||
fi
|
||||
echo "Invalid value. Please try again."
|
||||
done
|
||||
}
|
||||
|
||||
prompt_secret_until_valid_with_default() {
|
||||
local prompt="$1"
|
||||
local default="$2"
|
||||
local validator="$3"
|
||||
shift 3
|
||||
local value
|
||||
|
||||
while true; do
|
||||
value="$(prompt_secret_with_default "$prompt" "$default")"
|
||||
if "$validator" "$value" "$@"; then
|
||||
printf '%s' "$value"
|
||||
return 0
|
||||
fi
|
||||
echo "Invalid value. Please try again."
|
||||
done
|
||||
}
|
||||
|
||||
prompt_required_secret() {
|
||||
local prompt="$1"
|
||||
local value
|
||||
|
||||
while true; do
|
||||
value="$(mask_sensitive_input "$prompt")"
|
||||
if [[ -n "$value" ]]; then
|
||||
printf '%s' "$value"
|
||||
return 0
|
||||
fi
|
||||
echo "Value cannot be empty. Please try again."
|
||||
done
|
||||
}
|
||||
|
||||
prompt_choice() {
|
||||
local prompt="$1"
|
||||
local default="$2"
|
||||
shift 2
|
||||
local options=("$@")
|
||||
local choice
|
||||
local index=1
|
||||
local default_index=""
|
||||
local count="${#options[@]}"
|
||||
|
||||
for option in "${options[@]}"; do
|
||||
if [[ "$option" == "$default" ]]; then
|
||||
default_index="$index"
|
||||
fi
|
||||
index=$((index + 1))
|
||||
done
|
||||
|
||||
while true; do
|
||||
printf '%s\n' "${COLOR_BLUE}${prompt}${COLOR_RESET} options:" >&2
|
||||
index=1
|
||||
for option in "${options[@]}"; do
|
||||
if [[ "$index" == "$default_index" ]]; then
|
||||
printf ' %s) %s%s%s\n' \
|
||||
"${COLOR_GREEN}${index}${COLOR_RESET}" \
|
||||
"${COLOR_YELLOW}" \
|
||||
"$option" \
|
||||
"${COLOR_RESET}" >&2
|
||||
else
|
||||
printf ' %s) %s\n' "${COLOR_GREEN}${index}${COLOR_RESET}" "$option" >&2
|
||||
fi
|
||||
index=$((index + 1))
|
||||
done
|
||||
if [[ -n "$default_index" ]]; then
|
||||
printf 'Enter number (default: %s): ' "$default_index" >&2
|
||||
else
|
||||
printf 'Enter number: ' >&2
|
||||
fi
|
||||
|
||||
if ((count <= 9)); then
|
||||
read -r -n 1 choice
|
||||
printf '\n' >&2
|
||||
else
|
||||
read -r choice
|
||||
fi
|
||||
|
||||
if [[ -z "$choice" ]]; then
|
||||
if [[ -n "$default_index" ]]; then
|
||||
printf '%s' "${options[default_index-1]}"
|
||||
return 0
|
||||
fi
|
||||
elif [[ "$choice" =~ ^[0-9]+$ ]] && ((choice >= 1 && choice <= count)); then
|
||||
printf '%s' "${options[choice-1]}"
|
||||
return 0
|
||||
fi
|
||||
|
||||
printf '%s\n' "${COLOR_YELLOW}Invalid selection.${COLOR_RESET} Please enter a number between 1 and ${count}." >&2
|
||||
done
|
||||
}
|
||||
@@ -0,0 +1,84 @@
|
||||
# Storage backend options and required environment variables.
|
||||
# shellcheck disable=SC2034
|
||||
|
||||
declare -ag KV_STORAGE_OPTIONS=(
|
||||
"JsonKVStorage"
|
||||
"PGKVStorage"
|
||||
"MongoKVStorage"
|
||||
"OpenSearchKVStorage"
|
||||
"RedisKVStorage"
|
||||
)
|
||||
|
||||
declare -ag GRAPH_STORAGE_OPTIONS=(
|
||||
"NetworkXStorage"
|
||||
"PGGraphStorage"
|
||||
"MongoGraphStorage"
|
||||
"OpenSearchGraphStorage"
|
||||
"MemgraphStorage"
|
||||
"Neo4JStorage"
|
||||
)
|
||||
|
||||
declare -ag VECTOR_STORAGE_OPTIONS=(
|
||||
"NanoVectorDBStorage"
|
||||
"PGVectorStorage"
|
||||
"MongoVectorDBStorage"
|
||||
"OpenSearchVectorDBStorage"
|
||||
"MilvusVectorDBStorage"
|
||||
"FaissVectorDBStorage"
|
||||
"QdrantVectorDBStorage"
|
||||
)
|
||||
|
||||
declare -ag DOC_STATUS_STORAGE_OPTIONS=(
|
||||
"JsonDocStatusStorage"
|
||||
"PGDocStatusStorage"
|
||||
"MongoDocStatusStorage"
|
||||
"OpenSearchDocStatusStorage"
|
||||
"RedisDocStatusStorage"
|
||||
)
|
||||
|
||||
declare -Ag STORAGE_ENV_REQUIREMENTS=(
|
||||
["JsonKVStorage"]=""
|
||||
["MongoKVStorage"]="MONGO_URI MONGO_DATABASE"
|
||||
["RedisKVStorage"]="REDIS_URI"
|
||||
["PGKVStorage"]="POSTGRES_USER POSTGRES_PASSWORD POSTGRES_DATABASE"
|
||||
["OpenSearchKVStorage"]="OPENSEARCH_HOSTS OPENSEARCH_USER OPENSEARCH_PASSWORD"
|
||||
["NetworkXStorage"]=""
|
||||
["Neo4JStorage"]="NEO4J_URI NEO4J_USERNAME NEO4J_PASSWORD"
|
||||
["MongoGraphStorage"]="MONGO_URI MONGO_DATABASE"
|
||||
["MemgraphStorage"]="MEMGRAPH_URI"
|
||||
["PGGraphStorage"]="POSTGRES_USER POSTGRES_PASSWORD POSTGRES_DATABASE"
|
||||
["OpenSearchGraphStorage"]="OPENSEARCH_HOSTS OPENSEARCH_USER OPENSEARCH_PASSWORD"
|
||||
["NanoVectorDBStorage"]=""
|
||||
["MilvusVectorDBStorage"]="MILVUS_URI MILVUS_DB_NAME"
|
||||
["PGVectorStorage"]="POSTGRES_USER POSTGRES_PASSWORD POSTGRES_DATABASE"
|
||||
["FaissVectorDBStorage"]=""
|
||||
["QdrantVectorDBStorage"]="QDRANT_URL"
|
||||
["MongoVectorDBStorage"]="MONGO_URI MONGO_DATABASE"
|
||||
["OpenSearchVectorDBStorage"]="OPENSEARCH_HOSTS OPENSEARCH_USER OPENSEARCH_PASSWORD"
|
||||
["JsonDocStatusStorage"]=""
|
||||
["RedisDocStatusStorage"]="REDIS_URI"
|
||||
["PGDocStatusStorage"]="POSTGRES_USER POSTGRES_PASSWORD POSTGRES_DATABASE"
|
||||
["MongoDocStatusStorage"]="MONGO_URI MONGO_DATABASE"
|
||||
["OpenSearchDocStatusStorage"]="OPENSEARCH_HOSTS OPENSEARCH_USER OPENSEARCH_PASSWORD"
|
||||
)
|
||||
|
||||
declare -Ag STORAGE_DB_TYPES=(
|
||||
["MongoKVStorage"]="mongodb"
|
||||
["MongoGraphStorage"]="mongodb"
|
||||
["MongoVectorDBStorage"]="mongodb"
|
||||
["MongoDocStatusStorage"]="mongodb"
|
||||
["RedisKVStorage"]="redis"
|
||||
["RedisDocStatusStorage"]="redis"
|
||||
["PGKVStorage"]="postgresql"
|
||||
["PGGraphStorage"]="postgresql"
|
||||
["PGVectorStorage"]="postgresql"
|
||||
["PGDocStatusStorage"]="postgresql"
|
||||
["Neo4JStorage"]="neo4j"
|
||||
["MemgraphStorage"]="memgraph"
|
||||
["MilvusVectorDBStorage"]="milvus"
|
||||
["QdrantVectorDBStorage"]="qdrant"
|
||||
["OpenSearchKVStorage"]="opensearch"
|
||||
["OpenSearchGraphStorage"]="opensearch"
|
||||
["OpenSearchVectorDBStorage"]="opensearch"
|
||||
["OpenSearchDocStatusStorage"]="opensearch"
|
||||
)
|
||||
@@ -0,0 +1,528 @@
|
||||
# Validation helpers for interactive setup.
|
||||
|
||||
validate_uri() {
|
||||
local uri="$1"
|
||||
local db_type="$2"
|
||||
|
||||
if [[ -z "$uri" ]]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
case "$db_type" in
|
||||
postgresql)
|
||||
[[ "$uri" =~ ^postgres(ql)?://.+ ]]
|
||||
return $?; ;;
|
||||
neo4j)
|
||||
[[ "$uri" =~ ^(neo4j(\+s|\+ssc)?|bolt)://.+ ]]
|
||||
return $?; ;;
|
||||
mongodb)
|
||||
[[ "$uri" =~ ^mongodb(\+srv)?://.+ ]]
|
||||
return $?; ;;
|
||||
redis)
|
||||
[[ "$uri" =~ ^rediss?://.+ ]]
|
||||
return $?; ;;
|
||||
milvus|qdrant)
|
||||
[[ "$uri" =~ ^https?://.+ ]]
|
||||
return $?; ;;
|
||||
memgraph)
|
||||
[[ "$uri" =~ ^bolt://.+ ]]
|
||||
return $?; ;;
|
||||
*)
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
validate_api_key() {
|
||||
local key="$1"
|
||||
local provider="$2"
|
||||
|
||||
if [[ -z "$key" ]]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
case "$provider" in
|
||||
openai|openrouter)
|
||||
return 0; ;;
|
||||
*)
|
||||
[[ ${#key} -ge 8 ]]
|
||||
return $?; ;;
|
||||
esac
|
||||
}
|
||||
|
||||
validate_port() {
|
||||
local port="$1"
|
||||
|
||||
if [[ ! "$port" =~ ^[0-9]+$ ]]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if (( port < 1 || port > 65535 )); then
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
validate_positive_integer() {
|
||||
local value="$1"
|
||||
|
||||
if [[ ! "$value" =~ ^[0-9]+$ ]]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
(( 10#$value > 0 ))
|
||||
}
|
||||
|
||||
validate_non_negative_integer() {
|
||||
local value="$1"
|
||||
|
||||
if [[ ! "$value" =~ ^[0-9]+$ ]]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
(( 10#$value >= 0 ))
|
||||
}
|
||||
|
||||
validate_non_empty() {
|
||||
local value="$1"
|
||||
|
||||
[[ -n "$value" ]]
|
||||
}
|
||||
|
||||
validate_existing_file() {
|
||||
local path="$1"
|
||||
|
||||
[[ -n "$path" && -f "$path" ]]
|
||||
}
|
||||
|
||||
check_storage_compatibility() {
|
||||
local kv_storage="$1"
|
||||
local vector_storage="$2"
|
||||
local graph_storage="$3"
|
||||
local doc_status_storage="$4"
|
||||
local warnings=()
|
||||
|
||||
if [[ "$vector_storage" == "MongoVectorDBStorage" ]]; then
|
||||
warnings+=("MongoDB vector storage requires Atlas Search / Vector Search support, such as an Atlas cluster or Atlas Local deployment.")
|
||||
fi
|
||||
|
||||
if [[ "$graph_storage" == "Neo4JStorage" && "$kv_storage" == "JsonKVStorage" ]]; then
|
||||
warnings+=("Neo4j graph with JSON KV storage is fine for dev, but not ideal for production.")
|
||||
fi
|
||||
|
||||
if [[ "$graph_storage" == "NetworkXStorage" ]]; then
|
||||
warnings+=("NetworkX graph storage is memory-bound and suited for small datasets only.")
|
||||
fi
|
||||
|
||||
if [[ "$vector_storage" == "FaissVectorDBStorage" ]]; then
|
||||
warnings+=("Faiss vector storage is local-only and requires manual persistence management.")
|
||||
fi
|
||||
|
||||
if [[ "$kv_storage" == "JsonKVStorage" || "$doc_status_storage" == "JsonDocStatusStorage" ]]; then
|
||||
warnings+=("JSON-based KV/doc status storage is recommended only for local development.")
|
||||
fi
|
||||
|
||||
if ((${#warnings[@]} > 0)); then
|
||||
echo "${COLOR_YELLOW:-}Storage compatibility/performance warnings:${COLOR_RESET:-}" >&2
|
||||
for warning in "${warnings[@]}"; do
|
||||
echo " - $warning" >&2
|
||||
done
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
format_error() {
|
||||
local message="$1"
|
||||
local suggestion="${2:-}"
|
||||
|
||||
echo "${COLOR_RED:-}Error:${COLOR_RESET:-} $message" >&2
|
||||
if [[ -n "$suggestion" ]]; then
|
||||
echo "${COLOR_YELLOW:-}Hint:${COLOR_RESET:-} $suggestion" >&2
|
||||
fi
|
||||
}
|
||||
|
||||
contains_env_interpolation_syntax() {
|
||||
local value="$1"
|
||||
|
||||
[[ "$value" == *'${'* ]]
|
||||
}
|
||||
|
||||
is_sensitive_env_key() {
|
||||
local key="$1"
|
||||
|
||||
case "$key" in
|
||||
AUTH_ACCOUNTS|*API_KEY*|*ACCESS_KEY*|*PUBLIC_KEY*|*SECRET*|*PASSWORD*|*TOKEN*)
|
||||
return 0
|
||||
;;
|
||||
*)
|
||||
return 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
validate_sensitive_env_literals() {
|
||||
local key value
|
||||
local invalid_keys=()
|
||||
|
||||
for key in "${!ENV_VALUES[@]}"; do
|
||||
if ! is_sensitive_env_key "$key"; then
|
||||
continue
|
||||
fi
|
||||
|
||||
value="${ENV_VALUES[$key]:-}"
|
||||
if [[ -n "$value" ]] && contains_env_interpolation_syntax "$value"; then
|
||||
invalid_keys+=("$key")
|
||||
fi
|
||||
done
|
||||
|
||||
if ((${#invalid_keys[@]} > 0)); then
|
||||
format_error \
|
||||
"Sensitive values must not contain \${...} interpolation syntax: ${invalid_keys[*]}" \
|
||||
"Use literal values, plain \$ characters, or inject those secrets via runtime environment variables instead of .env."
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
validate_required_variables() {
|
||||
local storages=("$@")
|
||||
local missing=()
|
||||
local unknown=()
|
||||
local storage required var
|
||||
|
||||
for storage in "${storages[@]}"; do
|
||||
if [[ -z "$storage" ]]; then
|
||||
continue
|
||||
fi
|
||||
if [[ ! -v "STORAGE_ENV_REQUIREMENTS[$storage]" ]]; then
|
||||
unknown+=("$storage")
|
||||
continue
|
||||
fi
|
||||
required="${STORAGE_ENV_REQUIREMENTS[$storage]}"
|
||||
if [[ -z "$required" ]]; then
|
||||
continue
|
||||
fi
|
||||
for var in $required; do
|
||||
if [[ -z "${ENV_VALUES[$var]:-}" ]]; then
|
||||
missing+=("$var")
|
||||
fi
|
||||
done
|
||||
done
|
||||
|
||||
if ((${#unknown[@]} > 0)); then
|
||||
format_error \
|
||||
"Unsupported storage selections: ${unknown[*]}" \
|
||||
"Use a supported LightRAG storage class name or rerun setup to pick a valid backend."
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ((${#missing[@]} > 0)); then
|
||||
format_error "Missing required variables: ${missing[*]}" "Fill them in .env or re-run setup."
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
validate_opensearch_hosts_format() {
|
||||
local hosts="${1:-${ENV_VALUES[OPENSEARCH_HOSTS]:-}}"
|
||||
local entry=""
|
||||
local trimmed=""
|
||||
local has_host="no"
|
||||
local -a entries=()
|
||||
|
||||
if [[ "$hosts" == *"://"* ]]; then
|
||||
format_error \
|
||||
"OPENSEARCH_HOSTS must use bare host:port entries, not URLs." \
|
||||
"Set comma-separated host:port values such as localhost:9200; control TLS with OPENSEARCH_USE_SSL."
|
||||
return 1
|
||||
fi
|
||||
|
||||
IFS=',' read -r -a entries <<< "$hosts"
|
||||
for entry in "${entries[@]}"; do
|
||||
trimmed="${entry#"${entry%%[![:space:]]*}"}"
|
||||
trimmed="${trimmed%"${trimmed##*[![:space:]]}"}"
|
||||
if [[ -z "$trimmed" ]]; then
|
||||
format_error \
|
||||
"OPENSEARCH_HOSTS must not contain empty host entries." \
|
||||
"Use comma-separated host:port values such as localhost:9200 or host1:9200,host2:9200."
|
||||
return 1
|
||||
fi
|
||||
has_host="yes"
|
||||
done
|
||||
|
||||
if [[ "$has_host" != "yes" ]]; then
|
||||
format_error \
|
||||
"OPENSEARCH_HOSTS must include at least one host:port entry." \
|
||||
"Set it to a value such as localhost:9200."
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
validate_opensearch_password_strength() {
|
||||
local password="${1:-${ENV_VALUES[OPENSEARCH_PASSWORD]:-}}"
|
||||
|
||||
if [[ ${#password} -lt 8 || ! "$password" =~ [A-Z] || ! "$password" =~ [a-z] || ! "$password" =~ [0-9] || ! "$password" =~ [^A-Za-z0-9] ]]; then
|
||||
format_error \
|
||||
"OpenSearch requires a strong OPENSEARCH_PASSWORD." \
|
||||
"Use at least 8 characters with uppercase, lowercase, number, and special character."
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
validate_opensearch_config() {
|
||||
local deployment_mode="${1:-${ENV_VALUES[LIGHTRAG_SETUP_OPENSEARCH_DEPLOYMENT]:-}}"
|
||||
local hosts="${2:-${ENV_VALUES[OPENSEARCH_HOSTS]:-}}"
|
||||
local user="${3:-${ENV_VALUES[OPENSEARCH_USER]:-}}"
|
||||
local password="${4:-${ENV_VALUES[OPENSEARCH_PASSWORD]:-}}"
|
||||
local num_shards="${5-${ENV_VALUES[OPENSEARCH_NUMBER_OF_SHARDS]-1}}"
|
||||
local num_replicas="${6-${ENV_VALUES[OPENSEARCH_NUMBER_OF_REPLICAS]-0}}"
|
||||
|
||||
if ! validate_opensearch_hosts_format "$hosts"; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [[ -z "$user" || -z "$password" ]]; then
|
||||
if [[ "$deployment_mode" == "docker" ]]; then
|
||||
format_error \
|
||||
"Bundled OpenSearch requires OPENSEARCH_USER and OPENSEARCH_PASSWORD." \
|
||||
"Set both variables or rerun setup; the managed Docker service starts with security enabled."
|
||||
else
|
||||
format_error \
|
||||
"OpenSearch requires both OPENSEARCH_USER and OPENSEARCH_PASSWORD." \
|
||||
"This setup wizard only supports authenticated OpenSearch clusters. Set both values or rerun setup."
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! validate_opensearch_password_strength "$password"; then
|
||||
if [[ "$deployment_mode" == "docker" ]]; then
|
||||
echo "${COLOR_YELLOW:-}Hint:${COLOR_RESET:-} The managed Docker image also enforces this password strength at startup." >&2
|
||||
fi
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! validate_positive_integer "$num_shards"; then
|
||||
format_error \
|
||||
"OPENSEARCH_NUMBER_OF_SHARDS must be a positive integer." \
|
||||
"Set it to 1 or greater, or rerun setup to regenerate the OpenSearch index settings."
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! validate_non_negative_integer "$num_replicas"; then
|
||||
format_error \
|
||||
"OPENSEARCH_NUMBER_OF_REPLICAS must be a non-negative integer." \
|
||||
"Set it to 0 or greater, or rerun setup to regenerate the OpenSearch index settings."
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
validate_mongo_vector_storage_config() {
|
||||
local vector_storage="$1"
|
||||
local mongo_uri="${2:-${ENV_VALUES[MONGO_URI]:-}}"
|
||||
local mongo_deployment="${3:-${ENV_VALUES[LIGHTRAG_SETUP_MONGODB_DEPLOYMENT]:-}}"
|
||||
|
||||
if [[ "$vector_storage" != "MongoVectorDBStorage" ]]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
if ! validate_uri "$mongo_uri" mongodb; then
|
||||
format_error \
|
||||
"MongoVectorDBStorage requires a valid MongoDB URI." \
|
||||
"Set MONGO_URI to a mongodb:// or mongodb+srv:// endpoint that supports Atlas Search / Vector Search."
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [[ "$mongo_deployment" == "docker" ]]; then
|
||||
if [[ ! "$mongo_uri" =~ ^mongodb://([^/?#]+@)?(mongodb|localhost|127\.0\.0\.1|0\.0\.0\.0):27017([/?#].*)?$ ]] || ! _mongo_uri_has_direct_connection_true "$mongo_uri"; then
|
||||
format_error \
|
||||
"MongoVectorDBStorage requires the bundled Atlas Local endpoint when LIGHTRAG_SETUP_MONGODB_DEPLOYMENT=docker." \
|
||||
"Set MONGO_URI to the wizard-managed local MongoDB URI, or remove the docker deployment marker and use a mongodb+srv:// Atlas cluster URI."
|
||||
return 1
|
||||
fi
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [[ "$mongo_uri" =~ ^mongodb\+srv:// ]]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
if ! _mongo_uri_has_direct_connection_true "$mongo_uri"; then
|
||||
format_error \
|
||||
"MongoVectorDBStorage requires an Atlas-capable MongoDB URI." \
|
||||
"Use a mongodb+srv:// Atlas cluster URI, a mongodb:// Atlas Local URI with ?directConnection=true, or rerun the wizard with the bundled Atlas Local Docker MongoDB service."
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
_mongo_uri_has_direct_connection_true() {
|
||||
local uri="$1"
|
||||
local direct_connection_pattern='[?&]directConnection=true([&#]|$)'
|
||||
|
||||
[[ "$uri" =~ ^mongodb:// ]] && [[ "$uri" =~ $direct_connection_pattern ]]
|
||||
}
|
||||
|
||||
validate_auth_accounts_format() {
|
||||
local auth_accounts="$1"
|
||||
local entry username password
|
||||
|
||||
if [[ -z "$auth_accounts" ]]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
if [[ "$auth_accounts" == ,* || "$auth_accounts" == *, || "$auth_accounts" == *",,"* ]]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
IFS=',' read -r -a entries <<< "$auth_accounts"
|
||||
for entry in "${entries[@]}"; do
|
||||
if [[ -z "$entry" || "$entry" != *:* ]]; then
|
||||
return 1
|
||||
fi
|
||||
|
||||
username="${entry%%:*}"
|
||||
password="${entry#*:}"
|
||||
if [[ -z "$username" || -z "$password" ]]; then
|
||||
return 1
|
||||
fi
|
||||
done
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
validate_auth_accounts_password_safety() {
|
||||
local auth_accounts="$1"
|
||||
local entry password normalized_password
|
||||
|
||||
if [[ -z "$auth_accounts" ]]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
IFS=',' read -r -a entries <<< "$auth_accounts"
|
||||
for entry in "${entries[@]}"; do
|
||||
password="${entry#*:}"
|
||||
normalized_password="${password,,}"
|
||||
if [[ "$normalized_password" == admin* || "$normalized_password" == pass* ]]; then
|
||||
return 1
|
||||
fi
|
||||
done
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
validate_auth_accounts_runtime_config() {
|
||||
local auth_accounts="$1"
|
||||
|
||||
if [[ -z "$auth_accounts" ]]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
if ! validate_auth_accounts_format "$auth_accounts"; then
|
||||
format_error \
|
||||
"AUTH_ACCOUNTS must use comma-separated user:password pairs." \
|
||||
"Use entries like admin:{bcrypt}<hash> or admin:secret,reader:another-secret."
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
whitelist_exposes_api_routes() {
|
||||
local whitelist_paths="$1"
|
||||
local entry trimmed_entry prefix
|
||||
local entries=()
|
||||
|
||||
IFS=',' read -r -a entries <<< "$whitelist_paths"
|
||||
for entry in "${entries[@]}"; do
|
||||
trimmed_entry="${entry#"${entry%%[![:space:]]*}"}"
|
||||
trimmed_entry="${trimmed_entry%"${trimmed_entry##*[![:space:]]}"}"
|
||||
[[ -z "$trimmed_entry" ]] && continue
|
||||
|
||||
if [[ "$trimmed_entry" == *"/*" ]]; then
|
||||
# Prefix match (mirrors get_combined_auth_dependency): the entry exempts
|
||||
# an /api route when "/api" starts with the prefix — which includes the
|
||||
# empty prefix produced by the catch-all "/*" — or the prefix is itself
|
||||
# under "/api/". The "/api/" boundary matters: "/apiary/*" only exempts
|
||||
# /apiary..., not /api/chat, so it must NOT be flagged.
|
||||
prefix="${trimmed_entry%/\*}"
|
||||
if [[ "/api" == "$prefix"* || "$prefix" == "/api/"* ]]; then
|
||||
return 0
|
||||
fi
|
||||
else
|
||||
# Exact match: only this literal path is exempted.
|
||||
if [[ "$trimmed_entry" == "/api" || "$trimmed_entry" == "/api/"* ]]; then
|
||||
return 0
|
||||
fi
|
||||
fi
|
||||
done
|
||||
|
||||
return 1
|
||||
}
|
||||
|
||||
validate_security_config() {
|
||||
local auth_accounts="${1:-${ENV_VALUES[AUTH_ACCOUNTS]:-}}"
|
||||
local token_secret="${2:-${ENV_VALUES[TOKEN_SECRET]:-}}"
|
||||
local _api_key="${3:-${ENV_VALUES[LIGHTRAG_API_KEY]:-}}"
|
||||
local _unused_flag="${4:-no}"
|
||||
local _unused_whitelist="${5:-${ENV_VALUES[WHITELIST_PATHS]:-}}"
|
||||
local _unused_whitelist_is_set="${6:-}"
|
||||
|
||||
if [[ -z "$auth_accounts" ]]; then
|
||||
return 0
|
||||
fi
|
||||
|
||||
if ! validate_auth_accounts_format "$auth_accounts"; then
|
||||
format_error \
|
||||
"AUTH_ACCOUNTS must use comma-separated user:password pairs." \
|
||||
"Use entries like admin:{bcrypt}<hash> or admin:secret,reader:another-secret."
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! validate_auth_accounts_password_safety "$auth_accounts"; then
|
||||
format_error \
|
||||
"AUTH_ACCOUNTS passwords must not start with 'admin' or 'pass'." \
|
||||
"Choose a less predictable password or use lightrag-hash-password to generate a {bcrypt} value."
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [[ -z "$token_secret" ]]; then
|
||||
format_error \
|
||||
"AUTH_ACCOUNTS is set but TOKEN_SECRET is missing." \
|
||||
"Set a non-empty JWT signing secret before enabling account-based authentication."
|
||||
return 1
|
||||
fi
|
||||
|
||||
if [[ "$token_secret" == "lightrag-jwt-default-secret-key!" ]]; then
|
||||
format_error \
|
||||
"TOKEN_SECRET must not use the built-in default value when AUTH_ACCOUNTS is enabled." \
|
||||
"Generate a unique JWT signing secret and update TOKEN_SECRET."
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
check_docker_availability() {
|
||||
if ! command -v docker >/dev/null 2>&1; then
|
||||
format_error "Docker is not installed or not in PATH." "Install Docker or disable docker service generation."
|
||||
return 1
|
||||
fi
|
||||
|
||||
if ! docker compose version >/dev/null 2>&1; then
|
||||
format_error "Docker Compose is not available." "Install the Docker Compose plugin or use docker-compose."
|
||||
return 1
|
||||
fi
|
||||
|
||||
return 0
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,16 @@
|
||||
memgraph:
|
||||
image: memgraph/memgraph:latest
|
||||
ports:
|
||||
- "${MEMGRAPH_BOLT_PORT:-7687}:7687"
|
||||
volumes:
|
||||
- memgraph_data:/var/lib/memgraph
|
||||
healthcheck:
|
||||
test:
|
||||
- CMD-SHELL
|
||||
- 'PORT_HEX="$(printf ''%04X'' 7687)"; cat /proc/net/tcp /proc/net/tcp6 2>/dev/null | grep -q ":$${PORT_HEX} "'
|
||||
interval: 5s
|
||||
timeout: 3s
|
||||
retries: 20
|
||||
start_period: 10s
|
||||
stop_grace_period: 30s
|
||||
restart: unless-stopped
|
||||
@@ -0,0 +1,73 @@
|
||||
milvus:
|
||||
image: milvusdb/milvus:v2.6.11-gpu
|
||||
command: ["milvus", "run", "standalone"]
|
||||
security_opt:
|
||||
- seccomp:unconfined
|
||||
environment:
|
||||
ETCD_ENDPOINTS: milvus-etcd:2379
|
||||
MINIO_ADDRESS: milvus-minio:9000
|
||||
MINIO_ACCESS_KEY_ID: "${MINIO_ACCESS_KEY_ID:?missing}"
|
||||
MINIO_SECRET_ACCESS_KEY: "${MINIO_SECRET_ACCESS_KEY:?missing}"
|
||||
ports:
|
||||
- "19530:19530"
|
||||
- "9091:9091"
|
||||
volumes:
|
||||
- milvus_data:/var/lib/milvus
|
||||
deploy:
|
||||
resources:
|
||||
reservations:
|
||||
devices:
|
||||
- driver: nvidia
|
||||
capabilities: ["gpu"]
|
||||
healthcheck:
|
||||
test:
|
||||
- CMD-SHELL
|
||||
- 'PORT_HEX="$(printf ''%04X'' 19530)"; cat /proc/net/tcp /proc/net/tcp6 2>/dev/null | grep -q ":$${PORT_HEX} "'
|
||||
interval: 5s
|
||||
timeout: 3s
|
||||
retries: 20
|
||||
start_period: 10s
|
||||
depends_on:
|
||||
milvus-etcd:
|
||||
condition: service_healthy
|
||||
milvus-minio:
|
||||
condition: service_healthy
|
||||
restart: unless-stopped
|
||||
|
||||
milvus-etcd:
|
||||
image: quay.io/coreos/etcd:v3.5.25
|
||||
environment:
|
||||
ETCD_AUTO_COMPACTION_MODE: revision
|
||||
ETCD_AUTO_COMPACTION_RETENTION: "1000"
|
||||
ETCD_QUOTA_BACKEND_BYTES: "4294967296"
|
||||
ETCD_SNAPSHOT_COUNT: "50000"
|
||||
volumes:
|
||||
- milvus-etcd_data:/etcd
|
||||
command: >
|
||||
etcd
|
||||
-advertise-client-urls=http://0.0.0.0:2379
|
||||
-listen-client-urls=http://0.0.0.0:2379
|
||||
-data-dir /etcd
|
||||
healthcheck:
|
||||
test: ["CMD", "etcdctl", "endpoint", "health"]
|
||||
interval: 30s
|
||||
timeout: 20s
|
||||
retries: 3
|
||||
stop_grace_period: 30s
|
||||
restart: unless-stopped
|
||||
|
||||
milvus-minio:
|
||||
image: minio/minio:RELEASE.2025-09-07T16-13-09Z
|
||||
environment:
|
||||
MINIO_ROOT_USER: "${MINIO_ACCESS_KEY_ID:?missing}"
|
||||
MINIO_ROOT_PASSWORD: "${MINIO_SECRET_ACCESS_KEY:?missing}"
|
||||
volumes:
|
||||
- milvus-minio_data:/minio_data
|
||||
command: minio server /minio_data --console-address ":9001"
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
|
||||
interval: 30s
|
||||
timeout: 20s
|
||||
retries: 3
|
||||
stop_grace_period: 30s
|
||||
restart: unless-stopped
|
||||
@@ -0,0 +1,67 @@
|
||||
milvus:
|
||||
image: milvusdb/milvus:v2.6.11
|
||||
command: ["milvus", "run", "standalone"]
|
||||
security_opt:
|
||||
- seccomp:unconfined
|
||||
environment:
|
||||
ETCD_ENDPOINTS: milvus-etcd:2379
|
||||
MINIO_ADDRESS: milvus-minio:9000
|
||||
MINIO_ACCESS_KEY_ID: "${MINIO_ACCESS_KEY_ID:?missing}"
|
||||
MINIO_SECRET_ACCESS_KEY: "${MINIO_SECRET_ACCESS_KEY:?missing}"
|
||||
ports:
|
||||
- "19530:19530"
|
||||
- "9091:9091"
|
||||
volumes:
|
||||
- milvus_data:/var/lib/milvus
|
||||
healthcheck:
|
||||
test:
|
||||
- CMD-SHELL
|
||||
- 'PORT_HEX="$(printf ''%04X'' 19530)"; cat /proc/net/tcp /proc/net/tcp6 2>/dev/null | grep -q ":$${PORT_HEX} "'
|
||||
interval: 5s
|
||||
timeout: 3s
|
||||
retries: 20
|
||||
start_period: 10s
|
||||
depends_on:
|
||||
milvus-etcd:
|
||||
condition: service_healthy
|
||||
milvus-minio:
|
||||
condition: service_healthy
|
||||
restart: unless-stopped
|
||||
|
||||
milvus-etcd:
|
||||
image: quay.io/coreos/etcd:v3.5.25
|
||||
environment:
|
||||
ETCD_AUTO_COMPACTION_MODE: revision
|
||||
ETCD_AUTO_COMPACTION_RETENTION: "1000"
|
||||
ETCD_QUOTA_BACKEND_BYTES: "4294967296"
|
||||
ETCD_SNAPSHOT_COUNT: "50000"
|
||||
volumes:
|
||||
- milvus-etcd_data:/etcd
|
||||
command: >
|
||||
etcd
|
||||
-advertise-client-urls=http://0.0.0.0:2379
|
||||
-listen-client-urls=http://0.0.0.0:2379
|
||||
-data-dir /etcd
|
||||
healthcheck:
|
||||
test: ["CMD", "etcdctl", "endpoint", "health"]
|
||||
interval: 30s
|
||||
timeout: 20s
|
||||
retries: 3
|
||||
stop_grace_period: 30s
|
||||
restart: unless-stopped
|
||||
|
||||
milvus-minio:
|
||||
image: minio/minio:RELEASE.2025-09-07T16-13-09Z
|
||||
environment:
|
||||
MINIO_ROOT_USER: "${MINIO_ACCESS_KEY_ID:?missing}"
|
||||
MINIO_ROOT_PASSWORD: "${MINIO_SECRET_ACCESS_KEY:?missing}"
|
||||
volumes:
|
||||
- milvus-minio_data:/minio_data
|
||||
command: minio server /minio_data --console-address ":9001"
|
||||
healthcheck:
|
||||
test: ["CMD", "curl", "-f", "http://localhost:9000/minio/health/live"]
|
||||
interval: 30s
|
||||
timeout: 20s
|
||||
retries: 3
|
||||
stop_grace_period: 30s
|
||||
restart: unless-stopped
|
||||
@@ -0,0 +1,11 @@
|
||||
mongodb:
|
||||
hostname: mongodb
|
||||
image: mongodb/mongodb-atlas-local:8
|
||||
ports:
|
||||
- "27017:27017"
|
||||
volumes:
|
||||
- mongo_data:/data/db
|
||||
- mongo_config_data:/data/configdb
|
||||
- mongo_mongot_data:/data/mongot
|
||||
stop_grace_period: 30s
|
||||
restart: unless-stopped
|
||||
@@ -0,0 +1,17 @@
|
||||
neo4j:
|
||||
image: neo4j:5-community
|
||||
ports:
|
||||
- "7474:7474"
|
||||
- "7687:7687"
|
||||
volumes:
|
||||
- neo4j_data:/data
|
||||
healthcheck:
|
||||
test:
|
||||
- CMD-SHELL
|
||||
- 'PORT_HEX="$(printf ''%04X'' 7687)"; cat /proc/net/tcp /proc/net/tcp6 2>/dev/null | grep -q ":$${PORT_HEX} "'
|
||||
interval: 5s
|
||||
timeout: 3s
|
||||
retries: 20
|
||||
start_period: 10s
|
||||
stop_grace_period: 30s
|
||||
restart: unless-stopped
|
||||
@@ -0,0 +1,50 @@
|
||||
opensearch:
|
||||
image: opensearchproject/opensearch:3
|
||||
environment:
|
||||
- discovery.type=single-node
|
||||
- OPENSEARCH_INITIAL_ADMIN_PASSWORD=${OPENSEARCH_PASSWORD:?missing}
|
||||
- OPENSEARCH_JAVA_OPTS=-Xms512m -Xmx512m
|
||||
ports:
|
||||
- "9200:9200"
|
||||
ulimits:
|
||||
memlock:
|
||||
soft: -1
|
||||
hard: -1
|
||||
nofile:
|
||||
soft: 65536
|
||||
hard: 65536
|
||||
volumes:
|
||||
- opensearch_data:/usr/share/opensearch/data
|
||||
healthcheck:
|
||||
test:
|
||||
- CMD-SHELL
|
||||
- 'PORT_HEX="$(printf ''%04X'' 9200)"; cat /proc/net/tcp /proc/net/tcp6 2>/dev/null | grep -q ":$${PORT_HEX} "'
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 30
|
||||
start_period: 30s
|
||||
stop_grace_period: 30s
|
||||
restart: unless-stopped
|
||||
|
||||
dashboards:
|
||||
image: opensearchproject/opensearch-dashboards:3
|
||||
environment:
|
||||
OPENSEARCH_HOSTS: '["https://opensearch:9200"]'
|
||||
OPENSEARCH_USERNAME: admin
|
||||
OPENSEARCH_PASSWORD: "${OPENSEARCH_PASSWORD:?missing}"
|
||||
OPENSEARCH_SSL_VERIFICATIONMODE: none
|
||||
ports:
|
||||
- "5601:5601"
|
||||
healthcheck:
|
||||
test:
|
||||
- CMD-SHELL
|
||||
- 'PORT_HEX="$(printf ''%04X'' 5601)"; cat /proc/net/tcp /proc/net/tcp6 2>/dev/null | grep -q ":$${PORT_HEX} "'
|
||||
interval: 10s
|
||||
timeout: 5s
|
||||
retries: 30
|
||||
start_period: 30s
|
||||
depends_on:
|
||||
opensearch:
|
||||
condition: service_healthy
|
||||
stop_grace_period: 30s
|
||||
restart: unless-stopped
|
||||
@@ -0,0 +1,16 @@
|
||||
postgres:
|
||||
image: gzdaniel/postgres-for-rag:pg18-age-pgvector
|
||||
ports:
|
||||
- "5432:5432"
|
||||
volumes:
|
||||
- postgres_data:/var/lib/postgresql
|
||||
healthcheck:
|
||||
test:
|
||||
- CMD-SHELL
|
||||
- 'PORT_HEX="$(printf ''%04X'' 5432)"; cat /proc/net/tcp /proc/net/tcp6 2>/dev/null | grep -q ":$${PORT_HEX} "'
|
||||
interval: 5s
|
||||
timeout: 3s
|
||||
retries: 20
|
||||
start_period: 10s
|
||||
stop_grace_period: 30s
|
||||
restart: unless-stopped
|
||||
@@ -0,0 +1,22 @@
|
||||
qdrant:
|
||||
image: qdrant/qdrant:gpu-nvidia-latest
|
||||
ports:
|
||||
- "6333:6333"
|
||||
volumes:
|
||||
- qdrant_data:/qdrant/storage
|
||||
deploy:
|
||||
resources:
|
||||
reservations:
|
||||
devices:
|
||||
- driver: nvidia
|
||||
capabilities: ["gpu"]
|
||||
healthcheck:
|
||||
test:
|
||||
- CMD-SHELL
|
||||
- 'PORT_HEX="$(printf ''%04X'' 6333)"; cat /proc/net/tcp /proc/net/tcp6 2>/dev/null | grep -q ":$${PORT_HEX} "'
|
||||
interval: 5s
|
||||
timeout: 3s
|
||||
retries: 20
|
||||
start_period: 10s
|
||||
stop_grace_period: 30s
|
||||
restart: unless-stopped
|
||||
@@ -0,0 +1,16 @@
|
||||
qdrant:
|
||||
image: qdrant/qdrant:latest
|
||||
ports:
|
||||
- "6333:6333"
|
||||
volumes:
|
||||
- qdrant_data:/qdrant/storage
|
||||
healthcheck:
|
||||
test:
|
||||
- CMD-SHELL
|
||||
- 'PORT_HEX="$(printf ''%04X'' 6333)"; cat /proc/net/tcp /proc/net/tcp6 2>/dev/null | grep -q ":$${PORT_HEX} "'
|
||||
interval: 5s
|
||||
timeout: 3s
|
||||
retries: 20
|
||||
start_period: 10s
|
||||
stop_grace_period: 30s
|
||||
restart: unless-stopped
|
||||
@@ -0,0 +1,36 @@
|
||||
# redis.conf - setup-managed default for the bundled Redis service
|
||||
|
||||
# Network settings
|
||||
bind 0.0.0.0
|
||||
port 6379
|
||||
protected-mode no
|
||||
|
||||
# General settings
|
||||
daemonize no
|
||||
loglevel warning
|
||||
logfile "/data/redis.log"
|
||||
dir /data
|
||||
|
||||
# RDB persistence
|
||||
save 900 1
|
||||
save 300 10
|
||||
save 60 1000
|
||||
stop-writes-on-bgsave-error yes
|
||||
rdbcompression yes
|
||||
rdbchecksum yes
|
||||
dbfilename dump.rdb
|
||||
|
||||
# AOF persistence
|
||||
appendonly yes
|
||||
appendfilename "appendonly.aof"
|
||||
appendfsync everysec
|
||||
no-appendfsync-on-rewrite no
|
||||
auto-aof-rewrite-percentage 100
|
||||
auto-aof-rewrite-min-size 64mb
|
||||
|
||||
# Client limits
|
||||
maxclients 10000
|
||||
|
||||
# Memory management
|
||||
maxmemory 4gb
|
||||
maxmemory-policy noeviction
|
||||
@@ -0,0 +1,18 @@
|
||||
redis:
|
||||
image: redis:latest
|
||||
command: ["redis-server", "/usr/local/etc/redis/redis.conf"]
|
||||
ports:
|
||||
- "6379:6379"
|
||||
volumes:
|
||||
- redis_data:/data
|
||||
- ./data/config/redis.conf:/usr/local/etc/redis/redis.conf:ro
|
||||
healthcheck:
|
||||
test:
|
||||
- CMD-SHELL
|
||||
- 'PORT_HEX="$(printf ''%04X'' 6379)"; cat /proc/net/tcp /proc/net/tcp6 2>/dev/null | grep -q ":$${PORT_HEX} "'
|
||||
interval: 5s
|
||||
timeout: 3s
|
||||
retries: 20
|
||||
start_period: 10s
|
||||
stop_grace_period: 30s
|
||||
restart: unless-stopped
|
||||
@@ -0,0 +1,33 @@
|
||||
vllm-embed:
|
||||
image: vllm/vllm-openai:latest
|
||||
runtime: nvidia
|
||||
command: >
|
||||
--model ${VLLM_EMBED_MODEL:-BAAI/bge-m3}
|
||||
--port ${VLLM_EMBED_PORT:-8001}
|
||||
--dtype float16
|
||||
--api-key ${VLLM_EMBED_API_KEY}
|
||||
${VLLM_EMBED_EXTRA_ARGS:-}
|
||||
environment:
|
||||
NVIDIA_VISIBLE_DEVICES: ${NVIDIA_VISIBLE_DEVICES:-all}
|
||||
NVIDIA_DRIVER_CAPABILITIES: ${NVIDIA_DRIVER_CAPABILITIES:-compute,utility}
|
||||
ports:
|
||||
- "${VLLM_EMBED_PORT:-8001}:${VLLM_EMBED_PORT:-8001}"
|
||||
volumes:
|
||||
- vllm_embed_cache:/root/.cache/huggingface
|
||||
ipc: host
|
||||
healthcheck:
|
||||
test:
|
||||
- CMD-SHELL
|
||||
- 'PORT_HEX="$(printf ''%04X'' ${VLLM_EMBED_PORT:-8001})"; cat /proc/net/tcp /proc/net/tcp6 2>/dev/null | grep -q ":$${PORT_HEX} "'
|
||||
interval: 5s
|
||||
timeout: 3s
|
||||
retries: 120
|
||||
start_period: 10s
|
||||
deploy:
|
||||
resources:
|
||||
reservations:
|
||||
devices:
|
||||
- driver: nvidia
|
||||
count: all
|
||||
capabilities: [gpu]
|
||||
restart: unless-stopped
|
||||
@@ -0,0 +1,21 @@
|
||||
vllm-embed:
|
||||
image: vllm/vllm-openai-cpu:latest
|
||||
command: >
|
||||
--model ${VLLM_EMBED_MODEL:-BAAI/bge-m3}
|
||||
--port ${VLLM_EMBED_PORT:-8001}
|
||||
--dtype float32
|
||||
--api-key ${VLLM_EMBED_API_KEY}
|
||||
${VLLM_EMBED_EXTRA_ARGS:-}
|
||||
ports:
|
||||
- "${VLLM_EMBED_PORT:-8001}:${VLLM_EMBED_PORT:-8001}"
|
||||
volumes:
|
||||
- vllm_embed_cache:/root/.cache/huggingface
|
||||
healthcheck:
|
||||
test:
|
||||
- CMD-SHELL
|
||||
- 'PORT_HEX="$(printf ''%04X'' ${VLLM_EMBED_PORT:-8001})"; cat /proc/net/tcp /proc/net/tcp6 2>/dev/null | grep -q ":$${PORT_HEX} "'
|
||||
interval: 5s
|
||||
timeout: 3s
|
||||
retries: 120
|
||||
start_period: 10s
|
||||
restart: unless-stopped
|
||||
@@ -0,0 +1,33 @@
|
||||
vllm-rerank:
|
||||
image: vllm/vllm-openai:latest
|
||||
runtime: nvidia
|
||||
command: >
|
||||
--model ${VLLM_RERANK_MODEL:-BAAI/bge-reranker-v2-m3}
|
||||
--port ${VLLM_RERANK_PORT:-8000}
|
||||
--dtype float16
|
||||
--api-key ${VLLM_RERANK_API_KEY}
|
||||
${VLLM_RERANK_EXTRA_ARGS:-}
|
||||
environment:
|
||||
NVIDIA_VISIBLE_DEVICES: ${NVIDIA_VISIBLE_DEVICES:-all}
|
||||
NVIDIA_DRIVER_CAPABILITIES: ${NVIDIA_DRIVER_CAPABILITIES:-compute,utility}
|
||||
ports:
|
||||
- "${VLLM_RERANK_PORT:-8000}:${VLLM_RERANK_PORT:-8000}"
|
||||
volumes:
|
||||
- vllm_rerank_cache:/root/.cache/huggingface
|
||||
ipc: host
|
||||
healthcheck:
|
||||
test:
|
||||
- CMD-SHELL
|
||||
- 'PORT_HEX="$(printf ''%04X'' ${VLLM_RERANK_PORT:-8000})"; cat /proc/net/tcp /proc/net/tcp6 2>/dev/null | grep -q ":$${PORT_HEX} "'
|
||||
interval: 5s
|
||||
timeout: 3s
|
||||
retries: 120
|
||||
start_period: 10s
|
||||
deploy:
|
||||
resources:
|
||||
reservations:
|
||||
devices:
|
||||
- driver: nvidia
|
||||
count: all
|
||||
capabilities: [gpu]
|
||||
restart: unless-stopped
|
||||
@@ -0,0 +1,21 @@
|
||||
vllm-rerank:
|
||||
image: vllm/vllm-openai-cpu:latest
|
||||
command: >
|
||||
--model ${VLLM_RERANK_MODEL:-BAAI/bge-reranker-v2-m3}
|
||||
--port ${VLLM_RERANK_PORT:-8000}
|
||||
--dtype float32
|
||||
--api-key ${VLLM_RERANK_API_KEY}
|
||||
${VLLM_RERANK_EXTRA_ARGS:-}
|
||||
ports:
|
||||
- "${VLLM_RERANK_PORT:-8000}:${VLLM_RERANK_PORT:-8000}"
|
||||
volumes:
|
||||
- vllm_rerank_cache:/root/.cache/huggingface
|
||||
healthcheck:
|
||||
test:
|
||||
- CMD-SHELL
|
||||
- 'PORT_HEX="$(printf ''%04X'' ${VLLM_RERANK_PORT:-8000})"; cat /proc/net/tcp /proc/net/tcp6 2>/dev/null | grep -q ":$${PORT_HEX} "'
|
||||
interval: 5s
|
||||
timeout: 3s
|
||||
retries: 120
|
||||
start_period: 10s
|
||||
restart: unless-stopped
|
||||
Reference in New Issue
Block a user