2 # SPDX-license-identifier: Apache-2.0
3 ##############################################################################
5 # All rights reserved. This program and the accompanying materials
6 # are made available under the terms of the Apache License, Version 2.0
7 # which accompanies this distribution, and is available at
8 # http://www.apache.org/licenses/LICENSE-2.0
9 ##############################################################################
15 FUNCTIONS_DIR="$(readlink -f "$(dirname "${BASH_SOURCE[0]}")")"
17 # Do not overwrite any user modifications to PATH when sourcing
20 source /etc/environment
22 source $FUNCTIONS_DIR/_common_test.sh
26 local RED='\033[0;31m'
29 echo -e "${RED} $msg ---------------------------------------${NC}"
32 function ssh_cluster {
33 master_ip=$(kubectl cluster-info | grep "Kubernetes master" | awk -F '[:/]' '{print $4}')
34 ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null ${master_ip} -- "$@"
37 function get_ovn_central_address {
38 #Reuse OVN_CENTRAL_ADDRESS if available (bypassable by --force flag)
39 if [[ "${1:-}" != "--force" ]] && [[ -n "${OVN_CENTRAL_ADDRESS:-}" ]]; then
40 echo "${OVN_CENTRAL_ADDRESS}"
44 local remote_command="ip address show dev $OVN_CENTRAL_INTERFACE primary"
45 declare -a ansible_command=(ansible ovn-central[0] -i \
46 "${FUNCTIONS_DIR}/../hosting_providers/vagrant/inventory/hosts.ini")
47 declare -a filter=(awk -F '[ \t/]+' \
48 'BEGIN {r=1} {for (i=1; i<=NF; i++) if ($i == "inet") {print $(i+1); r=0}} END {exit r}')
51 #Determine OVN_CENTRAL_INTERFACE address
52 if ! result="$("${ansible_command[@]}" -a "${remote_command}")"; then
53 echo "Ansible error for remote host ovn-central[0]" >&2
56 if [[ "${result}" != *CHANGED* ]]; then
57 echo "Failed to execute command on remote host ovn-central[0]" >&2
60 if ! result="$("${filter[@]}" <<< "${result}")"; then
61 echo "Failed to retrieve interface address from command output" >&2
71 #Runs curl with passed flags and provides
72 #additional error handling and debug information
74 #Function outputs server response body
75 #and performs validation of http_code
78 local curl_response_file="$(mktemp -p /tmp)"
79 local curl_common_flags=(-s -w "%{http_code}" -o "${curl_response_file}")
80 local command=(curl "${curl_common_flags[@]}" "$@")
82 echo "[INFO] Running '${command[@]}'" >&2
83 if ! status="$("${command[@]}")"; then
84 echo "[ERROR] Internal curl error! '$status'" >&2
85 cat "${curl_response_file}"
86 rm "${curl_response_file}"
89 echo "[INFO] Server replied with status: ${status}" >&2
90 cat "${curl_response_file}"
91 rm "${curl_response_file}"
92 if [[ "${status:0:1}" =~ [45] ]]; then
100 function call_api_nox {
101 # this version doesn't exit the script if there's
104 #Runs curl with passed flags and provides
105 #additional error handling and debug information
107 #Function outputs server response body
108 #and performs validation of http_code
111 local curl_response_file="$(mktemp -p /tmp)"
112 local curl_common_flags=(-s -w "%{http_code}" -o "${curl_response_file}")
113 local command=(curl "${curl_common_flags[@]}" "$@")
115 echo "[INFO] Running '${command[@]}'" >&2
116 if ! status="$("${command[@]}")"; then
117 echo "[ERROR] Internal curl error! '$status'" >&2
118 cat "${curl_response_file}"
119 rm "${curl_response_file}"
121 echo "[INFO] Server replied with status: ${status}" >&2
122 if [[ "${status:0:1}" =~ [45] ]]; then
123 cat "${curl_response_file}"
125 cat "${curl_response_file}" | jq .
127 rm "${curl_response_file}"
131 function delete_resource {
132 #Issues DELETE http call to provided endpoint
133 #and further validates by following GET request
135 call_api -X DELETE "$1"
136 ! call_api -X GET "$1" >/dev/null
139 # init_network() - This function creates the OVN resouces required by the test
140 function init_network {
142 local router_name="ovn4nfv-master"
144 name=$(cat $fname | yq '.spec.name' | xargs)
145 subnet=$(cat $fname | yq '.spec.subnet' | xargs)
146 gateway=$(cat $fname | yq '.spec.gateway' | xargs)
147 ovn_central_address=$(get_ovn_central_address)
149 router_mac=$(printf '00:00:00:%02X:%02X:%02X' $((RANDOM%256)) $((RANDOM%256)) $((RANDOM%256)))
150 ovn-nbctl --may-exist --db tcp:$ovn_central_address ls-add $name -- set logical_switch $name other-config:subnet=$subnet external-ids:gateway_ip=$gateway
151 ovn-nbctl --may-exist --db tcp:$ovn_central_address lrp-add $router_name rtos-$name $router_mac $gateway
152 ovn-nbctl --may-exist --db tcp:$ovn_central_address lsp-add $name stor-$name -- set logical_switch_port stor-$name type=router options:router-port=rtos-$name addresses=\"$router_mac\"
155 # cleanup_network() - This function removes the OVN resources created for the test
156 function cleanup_network {
159 name=$(cat $fname | yq '.spec.name' | xargs)
160 ovn_central_address=$(get_ovn_central_address)
162 for cmd in "ls-del $name" "lrp-del rtos-$name" "lsp-del stor-$name"; do
163 ovn-nbctl --if-exist --db tcp:$ovn_central_address $cmd
167 function _checks_args {
169 echo "Missing CSAR ID argument"
172 if [[ -z $CSAR_DIR ]]; then
173 echo "CSAR_DIR global environment value is empty"
176 mkdir -p ${CSAR_DIR}/${1}
183 echo "$(date +%H:%M:%S) - $name : Destroying $type"
184 kubectl delete $type $name --ignore-not-found=true --now
185 while kubectl get $type $name &>/dev/null; do
186 echo "$(date +%H:%M:%S) - $name : Destroying $type"
190 # destroy_deployment() - This function ensures that a specific deployment is
191 # destroyed in Kubernetes
192 function destroy_deployment {
193 local deployment_name=$1
195 _destroy "deployment" $deployment_name
203 kubectl create -f $name.yaml
206 # wait_deployment() - Wait process to Running status on the Deployment's pods
207 function wait_deployment {
208 local deployment_name=$1
211 while [[ $status_phase != "Running" ]]; do
212 new_phase=$(kubectl get pods | grep $deployment_name | awk '{print $3}')
213 if [[ $new_phase != $status_phase ]]; then
214 echo "$(date +%H:%M:%S) - $deployment_name : $new_phase"
215 status_phase=$new_phase
217 if [[ $new_phase == "Err"* ]]; then
223 # wait_for_pod() - Wait until first pod matched by kubectl filters is in running status
224 function wait_for_pod {
226 # wait_for_pods example_pod
227 # wait_for_pods --namespace test different_pod
228 # wait_for_pods -n test -l app=plugin_test
231 while [[ "$status_phase" != "Running" ]]; do
232 new_phase="$(kubectl get pods -o 'go-template={{ index .items 0 "status" "phase" }}' "$@" )"
233 if [[ "$new_phase" != "$status_phase" ]]; then
234 echo "$(date +%H:%M:%S) - Filter=[$*] : $new_phase"
235 status_phase="$new_phase"
237 if [[ "$new_phase" == "Err"* ]]; then
243 # wait_for_deployment() - Wait until the deployment is ready
244 function wait_for_deployment {
246 # wait_for_deployment $DEPLOYMENT_NAME $REPLICAS
247 # wait_for_deployment example_deployment 2
251 while [[ "$status" != $2* ]]; do
252 new_status=`kubectl get deployment -A | grep $1 | awk '{print $3}'`
253 if [[ "$new_status" != "$status" ]]; then
257 pod_status=`kubectl get pods -A | grep $1 | awk '{print $4}'`
258 if [[ $pod_status =~ "Err" ]]; then
259 echo "Deployment $1 error"
265 # wait_for_deployment_status() - Wait until the deployment intent group is the specified status
266 function wait_for_deployment_status {
268 # wait_for_deployment_status {base-url-orchestrator}/projects/{project-name}/composite-apps/{composite-app-name}/{composite-app-version}/deployment-intent-groups/{deployment-intent-group-name}/status Instantiated
269 if [ "$#" -ne 2 ]; then
270 echo "Usage: wait_for_deployment_status URL STATUS"
273 for try in {0..59}; do
275 new_phase="$(call_api $1 | jq -r .status)"
276 echo "$(date +%H:%M:%S) - Filter=[$*] : $new_phase"
277 if [[ "$new_phase" == "$2" ]]; then
284 function setup_type {
288 if ! $(kubectl version &>/dev/null); then
289 echo "This funtional test requires kubectl client"
293 _recreate $type $name
297 wait_deployment $name
301 function teardown_type {
310 # setup() - Base testing setup shared among functional tests
312 setup_type "deployment" $@
315 # teardown() - Base testing teardown function
317 teardown_type "deployment" $@
320 # check_ip_range() - Verifying IP address in address range
321 function check_ip_range {
327 if [[ ! -e /usr/bin/ipcalc ]]; then
328 echo -e "Command 'ipcalc' not found"
332 if [[ -z ${IP} ]] || [[ -z ${MASK} ]]; then
335 min=`/usr/bin/ipcalc $MASK|awk '/HostMin:/{print $2}'`
336 max=`/usr/bin/ipcalc $MASK|awk '/HostMax:/{print $2}'`
337 MIN=`echo $min|awk -F"." '{printf"%.0f\n",$1*256*256*256+$2*256*256+$3*256+$4}'`
338 MAX=`echo $max|awk -F"." '{printf"%.0f\n",$1*256*256*256+$2*256*256+$3*256+$4}'`
339 IPvalue=`echo $IP|awk -F"." '{printf"%.0f\n",$1*256*256*256+$2*256*256+$3*256+$4}'`
340 if [[ "$IPvalue" -gt "$MIN" ]] && [[ "$IPvalue" -lt "$MAX" ]]; then
341 echo -e "$IP in ipset $MASK"
344 echo -e "$IP not in ipset $MASK"
348 test_folder=${FUNCTIONS_DIR}