Skip to content

Commit

Permalink
refactor qdrant scripts
Browse files Browse the repository at this point in the history
  • Loading branch information
Y-Rookie committed Oct 25, 2024
1 parent 3b02103 commit ea9745a
Show file tree
Hide file tree
Showing 8 changed files with 290 additions and 185 deletions.
11 changes: 8 additions & 3 deletions addons/qdrant/Chart.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,24 @@ version: 1.0.0-alpha.0
# This is the version number of qdrant.
appVersion: "1.10.0"

# Add a dependency to the kubeblocks definition library chart
dependencies:
- name: kblib
version: 0.1.0
repository: file://../kblib
alias: extra

home: https://qdrant.tech/
icon: https://qdrant.tech/images/logo_with_text.svg


maintainers:
- name: iziang
url: https://github.com/apecloud/kubeblocks/


sources:
- https://github.com/apecloud/kubeblocks/

annotations:
addon.kubeblocks.io/kubeblocks-version: ">=0.9.0"
addon.kubeblocks.io/kubeblocks-version: ">=1.0.0"
addon.kubeblocks.io/model: "vector"
addon.kubeblocks.io/provider: "community"
138 changes: 106 additions & 32 deletions addons/qdrant/scripts/qdrant-backup.sh
Original file line number Diff line number Diff line change
@@ -1,47 +1,121 @@
#!/usr/bin/env bash

set -e
set -o pipefail
export PATH="$PATH:$DP_DATASAFED_BIN_PATH"
export DATASAFED_BACKEND_BASE_PATH="$DP_BACKUP_BASE_PATH"
# shellcheck disable=SC2034
ut_mode="false"
test || __() {
# when running in non-unit test mode, set the options "set -ex".
set -ex;
}

init_env() {
PATH="$PATH:$DP_DATASAFED_BIN_PATH"
export PATH
DATASAFED_BACKEND_BASE_PATH="$DP_BACKUP_BASE_PATH"
export DATASAFED_BACKEND_BASE_PATH

endpoint="http://${DP_DB_HOST}:6333"
}

# if the script exits with a non-zero exit code, touch a file to indicate that the backup failed,
# the sync progress container will check this file and exit if it exists
function handle_exit() {
handle_exit() {
exit_code=$?
if [ $exit_code -ne 0 ]; then
echo "failed with exit code $exit_code"
touch "${DP_BACKUP_INFO_FILE}.exit"
exit 1
fi
}
trap handle_exit EXIT

function save_backup_size() {
export DATASAFED_BACKEND_BASE_PATH="$(dirname $DP_BACKUP_BASE_PATH)"
TOTAL_SIZE=$(datasafed stat / | grep TotalSize | awk '{print $2}')
echo "{\"totalSize\":\"$TOTAL_SIZE\"}" >"${DP_BACKUP_INFO_FILE}"
}

endpoint=http://${DP_DB_HOST}:6333
collectionRes=$(curl ${endpoint}/collections)
collections=$(echo ${collectionRes} | jq -r '.result.collections[].name')
if [ -z $collections ]; then
save_backup_size
exit 0
fi
# snapshot all collections
for c in ${collections}; do
echo "INFO: start to snapshot collection ${c}..."
snapshot=$(curl -XPOST ${endpoint}/collections/${c}/snapshots)
status=$(echo ${snapshot} | jq '.status')
save_backup_size() {
DATASAFED_BACKEND_BASE_PATH="$(dirname "$DP_BACKUP_BASE_PATH")"
export DATASAFED_BACKEND_BASE_PATH

TOTAL_SIZE=$(datasafed stat / | grep TotalSize | awk '{print $2}')
echo "{\"totalSize\":\"$TOTAL_SIZE\"}" > "${DP_BACKUP_INFO_FILE}"
}

get_collections() {
collections_response=$(curl "${endpoint}/collections")
echo "${collections_response}" | jq -r '.result.collections[].name'
}

create_snapshot() {
collection="$1"
snapshot_response=$(curl -XPOST "${endpoint}/collections/${collection}/snapshots")
echo "${snapshot_response}"
}

validate_snapshot_status() {
snapshot_response="$1"
status=$(echo "${snapshot_response}" | jq '.status')

if [ "${status}" != "ok" ] && [ "${status}" != "\"ok\"" ]; then
echo "backup failed, status: ${status}"
exit 1
echo "backup failed, status: ${status}" >&2
return 1
fi
return 0
}

upload_snapshot() {
collection="$1"
name="$2"

curl -v --fail-with-body \
"${endpoint}/collections/${collection}/snapshots/${name}" | \
datasafed push - "/${collection}.snapshot"
}

delete_snapshot() {
collection="$1"
name="$2"

curl -XDELETE "${endpoint}/collections/${collection}/snapshots/${name}"
}

backup_collection() {
collection="$1"
echo "INFO: start to snapshot collection ${collection}..."

snapshot_response=$(create_snapshot "${collection}")
validate_snapshot_status "${snapshot_response}" || return 1

name=$(echo "${snapshot_response}" | jq -r '.result.name')
upload_snapshot "${collection}" "${name}"
delete_snapshot "${collection}" "${name}"

echo "INFO: snapshot collection ${collection} successfully."
}

backup_all_collections() {
collections=$(get_collections)
if [ -z "${collections}" ]; then
save_backup_size
exit 0
fi
name=$(echo ${snapshot} | jq -r '.result.name')
curl -v --fail-with-body ${endpoint}/collections/${c}/snapshots/${name} | datasafed push - "/${c}.snapshot"
curl -XDELETE ${endpoint}/collections/${c}/snapshots/${name}
echo "INFO: snapshot collection ${c} successfully."
done
save_backup_size

for collection in ${collections}; do
if ! backup_collection "${collection}"; then
echo "backup failed for collection ${collection}" >&2
exit 1
fi
done

save_backup_size
}

do_backup() {
init_env
backup_all_collections
}

# This is magic for shellspec ut framework.
# Sometime, functions are defined in a single shell script.
# You will want to test it. but you do not want to run the script.
# When included from shellspec, __SOURCED__ variable defined and script
# end here. The script path is assigned to the __SOURCED__ variable.
${__SOURCED__:+false} : || return 0

# main
trap handle_exit EXIT
do_backup
91 changes: 50 additions & 41 deletions addons/qdrant/scripts/qdrant-member-leave.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,64 +5,73 @@ set -o errtrace
set -o nounset
set -o pipefail

leave_peer_uri=http://${KB_LEAVE_MEMBER_POD_IP}:6333
cluster_info=`curl -s ${leave_peer_uri}/cluster`
leave_peer_id=`echo "${cluster_info}"| jq -r .result.peer_id`
leader_peer_id=`echo "${cluster_info}" | jq -r .result.raft_info.leader`
leave_peer_uri="http://${KB_LEAVE_MEMBER_POD_IP}:6333"
cluster_info=$(curl -s "${leave_peer_uri}/cluster")
leave_peer_id=$(echo "${cluster_info}" | jq -r .result.peer_id)
leader_peer_id=$(echo "${cluster_info}" | jq -r .result.raft_info.leader)

move_shards() {
cols=`curl -s ${leave_peer_uri}/collections`
col_count=`echo ${cols} | jq -r '.result.collections | length'`
if [[ ${col_count} -eq 0 ]]; then
echo "no collections found in the cluster"
return
cols=$(curl -s "${leave_peer_uri}/collections")
col_count=$(echo "${cols}" | jq -r '.result.collections | length')

if [ "${col_count}" -eq 0 ]; then
echo "no collections found in the cluster"
return
fi

col_names=$(echo "${cols}" | jq -r '.result.collections[].name')
for col_name in ${col_names}; do
col_cluster_info=$(curl -s "${leave_peer_uri}/collections/${col_name}/cluster")
col_shard_count=$(echo "${col_cluster_info}" | jq -r '.result.local_shards[] | length')

if [ "${col_shard_count}" -eq 0 ]; then
echo "no shards found in collection ${col_name}"
continue
fi
col_names=`echo ${cols} | jq -r '.result.collections[].name'`
for col_name in ${col_names}; do
col_cluster_info=`curl -s ${leave_peer_uri}/collections/${col_name}/cluster`
col_shard_count=`echo ${col_cluster_info} | jq -r '.result.local_shards[] | length'`
if [[ ${col_shard_count} -eq 0 ]]; then
echo "no shards found in collection ${col_name}"
continue
fi

leave_shard_ids=`echo ${col_cluster_info} | jq -r '.result.local_shards[].shard_id'`
for shard_id in ${leave_shard_ids}; do
echo "move shard ${shard_id} in col_name ${col_name} from ${leave_peer_id} to ${leader_peer_id}"
curl -s -X POST -H "Content-Type: application/json" \
-d '{"move_shard":{"shard_id": '${shard_id}',"to_peer_id": '${leader_peer_id}',"from_peer_id": '${leave_peer_id}}}'' \
${leave_peer_uri}/collections/${col_name}/cluster
done
leave_shard_ids=$(echo "${col_cluster_info}" | jq -r '.result.local_shards[].shard_id')
for shard_id in ${leave_shard_ids}; do
echo "move shard ${shard_id} in col_name ${col_name} from ${leave_peer_id} to ${leader_peer_id}"
curl -s -X POST -H "Content-Type: application/json" \
-d "{\"move_shard\":{\"shard_id\": ${shard_id},\"to_peer_id\": ${leader_peer_id},\"from_peer_id\": ${leave_peer_id}}}" \
"${leave_peer_uri}/collections/${col_name}/cluster"
done

while true; do
col_cluster_info=`curl -s ${leave_peer_uri}/collections/${col_name}/cluster`
leave_shard_ids=`echo ${col_cluster_info} | jq -r '.result.local_shards[].shard_id'`
if [ -z "${leave_shard_ids}" ]; then
echo "all shards in collection ${col_name} has been moved"
break
fi
sleep 1
done
while true; do
col_cluster_info=$(curl -s "${leave_peer_uri}/collections/${col_name}/cluster")
leave_shard_ids=$(echo "${col_cluster_info}" | jq -r '.result.local_shards[].shard_id')
if [ -z "${leave_shard_ids}" ]; then
echo "all shards in collection ${col_name} has been moved"
break
fi
sleep 1
done
done
}

remove_peer() {
echo "remove peer ${leave_peer_id} from cluster"
curl -v -XDELETE ${leave_peer_uri}/cluster/peer/${leave_peer_id}
echo "remove peer ${leave_peer_id} from cluster"
curl -v -XDELETE "${leave_peer_uri}/cluster/peer/${leave_peer_id}"
}

leave_member() {
echo "scaling in, we need to move local shards to other peers and remove local peer from the cluster"
echo "cluster info: ${cluster_info}"
move_shards
remove_peer
echo "scaling in, we need to move local shards to other peers and remove local peer from the cluster"
echo "cluster info: ${cluster_info}"
move_shards
remove_peer
}

# This is magic for shellspec ut framework.
# Sometime, functions are defined in a single shell script.
# You will want to test it. but you do not want to run the script.
# When included from shellspec, __SOURCED__ variable defined and script
# end here. The script path is assigned to the __SOURCED__ variable.
${__SOURCED__:+false} : || return 0

# lock file to prevent concurrent leave_member
# flock will return 1 if the lock is already held by another process, this is expected
(
flock -n -x 9
if [ $? != 0 ]; then
if ! flock -n -x 9; then
echo "member is already in leaving"
exit 1
fi
Expand Down
79 changes: 0 additions & 79 deletions addons/qdrant/scripts/qdrant-pre-stop.sh

This file was deleted.

Loading

0 comments on commit ea9745a

Please sign in to comment.