feat: Add gateway environment variables support
- Add 'gateway_env_vars' configuration option to addon config - Parse semicolon-separated KEY=VALUE pairs from add-on options - Export environment variables to gateway process at startup - Store parsed env vars in openclaw.json (gateway.env) Allows users to pass custom environment variables to the gateway via Home Assistant add-on configuration, e.g.: gateway_env_vars: 'SERVICE_API_KEY=123;SERVICE2_API=1231' These variables are exported to the gateway process and can be used for API authentication, feature flags, or other configuration needs.
This commit is contained in:
@@ -88,6 +88,11 @@ options:
|
|||||||
# (can affect Telegram API polling in some HAOS/VM setups).
|
# (can affect Telegram API polling in some HAOS/VM setups).
|
||||||
force_ipv4_dns: false
|
force_ipv4_dns: false
|
||||||
|
|
||||||
|
# Environment variables to pass to the gateway (semicolon-separated key=value pairs)
|
||||||
|
# Example: "SERVICE_API=123;SERVICE2_API=1231"
|
||||||
|
# These will be exported as environment variables when running the gateway
|
||||||
|
gateway_env_vars: ""
|
||||||
|
|
||||||
|
|
||||||
schema:
|
schema:
|
||||||
timezone: str
|
timezone: str
|
||||||
@@ -109,3 +114,4 @@ schema:
|
|||||||
enable_openai_api: bool?
|
enable_openai_api: bool?
|
||||||
allow_insecure_auth: bool?
|
allow_insecure_auth: bool?
|
||||||
force_ipv4_dns: bool?
|
force_ipv4_dns: bool?
|
||||||
|
gateway_env_vars: str?
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ def set_gateway_setting(key, value):
|
|||||||
return write_config(cfg)
|
return write_config(cfg)
|
||||||
|
|
||||||
|
|
||||||
def apply_gateway_settings(mode: str, bind_mode: str, port: int, enable_openai_api: bool, allow_insecure_auth: bool):
|
def apply_gateway_settings(mode: str, bind_mode: str, port: int, enable_openai_api: bool, allow_insecure_auth: bool, env_vars: str = ""):
|
||||||
"""
|
"""
|
||||||
Apply gateway settings to OpenClaw config.
|
Apply gateway settings to OpenClaw config.
|
||||||
|
|
||||||
@@ -67,6 +67,7 @@ def apply_gateway_settings(mode: str, bind_mode: str, port: int, enable_openai_a
|
|||||||
port: Port number to listen on (must be 1-65535)
|
port: Port number to listen on (must be 1-65535)
|
||||||
enable_openai_api: Enable OpenAI-compatible Chat Completions endpoint
|
enable_openai_api: Enable OpenAI-compatible Chat Completions endpoint
|
||||||
allow_insecure_auth: Allow insecure HTTP authentication
|
allow_insecure_auth: Allow insecure HTTP authentication
|
||||||
|
env_vars: Semicolon-separated environment variables (e.g., "VAR1=value1;VAR2=value2")
|
||||||
"""
|
"""
|
||||||
# Validate gateway mode
|
# Validate gateway mode
|
||||||
if mode not in ["local", "remote"]:
|
if mode not in ["local", "remote"]:
|
||||||
@@ -112,6 +113,7 @@ def apply_gateway_settings(mode: str, bind_mode: str, port: int, enable_openai_a
|
|||||||
current_port = gateway.get("port", 18789)
|
current_port = gateway.get("port", 18789)
|
||||||
current_openai_api = chat_completions.get("enabled", False)
|
current_openai_api = chat_completions.get("enabled", False)
|
||||||
current_insecure = control_ui.get("allowInsecureAuth", False)
|
current_insecure = control_ui.get("allowInsecureAuth", False)
|
||||||
|
current_env_vars = gateway.get("env", {})
|
||||||
|
|
||||||
changes = []
|
changes = []
|
||||||
|
|
||||||
@@ -135,6 +137,37 @@ def apply_gateway_settings(mode: str, bind_mode: str, port: int, enable_openai_a
|
|||||||
control_ui["allowInsecureAuth"] = allow_insecure_auth
|
control_ui["allowInsecureAuth"] = allow_insecure_auth
|
||||||
changes.append(f"allowInsecureAuth: {current_insecure} -> {allow_insecure_auth}")
|
changes.append(f"allowInsecureAuth: {current_insecure} -> {allow_insecure_auth}")
|
||||||
|
|
||||||
|
# Parse and apply environment variables
|
||||||
|
new_env_vars = {}
|
||||||
|
if env_vars.strip():
|
||||||
|
try:
|
||||||
|
# Parse semicolon-separated key=value pairs
|
||||||
|
pairs = env_vars.split(';')
|
||||||
|
for pair in pairs:
|
||||||
|
pair = pair.strip()
|
||||||
|
if not pair:
|
||||||
|
continue
|
||||||
|
if '=' not in pair:
|
||||||
|
print(f"WARN: Invalid env var format '{pair}' (missing '=')")
|
||||||
|
continue
|
||||||
|
key, value = pair.split('=', 1)
|
||||||
|
key = key.strip()
|
||||||
|
value = value.strip()
|
||||||
|
if not key:
|
||||||
|
print(f"WARN: Invalid env var key (empty)")
|
||||||
|
continue
|
||||||
|
new_env_vars[key] = value
|
||||||
|
except Exception as e:
|
||||||
|
print(f"ERROR: Failed to parse environment variables: {e}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
if new_env_vars != current_env_vars:
|
||||||
|
gateway["env"] = new_env_vars
|
||||||
|
if new_env_vars:
|
||||||
|
changes.append(f"env: {len(new_env_vars)} variables")
|
||||||
|
else:
|
||||||
|
changes.append("env: cleared")
|
||||||
|
|
||||||
if changes:
|
if changes:
|
||||||
if write_config(cfg):
|
if write_config(cfg):
|
||||||
print(f"INFO: Updated gateway settings: {', '.join(changes)}")
|
print(f"INFO: Updated gateway settings: {', '.join(changes)}")
|
||||||
@@ -143,7 +176,7 @@ def apply_gateway_settings(mode: str, bind_mode: str, port: int, enable_openai_a
|
|||||||
print("ERROR: Failed to write config")
|
print("ERROR: Failed to write config")
|
||||||
return False
|
return False
|
||||||
else:
|
else:
|
||||||
print(f"INFO: Gateway settings already correct (mode={mode}, bind={bind_mode}, port={port}, chatCompletions={enable_openai_api}, allowInsecureAuth={allow_insecure_auth})")
|
print(f"INFO: Gateway settings already correct (mode={mode}, bind={bind_mode}, port={port}, chatCompletions={enable_openai_api}, allowInsecureAuth={allow_insecure_auth}, env vars={len(current_env_vars)})")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
@@ -156,15 +189,16 @@ def main():
|
|||||||
cmd = sys.argv[1]
|
cmd = sys.argv[1]
|
||||||
|
|
||||||
if cmd == "apply-gateway-settings":
|
if cmd == "apply-gateway-settings":
|
||||||
if len(sys.argv) != 7:
|
if len(sys.argv) < 7:
|
||||||
print("Usage: oc_config_helper.py apply-gateway-settings <local|remote> <auto|loopback|lan|tailnet> <port> <enable_openai_api:true|false> <allow_insecure:true|false>")
|
print("Usage: oc_config_helper.py apply-gateway-settings <local|remote> <auto|loopback|lan|tailnet> <port> <enable_openai_api:true|false> <allow_insecure:true|false> [env_vars]")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
mode = sys.argv[2]
|
mode = sys.argv[2]
|
||||||
bind_mode = sys.argv[3]
|
bind_mode = sys.argv[3]
|
||||||
port = int(sys.argv[4])
|
port = int(sys.argv[4])
|
||||||
enable_openai_api = sys.argv[5].lower() == "true"
|
enable_openai_api = sys.argv[5].lower() == "true"
|
||||||
allow_insecure_auth = sys.argv[6].lower() == "true"
|
allow_insecure_auth = sys.argv[6].lower() == "true"
|
||||||
success = apply_gateway_settings(mode, bind_mode, port, enable_openai_api, allow_insecure_auth)
|
env_vars = sys.argv[7] if len(sys.argv) > 7 else ""
|
||||||
|
success = apply_gateway_settings(mode, bind_mode, port, enable_openai_api, allow_insecure_auth, env_vars)
|
||||||
sys.exit(0 if success else 1)
|
sys.exit(0 if success else 1)
|
||||||
|
|
||||||
elif cmd == "get":
|
elif cmd == "get":
|
||||||
|
|||||||
@@ -52,6 +52,7 @@ GATEWAY_PORT=$(jq -r '.gateway_port // 18789' "$OPTIONS_FILE")
|
|||||||
ENABLE_OPENAI_API=$(jq -r '.enable_openai_api // false' "$OPTIONS_FILE")
|
ENABLE_OPENAI_API=$(jq -r '.enable_openai_api // false' "$OPTIONS_FILE")
|
||||||
ALLOW_INSECURE_AUTH=$(jq -r '.allow_insecure_auth // false' "$OPTIONS_FILE")
|
ALLOW_INSECURE_AUTH=$(jq -r '.allow_insecure_auth // false' "$OPTIONS_FILE")
|
||||||
FORCE_IPV4_DNS=$(jq -r '.force_ipv4_dns // false' "$OPTIONS_FILE")
|
FORCE_IPV4_DNS=$(jq -r '.force_ipv4_dns // false' "$OPTIONS_FILE")
|
||||||
|
GW_ENV_VARS=$(jq -r '.gateway_env_vars // empty' "$OPTIONS_FILE")
|
||||||
|
|
||||||
export TZ="$TZNAME"
|
export TZ="$TZNAME"
|
||||||
|
|
||||||
@@ -147,6 +148,27 @@ export PNPM_HOME="${PERSISTENT_NODE_GLOBAL}/pnpm"
|
|||||||
mkdir -p "$PNPM_HOME"
|
mkdir -p "$PNPM_HOME"
|
||||||
export PATH="${PNPM_HOME}:${PATH}"
|
export PATH="${PNPM_HOME}:${PATH}"
|
||||||
|
|
||||||
|
# Export gateway environment variables from add-on config
|
||||||
|
# These are user-defined variables that should be available to the gateway process
|
||||||
|
if [ -n "$GW_ENV_VARS" ]; then
|
||||||
|
echo "INFO: Setting gateway environment variables from add-on config..."
|
||||||
|
IFS=';' read -ra ENV_VARS <<< "$GW_ENV_VARS"
|
||||||
|
for var in "${ENV_VARS[@]}"; do
|
||||||
|
var=$(echo "$var" | xargs) # trim whitespace
|
||||||
|
if [ -z "$var" ]; then
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
if [[ ! "$var" =~ ^[A-Za-z_][A-Za-z0-9_]*=.*$ ]]; then
|
||||||
|
echo "WARN: Invalid environment variable format: '$var' (skipping)"
|
||||||
|
continue
|
||||||
|
fi
|
||||||
|
export "$var"
|
||||||
|
# Extract key for logging (don't log values for security)
|
||||||
|
key="${var%%=*}"
|
||||||
|
echo "INFO: Exported gateway env var: $key"
|
||||||
|
done
|
||||||
|
fi
|
||||||
|
|
||||||
# ------------------------------------------------------------------------------
|
# ------------------------------------------------------------------------------
|
||||||
# Persist Linuxbrew/Homebrew across Docker image rebuilds
|
# Persist Linuxbrew/Homebrew across Docker image rebuilds
|
||||||
# Homebrew installs to /home/linuxbrew/.linuxbrew/ which is ephemeral.
|
# Homebrew installs to /home/linuxbrew/.linuxbrew/ which is ephemeral.
|
||||||
@@ -353,7 +375,7 @@ fi
|
|||||||
|
|
||||||
if [ -f "$OPENCLAW_CONFIG_PATH" ]; then
|
if [ -f "$OPENCLAW_CONFIG_PATH" ]; then
|
||||||
if [ -f "$HELPER_PATH" ]; then
|
if [ -f "$HELPER_PATH" ]; then
|
||||||
if ! python3 "$HELPER_PATH" apply-gateway-settings "$GATEWAY_MODE" "$GATEWAY_BIND_MODE" "$GATEWAY_PORT" "$ENABLE_OPENAI_API" "$ALLOW_INSECURE_AUTH"; then
|
if ! python3 "$HELPER_PATH" apply-gateway-settings "$GATEWAY_MODE" "$GATEWAY_BIND_MODE" "$GATEWAY_PORT" "$ENABLE_OPENAI_API" "$ALLOW_INSECURE_AUTH" "$GW_ENV_VARS"; then
|
||||||
rc=$?
|
rc=$?
|
||||||
echo "ERROR: Failed to apply gateway settings via oc_config_helper.py (exit code ${rc})."
|
echo "ERROR: Failed to apply gateway settings via oc_config_helper.py (exit code ${rc})."
|
||||||
echo "ERROR: Gateway configuration may be incorrect; aborting startup."
|
echo "ERROR: Gateway configuration may be incorrect; aborting startup."
|
||||||
|
|||||||
Reference in New Issue
Block a user