vitess.io/vitess@v0.16.2/test/vtop_example.sh (about) 1 #!/bin/bash 2 3 # Copyright 2022 The Vitess Authors. 4 # 5 # Licensed under the Apache License, Version 2.0 (the "License"); 6 # you may not use this file except in compliance with the License. 7 # You may obtain a copy of the License at 8 # 9 # http://www.apache.org/licenses/LICENSE-2.0 10 # 11 # Unless required by applicable law or agreed to in writing, software 12 # distributed under the License is distributed on an "AS IS" BASIS, 13 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 # See the License for the specific language governing permissions and 15 # limitations under the License. 16 17 # This test runs through the scripts in examples/operator to make sure they work. 18 # It should be kept in sync with the steps in https://vitess.io/docs/get-started/operator/ 19 # So we can detect if a regression affecting a tutorial is introduced. 20 21 22 ## This script should be called with kind and kubectl already installed 23 24 source build.env 25 26 # Use this to debug issues. It will print the commands as they run 27 # set -x 28 shopt -s expand_aliases 29 alias vtctlclient="vtctlclient --server=localhost:15999" 30 alias vtctldclient="vtctldclient --server=localhost:15999" 31 alias mysql="mysql -h 127.0.0.1 -P 15306 -u user" 32 33 cd "$VTROOT" 34 unset VTROOT # ensure that the examples can run without VTROOT now. 35 36 function checkSemiSyncSetup() { 37 for vttablet in $(kubectl get pods --no-headers -o custom-columns=":metadata.name" | grep "vttablet") ; do 38 echo "Checking semi-sync in $vttablet" 39 kubectl exec "$vttablet" -c mysqld -- mysql -S "/vt/socket/mysql.sock" -u root -e "show variables like 'rpl_semi_sync_slave_enabled'" | grep "OFF" 40 if [ $? -ne 0 ]; then 41 echo "Semi Sync setup on $vttablet" 42 exit 1 43 fi 44 done 45 } 46 47 # checkPodStatusWithTimeout: 48 # $1: regex used to match pod names 49 # $2: number of pods to match (default: 1) 50 function checkPodStatusWithTimeout() { 51 regex=$1 52 nb=$2 53 54 # Number of pods to match defaults to one 55 if [ -z "$nb" ]; then 56 nb=1 57 fi 58 59 # We use this for loop instead of `kubectl wait` because we don't have access to the full pod name 60 # and `kubectl wait` does not support regex to match resource name. 61 for i in {1..1200} ; do 62 out=$(kubectl get pods) 63 echo "$out" | grep -E "$regex" | wc -l | grep "$nb" > /dev/null 2>&1 64 if [ $? -eq 0 ]; then 65 echo "$regex found" 66 return 67 fi 68 sleep 1 69 done 70 echo -e "ERROR: checkPodStatusWithTimeout timeout to find pod matching:\ngot:\n$out\nfor regex: $regex" 71 exit 1 72 } 73 74 # changeImageAndApply changes the vitess images in the yaml configuration 75 # to the ones produced down below before applying them 76 function changeImageAndApply() { 77 file=$1 78 sed 's/vitess\/lite:.*/vitess\/lite:pr/g' "$file" | sed 's/vitess\/vtadmin:.*/vitess\/vtadmin:pr/g' > temp.yaml 79 kubectl apply -f temp.yaml 80 rm temp.yaml 81 } 82 83 function waitForKeyspaceToBeServing() { 84 ks=$1 85 shard=$2 86 nb_of_replica=$3 87 for i in {1..600} ; do 88 out=$(mysql --table --execute="show vitess_tablets") 89 echo "$out" | grep -E "$ks(.*)$shard(.*)PRIMARY(.*)SERVING|$ks(.*)$shard(.*)REPLICA(.*)SERVING" | wc -l | grep "$((nb_of_replica+1))" 90 if [ $? -eq 0 ]; then 91 echo "Shard $ks/$shard is serving" 92 return 93 fi 94 echo "Shard $ks/$shard is not fully serving, retrying (attempt #$i) ..." 95 sleep 10 96 done 97 } 98 99 function applySchemaWithRetry() { 100 schema=$1 101 ks=$2 102 drop_sql=$3 103 for i in {1..600} ; do 104 vtctldclient ApplySchema --sql-file="$schema" $ks 105 if [ $? -eq 0 ]; then 106 return 107 fi 108 if [ -n "$drop_sql" ]; then 109 mysql --table < $drop_sql 110 fi 111 echo "failed to apply schema $schema, retrying (attempt #$i) ..." 112 sleep 1 113 done 114 } 115 116 function printMysqlErrorFiles() { 117 for vttablet in $(kubectl get pods --no-headers -o custom-columns=":metadata.name" | grep "vttablet") ; do 118 echo "Finding error.log file in $vttablet" 119 kubectl logs "$vttablet" -c mysqld 120 kubectl logs "$vttablet" -c vttablet 121 done 122 } 123 124 function insertWithRetry() { 125 for i in {1..600} ; do 126 mysql --table < ./delete_commerce_data.sql && mysql --table < ../common/insert_commerce_data.sql 127 if [ $? -eq 0 ]; then 128 return 129 fi 130 echo "failed to insert commerce data, retrying (attempt #$i) ..." 131 sleep 1 132 done 133 } 134 135 function assertSelect() { 136 sql=$1 137 shard=$2 138 expected=$3 139 data=$(mysql --table < $sql) 140 echo "$data" | grep "$expected" > /dev/null 2>&1 141 if [ $? -ne 0 ]; then 142 echo -e "The data in $shard's tables is incorrect, got:\n$data" 143 exit 1 144 fi 145 } 146 147 # get_started: 148 function get_started() { 149 echo "Apply operator.yaml" 150 changeImageAndApply "operator.yaml" 151 checkPodStatusWithTimeout "vitess-operator(.*)1/1(.*)Running(.*)" 152 153 echo "Apply 101_initial_cluster.yaml" 154 changeImageAndApply "101_initial_cluster.yaml" 155 checkPodStatusWithTimeout "example-zone1-vtctld(.*)1/1(.*)Running(.*)" 156 checkPodStatusWithTimeout "example-zone1-vtgate(.*)1/1(.*)Running(.*)" 157 checkPodStatusWithTimeout "example-etcd(.*)1/1(.*)Running(.*)" 3 158 checkPodStatusWithTimeout "example-vttablet-zone1(.*)3/3(.*)Running(.*)" 2 159 checkPodStatusWithTimeout "example-zone1-vtadmin(.*)2/2(.*)Running(.*)" 160 checkPodStatusWithTimeout "example-commerce-x-x-zone1-vtorc(.*)1/1(.*)Running(.*)" 161 162 sleep 10 163 echo "Creating vschema and commerce SQL schema" 164 165 ./pf.sh > /dev/null 2>&1 & 166 sleep 5 167 168 waitForKeyspaceToBeServing commerce - 1 169 sleep 5 170 171 applySchemaWithRetry create_commerce_schema.sql commerce drop_all_commerce_tables.sql 172 vtctldclient ApplyVSchema --vschema-file="vschema_commerce_initial.json" commerce 173 if [ $? -ne 0 ]; then 174 echo "ApplySchema failed for initial commerce" 175 printMysqlErrorFiles 176 exit 1 177 fi 178 sleep 5 179 180 echo "show databases;" | mysql | grep "commerce" > /dev/null 2>&1 181 if [ $? -ne 0 ]; then 182 echo "Could not find commerce database" 183 printMysqlErrorFiles 184 exit 1 185 fi 186 187 echo "show tables;" | mysql commerce | grep -E 'corder|customer|product' | wc -l | grep 3 > /dev/null 2>&1 188 if [ $? -ne 0 ]; then 189 echo "Could not find commerce's tables" 190 printMysqlErrorFiles 191 exit 1 192 fi 193 194 insertWithRetry 195 196 assertSelect ../common/select_commerce_data.sql "commerce" <<EOF 197 Using commerce 198 Customer 199 +-------------+--------------------+ 200 | customer_id | email | 201 +-------------+--------------------+ 202 | 1 | alice@domain.com | 203 | 2 | bob@domain.com | 204 | 3 | charlie@domain.com | 205 | 4 | dan@domain.com | 206 | 5 | eve@domain.com | 207 +-------------+--------------------+ 208 Product 209 +----------+-------------+-------+ 210 | sku | description | price | 211 +----------+-------------+-------+ 212 | SKU-1001 | Monitor | 100 | 213 | SKU-1002 | Keyboard | 30 | 214 +----------+-------------+-------+ 215 COrder 216 +----------+-------------+----------+-------+ 217 | order_id | customer_id | sku | price | 218 +----------+-------------+----------+-------+ 219 | 1 | 1 | SKU-1001 | 100 | 220 | 2 | 2 | SKU-1002 | 30 | 221 | 3 | 3 | SKU-1002 | 30 | 222 | 4 | 4 | SKU-1002 | 30 | 223 | 5 | 5 | SKU-1002 | 30 | 224 +----------+-------------+----------+-------+ 225 EOF 226 } 227 228 # verifyVtadminSetup verifies that we can query the vtadmin api end point 229 function verifyVtadminSetup() { 230 # Verify the debug/env page can be curled and it contains the kubernetes environment variables like HOSTNAME 231 curlGetRequestWithRetry "localhost:14001/debug/env" "HOSTNAME=example-zone1-vtadmin" 232 # Verify the api/keyspaces page can be curled and it contains the name of the keyspace created 233 curlGetRequestWithRetry "localhost:14001/api/keyspaces" "commerce" 234 # Verify the other APIs work as well 235 curlGetRequestWithRetry "localhost:14001/api/tablets" '"tablets":\[{"cluster":{"id":"example","name":"example"},"tablet":{"alias":{"cell":"zone1"' 236 curlGetRequestWithRetry "localhost:14001/api/schemas" '"keyspace":"commerce","table_definitions":\[{"name":"corder","schema":"CREATE TABLE `corder` (\\n `order_id` bigint NOT NULL AUTO_INCREMENT' 237 # Verify that we are able to create a keyspace 238 curlPostRequest "localhost:14001/api/keyspace/example" '{"name":"testKeyspace"}' 239 # List the keyspaces and check that we have them both 240 curlGetRequestWithRetry "localhost:14001/api/keyspaces" "commerce.*testKeyspace" 241 # Try and delete the keyspace but this should fail because of the rbac rules 242 curlDeleteRequest "localhost:14001/api/keyspace/example/testKeyspace" "unauthorized.*cannot.*delete.*keyspace" 243 # We should still have both the keyspaces 244 curlGetRequestWithRetry "localhost:14001/api/keyspaces" "commerce.*testKeyspace" 245 # Delete the keyspace by using the vtctlclient 246 vtctldclient DeleteKeyspace testKeyspace 247 # Verify we still have the commerce keyspace and no other keyspace 248 curlGetRequestWithRetry "localhost:14001/api/keyspaces" "commerce.*}}}}]" 249 } 250 251 # verifyVTOrcSetup verifies that VTOrc is running and repairing things that we mess up 252 function verifyVTOrcSetup() { 253 # Set the primary tablet to readOnly using the vtctld and wait for VTOrc to repair 254 primaryTablet=$(getPrimaryTablet) 255 vtctldclient SetWritable "$primaryTablet" false 256 257 # Now that we have set the primary tablet to read only, we know that this will 258 # only succeed if VTOrc is able to fix it 259 tryInsert 260 # We now delete the row because the move tables workflow assertions are not expecting this row to be present 261 mysql -e "delete from customer where email = 'newemail@domain.com';" 262 } 263 264 function tryInsert() { 265 for i in {1..600} ; do 266 mysql -e "insert into customer(email) values('newemail@domain.com');" 267 if [ $? -eq 0 ]; then 268 return 269 fi 270 echo "failed to insert data, retrying (attempt #$i) ..." 271 sleep 1 272 done 273 } 274 275 # getPrimaryTablet returns the primary tablet 276 function getPrimaryTablet() { 277 vtctlclient ListAllTablets | grep "primary" | awk '{print $1}' 278 } 279 280 function curlGetRequestWithRetry() { 281 url=$1 282 dataToAssert=$2 283 for i in {1..600} ; do 284 res=$(curl "$url") 285 if [ $? -eq 0 ]; then 286 echo "$res" | grep "$dataToAssert" > /dev/null 2>&1 287 if [ $? -ne 0 ]; then 288 echo -e "The data in $url is incorrect, got:\n$res" 289 exit 1 290 fi 291 return 292 fi 293 echo "failed to query url $url, retrying (attempt #$i) ..." 294 sleep 1 295 done 296 } 297 298 function curlDeleteRequest() { 299 url=$1 300 dataToAssert=$2 301 res=$(curl -X DELETE "$url") 302 if [ $? -ne 0 ]; then 303 echo -e "The DELETE request to $url failed\n" 304 exit 1 305 fi 306 echo "$res" | grep "$dataToAssert" > /dev/null 2>&1 307 if [ $? -ne 0 ]; then 308 echo -e "The data in delete request to $url is incorrect, got:\n$res" 309 exit 1 310 fi 311 } 312 313 function curlPostRequest() { 314 url=$1 315 data=$2 316 curl -X POST -d "$data" "$url" 317 if [ $? -ne 0 ]; then 318 echo -e "The POST request to $url with data $data failed\n" 319 exit 1 320 fi 321 } 322 323 function move_tables() { 324 echo "Apply 201_customer_tablets.yaml" 325 changeImageAndApply 201_customer_tablets.yaml 326 checkPodStatusWithTimeout "example-vttablet-zone1(.*)3/3(.*)Running(.*)" 4 327 328 killall kubectl 329 ./pf.sh > /dev/null 2>&1 & 330 331 waitForKeyspaceToBeServing customer - 1 332 333 sleep 10 334 335 vtctldclient LegacyVtctlCommand -- MoveTables --source commerce --tables 'customer,corder' Create customer.commerce2customer 336 if [ $? -ne 0 ]; then 337 echo "MoveTables failed" 338 printMysqlErrorFiles 339 exit 1 340 fi 341 342 sleep 10 343 344 vdiff_out=$(vtctldclient LegacyVtctlCommand -- VDiff customer.commerce2customer) 345 echo "$vdiff_out" | grep "ProcessedRows: 5" | wc -l | grep "2" > /dev/null 346 if [ $? -ne 0 ]; then 347 echo -e "VDiff output is invalid, got:\n$vdiff_out" 348 # Allow failure 349 fi 350 351 vtctldclient LegacyVtctlCommand -- MoveTables --tablet_types='rdonly,replica' SwitchTraffic customer.commerce2customer 352 if [ $? -ne 0 ]; then 353 echo "SwitchTraffic for rdonly and replica failed" 354 printMysqlErrorFiles 355 exit 1 356 fi 357 358 vtctldclient LegacyVtctlCommand -- MoveTables --tablet_types='primary' SwitchTraffic customer.commerce2customer 359 if [ $? -ne 0 ]; then 360 echo "SwitchTraffic for primary failed" 361 printMysqlErrorFiles 362 exit 1 363 fi 364 365 vtctldclient LegacyVtctlCommand -- MoveTables Complete customer.commerce2customer 366 if [ $? -ne 0 ]; then 367 echo "MoveTables Complete failed" 368 printMysqlErrorFiles 369 exit 1 370 fi 371 372 sleep 10 373 } 374 375 function resharding() { 376 echo "Create new schemas for new shards" 377 applySchemaWithRetry create_commerce_seq.sql commerce 378 sleep 4 379 vtctldclient ApplyVSchema --vschema-file="vschema_commerce_seq.json" commerce 380 if [ $? -ne 0 ]; then 381 echo "ApplyVschema commerce_seq during resharding failed" 382 printMysqlErrorFiles 383 exit 1 384 fi 385 sleep 4 386 vtctldclient ApplyVSchema --vschema-file="vschema_customer_sharded.json" customer 387 if [ $? -ne 0 ]; then 388 echo "ApplyVschema customer_sharded during resharding failed" 389 printMysqlErrorFiles 390 exit 1 391 fi 392 sleep 4 393 applySchemaWithRetry create_customer_sharded.sql customer 394 sleep 4 395 396 echo "Apply 302_new_shards.yaml" 397 changeImageAndApply 302_new_shards.yaml 398 checkPodStatusWithTimeout "example-vttablet-zone1(.*)3/3(.*)Running(.*)" 8 399 400 killall kubectl 401 ./pf.sh > /dev/null 2>&1 & 402 sleep 5 403 404 waitForKeyspaceToBeServing customer -80 1 405 waitForKeyspaceToBeServing customer 80- 1 406 407 echo "Ready to reshard ..." 408 sleep 15 409 410 vtctldclient LegacyVtctlCommand -- Reshard --source_shards '-' --target_shards '-80,80-' Create customer.cust2cust 411 if [ $? -ne 0 ]; then 412 echo "Reshard Create failed" 413 printMysqlErrorFiles 414 exit 1 415 fi 416 417 sleep 15 418 419 vdiff_out=$(vtctldclient LegacyVtctlCommand -- VDiff customer.cust2cust) 420 echo "$vdiff_out" | grep "ProcessedRows: 5" | wc -l | grep "2" > /dev/null 421 if [ $? -ne 0 ]; then 422 echo -e "VDiff output is invalid, got:\n$vdiff_out" 423 # Allow failure 424 fi 425 426 vtctldclient LegacyVtctlCommand -- Reshard --tablet_types='rdonly,replica' SwitchTraffic customer.cust2cust 427 if [ $? -ne 0 ]; then 428 echo "Reshard SwitchTraffic for replica,rdonly failed" 429 printMysqlErrorFiles 430 exit 1 431 fi 432 vtctldclient LegacyVtctlCommand -- Reshard --tablet_types='primary' SwitchTraffic customer.cust2cust 433 if [ $? -ne 0 ]; then 434 echo "Reshard SwitchTraffic for primary failed" 435 printMysqlErrorFiles 436 exit 1 437 fi 438 439 sleep 10 440 441 assertSelect ../common/select_customer-80_data.sql "customer/-80" << EOF 442 Using customer/-80 443 Customer 444 +-------------+--------------------+ 445 | customer_id | email | 446 +-------------+--------------------+ 447 | 1 | alice@domain.com | 448 | 2 | bob@domain.com | 449 | 3 | charlie@domain.com | 450 | 5 | eve@domain.com | 451 +-------------+--------------------+ 452 COrder 453 +----------+-------------+----------+-------+ 454 | order_id | customer_id | sku | price | 455 +----------+-------------+----------+-------+ 456 | 1 | 1 | SKU-1001 | 100 | 457 | 2 | 2 | SKU-1002 | 30 | 458 | 3 | 3 | SKU-1002 | 30 | 459 | 5 | 5 | SKU-1002 | 30 | 460 +----------+-------------+----------+-------+ 461 EOF 462 463 assertSelect ../common/select_customer80-_data.sql "customer/80-" << EOF 464 Using customer/80- 465 Customer 466 +-------------+----------------+ 467 | customer_id | email | 468 +-------------+----------------+ 469 | 4 | dan@domain.com | 470 +-------------+----------------+ 471 COrder 472 +----------+-------------+----------+-------+ 473 | order_id | customer_id | sku | price | 474 +----------+-------------+----------+-------+ 475 | 4 | 4 | SKU-1002 | 30 | 476 +----------+-------------+----------+-------+ 477 EOF 478 479 changeImageAndApply 306_down_shard_0.yaml 480 checkPodStatusWithTimeout "example-vttablet-zone1(.*)3/3(.*)Running(.*)" 6 481 waitForKeyspaceToBeServing customer -80 1 482 waitForKeyspaceToBeServing customer 80- 1 483 } 484 485 486 # Build the docker image for vitess/lite using the local code 487 docker build -f docker/lite/Dockerfile -t vitess/lite:pr . 488 # Build the docker image for vitess/vtadmin using the local code 489 docker build -f docker/base/Dockerfile -t vitess/base:pr . 490 docker build -f docker/k8s/Dockerfile --build-arg VT_BASE_VER=pr -t vitess/k8s:pr . 491 docker build -f docker/k8s/vtadmin/Dockerfile --build-arg VT_BASE_VER=pr -t vitess/vtadmin:pr . 492 493 # Print the docker images available 494 docker image ls 495 496 echo "Creating Kind cluster" 497 kind create cluster --wait 30s --name kind 498 echo "Loading docker images into Kind cluster" 499 kind load docker-image vitess/lite:pr --name kind 500 kind load docker-image vitess/vtadmin:pr --name kind 501 502 cd "./examples/operator" 503 killall kubectl 504 505 # Start all the vitess components 506 get_started 507 checkSemiSyncSetup 508 509 # Check Vtadmin is setup 510 # In get_started we verify that the pod for vtadmin exists and is healthy 511 # We now try and query the vtadmin api 512 verifyVtadminSetup 513 # Next we check that VTOrc is running properly and is able to fix issues as they come up 514 verifyVTOrcSetup 515 move_tables 516 resharding 517 518 # Teardown 519 echo "Deleting Kind cluster. This also deletes the volume associated with it" 520 kind delete cluster --name kind