Skip to content

Commit

Permalink
add redis cluster manage ut
Browse files Browse the repository at this point in the history
  • Loading branch information
Y-Rookie committed Oct 8, 2024
1 parent 3eb7c50 commit 8e8d3dc
Show file tree
Hide file tree
Showing 4 changed files with 254 additions and 27 deletions.
21 changes: 21 additions & 0 deletions addons/redis/redis-cluster-scripts/redis-cluster-common.sh
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,27 @@ get_all_shards_pods() {
done <<< "$envs"
}

## the pod fqdn list for all shard pod, it will generate a set of variables with the shard name suffix like:
## - ALL_SHARDS_POD_FQDN_LIST_SHARD_98X="redis-shard-98x-0.redis-shard-98x-headless.default.cluster.local,redis-shard-98x-1.redis-shard-98x-headless.default.cluster.local"
## - ALL_SHARDS_POD_FQDN_LIST_SHARD_CQ7="redis-shard-cq7-0.redis-shard-cq7-headless.default.cluster.local,redis-shard-cq7-1.redis-shard-cq7-headless.default.cluster.local"
## - ALL_SHARDS_POD_FQDN_LIST_SHARD_HY7="redis-shard-hy7-0.redis-shard-hy7-headless.default.cluster.local,redis-shard-hy7-1.redis-shard-hy7-headless.default.cluster.local"
get_all_shards_pod_fqdns() {
## list all Envs name prefix with ALL_SHARDS_POD_FQDN_LIST and get them value combined with ","
local all_shards_pod_fqdns
envs=$(env | grep "^ALL_SHARDS_POD_FQDN_LIST" | awk -F '=' '{print $2}')
while read -r line; do
## remove the \n at the end of the string
line=$(echo "$line" | tr -d '\n')

## remove the , at the beginning of the string
if is_empty "$all_shards_pod_fqdns"; then
all_shards_pod_fqdns="${line}"
continue
fi
all_shards_pod_fqdns="$all_shards_pod_fqdns,${line}"
done <<< "$envs"
}

shutdown_redis_server() {
local service_port="$1"
unset_xtrace_when_ut_mode_false
Expand Down
50 changes: 25 additions & 25 deletions addons/redis/redis-cluster-scripts/redis-cluster-manage.sh
Original file line number Diff line number Diff line change
Expand Up @@ -93,15 +93,17 @@ init_other_components_and_pods_info() {
fi

# skip the pod belongs to the deleting component
pod_name_prefix=$(extract_pod_name_prefix "${pod_names[$index]}")
if echo "${deleting_components[@]}" | grep -q "$pod_name_prefix"; then
echo "skip the pod ${pod_names[$index]} as it belongs to the deleting component $pod_name_prefix"
continue
fi
for deleting_comp in "${deleting_components[@]}"; do
if echo "${pod_names[$index]}" | grep "$deleting_comp-"; then
echo "skip the pod ${pod_names[$index]} as it belongs the deleting component $deleting_comp"
continue 2
fi
done

other_undeleted_component_pod_ips+=("${pod_ips[$index]}")
other_undeleted_component_pod_names+=("${pod_names[$index]}")

# TODO: resolve the pod fqdn from the Vars
pod_name_prefix=$(extract_pod_name_prefix "${pod_names[$index]}")
pod_fqdn="${pod_names[$index]}.$pod_name_prefix-headless"
other_undeleted_component_nodes+=("$pod_fqdn:$SERVICE_PORT")
Expand Down Expand Up @@ -145,52 +147,50 @@ parse_host_ip_from_built_in_envs() {
local all_pod_host_ip_list="$3"

if is_empty "$all_pod_name_list" || is_empty "$all_pod_host_ip_list"; then
echo "Error: Required environment variables all_pod_name_lis or all_pod_host_ip_list are not set."
exit 1
echo "Error: Required environment variables all_pod_name_lis or all_pod_host_ip_list are not set." >&2
return 1
fi

pod_name_list=($(split "$all_pod_name_list" ","))
pod_ip_list=($(split "$all_pod_host_ip_list" ","))
while [ -n "$pod_name_list" ]; do
pod_name="${pod_name_list%%,*}"
host_ip="${pod_ip_list%%,*}"

while [ -n "${pod_name_list[0]}" ]; do
pod_name="${pod_name_list[0]}"
host_ip="${pod_ip_list[0]}"
if equals "$pod_name" "$given_pod_name"; then
echo "$host_ip"
return 0
fi

if equals "$pod_name_list" "$pod_name"; then
pod_name_list=''
pod_ip_list=''
if equals "${pod_name_list[-1]}" "$pod_name"; then
pod_name_list=()
pod_ip_list=()
else
pod_name_list="${pod_name_list#*,}"
pod_ip_list="${pod_ip_list#*,}"
pod_name_list=("${pod_name_list[@]:1}")
pod_ip_list=("${pod_ip_list[@]:1}")
fi
done

echo "parse_host_ip_from_built_in_envs the given pod name $given_pod_name not found."
exit 1
echo "parse_host_ip_from_built_in_envs the given pod name $given_pod_name not found." >&2
return 1
}

extract_pod_name_prefix() {
local pod_name="$1"
# shellcheck disable=SC2001
prefix=$(echo "$pod_name" | sed 's/-[0-9]\+$//')
prefix=$(echo "$pod_name" | sed 's/-[0-9]*$//')
echo "$prefix"
}

# get the current component primary node and other nodes for scale in
get_current_comp_nodes_for_scale_in() {
local cluster_node="$1"
local cluster_node_port="$2"
set +x
if [ -z "$REDIS_DEFAULT_PASSWORD" ]; then
cluster_nodes_info=$(redis-cli -h "$cluster_node" -p "$cluster_node_port" cluster nodes)
else
cluster_nodes_info=$(redis-cli -h "$cluster_node" -p "$cluster_node_port" -a "$REDIS_DEFAULT_PASSWORD" cluster nodes)
cluster_nodes_info=$(get_cluster_nodes_info "$cluster_node" "$cluster_node_port")
status=$?
if [ $status -ne 0 ]; then
echo "Failed to get cluster nodes info in get_current_comp_nodes_for_scale_in" >&2
return 1
fi
set -x

current_comp_primary_node=()
current_comp_other_nodes=()
Expand Down
205 changes: 205 additions & 0 deletions addons/redis/scripts-ut-spec/redis_cluster_manage_spec.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,205 @@
# shellcheck shell=bash
# shellcheck disable=SC2034

# we need bash 4 or higher to run this script in some cases
should_skip_when_shell_type_and_version_invalid() {
# validate_shell_type_and_version defined in shellspec/spec_helper.sh used to validate the expected shell type and version this script needs to run.
if validate_shell_type_and_version "bash" 4 &>/dev/null; then
# should not skip
return 1
fi
echo "redis_cluster_manage_spec.sh skip cases because dependency bash version 4 or higher is not installed."
return 0
}

source ./utils.sh

# The unit test needs to rely on the common library functions defined in kblib.
# Therefore, we first dynamically generate the required common library files from the kblib library chart.
common_library_file="./common.sh"
generate_common_library $common_library_file

Describe "Redis Cluster Manage Bash Script Tests"
# load the scripts to be tested and dependencies
Include $common_library_file
Include ../redis-cluster-scripts/redis-cluster-common.sh
Include ../redis-cluster-scripts/redis-cluster-manage.sh

init() {
# set ut_mode to true to hack control flow in the script
ut_mode="true"
}
BeforeAll "init"

cleanup() {
rm -f $common_library_file;
}
AfterAll 'cleanup'

Describe "init_other_components_and_pods_info()"
It "initializes other components and pods info correctly"
export KB_CLUSTER_COMPONENT_LIST="component1,component2,component3"
export KB_CLUSTER_COMPONENT_DELETING_LIST="component2"
export KB_CLUSTER_COMPONENT_UNDELETED_LIST="component1,component3"
export KB_CLUSTER_POD_IP_LIST="10.0.0.1,10.0.0.2,10.0.0.3,10.0.0.4"
export KB_CLUSTER_POD_NAME_LIST="component1-0,component2-0,component3-0,component3-1"
export SERVICE_PORT="6379"

When call init_other_components_and_pods_info "component1" "$KB_CLUSTER_POD_IP_LIST" "$KB_CLUSTER_POD_NAME_LIST" "$KB_CLUSTER_COMPONENT_LIST" "$KB_CLUSTER_COMPONENT_DELETING_LIST" "$KB_CLUSTER_COMPONENT_UNDELETED_LIST"
The status should be success
The output should include "other_components: component2 component3"
The output should include "other_deleting_components: component2"
The output should include "other_undeleted_components: component3"
The output should include "other_undeleted_component_pod_ips: 10.0.0.3 10.0.0.4"
The output should include "other_undeleted_component_pod_names: component3-0 component3-1"
The output should include "other_undeleted_component_nodes: component3-0.component3-headless:6379 component3-1.component3-headless:6379"
End
End

Describe "find_exist_available_node()"
It "finds an available node from other undeleted components"
check_slots_covered() { %text
if [ "$1" = "node1:6379" ]; then
return 0
else
return 1
fi
}
get_cluster_nodes_info() { %text
echo "node1 10.0.0.1:6379@16379 myself,master - 0 0 1 connected 0-5460"
}
export other_undeleted_component_nodes=("node1:6379" "node2:6379")
export SERVICE_PORT="6379"
When call find_exist_available_node
The status should be success
The output should eq "10.0.0.1:6379"
End

It "returns empty string when no available node found"
check_slots_covered() { return 1; }
get_cluster_nodes_info() { return 1; }
export other_undeleted_component_nodes=("node1:6379" "node2:6379")
export SERVICE_PORT="6379"
When call find_exist_available_node
The status should be success
The output should be blank
End
End

Describe "parse_host_ip_from_built_in_envs()"
It "parses host IP from built-in environment variables"
export KB_CLUSTER_POD_NAME_LIST="pod1,pod2,pod3"
export KB_CLUSTER_POD_HOST_IP_LIST="10.0.0.1,10.0.0.2,10.0.0.3"
When call parse_host_ip_from_built_in_envs "pod2" "$KB_CLUSTER_POD_NAME_LIST" "$KB_CLUSTER_POD_HOST_IP_LIST"
The status should be success
The output should eq "10.0.0.2"
End

It "exits with error when pod name not found"
export KB_CLUSTER_POD_NAME_LIST="pod1,pod2,pod3"
export KB_CLUSTER_POD_HOST_IP_LIST="10.0.0.1,10.0.0.2,10.0.0.3"
When call parse_host_ip_from_built_in_envs "pod4" "$KB_CLUSTER_POD_NAME_LIST" "$KB_CLUSTER_POD_HOST_IP_LIST"
The status should be failure
The stderr should include "the given pod name pod4 not found"
End
End

Describe "extract_pod_name_prefix()"
It "extracts the prefix from the pod name"
When call extract_pod_name_prefix "component1-0"
The status should be success
The output should eq "component1"
End

It "extracts the prefix from the pod name"
When call extract_pod_name_prefix "component1-0-1"
The status should be success
The output should eq "component1-0"
End
End

Describe "get_current_comp_nodes_for_scale_in()"
Context "when cluster nodes info contains only one line"
get_cluster_nodes_info() {
cluster_nodes_info="4958e6dca033cd1b321922508553fab869a29d 10.42.0.227:6379@16379,redis-shard-sxj-0.redis-shard-sxj-headless.default.svc master - 0 1711958289570 4 connected 0-1364 5461-6826 10923-12287"
echo "$cluster_nodes_info"
}
It "returns early when cluster nodes info contains only one line"
When call get_current_comp_nodes_for_scale_in "redis-shard-sxj-0.redis-shard-sxj-headless.default.svc" "6379"
The status should be success
The stdout should include "Cluster nodes info contains only one line, returning..."
End
End

Context "when using advertised ports"
get_cluster_nodes_info() {
cluster_nodes_info="4958e6dca033cd1b321922508553fab869a29d 10.42.0.227:31000@32000,redis-shard-sxj-0.redis-shard-sxj-headless.default.svc master - 0 1711958289570 4 connected 0-1364 5461-6826 10923-12287"$'\n'"7381c6dca033cd1b321922508553fab869a29e 10.42.0.228:31001@32001,redis-shard-sxj-1.redis-shard-sxj-headless.default.svc slave 4958e6dca033cd1b321922508553fab869a29d 0 1711958289570 4 connected"
echo "$cluster_nodes_info"
}

setup() {
export CURRENT_SHARD_ADVERTISED_PORT="redis-shard-sxj-0:31000,redis-shard-sxj-1:31001"
export current_comp_primary_node=()
export current_comp_other_nodes=()
}
Before "setup"

un_setup() {
unset CURRENT_SHARD_ADVERTISED_PORT
unset cluster_nodes_info
}
After "un_setup"

It "parses current component nodes correctly when using advertised ports"
When call get_current_comp_nodes_for_scale_in "redis-shard-sxj-0.redis-shard-sxj-headless.default.svc" "6379"
The status should be success
The variable current_comp_primary_node should equal "10.42.0.227:31000"
The variable current_comp_other_nodes should equal "10.42.0.228:31001"
The stdout should include "current_comp_primary_node: 10.42.0.227:31000"
End
End

Context "when not using advertised ports"
get_cluster_nodes_info() {
cluster_nodes_info="4958e6dca033cd1b321922508553fab869a29d 10.42.0.227:6379@16379,redis-shard-sxj-0.redis-shard-sxj-headless.default.svc master - 0 1711958289570 4 connected 0-1364 5461-6826 10923-12287"$'\n'"7381c6dca033cd1b321922508553fab869a29e 10.42.0.228:6379@16379,redis-shard-sxj-1.redis-shard-sxj-headless.default.svc slave 4958e6dca033cd1b321922508553fab869a29d 0 1711958289570 4 connected"
echo "$cluster_nodes_info"
}
setup() {
unset CURRENT_SHARD_ADVERTISED_PORT
export KB_CLUSTER_COMP_NAME="redis-shard-sxj"
export SERVICE_PORT="6379"
export current_comp_primary_node=()
export current_comp_other_nodes=()
}
Before "setup"

un_setup() {
unset KB_CLUSTER_COMP_NAME
unset SERVICE_PORT
unset cluster_nodes_info
}
After "un_setup"

It "parses current component nodes correctly when not using advertised ports"
When call get_current_comp_nodes_for_scale_in "redis-shard-sxj-0.redis-shard-sxj-headless.default.svc" "6379"
The status should be success
The variable current_comp_primary_node should equal "redis-shard-sxj-0.redis-shard-sxj-headless.default.svc:6379"
The variable current_comp_other_nodes should equal "redis-shard-sxj-1.redis-shard-sxj-headless.default.svc:6379"
The stdout should include "current_comp_primary_node: redis-shard-sxj-0.redis-shard-sxj-headless.default.svc:6379"
End
End

Context "when failed to get cluster nodes info"
get_cluster_nodes_info() {
return 1
}

It "returns error when failed to get cluster nodes info"
When call get_current_comp_nodes_for_scale_in "redis-shard-sxj-0.redis-shard-sxj-headless.default.svc" "6379"
The status should be failure
The stderr should include "Failed to get cluster nodes info in get_current_comp_nodes_for_scale_in"
End
End
End

End
5 changes: 3 additions & 2 deletions addons/redis/templates/cmpd-redis-cluster-7.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ spec:
valueFrom:
componentVarRef:
compDef: {{ include "redisCluster7.cmpdName" . }}
optional: true
optional: false
podNames: Required
multipleClusterObjectOption:
strategy: individual
Expand All @@ -194,7 +194,8 @@ spec:
- name: ALL_SHARDS_POD_FQDN_LIST
valueFrom:
componentVarRef:
optional: true
compDef: {{ include "redisCluster7.cmpdName" . }}
optional: false
podFQDNs: Required
multipleClusterObjectOption:
strategy: individual
Expand Down

0 comments on commit 8e8d3dc

Please sign in to comment.