vitess.io/vitess@v0.16.2/go/test/endtoend/docker/vttestserver.go (about)

     1  /*
     2  Copyright 2021 The Vitess Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package docker
    18  
    19  import (
    20  	"encoding/json"
    21  	"fmt"
    22  	"os"
    23  	"os/exec"
    24  	"path"
    25  	"strconv"
    26  	"strings"
    27  	"time"
    28  
    29  	"vitess.io/vitess/go/vt/log"
    30  )
    31  
    32  const (
    33  	vttestserverMysql57image = "vttestserver-e2etest/mysql57"
    34  	vttestserverMysql80image = "vttestserver-e2etest/mysql80"
    35  )
    36  
    37  type vttestserver struct {
    38  	dockerImage          string
    39  	keyspaces            []string
    40  	numShards            []int
    41  	mysqlMaxConnecetions int
    42  	port                 int
    43  }
    44  
    45  func newVttestserver(dockerImage string, keyspaces []string, numShards []int, mysqlMaxConnections, port int) *vttestserver {
    46  	return &vttestserver{
    47  		dockerImage:          dockerImage,
    48  		keyspaces:            keyspaces,
    49  		numShards:            numShards,
    50  		mysqlMaxConnecetions: mysqlMaxConnections,
    51  		port:                 port,
    52  	}
    53  }
    54  
    55  func (v *vttestserver) teardown() {
    56  	cmd := exec.Command("docker", "rm", "--force", "vttestserver-end2end-test")
    57  	err := cmd.Run()
    58  	if err != nil {
    59  		log.Errorf("docker teardown failed :- %s", err.Error())
    60  	}
    61  }
    62  
    63  // startDockerImage starts the docker image for the vttestserver
    64  func (v *vttestserver) startDockerImage() error {
    65  	cmd := exec.Command("docker", "run")
    66  	cmd.Args = append(cmd.Args, "--name=vttestserver-end2end-test")
    67  	cmd.Args = append(cmd.Args, "-p", fmt.Sprintf("%d:33577", v.port))
    68  	cmd.Args = append(cmd.Args, "-e", "PORT=33574")
    69  	cmd.Args = append(cmd.Args, "-e", fmt.Sprintf("KEYSPACES=%s", strings.Join(v.keyspaces, ",")))
    70  	cmd.Args = append(cmd.Args, "-e", fmt.Sprintf("NUM_SHARDS=%s", strings.Join(convertToStringSlice(v.numShards), ",")))
    71  	cmd.Args = append(cmd.Args, "-e", "MYSQL_BIND_HOST=0.0.0.0")
    72  	cmd.Args = append(cmd.Args, "-e", fmt.Sprintf("MYSQL_MAX_CONNECTIONS=%d", v.mysqlMaxConnecetions))
    73  	cmd.Args = append(cmd.Args, "--health-cmd", "mysqladmin ping -h127.0.0.1 -P33577")
    74  	cmd.Args = append(cmd.Args, "--health-interval=5s")
    75  	cmd.Args = append(cmd.Args, "--health-timeout=2s")
    76  	cmd.Args = append(cmd.Args, "--health-retries=5")
    77  	cmd.Args = append(cmd.Args, v.dockerImage)
    78  
    79  	err := cmd.Start()
    80  	if err != nil {
    81  		return err
    82  	}
    83  	return nil
    84  }
    85  
    86  // dockerStatus is a struct used to unmarshal json output from `docker inspect`
    87  type dockerStatus struct {
    88  	State struct {
    89  		Health struct {
    90  			Status string
    91  		}
    92  	}
    93  }
    94  
    95  // waitUntilDockerHealthy waits until the docker image is healthy. It takes in as argument the amount of seconds to wait before timeout
    96  func (v *vttestserver) waitUntilDockerHealthy(timeoutDelay int) error {
    97  	timeOut := time.After(time.Duration(timeoutDelay) * time.Second)
    98  
    99  	for {
   100  		select {
   101  		case <-timeOut:
   102  			// return error due to timeout
   103  			return fmt.Errorf("timed out waiting for docker image to start")
   104  		case <-time.After(time.Second):
   105  			cmd := exec.Command("docker", "inspect", "vttestserver-end2end-test")
   106  			out, err := cmd.Output()
   107  			if err != nil {
   108  				return err
   109  			}
   110  			var x []dockerStatus
   111  			err = json.Unmarshal(out, &x)
   112  			if err != nil {
   113  				return err
   114  			}
   115  			if len(x) > 0 {
   116  				status := x[0].State.Health.Status
   117  				if status == "healthy" {
   118  					return nil
   119  				}
   120  			}
   121  		}
   122  	}
   123  }
   124  
   125  // convertToStringSlice converts an integer slice to string slice
   126  func convertToStringSlice(intSlice []int) []string {
   127  	var stringSlice []string
   128  	for _, val := range intSlice {
   129  		str := strconv.Itoa(val)
   130  		stringSlice = append(stringSlice, str)
   131  	}
   132  	return stringSlice
   133  }
   134  
   135  // makeVttestserverDockerImages creates the vttestserver docker images for both MySQL57 and MySQL80
   136  func makeVttestserverDockerImages() error {
   137  	mainVitessPath := path.Join(os.Getenv("PWD"), "../../../..")
   138  	dockerFilePath := path.Join(mainVitessPath, "docker/vttestserver/Dockerfile.mysql57")
   139  	cmd57 := exec.Command("docker", "build", "-f", dockerFilePath, "-t", vttestserverMysql57image, ".")
   140  	cmd57.Dir = mainVitessPath
   141  	err := cmd57.Start()
   142  	if err != nil {
   143  		return err
   144  	}
   145  
   146  	dockerFilePath = path.Join(mainVitessPath, "docker/vttestserver/Dockerfile.mysql80")
   147  	cmd80 := exec.Command("docker", "build", "-f", dockerFilePath, "-t", vttestserverMysql80image, ".")
   148  	cmd80.Dir = mainVitessPath
   149  	err = cmd80.Start()
   150  	if err != nil {
   151  		return err
   152  	}
   153  
   154  	err = cmd57.Wait()
   155  	if err != nil {
   156  		return err
   157  	}
   158  
   159  	err = cmd80.Wait()
   160  	if err != nil {
   161  		return err
   162  	}
   163  
   164  	return nil
   165  }