github.com/pingcap/ticdc@v0.0.0-20220526033649-485a10ef2652/integration/framework/docker_env.go (about)

     1  // Copyright 2020 PingCAP, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  package framework
    15  
    16  import (
    17  	"context"
    18  	"database/sql"
    19  	"fmt"
    20  	"os/exec"
    21  
    22  	"github.com/pingcap/log"
    23  	cerrors "github.com/pingcap/ticdc/pkg/errors"
    24  	"github.com/pingcap/ticdc/pkg/retry"
    25  	"go.uber.org/zap"
    26  )
    27  
    28  const (
    29  	// UpstreamDSN is upstream database dsn
    30  	UpstreamDSN = "root@tcp(127.0.0.1:4000)/"
    31  	// DownstreamDSN is downstream database dsn
    32  	DownstreamDSN = "root@tcp(127.0.0.1:5000)/"
    33  )
    34  
    35  // DockerEnv represents the docker-compose service
    36  type DockerEnv struct {
    37  	DockerComposeOperator
    38  }
    39  
    40  // Reset implements Environment
    41  func (e *DockerEnv) Reset() {
    42  	stdout, err := e.ExecInController(`/cdc cli unsafe reset --no-confirm --pd="http://upstream-pd:2379"`)
    43  	if err != nil {
    44  		log.Fatal("ResetEnv: cannot reset the cdc cluster", zap.ByteString("stdout", stdout), zap.Error(err))
    45  	}
    46  	log.Info("ResetEnv: reset the cdc cluster", zap.ByteString("stdout", stdout))
    47  
    48  	upstream, err := sql.Open("mysql", UpstreamDSN)
    49  	if err != nil {
    50  		log.Fatal("ResetEnv: cannot connect to upstream database", zap.Error(err))
    51  	}
    52  	defer upstream.Close()
    53  	if err := dropAllSchemas(upstream); err != nil {
    54  		log.Fatal("ResetEnv: error found when dropping all schema", zap.Error(err))
    55  	}
    56  
    57  	downstream, err := sql.Open("mysql", DownstreamDSN)
    58  	if err != nil {
    59  		log.Fatal("ResetEnv: cannot connect to downstream database", zap.Error(err))
    60  	}
    61  	defer downstream.Close()
    62  	if err := dropAllSchemas(downstream); err != nil {
    63  		log.Fatal("ResetEnv: error found when dropping all schema", zap.Error(err))
    64  	}
    65  }
    66  
    67  // RunTest implements Environment
    68  func (e *DockerEnv) RunTest(task Task) {
    69  	cmdLine := "/cdc " + task.GetCDCProfile().String()
    70  	bytes, err := e.ExecInController(cmdLine)
    71  	if err != nil {
    72  		log.Fatal("RunTest failed: cannot setup changefeed",
    73  			zap.Error(err),
    74  			zap.ByteString("stdout", bytes),
    75  			zap.ByteString("stderr", err.(*exec.ExitError).Stderr))
    76  	}
    77  
    78  	upstream, err := sql.Open("mysql", UpstreamDSN)
    79  	if err != nil {
    80  		log.Fatal("RunTest: cannot connect to upstream database", zap.Error(err))
    81  	}
    82  
    83  	downstream, err := sql.Open("mysql", DownstreamDSN)
    84  	if err != nil {
    85  		log.Fatal("RunTest: cannot connect to downstream database", zap.Error(err))
    86  	}
    87  
    88  	taskCtx := &TaskContext{
    89  		Upstream:   upstream,
    90  		Downstream: downstream,
    91  		Env:        e,
    92  		WaitForReady: func() error {
    93  			return retry.Do(context.Background(), e.HealthChecker, retry.WithBackoffBaseDelay(1000), retry.WithMaxTries(120), retry.WithIsRetryableErr(cerrors.IsRetryableError))
    94  		},
    95  		Ctx: context.Background(),
    96  	}
    97  
    98  	err = task.Prepare(taskCtx)
    99  	if err != nil {
   100  		e.TearDown()
   101  		log.Fatal("RunTest: task preparation failed", zap.String("name", task.Name()), zap.Error(err))
   102  	}
   103  
   104  	log.Info("Start running task", zap.String("name", task.Name()))
   105  	err = task.Run(taskCtx)
   106  	if err != nil {
   107  		err1 := e.DumpStdout()
   108  		if err1 != nil {
   109  			log.Warn("Failed to dump container logs", zap.Error(err1))
   110  		}
   111  		e.TearDown()
   112  		log.Fatal("RunTest: task failed", zap.String("name", task.Name()), zap.Error(err))
   113  	}
   114  	log.Info("Finished running task", zap.String("name", task.Name()))
   115  }
   116  
   117  // SetListener implements Environment. Currently unfinished, will be used to monitor Kafka output
   118  func (e *DockerEnv) SetListener(states interface{}, listener MqListener) {
   119  	// TODO
   120  }
   121  
   122  var systemSchema = map[string]struct{}{
   123  	"INFORMATION_SCHEMA": {},
   124  	"METRICS_SCHEMA":     {},
   125  	"PERFORMANCE_SCHEMA": {},
   126  	"mysql":              {},
   127  }
   128  
   129  func dropAllSchemas(db *sql.DB) error {
   130  	result, err := db.Query("show databases;")
   131  	if err != nil {
   132  		return err
   133  	}
   134  	var schemaNames []string
   135  	var schema string
   136  	for result.Next() {
   137  		err := result.Scan(&schema)
   138  		if err != nil {
   139  			return err
   140  		}
   141  		schemaNames = append(schemaNames, schema)
   142  	}
   143  	for _, schema := range schemaNames {
   144  		if _, ok := systemSchema[schema]; ok {
   145  			continue
   146  		}
   147  		_, err := db.Exec(fmt.Sprintf("drop database %s;", schema))
   148  		if err != nil {
   149  			return err
   150  		}
   151  	}
   152  	return nil
   153  }