234 lines
9.6 KiB
Bash
Executable File
234 lines
9.6 KiB
Bash
Executable File
#!/usr/bin/env bash
|
|
set -euo pipefail
|
|
|
|
provider_id="${1:?provider_id required}"
|
|
model_name="${2:?model_name required}"
|
|
env_var="${3:?env var required}"
|
|
key_file="${4:-}"
|
|
|
|
ROOT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
|
|
# shellcheck disable=SC1091
|
|
source "$ROOT_DIR/scripts/host_access_prep_lib.sh"
|
|
|
|
KEY="${KEY:-/home/long/下载/zjsea.pem}"
|
|
REMOTE="${REMOTE:-ubuntu@43.155.133.187}"
|
|
CRM_BASE="${CRM_BASE:-http://127.0.0.1:18088}"
|
|
HOST_BASE="${HOST_BASE:-http://127.0.0.1:18087}"
|
|
PACK_PATH="${PACK_PATH:-/home/ubuntu/sub2api-cn-relay-manager/packs/openai-cn-pack}"
|
|
ROOT="${ROOT:-$ROOT_DIR/artifacts/real-host-acceptance}"
|
|
ART="${ART:-$ROOT/$(date +%Y%m%d_%H%M%S)_remote43_${provider_id}_key_import}"
|
|
MIN_BALANCE="${MIN_BALANCE:-10}"
|
|
SUBSCRIPTION_DAYS="${SUBSCRIPTION_DAYS:-30}"
|
|
SUBSCRIPTION_NOTES="${SUBSCRIPTION_NOTES:-hermes remote subscription validation}"
|
|
mkdir -p "$ART"
|
|
|
|
if [[ -n "$key_file" ]]; then
|
|
upstream_key="$(tr -d '\r\n' < "$key_file")"
|
|
key_source="file:$key_file"
|
|
else
|
|
upstream_key="${!env_var:-}"
|
|
key_source="env:$env_var"
|
|
fi
|
|
if [[ -z "$upstream_key" ]]; then
|
|
echo "missing key from $key_source" >&2
|
|
exit 2
|
|
fi
|
|
|
|
ssh_cmd() {
|
|
local cmd="$1"
|
|
ssh -i "$KEY" -o StrictHostKeyChecking=no "$REMOTE" "$cmd"
|
|
}
|
|
|
|
remote_pg_exec() {
|
|
local sql="$1"
|
|
local encoded
|
|
encoded="$(printf '%s' "$sql" | base64 -w0)"
|
|
ssh_cmd "printf '%s' '$encoded' | base64 -d | sudo -n docker exec -i sub2api-relaymgr-pg psql -U sub2api -d sub2api"
|
|
}
|
|
|
|
remote_fetch_group_state() {
|
|
local group_id="$1"
|
|
local user_id="$2"
|
|
local api_key="$3"
|
|
local output_path="$4"
|
|
local encoded
|
|
encoded="$(python3 - "$group_id" "$user_id" "$api_key" <<'PY'
|
|
import json, sys
|
|
|
|
group_id, user_id, api_key = sys.argv[1:4]
|
|
query = f"""
|
|
WITH group_row AS (
|
|
SELECT row_to_json(g) AS data FROM groups g WHERE g.id = {group_id}
|
|
),
|
|
subscription_row AS (
|
|
SELECT row_to_json(s) AS data FROM user_subscriptions s
|
|
WHERE s.user_id = {user_id} AND s.group_id = {group_id} AND s.deleted_at IS NULL
|
|
ORDER BY s.id DESC LIMIT 1
|
|
),
|
|
key_row AS (
|
|
SELECT row_to_json(k) AS data FROM api_keys k WHERE k.key = {json.dumps(api_key)}
|
|
)
|
|
SELECT json_build_object(
|
|
'group_id', {group_id},
|
|
'group', (SELECT data FROM group_row),
|
|
'subscription', (SELECT data FROM subscription_row),
|
|
'key', (SELECT data FROM key_row)
|
|
);
|
|
"""
|
|
print(query)
|
|
PY
|
|
)"
|
|
ssh_cmd "printf '%s' '$encoded' | base64 -d | sudo -n docker exec -i sub2api-relaymgr-pg psql -U sub2api -d sub2api -At -F ''" > "$output_path"
|
|
}
|
|
|
|
python3 - "$ART/00-local-key-source.json" "$key_source" "$provider_id" "$upstream_key" <<'PY'
|
|
import json, sys, pathlib
|
|
path, source, provider_id, key = sys.argv[1:5]
|
|
pathlib.Path(path).write_text(json.dumps({
|
|
'source': source,
|
|
'provider_id': provider_id,
|
|
'upstream_key_prefix': key[:12],
|
|
'upstream_key_suffix': key[-6:],
|
|
}, ensure_ascii=False, indent=2), encoding='utf-8')
|
|
PY
|
|
|
|
crm_token="$(ssh_cmd "grep ^SUB2API_CRM_ADMIN_TOKEN= /home/ubuntu/sub2api-cn-relay-manager/.env.remote | cut -d= -f2-")"
|
|
crm_token="${crm_token##*$'\n'}"
|
|
admin_key="$(ssh_cmd "sudo -n docker exec sub2api-relaymgr-pg psql -U sub2api -d sub2api -Atc \"select value from settings where key='admin_api_key';\"")"
|
|
admin_key="${admin_key##*$'\n'}"
|
|
admin_uid="$(ssh_cmd "sudo -n docker exec sub2api-relaymgr-pg psql -U sub2api -d sub2api -Atc \"select id from users where role='admin' order by id asc limit 1;\"")"
|
|
admin_uid="${admin_uid##*$'\n'}"
|
|
sub_uid="$(ssh_cmd "sudo -n docker exec sub2api-relaymgr-pg psql -U sub2api -d sub2api -Atc \"select id from users where email like 'relay-sub-%@sub2api.local' order by id desc limit 1;\"")"
|
|
sub_uid="${sub_uid##*$'\n'}"
|
|
sub_key="$(ssh_cmd "sudo -n docker exec sub2api-relaymgr-pg psql -U sub2api -d sub2api -Atc \"select k.key from users u join api_keys k on k.user_id=u.id where u.email like 'relay-sub-%@sub2api.local' order by u.id desc limit 1;\"")"
|
|
sub_key="${sub_key##*$'\n'}"
|
|
|
|
python3 - "$ART/01-runtime-context.json" "$CRM_BASE" "$HOST_BASE" "$provider_id" "$sub_uid" "$sub_key" <<'PY'
|
|
import json, sys, pathlib
|
|
path, crm, host, provider_id, sub_uid, sub_key = sys.argv[1:7]
|
|
pathlib.Path(path).write_text(json.dumps({
|
|
'crm_base': crm,
|
|
'host_base': host,
|
|
'provider_id': provider_id,
|
|
'subscription_user_id': sub_uid,
|
|
'subscription_user_key_prefix': sub_key[:12],
|
|
}, ensure_ascii=False, indent=2), encoding='utf-8')
|
|
PY
|
|
|
|
payload="$(python3 - "$HOST_BASE" "$admin_key" "$PACK_PATH" "$provider_id" "$upstream_key" "$sub_key" "$sub_uid" "$SUBSCRIPTION_DAYS" <<'PY'
|
|
import json, sys
|
|
host_base, admin_key, pack_path, provider_id, upstream_key, sub_key, sub_uid, subscription_days = sys.argv[1:9]
|
|
print(json.dumps({
|
|
'host_base_url': host_base,
|
|
'host_api_key': admin_key,
|
|
'pack_path': pack_path,
|
|
'provider_id': provider_id,
|
|
'keys': [upstream_key],
|
|
'mode': 'partial',
|
|
'access_mode': 'subscription',
|
|
'access_api_key': sub_key,
|
|
'subscription_days': int(subscription_days),
|
|
'subscription_users': [sub_uid],
|
|
}, ensure_ascii=False))
|
|
PY
|
|
)"
|
|
|
|
ssh_cmd "curl -sS -D /tmp/import_headers.txt -o /tmp/import_body.json -X POST -H 'Authorization: Bearer $crm_token' -H 'Content-Type: application/json' $CRM_BASE/api/providers/$provider_id/import -d $(printf %q "$payload")"
|
|
ssh_cmd "cat /tmp/import_headers.txt" > "$ART/02-import.headers.txt"
|
|
ssh_cmd "cat /tmp/import_body.json" > "$ART/03-import.body.json"
|
|
|
|
batch_id="$(python3 - "$ART/03-import.body.json" <<'PY'
|
|
import json, sys, pathlib
|
|
obj=json.loads(pathlib.Path(sys.argv[1]).read_text())
|
|
print(obj['batch_id'])
|
|
PY
|
|
)"
|
|
|
|
ssh_cmd "curl -sS -H 'Authorization: Bearer *** $CRM_BASE/api/import-batches/$batch_id" > "$ART/04-batch-detail-initial.json"
|
|
subscription_group_id="$(python3 - "$ART/04-batch-detail-initial.json" <<'PY'
|
|
import json, pathlib, sys
|
|
obj = json.loads(pathlib.Path(sys.argv[1]).read_text())
|
|
for item in obj.get('managed_resources', []):
|
|
if item.get('ResourceType') == 'group':
|
|
print(item.get('HostResourceID', ''))
|
|
break
|
|
else:
|
|
raise SystemExit('missing managed group in batch detail')
|
|
PY
|
|
)"
|
|
|
|
prep_sql="$(build_subscription_access_prep_sql "$sub_uid" "$sub_key" "$subscription_group_id" "$MIN_BALANCE" "$SUBSCRIPTION_DAYS" "$admin_uid" "$SUBSCRIPTION_NOTES")"
|
|
python3 - "$ART/05-subscription-access-prep.sql" "$prep_sql" <<'PY'
|
|
import pathlib, sys
|
|
pathlib.Path(sys.argv[1]).write_text(sys.argv[2], encoding='utf-8')
|
|
PY
|
|
remote_pg_exec "$prep_sql" > "$ART/06-subscription-access-prep.psql.txt"
|
|
ssh_cmd "sudo -n docker exec sub2api-relaymgr-redis redis-cli FLUSHDB" > "$ART/07-redis-flush.txt"
|
|
remote_fetch_group_state "$subscription_group_id" "$sub_uid" "$sub_key" "$ART/08-subscription-group-state.json"
|
|
|
|
python3 - "$ART/01-runtime-context.json" "$CRM_BASE" "$HOST_BASE" "$provider_id" "$sub_uid" "$sub_key" "$subscription_group_id" "$admin_uid" <<'PY'
|
|
import json, sys, pathlib
|
|
path, crm, host, provider_id, sub_uid, sub_key, group_id, admin_uid = sys.argv[1:9]
|
|
pathlib.Path(path).write_text(json.dumps({
|
|
'crm_base': crm,
|
|
'host_base': host,
|
|
'provider_id': provider_id,
|
|
'subscription_user_id': sub_uid,
|
|
'subscription_user_key_prefix': sub_key[:12],
|
|
'subscription_group_id': group_id,
|
|
'admin_user_id': admin_uid,
|
|
}, ensure_ascii=False, indent=2), encoding='utf-8')
|
|
PY
|
|
|
|
probe_payload="$(python3 - "$model_name" <<'PY'
|
|
import json, sys
|
|
print(json.dumps({
|
|
'model': sys.argv[1],
|
|
'messages': [{'role':'user','content':'ping'}],
|
|
'max_tokens': 8,
|
|
'temperature': 0,
|
|
}, ensure_ascii=False))
|
|
PY
|
|
)"
|
|
ssh_cmd "curl -sS -D /tmp/chat_headers.txt -o /tmp/chat_body.json -H 'Authorization: Bearer *** -H 'Content-Type: application/json' $HOST_BASE/v1/chat/completions -d $(printf %q "$probe_payload")"
|
|
ssh_cmd "cat /tmp/chat_headers.txt" > "$ART/09-chat.headers.txt"
|
|
ssh_cmd "cat /tmp/chat_body.json" > "$ART/10-chat.body.json"
|
|
|
|
ssh_cmd "curl -sS -H 'Authorization: Bearer *** $CRM_BASE/api/providers/$provider_id/status" > "$ART/11-provider-status.json"
|
|
ssh_cmd "curl -sS -H 'Authorization: Bearer *** $CRM_BASE/api/providers/$provider_id/access/status" > "$ART/12-access-status.json"
|
|
preview_payload="$(python3 - "$provider_id" <<'PY'
|
|
import json, sys
|
|
print(json.dumps({'provider_id': sys.argv[1], 'mode': 'subscription'}, ensure_ascii=False))
|
|
PY
|
|
)"
|
|
ssh_cmd "curl -sS -X POST -H 'Authorization: Bearer *** -H 'Content-Type: application/json' $CRM_BASE/api/providers/$provider_id/access/preview -d $(printf %q "$preview_payload")" > "$ART/13-access-preview.json"
|
|
ssh_cmd "curl -sS -H 'Authorization: Bearer *** $CRM_BASE/api/import-batches/$batch_id" > "$ART/14-batch-detail-final.json"
|
|
|
|
python3 - "$ART" "$provider_id" "$batch_id" <<'PY'
|
|
import json, pathlib, sys
|
|
art=pathlib.Path(sys.argv[1])
|
|
provider_id=sys.argv[2]
|
|
batch_id=int(sys.argv[3])
|
|
import_obj=json.loads((art/'03-import.body.json').read_text())
|
|
access_status=json.loads((art/'12-access-status.json').read_text())
|
|
preview=json.loads((art/'13-access-preview.json').read_text())
|
|
chat_headers=(art/'09-chat.headers.txt').read_text()
|
|
group_state=json.loads((art/'08-subscription-group-state.json').read_text())
|
|
summary={
|
|
'artifact_dir': str(art),
|
|
'provider_id': provider_id,
|
|
'batch_id': batch_id,
|
|
'batch_status': import_obj.get('batch_status'),
|
|
'access_status_from_import': import_obj.get('access_status'),
|
|
'provider_status_from_import': import_obj.get('provider_status'),
|
|
'direct_chat_http200': '200 OK' in chat_headers,
|
|
'latest_access_status': access_status.get('latest_access_status') or access_status.get('batch_access_status'),
|
|
'preview_available': preview.get('available'),
|
|
'accepted_keys_count': import_obj.get('accepted_keys_count'),
|
|
'subscription_group_id': group_state.get('group_id'),
|
|
'key_group_id': (group_state.get('key') or {}).get('group_id'),
|
|
'subscription_status': (group_state.get('subscription') or {}).get('status'),
|
|
}
|
|
print(json.dumps(summary, ensure_ascii=False))
|
|
PY
|