From 46b3be2a8068443a1737a5fd2bf551efc816ef32 Mon Sep 17 00:00:00 2001 From: Kawika Avilla Date: Thu, 30 Nov 2023 13:53:57 +0000 Subject: [PATCH] Setup scripts for local dev Setup scripts will assume it's in the root plugin directory of OSD and places the `scripts` folder into the OSD/scripts folder for run purposes with the following command: ``` yarn setup ``` This then will allow from the root OSD directory to run ``` yarn assistant:start ``` which will setup up the OpenSearch cluster as expected. Please note, at the time of writing this the feature/os-assistant and feature/2.11/os-assistant added the feature for installing OpenSearch assistant related plugins. Not main or 2.x. Signed-off-by: Kawika Avilla Includes: Update scripts/assistant/add_model.sh Update scripts/assistant/utils.sh Co-authored-by: Joshua Li Signed-off-by: Kawika Avilla --- DEVELOPER_GUIDE.md | 29 +++++++++ package.json | 10 ++-- public/utils/index.ts | 1 + scripts/assistant/add_model.sh | 88 +++++++++++++++++++++++++++ scripts/assistant/start.sh | 105 +++++++++++++++++++++++++++++++++ scripts/assistant/utils.sh | 70 ++++++++++++++++++++++ scripts/pre_install.sh | 22 +++++++ 7 files changed, 321 insertions(+), 4 deletions(-) create mode 100755 scripts/assistant/add_model.sh create mode 100755 scripts/assistant/start.sh create mode 100755 scripts/assistant/utils.sh create mode 100755 scripts/pre_install.sh diff --git a/DEVELOPER_GUIDE.md b/DEVELOPER_GUIDE.md index 9f4c0c74..3ed686d8 100644 --- a/DEVELOPER_GUIDE.md +++ b/DEVELOPER_GUIDE.md @@ -24,6 +24,35 @@ Ultimately, your directory structure should look like this: │ └── dashboards-assistant ``` +Setup local stack + +1. Export keys locally: +```sh +# defaults to us-west-2 +export REGION= +export AWS_ACCESS_KEY_ID= +export AWS_SECRET_ACCESS_KEY= +export AWS_SESSION_TOKEN= +``` +2. Setup OSD plugins +```sh +# from OSD root folder +cd plugins +git clone https://github.com/opensearch-project/dashboards-assistant +(cd dashboards-assistant && yarn setup) + +# example with security plugin +git clone --depth 1 --branch $VERSION https://github.com/opensearch-project/security-dashboards-plugin.git + +cd ../../ +yarn osd bootstrap +``` +2. Start local environment +```sh +# from OSD root folder +yarn start:assistant +``` + ### Build To build the plugin's distributable zip simply run `yarn build` in the plugin's directory. diff --git a/package.json b/package.json index ca933f15..1b2cef72 100644 --- a/package.json +++ b/package.json @@ -4,13 +4,15 @@ "main": "index.ts", "license": "Apache-2.0", "scripts": { - "osd": "node ../../scripts/osd", + "osd": "../../scripts/use_node ../../scripts/osd", "build": "yarn plugin-helpers build", "test:jest": "../../node_modules/.bin/jest --config ./test/jest.config.js", - "plugin-helpers": "node ../../scripts/plugin_helpers", + "plugin-helpers": "../../scripts/use_node ../../scripts/plugin_helpers", "prepare": "husky install", - "lint:es": "node ../../scripts/eslint", - "lint": "yarn lint:es" + "lint:es": "../../scripts/use_node ../../scripts/eslint", + "lint": "yarn lint:es", + "setup": "scripts/pre_install.sh", + "osd-version": "../../scripts/use_node -e \"console.log(require('./opensearch_dashboards.json').opensearchDashboardsVersion)\"" }, "lint-staged": { "*.{ts,tsx,js,jsx}": [ diff --git a/public/utils/index.ts b/public/utils/index.ts index 5c14d390..e0ef3d67 100644 --- a/public/utils/index.ts +++ b/public/utils/index.ts @@ -4,3 +4,4 @@ */ export * from './notebook'; +export { TAB_ID } from './constants'; diff --git a/scripts/assistant/add_model.sh b/scripts/assistant/add_model.sh new file mode 100755 index 00000000..ae605c93 --- /dev/null +++ b/scripts/assistant/add_model.sh @@ -0,0 +1,88 @@ +#!/usr/bin/env bash +set -e + +function add_model() { + [ -z "$SESSION_TOKEN" ] && SESSION_TOKEN_VALUE="" || SESSION_TOKEN_VALUE='"session_token": "'$SESSION_TOKEN'"' + [ -z "$SESSION_TOKEN_VALUE" ] && echo "[ User session disabled ]" + + ENDPOINT=https://${USERNAME}:${PASSWORD}@${BIND_ADDRESS}:${BIND_PORT} + + curl -s -k "${ENDPOINT}/_cluster/settings" -XPUT -H 'Content-Type: application/json' -d '{ + "persistent" : { + "plugins.ml_commons.trusted_connector_endpoints_regex": + [ "^https://runtime\\.sagemaker\\..*[a-z0-9-]\\.amazonaws\\.com/.*$", + "^https://api\\.openai\\.com/.*$", + "^https://api\\.cohere\\.ai/.*$", + "^https://bedrock-runtime\\.[a-z0-9-]+\\.amazonaws\\.com/.*$" + ] + } + }' | jq + + # shellcheck disable=2016 + CONNECTOR=$(curl -s -k "${ENDPOINT}/_plugins/_ml/connectors/_create" -XPOST -H 'Content-Type: application/json' -d '{ + "name": "BedRock test claude Connector", + "description": "The connector to BedRock service for claude model", + "version": 1, + "protocol": "aws_sigv4", + "parameters": { + "region": "'$REGION'", + "service_name": "bedrock", + "anthropic_version": "bedrock-2023-05-31", + "endpoint": "bedrock.'$REGION'.amazonaws.com", + "auth": "Sig_V4", + "content_type": "application/json" + }, + "credential": { + "access_key": "'$ACCESS_KEY_ID'", + "secret_key": "'$SECRET_ACCESS_KEY'", + '"$SESSION_TOKEN_VALUE"' + }, + "actions": [ + { + "action_type": "predict", + "method": "POST", + "url": "https://bedrock-runtime.'"$REGION"'.amazonaws.com/model/anthropic.claude-v1/invoke", + "headers": { + "content-type": "application/json", + "x-amz-content-sha256": "required" + }, + "request_body": "{\"prompt\":\"${parameters.prompt}\", \"max_tokens_to_sample\":${parameters.max_tokens_to_sample}, \"temperature\":${parameters.temperature}, \"anthropic_version\":\"${parameters.anthropic_version}\" }" + } + ] + }' | jq -r '.connector_id') + echo "Created connector id: ${CONNECTOR}" + + GROUP=$(curl -s -k "${ENDPOINT}/_plugins/_ml/model_groups/_register" -XPOST -H 'Content-Type: application/json' -d '{ + "name": "test_model_group_public", + "description": "This is a public model group" + }' | jq | grep -oP '(?<=ID: )(.+)(?=\.)|(?<=model_group_id": ")(.+)(?=",)' | head -n 1) + echo "Created group id: ${GROUP}" + + EMBEDDINGS_TASK=$(curl -s -k "${ENDPOINT}/_plugins/_ml/models/_register?deploy=true" -XPOST -H 'Content-Type: application/json' -d '{ + "name": "huggingface/sentence-transformers/all-mpnet-base-v2", + "version": "1.0.1", + "model_group_id": "'$GROUP'", + "model_format": "TORCH_SCRIPT" + }' | jq -r '.task_id') + echo "Created embeddings_task id: ${EMBEDDINGS_TASK}" + + MODEL=$(curl -s -k "${ENDPOINT}/_plugins/_ml/models/_register?deploy=true" -XPOST -H 'Content-Type: application/json' -d '{ + "name": "Claude model on bedrock", + "model_group_id": "'$GROUP'", + "function_name": "remote", + "version": "1.0.0", + "connector_id": "'$CONNECTOR'", + "description": "test model" + }' | jq -r '.model_id') + + echo "Created model id: ${MODEL}" + sleep 40 + EMBEDDINGS_MODEL=$(curl -s -k "${ENDPOINT}/_plugins/_ml/tasks/${EMBEDDINGS_TASK}" | jq -r '.model_id') + echo "Created embeddings_model id: ${EMBEDDINGS_MODEL}" + + curl -s -k "${ENDPOINT}/.chat-assistant-config/_doc/model-config" -XPOST -H 'Content-Type: application/json' -d '{ + "model_type":"claude_bedrock", + "embeddings_model_id":"'$EMBEDDINGS_MODEL'", + "model_id":"'$MODEL'" + }' | jq +} diff --git a/scripts/assistant/start.sh b/scripts/assistant/start.sh new file mode 100755 index 00000000..6d84c85c --- /dev/null +++ b/scripts/assistant/start.sh @@ -0,0 +1,105 @@ +#!/bin/bash + +# Copyright OpenSearch Contributors +# SPDX-License-Identifier: Apache-2.0 + +set -e + +. scripts/assistant/utils.sh +. scripts/assistant/add_model.sh + +RED_COLOR='\033[0;31m' +GREEN_COLOR='\033[0;32m' +NO_COLOR='\033[0m' + +function usage() { + echo "" + echo "This script is used to run OpenSearch Assistant" + echo "--------------------------------------------------------------------------" + echo "Usage: $0 [args]" + echo "" + echo "Optional arguments:" + echo -e "-b BIND_ADDRESS\t, defaults to localhost | 127.0.0.1, can be changed to any IP or domain name for the cluster location." + echo -e "-p BIND_PORT\t, defaults to 5601 depends on OpenSearch or Dashboards, can be changed to any port for the cluster location." + echo -e "-c CREDENTIAL\t(username:password), defaults to admin:admin" + echo -e "-h\tPrint this message." + echo "--------------------------------------------------------------------------" +} + +while getopts ":h:b:p:c:" arg; do + case $arg in + h) + usage + exit 1 + ;; + b) + BIND_ADDRESS=$OPTARG + ;; + p) + BIND_PORT=$OPTARG + ;; + c) + CREDENTIAL=$OPTARG + ;; + :) + echo "-${OPTARG} requires an argument" + usage + exit 1 + ;; + ?) + echo "Invalid option: -${OPTARG}" + exit 1 + ;; + esac +done + +[ -z "$ACCESS_KEY_ID" ] && ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID} +[ -z "$SECRET_ACCESS_KEY" ] && SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY} +[ -z "$SESSION_TOKEN" ] && SESSION_TOKEN=${AWS_SESSION_TOKEN} + +[ -z "$ACCESS_KEY_ID" ] && echo -e "[ ${RED_COLOR}Error${NO_COLOR}: requires env variable: ACCESS_KEY_ID ]" && exit 1 +[ -z "$SECRET_ACCESS_KEY" ] && echo -e "[ ${RED_COLOR}Error${NO_COLOR}: requires env variable: SECRET_ACCESS_KEY ]" && exit 1 + +[ -z "$BIND_ADDRESS" ] && BIND_ADDRESS="localhost" +[ -z "$BIND_PORT" ] && BIND_PORT="9200" +[ -z "$REGION" ] && REGION="us-west-2" +if [ -z "$CREDENTIAL" ] +then + CREDENTIAL="admin:admin" + USERNAME=`echo $CREDENTIAL | awk -F ':' '{print $1}'` + PASSWORD=`echo $CREDENTIAL | awk -F ':' '{print $2}'` +fi + +PARENT_PID_LIST=() + +PACKAGE_VERSION=$(yarn --silent pkg-version) + +# define assistant path +CWD=$(pwd) +SNAPSHOT_DIR="$CWD/.opensearch" +LOGS_DIR="$SNAPSHOT_DIR/$PACKAGE_VERSION/logs" + +# Main function +function execute() { + export initialAdminPassword=$PASSWORD + CLUSTER_SETTINGS="snapshot --assistant --security" + CLUSTER_SETTINGS+=" -E plugins.ml_commons.only_run_on_ml_node=true" + CLUSTER_SETTINGS+=" -E plugins.ml_commons.memory_feature_enabled=true" + + run_opensearch || clean + check_opensearch_status + echo "[ Attempting to add models... ]" + (add_model > $LOGS_DIR/add_model.log 2>&1 || clean) & + echo "Results found in $LOGS_DIR/add_model.log" + + export OPENSEARCH_USERNAME=kibanaserver + export OPENSEARCH_PASSWORD=kibanaserver + echo "[ Starting OpenSearch Dashboards... ]" + OSD_SETTINGS="--dev --security --assistant.chat.enabled=true" + OSD_SETTINGS+=" --home.newHomepage=true" + eval "$CWD/scripts/use_node $CWD/scripts/opensearch_dashboards $OSD_SETTINGS" || clean +} + +execute +clean +exit 0 \ No newline at end of file diff --git a/scripts/assistant/utils.sh b/scripts/assistant/utils.sh new file mode 100755 index 00000000..80840efa --- /dev/null +++ b/scripts/assistant/utils.sh @@ -0,0 +1,70 @@ +#!/bin/bash + +# Copyright OpenSearch Contributors +# SPDX-License-Identifier: Apache-2.0 + +set -e + +# remove the running opensearch process +function clean() { + echo "[ Attempting to Terminate Process with PID: ${PARENT_PID_LIST[*]} ]" + for pid_kill in "${PARENT_PID_LIST[@]}" + do + echo "Closing PID $pid_kill" + kill $pid_kill || true + done + PARENT_PID_LIST=() +} + +function spawn_process_and_save_PID() { + echo "Spawn '$*'" + eval $@ + curr_pid=$! + echo "PID: $curr_pid" + PARENT_PID_LIST+=( $curr_pid ) +} + +# Print out a textfile line by line +function print_txt() { + while IFS= read -r line; do + echo "text read from $1: $line" + done < $1 +} + +# this function is used to check the running status of OpenSearch or OpenSearch Dashboards +# $1 is the path to the tmp file which saves the running status +# $2 is the error msg to check +function check_status() { + # Calculate end time as 350s from now + check_status_end_time=$(expr 350 + "$(date '+%s')") + + while [ ! -e $1 ] || ! grep -q "$2" $1; do + sleep 1 + # Stop checking after $check_status_end_time + if [ $check_status_end_time -lt $(date '+%s') ]; then + echo -e "[ ${RED_COLOR}Error${NO_COLOR}: Status check has timed out ]" + exit 1 + fi + done +} + +# Checks the running status of OpenSearch +# it calls check_status and passes the OpenSearch tmp file path, error msg, url, and arguments +# if success, the while loop in the check_status will end and it prints out "OpenSearch is up!" +function check_opensearch_status() { + echo "[ Checking the status OpenSearch... ]" + # define other paths and tmp files + OPENSEARCH_FILE='opensearch.log' + OPENSEARCH_LOG_PATH="$LOGS_DIR/$OPENSEARCH_FILE" + + OPENSEARCH_MSG="ML configuration initialized successfully" + check_status $OPENSEARCH_LOG_PATH "$OPENSEARCH_MSG" 2>&1 + echo -e "[ ${GREEN_COLOR}Success${NO_COLOR}: OpenSearch is up! ]" +} + +# Starts OpenSearch +function run_opensearch() { + echo "[ Attempting to start OpenSearch... ]" + rm -rf $LOGS_DIR/opensearch.log + spawn_process_and_save_PID "$CWD/scripts/use_node $CWD/scripts/opensearch $CLUSTER_SETTINGS > $LOGS_DIR/opensearch.log 2>&1 &" +} diff --git a/scripts/pre_install.sh b/scripts/pre_install.sh new file mode 100755 index 00000000..0cc21d6d --- /dev/null +++ b/scripts/pre_install.sh @@ -0,0 +1,22 @@ +#!/bin/bash + +# Copyright OpenSearch Contributors +# SPDX-License-Identifier: Apache-2.0 + +set -e + +cp -r scripts/assistant ../../scripts + +SUPPORTED_VERSION=$(yarn --silent osd-version) + +echo "Plugin supports OpenSearch Dashboards v$SUPPORTED_VERSION" +read -n 1 -p "Would you like to force OpenSearch and OpenSearch Dashboards v$SUPPORTED_VERSION? [y/n] " REPLY +if [[ $REPLY =~ ^[Yy]$ ]] +then + sed -i -E "s|(\"version\": \")[^\"]*|\1${SUPPORTED_VERSION}|" ../../package.json +fi + +echo +echo "Pre-install complete. Please start with 'yarn start:assistant' from OSD root" + +