@@ -16,6 +16,10 @@ HA_NETWORK_V6_ARRAY[1]="2001:db8:20::/64"
16
16
BEHAVE_CASE_DIR=" $( dirname $0 ) /features/"
17
17
BEHAVE_CASE_EXCLUDE=" sbd|ocfs2"
18
18
19
+ declare -a hanode_list_to_form_cluster
20
+ declare -a hanode_list_new_members
21
+ declare -a hanode_list_current_cluster
22
+
19
23
read -r -d ' ' SSHD_CONFIG_AZURE << EOM
20
24
PermitRootLogin no
21
25
AuthorizedKeysFile .ssh/authorized_keys
@@ -103,6 +107,13 @@ is_number() {
103
107
test ! -z " $num " && test " $num " -eq " $num " 2> /dev/null && test " $num " -gt 0 2> /dev/null
104
108
}
105
109
110
+ is_num_or_seq__c_style () {
111
+ echo $1 | grep -q -e ' ^[0-9]\+$'
112
+ [ $? -eq 0 ] && [ " $1 " -gt 0 ] && return 1
113
+ echo $1 | grep -q -e ' ^[0-9]\+\.\.[0-9]\+$'
114
+ [ $? -eq 0 ] && return 2
115
+ return 0 # return 0 means error here
116
+ }
106
117
107
118
check_docker_env () {
108
119
# check if docker available
@@ -126,7 +137,7 @@ check_docker_env() {
126
137
for network in ${HA_NETWORK_ARRAY[@]} ; do
127
138
docker network ls| grep -q " $network "
128
139
if [ " $? " -eq 0 ]; then
129
- fatal " HA specific network \" $network \" already exists"
140
+ warning " HA specific network \" $network \" already exists"
130
141
fi
131
142
done
132
143
}
@@ -160,23 +171,33 @@ The container image is based on Tumbleweed with preinstalled packages of the clu
160
171
Users can make the code change under crmsh.git including test cases. This tool will pick up the code change and "make install" to all running containers.
161
172
162
173
OPTIONS:
163
- -h, --help Show this help message and exit
164
- -l List existing functional test cases and exit
165
- -n NUM Only setup a cluster with NUM nodes(containers)
174
+ -h, --help Show this help message and exit
175
+ -l List existing functional test cases and exit
176
+ -n < NUM|X..Y> NUM of nodes(containers) from hanode1 to hanode $NUM , or hanode $X to hanode $Y
166
177
-x Don't config corosync on containers(with -n option)
167
178
-d Cleanup the cluster containers
168
179
-u Create normal users, and Azure like ssh environment
169
180
-q Create a qnetd node(with -n and -x option)
170
181
171
182
EXAMPLES:
183
+
172
184
To launch 2 nodes with the running cluster with the very basic corosync.conf
173
185
# crmsh.git/test/run-functional-tests -n 2
174
186
187
+ To grow more nodes with a bigger number than '2' in the above example, and skip nodes if exist
188
+ # crmsh.git/test/run-functional-tests -n 5
189
+
190
+ To grow more nodes with the given sequence, even a leap, and skip nodes if exist
191
+ # crmsh.git/test/run-functional-tests -n 10..12
192
+
175
193
To launch 2 nodes without the cluster stack running to play with "crm cluster init/join"
176
- # crmsh.git/run-functional-tests -n 2 -x
194
+ # crmsh.git/test/run-functional-tests -n 2 -x
195
+
196
+ To grow more nodes without configure the cluster stack
197
+ # crmsh.git/test/run-functional-tests -n 3..5 -x
177
198
178
199
To launch 2 nodes without the cluster stack running, and a qnetd node(named 'qnetd-node')
179
- # crmsh.git/run-functional-tests -n 2 -x -q
200
+ # crmsh.git/test/ run-functional-tests -n 2 -x -q
180
201
181
202
To list the existing test cases. Users could add his own new test cases.
182
203
# crmsh.git/test/run-functional-tests -l
@@ -233,8 +254,12 @@ deploy_ha_node() {
233
254
234
255
info " Deploying \" $node_name \" ..."
235
256
docker run --restart always $docker_options $DOCKER_IMAGE & > /dev/null
257
+ if [ $? -ne 0 ]; then
258
+ warning Likely $node_name already exists.
259
+ return
260
+ fi
236
261
for network in ${HA_NETWORK_ARRAY[@]} ; do
237
- docker network connect $network $node_name
262
+ docker network connect $network $node_name & > /dev/null
238
263
done
239
264
240
265
if [ " $node_name " != " qnetd-node" ]; then
@@ -245,29 +270,29 @@ deploy_ha_node() {
245
270
docker_exec $node_name " echo 'StrictHostKeyChecking no' >> /etc/ssh/ssh_config"
246
271
247
272
if [ " $node_name " != " qnetd-node" ]; then
248
- docker cp $PROJECT_PATH $node_name :/opt/crmsh
249
- info " Building crmsh on \" $node_name \" ..."
250
- docker_exec $node_name " $make_cmd " 1> /dev/null || \
273
+ docker cp $PROJECT_PATH $node_name :/opt/crmsh
274
+ info " Building crmsh on \" $node_name \" ..."
275
+ docker_exec $node_name " $make_cmd " 1> /dev/null || \
251
276
fatal " Building failed on $node_name !"
252
- docker_exec $node_name " chown hacluster:haclient -R /var/log/crmsh"
253
- docker_exec $node_name " chmod g+w -R /var/log/crmsh"
254
- create_alice_bob_carol
255
- if [ " $NORMAL_USER_FLAG " -eq 1 ]; then
256
- set_sshd_config_like_in_azure $node_name
257
- fi
277
+ docker_exec $node_name " chown hacluster:haclient -R /var/log/crmsh"
278
+ docker_exec $node_name " chmod g+w -R /var/log/crmsh"
279
+ create_alice_bob_carol
280
+ if [ " $NORMAL_USER_FLAG " -eq 1 ]; then
281
+ set_sshd_config_like_in_azure $node_name
282
+ fi
258
283
else
259
- docker_exec $node_name " useradd -m -s /bin/bash alice 2>/dev/null"
260
- docker_exec $node_name " echo \" alice ALL=(ALL) NOPASSWD:ALL\" > /etc/sudoers.d/alice"
261
- docker_exec $node_name " cp -r /root/.ssh ~alice/ && chown alice:users -R ~alice/.ssh"
262
- info " Create user 'alice' on $node_name "
263
- [ " $NORMAL_USER_FLAG " -eq 1 ] && set_sshd_config_like_in_azure $node_name
284
+ docker_exec $node_name " useradd -m -s /bin/bash alice 2>/dev/null"
285
+ docker_exec $node_name " echo \" alice ALL=(ALL) NOPASSWD:ALL\" > /etc/sudoers.d/alice"
286
+ docker_exec $node_name " cp -r /root/.ssh ~alice/ && chown alice:users -R ~alice/.ssh"
287
+ info " Create user 'alice' on $node_name "
288
+ [ " $NORMAL_USER_FLAG " -eq 1 ] && set_sshd_config_like_in_azure $node_name
264
289
fi
265
290
}
266
291
267
292
268
293
create_node () {
269
294
info " Loading docker image $DOCKER_IMAGE ..."
270
- docker pull $DOCKER_IMAGE & > /dev/null
295
+ docker pull $DOCKER_IMAGE & > /dev/null
271
296
272
297
for index in ${! HA_NETWORK_ARRAY[@]} ; do
273
298
network=${HA_NETWORK_ARRAY[$index]}
@@ -281,40 +306,63 @@ create_node() {
281
306
wait
282
307
}
283
308
309
+ get_cluster_new_nodes () {
310
+ hanode_list_to_form_cluster=($( docker ps -a --format ' {{.Names}}' | grep hanode| sort -n -k1.7| tr ' \r' ' ' ) )
311
+ hanode_list_current_cluster=($( docker_exec hanode1 " crm node server 2>/dev/null" 2> /dev/null| sort -n -k1.7| tr ' \r' ' ' ) )
312
+ hanode_list_new_members=()
313
+ for element in " ${hanode_list_to_form_cluster[@]} " ; do
314
+ if ! [[ " ${hanode_list_current_cluster[@]} " =~ " $element " ]]; then
315
+ hanode_list_new_members+=(" $element " )
316
+ fi
317
+ done
318
+ # echo hanode_list_to_form_cluster= ${hanode_list_to_form_cluster[@]}
319
+ # echo hanode_list_current_cluster = ${hanode_list_current_cluster[@]}
320
+ # echo ${#hanode_list_new_members[@]} new nodes "'${hanode_list_new_members[@]}'"
321
+ }
284
322
285
323
config_cluster () {
286
- node_num=$#
287
- insert_str=" "
288
- container_ip_array=(` docker network inspect $HA_NETWORK_ARRAY -f ' {{range .Containers}}{{printf "%s " .IPv4Address}}{{end}}' ` )
324
+ get_cluster_new_nodes
325
+ info ${# hanode_list_new_members[@]} new node\( s\) " '${hanode_list_new_members[@]} '"
289
326
290
- for i in $( seq $node_num -1 1) ; do
291
- ip=` echo ${container_ip_array[$((i-1))]} | awk -F/ ' {print $1}' `
327
+ if [ ${# hanode_list_new_members[@]} -eq 0 ]; then
328
+ return
329
+ fi
330
+
331
+ insert_str=" "
332
+ for i in $( seq 1 ${# hanode_list_to_form_cluster[@]} ) ; do
333
+ node=${hanode_list_to_form_cluster[$((i-1))]}
334
+ ip=$( docker network inspect " $HA_NETWORK_ARRAY " --format ' {{range .Containers}}{{if eq .Name "' " ${node} " ' "}}{{.IPv4Address}}{{end}}{{end}}' | awk -F/ ' {print $1}' )
292
335
insert_str+=" \\ n\\ tnode {\n\t\tring0_addr: $ip \n\t\tnodeid: $i \n\t}"
293
336
done
337
+
294
338
corosync_conf_str=$( sed " /nodelist/a \\ ${insert_str} " <( echo " $COROSYNC_CONF_TEMPLATE " ) )
295
- if [ $node_num -eq 2 ]; then
339
+ docker_exec " hanode1" " echo \" $corosync_conf_str \" > $COROSYNC_CONF "
340
+ if [ ${# hanode_list_to_form_cluster[@]} -eq 2 ]; then
296
341
corosync_conf_str=$( sed " /corosync_votequorum/a \\\\ ttwo_node: 1" <( echo " $corosync_conf_str " ) )
297
342
fi
298
343
299
- info " Copy corosync.conf to $* "
300
- for node in $* ; do
301
- if [ $node == $1 ]; then
302
- docker_exec $1 " echo \" $corosync_conf_str \" >> $COROSYNC_CONF "
303
- docker_exec $1 " corosync-keygen -l -k $COROSYNC_AUTH &> /dev/null"
344
+ info " Copy corosync.conf to ${hanode_list_to_form_cluster[@]} "
345
+ for node in ${hanode_list_to_form_cluster[@]} ; do
346
+ if [ $node == " hanode1" ]; then
347
+ docker_exec " hanode1" " corosync-keygen -l -k $COROSYNC_AUTH &> /dev/null"
304
348
else
305
349
while :
306
350
do
307
- docker_exec $1 " ssh -T -o Batchmode=yes $node true &> /dev/null" && break
351
+ docker_exec " hanode1 " " ssh -T -o Batchmode=yes $node true &> /dev/null" && break
308
352
sleep 1
309
353
done
310
- docker_exec $1 " scp -p $COROSYNC_CONF $COROSYNC_AUTH $node :/etc/corosync &> /dev/null"
354
+ docker_exec " hanode1 " " scp -p $COROSYNC_CONF $COROSYNC_AUTH $node :/etc/corosync &> /dev/null"
311
355
fi
312
356
done
313
357
}
314
358
315
-
316
359
start_cluster () {
317
- for node in $* ; do
360
+ if [ ${# hanode_list_current_cluster[@]} -ne 0 ] && [ ${# hanode_list_new_members[@]} -ne 0 ]; then
361
+ docker_exec hanode1 " corosync-cfgtool -R > /dev/null"
362
+ info Cluster exists at ' hanode1' : Reloading corosync.conf... Done
363
+ fi
364
+
365
+ for node in ${hanode_list_new_members[@]} ; do
318
366
docker_exec $node " crm cluster enable && crm cluster start" 1> /dev/null
319
367
if [ " $? " -eq 0 ]; then
320
368
info " Cluster service started on \" $node \" "
@@ -324,35 +372,51 @@ start_cluster() {
324
372
done
325
373
}
326
374
327
-
328
- container_already_exists () {
329
- docker ps -a| grep -q " $1 "
330
- if [ " $? " -eq 0 ]; then
331
- fatal " Container \" $1 \" already running"
332
- fi
375
+ is_container_existing () {
376
+ docker ps -a --format ' {{.Names}}' | grep -q " ^$1 $"
333
377
}
334
378
335
-
336
379
setup_cluster () {
337
- hanodes_arry=()
338
- is_number $1
339
- if [ " $? " -eq 0 ]; then
340
- for i in $( seq 1 $1 ) ; do
341
- hanodes_arry+=(" hanode$i " )
380
+ get_cluster_new_nodes
381
+
382
+ hanodes_array=()
383
+ is_num_or_seq__c_style $1
384
+ ret=$?
385
+ if [ $ret -eq 1 ]; then
386
+ # add more nodes after the last node, ordered by the node name
387
+ if [ ${# hanode_list_to_form_cluster[@]} -gt 0 ]; then
388
+ last_node_num=" ${hanode_list_to_form_cluster[-1]: 6} "
389
+ else
390
+ last_node_num=0
391
+ fi
392
+ num_of_new_nodes=$(( $1 - ${# hanode_list_to_form_cluster[@]} ))
393
+ if [ " $num_of_new_nodes " -gt 0 ]; then
394
+ for i in $( seq $(( last_node_num + 1 )) $(( last_node_num + num_of_new_nodes )) ) ; do
395
+ hanodes_array+=(" hanode$i " )
396
+ done
397
+ else
398
+ info 0 new node
399
+ return
400
+ fi
401
+ elif [ $ret -eq 2 ]; then
402
+ is_container_existing " hanode1" || hanodes_array=(" hanode1" )
403
+ from_to=($( echo $1 | tr " .." " " ) )
404
+ for i in $( seq ${from_to[0]} ${from_to[1]} ) ; do
405
+ hanodes_array+=(" hanode$i " )
342
406
done
343
407
else
344
- hanodes_arry =($* )
408
+ hanodes_array =($* )
345
409
fi
346
410
347
411
if [ $WITH_QNETD_NODE -eq 1 ]; then
348
- create_node ${hanodes_arry [@]} " qnetd-node"
412
+ create_node ${hanodes_array [@]} " qnetd-node"
349
413
else
350
- create_node ${hanodes_arry [@]}
414
+ create_node ${hanodes_array [@]}
351
415
fi
352
416
353
417
[ " $CONFIG_COROSYNC_FLAG " -eq 0 ] && return
354
- config_cluster ${hanodes_arry[@]}
355
- start_cluster ${hanodes_arry[@]}
418
+ config_cluster
419
+ start_cluster
356
420
docker_exec " hanode1" " crm configure property stonith-enabled=false"
357
421
}
358
422
@@ -431,7 +495,7 @@ run_origin_regression_test() {
431
495
432
496
prepare_coverage_env () {
433
497
for node in $* ; do
434
- docker exec -t $node /bin/sh -c ' sed -i ' \' ' 1a\import coverage\nimport atexit\ncov=coverage.Coverage(config_file="/opt/crmsh/test/features/coveragerc")\natexit.register(lambda:(cov.stop(),cov.save()))\ncov.start()' \' ' /usr/sbin/crm'
498
+ docker exec -t $node /bin/sh -c ' sed -i ' \' ' 1a\import coverage\nimport atexit\ncov=coverage.Coverage(config_file="/opt/crmsh/test/features/coveragerc")\natexit.register(lambda:(cov.stop(),cov.save()))\ncov.start()' \' ' /usr/sbin/crm'
435
499
done
436
500
}
437
501
@@ -479,7 +543,7 @@ case $1 in
479
543
-n)
480
544
check_docker_env
481
545
shift
482
- is_number $1 || fatal " -n option need a number larger than 0"
546
+ is_num_or_seq__c_style $1 && fatal " -n option need a number larger than 0, or a sequence like 5..10 "
483
547
SETUP_N_NODES_CLUSTER=$1
484
548
shift
485
549
;;
@@ -490,7 +554,7 @@ case $1 in
490
554
esac
491
555
done
492
556
493
- if [ $SETUP_N_NODES_CLUSTER -ge 1 ]; then
557
+ if [ " $SETUP_N_NODES_CLUSTER " != " 0 " ]; then
494
558
setup_cluster $SETUP_N_NODES_CLUSTER
495
559
exit $?
496
560
fi
@@ -538,13 +602,13 @@ for case_num in $*;do
538
602
setup_cluster ${node_arry[@]}
539
603
adjust_test_case ${node_arry[0]} $case_file_in_container
540
604
echo
541
- prepare_coverage_env " ${node_arry[@]} "
605
+ prepare_coverage_env " ${node_arry[@]} "
542
606
if [ " $NORMAL_USER_FLAG " -eq 0 ]; then
543
607
info " Running \" $case_file_in_container \" under 'root'..."
544
608
docker_exec ${node_arry[0]} " behave --no-logcapture $case_file_in_container || exit 1" || exit 1
545
609
else
546
610
info " Running \" $case_file_in_container \" under normal user 'alice'..."
547
- docker_exec ${node_arry[0]} " su - alice -c 'sudo behave --no-logcapture $case_file_in_container || exit 1'" || exit 1
611
+ docker_exec ${node_arry[0]} " su - alice -c 'sudo behave --no-logcapture $case_file_in_container || exit 1'" || exit 1
548
612
fi
549
613
fetch_coverage_report " ${node_arry[@]} "
550
614
echo
0 commit comments