Merge "Change AtLevelLoggers to be initialized by lazy"
[dcaegen2/collectors/hv-ves.git] / development / bin / start-simulation.sh
1 #!/usr/bin/env bash
2 # ============LICENSE_START=======================================================
3 # dcaegen2-collectors-veshv
4 # ================================================================================
5 # Copyright (C) 2018 NOKIA
6 # ================================================================================
7 # Licensed under the Apache License, Version 2.0 (the "License");
8 # you may not use this file except in compliance with the License.
9 # You may obtain a copy of the License at
10 #
11 #      http://www.apache.org/licenses/LICENSE-2.0
12 #
13 # Unless required by applicable law or agreed to in writing, software
14 # distributed under the License is distributed on an "AS IS" BASIS,
15 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 # See the License for the specific language governing permissions and
17 # limitations under the License.
18 # ============LICENSE_END=========================================================
19
20 set -euo pipefail
21
22
23 function usage() {
24     echo ""
25     echo "Send messages to hv-ves from multiple xNF simulators"
26     echo "Usage: $0 [-h|--help] [-v|--verbose] [--messages-in-batch] [--docker-network] [--xnf-logs-directory]"
27     echo "              <hv ves hostname> <hv ves port> <simulators amount> <messages batches amount per simulator> <messages sending interval>"
28     echo ""
29     echo "  - hv ves hostname : HighVolume VES Collector network hostname"
30     echo "  - hv ves port : HighVolume VES Collector network port"
31     echo "  - simulators amount : Amount of xNF simulators to be launched"
32     echo "  - messages amount per simulator : Amount of messages to be sent from each xNF simulator to HV-VES"
33     echo "  - messages sending interval : interval in seconds between sending messages from xNFs"
34     echo "Optional parameters:"
35     echo "  - messages-in-batch : Amount of messages sent on each request"
36     echo "  - docker-network : Docker network to which xNF simulators should be added"
37     echo "  - xnf-logs-directory : Path to directory where logs from all xNF simulators should be stored"
38     echo "Example invocations:"
39     echo "./start-simulation.sh --messages-in-batch=5 --docker-network=development_default ves-hv-collector 6061 10 20 0.5"
40     echo "./start-simulation.sh --messages-in-batch=5 --xnf-logs-directory=/tmp/xnf-simulation localhost 6061 10 20 0.5"
41     exit 1
42 }
43
44 function verbose_log() {
45     if [ -n "${VERBOSE+x}" ]; then
46         echo $@
47     fi
48 }
49
50 function create_logs_dir() {
51     if [ -n "${XNF_LOGS_DIRECTORY+x}" ]; then
52         if [ ! -d "${XNF_LOGS_DIRECTORY}" ]; then
53             mkdir ${XNF_LOGS_DIRECTORY}
54         fi
55     fi
56 }
57
58 function create_xNFs_simulators() {
59     for i in $(seq 1 ${XNFS_AMOUNT}); do
60         local XNF_PORT=$(get_unoccupied_port 32000 65000)
61         verbose_log "Starting xNF simulator container on port ${XNF_PORT} using run-xnf-simulator script"
62         XNF_CONTAINER_ID=$(${DEVELOPMENT_BIN_DIRECTORY}/run-xnf-simulator.sh $XNF_PORT ${DOCKER_NETWORK:-})
63         CREATED_XNF_SIMULATORS_PORTS+=(${XNF_PORT})
64         verbose_log "Container id: ${XNF_CONTAINER_ID}"
65         CREATED_XNF_SIMULATORS_IDS+=(${XNF_CONTAINER_ID})
66     done
67 }
68
69 function get_unoccupied_port() {
70     local LPORT=$1
71     local UPORT=$2
72     while true; do
73         local MPORT=$[$LPORT + ($RANDOM % $UPORT)];
74         local LISTENING_PORTS=$(osqueryi --header=false --list "select port from listening_ports order by port");
75         if (echo "${LISTENING_PORTS[@]}" | grep -xqv $MPORT); then
76             echo $MPORT;
77             break;
78         fi
79     done
80 }
81
82 function wait_for_containers_startup_or_fail() {
83     local seconds_to_wait=10
84     local all_containers_healthy=1
85
86     verbose_log "Waiting ${seconds_to_wait}s for containers startup"
87     set +e
88     for i in $(seq 1 ${seconds_to_wait}); do
89         verbose_log "Try no. ${i}"
90         all_containers_healthy=1
91         for port in ${CREATED_XNF_SIMULATORS_PORTS[@]}; do
92             verbose_log "Checking container on port ${port}"
93             local status_code=$(curl -s -o /dev/null -I -w "%{http_code}" localhost:${port}/healthcheck)
94             if [ $status_code -ne 200 ]; then
95                 verbose_log "Container on port ${port} is unhealthy "
96                 all_containers_healthy=0
97                 break
98             fi
99         done
100         if [ $all_containers_healthy -eq 1 ]; then
101             break
102         fi
103         sleep 1
104     done
105     set -e
106
107     if [ $all_containers_healthy -ne 1 ]; then
108         echo "Some xNFs simulators failed at startup. Trying to cleanup..."
109         cleanup
110         echo "Exitting..."
111         exit 2
112     fi
113 }
114
115 function start_simulation() {
116     verbose_log "Simulation: every xNF will send ${MESSAGES_IN_BATCH} messages to hv-ves
117     ${MESSAGE_BATCHES_AMOUNT} times, once every ${MESSAGES_SENDING_INTERVAL}"
118     for port in ${CREATED_XNF_SIMULATORS_PORTS[@]}; do
119         start_single_simulation $port $MESSAGES_IN_BATCH &
120     done
121 }
122
123 function start_single_simulation() {
124     local port=$1
125     local messages_to_be_sent=$2
126     local message_type="VALID"
127     for i in $(seq 1 ${MESSAGE_BATCHES_AMOUNT}); do
128         ${DEVELOPMENT_BIN_DIRECTORY}/xnf-simulation.sh $port $messages_to_be_sent $message_type > /dev/null &
129         sleep $MESSAGES_SENDING_INTERVAL
130     done
131 }
132
133 function assure_all_xNFs_requests_were_sent {
134     WAIT_TIME_FOR_REQUESTS_TO_BE_SENT=$(echo ";1 + $MESSAGES_SENDING_INTERVAL * $MESSAGE_BATCHES_AMOUNT" | bc)
135     echo "Waiting ${WAIT_TIME_FOR_REQUESTS_TO_BE_SENT}s for all xNF requests to be sent"
136     sleep $WAIT_TIME_FOR_REQUESTS_TO_BE_SENT
137 }
138
139 function wait_for_simulators_to_finish_sending_messages() {
140     local seconds_to_wait=$1
141     local all_containers_finished=1
142
143     echo "Waiting up to ${seconds_to_wait}s for xNFs simulators to finish sending messages"
144     for i in $(seq 1 ${seconds_to_wait}); do
145         verbose_log "Wait no. ${i}"
146         all_containers_finished=1
147         for port in ${CREATED_XNF_SIMULATORS_PORTS[@]}; do
148             local container_status=$(curl --request GET -s localhost:${port}/healthcheck | jq -r '.["Detailed status"]')
149
150             verbose_log "Container on port ${port} status:  ${container_status}"
151             if [ "${container_status}" = "Busy" ]; then
152                 all_containers_finished=0
153                 break
154             fi
155         done
156         if [ $all_containers_finished -eq 1 ]; then
157             echo "All containers finished sending messages"
158             break
159         fi
160         sleep 1
161     done
162 }
163
164 function cleanup() {
165     echo "Cleaning up"
166     set +e
167     for container_id in ${CREATED_XNF_SIMULATORS_IDS[@]}; do
168         verbose_log "Stopping container: ${container_id}"
169         docker stop $container_id > /dev/null
170         if [ -n "${XNF_LOGS_DIRECTORY+x}" ]; then
171             local log_file=${XNF_LOGS_DIRECTORY}/${container_id}.log
172             verbose_log "Writing container logs to: ${log_file}"
173             docker logs ${container_id} > $log_file
174         fi
175         verbose_log "Removing container: ${container_id}"
176         docker rm $container_id > /dev/null
177     done
178     set -e
179 }
180
181
182 function parse_long_opts_with_arguments() {
183     if [[ ${OPTARG} =~ .*=.* ]] # is option in --key=value format
184     then
185         OPT=${OPTARG/=*/}
186         ((${#OPT} <= 1)) && {
187          echo "Invalid option '$OPT'" >&2
188          exit 2
189         }
190         OPTARG=${OPTARG#*=}
191     else
192         echo -e "No value provided for ${OPTARG}. Please use \"--${OPTARG}=VALUE\" format." >&2
193         usage
194     fi
195 }
196
197 # parse command line
198 optspec=":vh-:" # catch v, h and -
199 while getopts "$optspec" arg; do
200     case "${arg}" in
201         -) # handle longopts
202             case "${OPTARG}" in
203                 verbose)
204                     VERBOSE=True ;;
205                 help)
206                     usage ;;
207                 *)
208                     parse_long_opts_with_arguments
209                     case "${OPT}" in
210                         messages-in-batch)
211                             MESSAGES_IN_BATCH=$OPTARG ;;
212                         docker-network)
213                             DOCKER_NETWORK=$OPTARG ;;
214                         xnf-logs-directory)
215                             XNF_LOGS_DIRECTORY=$OPTARG ;;
216                         *)
217                             usage ;;
218                     esac ;;
219              esac ;;
220         v)
221             VERBOSE=True ;;
222         h)
223             usage ;;
224         *)
225             echo "Unknown option -${OPTARG}" >&2
226             usage ;;
227     esac
228 done
229 shift $((OPTIND-1))
230
231 [ $# -le 4 ] && (echo -e "Unsufficient arguments"; usage)
232
233
234 DEVELOPMENT_BIN_DIRECTORY=$(realpath $(dirname "$0"))
235 HV_VES_HOSTNAME=${1}
236 HV_VES_PORT=${2}
237 XNFS_AMOUNT=${3}
238 MESSAGE_BATCHES_AMOUNT=${4}
239 MESSAGES_SENDING_INTERVAL=${5}
240
241 # set defaults if absent
242 [ -z "${MESSAGES_IN_BATCH}" ] && MESSAGES_IN_BATCH=1
243
244 create_logs_dir
245
246
247 CREATED_XNF_SIMULATORS_PORTS=()
248 CREATED_XNF_SIMULATORS_IDS=()
249 echo "Creating ${XNFS_AMOUNT} xNFs simulators"
250 trap cleanup SIGINT SIGTERM
251 create_xNFs_simulators
252
253 wait_for_containers_startup_or_fail
254
255 echo "All xNFs containers are healthy, starting simulation"
256 start_simulation
257
258 assure_all_xNFs_requests_were_sent
259
260 assumed_message_sending_time=$(echo ";0.00025 * $XNFS_AMOUNT" | bc)
261 seconds_to_wait=$(echo ";$assumed_message_sending_time * $MESSAGE_BATCHES_AMOUNT * $MESSAGES_IN_BATCH" | bc)
262 wait_for_simulators_to_finish_sending_messages $seconds_to_wait
263 # there might be network lag between moment when xNF finished sending messages and they actually are received by hv-ves
264 # thus we cannot start removing xNFs immediately to prevent closing socket channels
265 sleep 5
266
267 cleanup