#!/bin/sh # Регистрация NebulaGraph и проверка полнотекстового индекса. # Запускается внутри контейнера ops, поэтому одинаково работает на macOS, Linux и Windows. set -eu : "${ELASTIC_PASSWORD:?ELASTIC_PASSWORD is required}" : "${STORAGED0_IP:?}" : "${STORAGED1_IP:?}" : "${STORAGED2_IP:?}" : "${ES01_IP:?}" : "${ES02_IP:?}" : "${ES03_IP:?}" : "${LISTENER_IP:?}" if ! command -v nebula-console >/dev/null 2>&1; then if [ -x /usr/local/bin/nebula-console ]; then PATH="/usr/local/bin:${PATH}" else found=$(find / -name nebula-console -type f 2>/dev/null | head -n 1 || true) if [ -z "$found" ]; then echo "nebula-console binary not found" exit 1 fi PATH="$(dirname "$found"):${PATH}" fi fi NGQL_OUT= run_ngql() { echo "" echo "+ $1" set +e NGQL_OUT=$(nebula-console -addr graphd -port 9669 -u root -p nebula -e "$1" 2>&1) NGQL_RC=$? set -e printf '%s\n' "$NGQL_OUT" if [ "$NGQL_RC" -eq 0 ] && ! printf '%s\n' "$NGQL_OUT" | grep -q '\[ERROR'; then return 0 fi return 1 } already_exists() { printf '%s\n' "$NGQL_OUT" | grep -Eqi 'exist' } wait_until() { attempts=$1 shift n=0 while [ "$n" -lt "$attempts" ]; do n=$((n + 1)) if "$@"; then return 0 fi echo "retry ${n}/${attempts}" sleep 5 done return 1 } console_up() { run_ngql "SHOW HOSTS;" } hosts_online() { run_ngql "SHOW HOSTS;" || return 1 on=$(printf '%s\n' "$NGQL_OUT" | grep -c ONLINE || true) off=$(printf '%s\n' "$NGQL_OUT" | grep -c OFFLINE || true) [ "$on" -ge 3 ] && [ "$off" -eq 0 ] } listener_online() { run_ngql "USE demo; SHOW LISTENER;" || return 1 on=$(printf '%s\n' "$NGQL_OUT" | grep -c ONLINE || true) off=$(printf '%s\n' "$NGQL_OUT" | grep -c OFFLINE || true) [ "$on" -ge 12 ] && [ "$off" -eq 0 ] } add_hosts() { stmt="ADD HOSTS \"${STORAGED0_IP}\":9779, \"${STORAGED1_IP}\":9779, \"${STORAGED2_IP}\":9779;" if run_ngql "$stmt"; then return 0 fi already_exists } sign_in() { stmt="SIGN IN TEXT SERVICE (${ES01_IP}:9200, HTTP, \"elastic\", \"${ELASTIC_PASSWORD}\"), (${ES02_IP}:9200, HTTP, \"elastic\", \"${ELASTIC_PASSWORD}\"), (${ES03_IP}:9200, HTTP, \"elastic\", \"${ELASTIC_PASSWORD}\");" if run_ngql "$stmt"; then return 0 fi if already_exists; then return 0 fi run_ngql "SHOW TEXT SEARCH CLIENTS;" || return 1 clients=$(printf '%s\n' "$NGQL_OUT" | grep -c ELASTICSEARCH || true) [ "$clients" -ge 3 ] } do_init() { echo "=== wait for graphd ===" wait_until 40 console_up echo "=== ADD HOSTS ===" wait_until 12 add_hosts echo "=== wait until storage is ONLINE ===" wait_until 36 hosts_online echo "=== SIGN IN TEXT SERVICE ===" wait_until 24 sign_in run_ngql "SHOW TEXT SEARCH CLIENTS;" } create_space() { run_ngql "CREATE SPACE IF NOT EXISTS demo (partition_num = 12, replica_factor = 3, vid_type = FIXED_STRING(64));" } create_tag() { run_ngql "USE demo; CREATE TAG IF NOT EXISTS document (title STRING, content STRING);" } add_listener() { if run_ngql "USE demo; ADD LISTENER ELASTICSEARCH \"${LISTENER_IP}\":9789;"; then return 0 fi already_exists } create_index() { if run_ngql "USE demo; CREATE FULLTEXT TAG INDEX document_search ON document(title, content) ANALYZER = \"standard\";"; then return 0 fi if printf '%s\n' "$NGQL_OUT" | grep -q 'SyntaxError'; then echo "fatal nGQL syntax error" exit 1 fi already_exists } insert_docs() { if run_ngql "USE demo; INSERT VERTEX document(title, content) VALUES \"doc-001\":(\"Kubernetes\", \"Container orchestration platform\"), \"doc-002\":(\"NebulaGraph\", \"Distributed graph database\");"; then return 0 fi already_exists } lookup_doc() { run_ngql "USE demo; LOOKUP ON document WHERE ES_QUERY(document_search, \"Kubernetes\") YIELD id(vertex);" || return 1 printf '%s\n' "$NGQL_OUT" | grep -q 'doc-001' } es_has_kubernetes() { if ! command -v bash >/dev/null 2>&1 || ! command -v base64 >/dev/null 2>&1; then echo "bash/base64 are not in the console image; LOOKUP already queried Elasticsearch" return 0 fi ES01_IP="$ES01_IP" ELASTIC_PASSWORD="$ELASTIC_PASSWORD" bash -c ' auth=$(printf "%s" "elastic:${ELASTIC_PASSWORD}" | base64 | tr -d "\n\r") exec 3<>"/dev/tcp/${ES01_IP}/9200" printf "GET /_search?q=Kubernetes HTTP/1.0\r\nHost: elasticsearch\r\nAuthorization: Basic %s\r\nConnection: close\r\n\r\n" "$auth" >&3 resp=$(cat <&3 || true) printf "%s\n" "$resp" printf "%s\n" "$resp" | grep -q Kubernetes ' } do_verify() { echo "=== CREATE SPACE demo ===" wait_until 24 create_space echo "=== CREATE TAG document ===" wait_until 24 create_tag echo "=== ADD LISTENER ELASTICSEARCH ===" wait_until 12 add_listener echo "=== wait until listener is ONLINE ===" wait_until 36 listener_online echo "=== CREATE FULLTEXT TAG INDEX ===" wait_until 24 create_index run_ngql "USE demo; SHOW FULLTEXT INDEXES;" echo "=== INSERT VERTEX ===" wait_until 12 insert_docs run_ngql "USE demo; REBUILD FULLTEXT INDEX;" || true echo "=== LOOKUP via Elasticsearch ===" wait_until 24 lookup_doc echo "=== direct Elasticsearch search ===" wait_until 12 es_has_kubernetes echo "" echo "VERIFY OK" } mode="${1:-verify}" case "$mode" in init) do_init ;; verify) do_init do_verify ;; *) echo "usage: sh cluster.sh init|verify" exit 2 ;; esac