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